mirror of
https://github.com/jbeder/yaml-cpp.git
synced 2025-09-09 12:41:17 +00:00
Compare commits
75 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
aa8d4e4750 | ||
![]() |
2f86d13775 | ||
![]() |
c9371de783 | ||
![]() |
28f93bdec6 | ||
![]() |
39f737443b | ||
![]() |
73ef0060aa | ||
![]() |
7470c2d871 | ||
![]() |
8a9a7b74ef | ||
![]() |
d45c4fba3e | ||
![]() |
61db89741d | ||
![]() |
7def2046ff | ||
![]() |
1da813f56a | ||
![]() |
f878043f12 | ||
![]() |
9ce5a25188 | ||
![]() |
ebfbf27115 | ||
![]() |
06ffaf3104 | ||
![]() |
0b945415fd | ||
![]() |
82f3c04081 | ||
![]() |
d8de96524c | ||
![]() |
5d9e4b6251 | ||
![]() |
28c0a1bc25 | ||
![]() |
72865f7d32 | ||
![]() |
f4bca79dc4 | ||
![]() |
d4e00bd473 | ||
![]() |
bd070a7b76 | ||
![]() |
3d2888cc8a | ||
![]() |
c2bec4c755 | ||
![]() |
29c59c01d4 | ||
![]() |
bc67157109 | ||
![]() |
da82fd982c | ||
![]() |
1f2b841949 | ||
![]() |
47cd2725d6 | ||
![]() |
850ec4f39e | ||
![]() |
84459a7f98 | ||
![]() |
ee9c4d19be | ||
![]() |
b38ac5b55f | ||
![]() |
7b469b4220 | ||
![]() |
8fbf344aee | ||
![]() |
06c3d1db51 | ||
![]() |
04dddd6999 | ||
![]() |
1f5e971f77 | ||
![]() |
b11eaf1631 | ||
![]() |
9f7babc3ff | ||
![]() |
b95aa146ec | ||
![]() |
1d8ca1f35e | ||
![]() |
76dc671573 | ||
![]() |
5c1bbbd276 | ||
![]() |
4afd53b0d3 | ||
![]() |
96f5c887f3 | ||
![]() |
c67d701ad8 | ||
![]() |
9eb1142900 | ||
![]() |
c28295bda4 | ||
![]() |
94710bb221 | ||
![]() |
c7639e81d5 | ||
![]() |
f30582fb09 | ||
![]() |
eaf7205372 | ||
![]() |
1c5a38eef3 | ||
![]() |
51adc5f739 | ||
![]() |
30e6933279 | ||
![]() |
db03655d58 | ||
![]() |
145eec5f3e | ||
![]() |
f791b955d8 | ||
![]() |
4fc5ec36bc | ||
![]() |
8106fcf1e5 | ||
![]() |
c26e047223 | ||
![]() |
ac144ed46c | ||
![]() |
4c061a5058 | ||
![]() |
37f1b8b8c9 | ||
![]() |
d046eea331 | ||
![]() |
9f31491b0f | ||
![]() |
016b2e7769 | ||
![]() |
2383e6d0f2 | ||
![]() |
6262201182 | ||
![]() |
fcbb8193b9 | ||
![]() |
c268020048 |
1
.bazelignore
Normal file
1
.bazelignore
Normal file
@@ -0,0 +1 @@
|
||||
test/googletest-1.13.0
|
@@ -8,7 +8,7 @@ EXAMPLE_PATH =
|
||||
|
||||
# One or more directories and files to exclude from documentation generation.
|
||||
# Use relative paths with respect to the repository root directory.
|
||||
EXCLUDE = test/gtest-1.8.0/
|
||||
EXCLUDE = test/googletest-1.13.0/
|
||||
|
||||
# One or more wildcard patterns to exclude files and directories from document
|
||||
# generation.
|
||||
|
11
.github/dependabot.yml
vendored
Normal file
11
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "monthly"
|
||||
groups:
|
||||
github-actions:
|
||||
patterns:
|
||||
- "*"
|
||||
|
103
.github/workflows/build.yml
vendored
103
.github/workflows/build.yml
vendored
@@ -6,49 +6,101 @@ on:
|
||||
branches: [ master ]
|
||||
workflow_dispatch:
|
||||
permissions: read-all
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
jobs:
|
||||
cmake-build:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||
cxx_standard: [11, 17, 20]
|
||||
build: [static, shared]
|
||||
googletest: [build, system]
|
||||
generator: ["Default Generator", "MinGW Makefiles"]
|
||||
exclude:
|
||||
- os: ubuntu-latest
|
||||
cxx_standard: 11
|
||||
googletest: system
|
||||
- os: macos-latest
|
||||
build: shared
|
||||
- os: macos-latest
|
||||
generator: "MinGW Makefiles"
|
||||
- os: ubuntu-latest
|
||||
generator: "MinGW Makefiles"
|
||||
- os: macos-latest
|
||||
googletest: system
|
||||
- os: windows-latest
|
||||
googletest: system
|
||||
env:
|
||||
YAML_BUILD_SHARED_LIBS: ${{ matrix.build == 'shared' && 'ON' || 'OFF' }}
|
||||
YAML_CPP_BUILD_TESTS: 'ON'
|
||||
YAML_USE_SYSTEM_GTEST: ${{ matrix.googletest == 'system' && 'ON' || 'OFF' }}
|
||||
CMAKE_GENERATOR: >-
|
||||
${{format(matrix.generator != 'Default Generator' && '-G "{0}"' || '', matrix.generator)}}
|
||||
CMAKE_INSTALL_PREFIX: "${{ github.workspace }}/install-prefix"
|
||||
CMAKE_BUILD_TYPE: Debug
|
||||
CMAKE_CXX_FLAGS_DEBUG: ${{ matrix.googletest == 'build' && '-g -D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC' || '-g' }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Get number of CPU cores
|
||||
uses: SimenB/github-actions-cpu-cores@v1
|
||||
- uses: awalsh128/cache-apt-pkgs-action@latest
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
with:
|
||||
packages: googletest libgmock-dev libgtest-dev
|
||||
version: 1.0
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Configure
|
||||
run: |
|
||||
cmake \
|
||||
${{ env.CMAKE_GENERATOR }} \
|
||||
-S "${{ github.workspace }}" \
|
||||
-B build \
|
||||
-D CMAKE_CXX_STANDARD=${{ matrix.cxx_standard }} \
|
||||
-D CMAKE_INSTALL_PREFIX="${{ env.CMAKE_INSTALL_PREFIX }}" \
|
||||
-D CMAKE_BUILD_TYPE=${{ env.CMAKE_BUILD_TYPE }} \
|
||||
-D CMAKE_CXX_FLAGS_DEBUG="${{ env.CMAKE_CXX_FLAGS_DEBUG }}" \
|
||||
-D YAML_BUILD_SHARED_LIBS=${{ env.YAML_BUILD_SHARED_LIBS }} \
|
||||
-D YAML_USE_SYSTEM_GTEST=${{ env.YAML_USE_SYSTEM_GTEST }} \
|
||||
-D YAML_CPP_BUILD_TESTS=ON
|
||||
|
||||
- name: Build
|
||||
shell: bash
|
||||
run: |
|
||||
cmake ${{ env.CMAKE_GENERATOR }} -S "${{ github.workspace }}" -B build -DYAML_BUILD_SHARED_LIBS=${{ env.YAML_BUILD_SHARED_LIBS }}
|
||||
cd build && cmake --build . --parallel ${{ steps.cpu-cores.outputs.count }}
|
||||
|
||||
- name: Build Tests
|
||||
shell: bash
|
||||
run: |
|
||||
cmake ${{ env.CMAKE_GENERATOR }} -S "${{ github.workspace }}" -B build -DYAML_BUILD_SHARED_LIBS=${{ env.YAML_BUILD_SHARED_LIBS }} -DYAML_CPP_BUILD_TESTS=${{ env.YAML_CPP_BUILD_TESTS }}
|
||||
cd build && cmake --build . --parallel ${{ steps.cpu-cores.outputs.count }}
|
||||
cmake \
|
||||
--build build \
|
||||
--config ${{ env.CMAKE_BUILD_TYPE }} \
|
||||
--verbose \
|
||||
--parallel
|
||||
|
||||
- name: Run Tests
|
||||
shell: bash
|
||||
run: |
|
||||
cd build && ctest -C Debug --output-on-failure --verbose
|
||||
ctest \
|
||||
--test-dir build \
|
||||
--build-config ${{ env.CMAKE_BUILD_TYPE }} \
|
||||
--output-on-failure \
|
||||
--verbose
|
||||
|
||||
- name: Install
|
||||
run: cmake --install build --config ${{ env.CMAKE_BUILD_TYPE }}
|
||||
|
||||
- name: Configure CMake package test
|
||||
run: |
|
||||
cmake \
|
||||
${{ env.CMAKE_GENERATOR }} \
|
||||
-S "${{ github.workspace }}/test/cmake" \
|
||||
-B consumer-build \
|
||||
-D CMAKE_BUILD_TYPE=${{ env.CMAKE_BUILD_TYPE }} \
|
||||
-D CMAKE_PREFIX_PATH="${{ env.CMAKE_INSTALL_PREFIX }}"
|
||||
|
||||
- name: Build CMake package test
|
||||
run: |
|
||||
cmake \
|
||||
--build consumer-build \
|
||||
--config ${{ env.CMAKE_BUILD_TYPE }} \
|
||||
--verbose
|
||||
|
||||
bazel-build:
|
||||
strategy:
|
||||
@@ -56,17 +108,34 @@ jobs:
|
||||
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Build
|
||||
shell: bash
|
||||
run: |
|
||||
cd "${{ github.workspace }}"
|
||||
bazel build :all
|
||||
|
||||
- name: Test
|
||||
shell: bash
|
||||
run: |
|
||||
cd "${{ github.workspace }}"
|
||||
bazel test test
|
||||
|
||||
bzlmod-build:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Build
|
||||
shell: bash
|
||||
run: |
|
||||
cd "${{ github.workspace }}"
|
||||
bazel build --enable_bzlmod :all
|
||||
|
||||
- name: Test
|
||||
shell: bash
|
||||
run: |
|
||||
cd "${{ github.workspace }}"
|
||||
bazel test --enable_bzlmod test
|
||||
|
19
.github/workflows/bzlmod-archive.yml
vendored
Normal file
19
.github/workflows/bzlmod-archive.yml
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
name: Bazel Release
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
jobs:
|
||||
# A release archive is required for bzlmod
|
||||
# See: https://blog.bazel.build/2023/02/15/github-archive-checksum.html
|
||||
bazel-release-archive:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
- run: git archive $GITHUB_REF -o "yaml-cpp-${GITHUB_REF:10}.tar.gz"
|
||||
- run: gh release upload ${GITHUB_REF:10} "yaml-cpp-${GITHUB_REF:10}.tar.gz"
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
@@ -1,5 +1,6 @@
|
||||
# 3.5 is actually available almost everywhere, but this a good minimum
|
||||
cmake_minimum_required(VERSION 3.4)
|
||||
# 3.5 is actually available almost everywhere.
|
||||
# 3.30 as the upper policy limit avoids CMake deprecation warnings.
|
||||
cmake_minimum_required(VERSION 3.5...3.30)
|
||||
|
||||
# enable MSVC_RUNTIME_LIBRARY target property
|
||||
# see https://cmake.org/cmake/help/latest/policy/CMP0091.html
|
||||
@@ -24,13 +25,19 @@ option(YAML_CPP_BUILD_CONTRIB "Enable yaml-cpp contrib in library" ON)
|
||||
option(YAML_CPP_BUILD_TOOLS "Enable parse tools" ON)
|
||||
option(YAML_BUILD_SHARED_LIBS "Build yaml-cpp shared library" ${BUILD_SHARED_LIBS})
|
||||
option(YAML_CPP_INSTALL "Enable generation of yaml-cpp install targets" ${YAML_CPP_MAIN_PROJECT})
|
||||
option(YAML_CPP_FORMAT_SOURCE "Format source" ON)
|
||||
option(YAML_CPP_FORMAT_SOURCE "Format source" ${YAML_CPP_MAIN_PROJECT})
|
||||
option(YAML_CPP_DISABLE_UNINSTALL "Disable uninstallation of yaml-cpp" OFF)
|
||||
option(YAML_USE_SYSTEM_GTEST "Use system googletest if found" OFF)
|
||||
option(YAML_ENABLE_PIC "Use Position-Independent Code " ON)
|
||||
|
||||
cmake_dependent_option(YAML_CPP_BUILD_TESTS
|
||||
"Enable yaml-cpp tests" OFF
|
||||
"BUILD_TESTING;YAML_CPP_MAIN_PROJECT" OFF)
|
||||
cmake_dependent_option(YAML_MSVC_SHARED_RT
|
||||
"MSVC: Build yaml-cpp with shared runtime libs (/MD)" ON
|
||||
"CMAKE_SYSTEM_NAME MATCHES Windows" OFF)
|
||||
set(YAML_CPP_INSTALL_CMAKEDIR "${CMAKE_INSTALL_LIBDIR}/cmake/yaml-cpp"
|
||||
CACHE STRING "Path to install the CMake package to")
|
||||
|
||||
if (YAML_CPP_FORMAT_SOURCE)
|
||||
find_program(YAML_CPP_CLANG_FORMAT_EXE NAMES clang-format)
|
||||
@@ -85,7 +92,7 @@ set_property(TARGET yaml-cpp
|
||||
CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
if (NOT YAML_BUILD_SHARED_LIBS)
|
||||
set_property(TARGET yaml-cpp PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
set_property(TARGET yaml-cpp PROPERTY POSITION_INDEPENDENT_CODE ${YAML_ENABLE_PIC})
|
||||
endif()
|
||||
|
||||
target_include_directories(yaml-cpp
|
||||
@@ -143,13 +150,12 @@ set_target_properties(yaml-cpp PROPERTIES
|
||||
PROJECT_LABEL "yaml-cpp ${yaml-cpp-label-postfix}"
|
||||
DEBUG_POSTFIX "${CMAKE_DEBUG_POSTFIX}")
|
||||
|
||||
set(CONFIG_EXPORT_DIR "${CMAKE_INSTALL_LIBDIR}/cmake/yaml-cpp")
|
||||
set(EXPORT_TARGETS yaml-cpp)
|
||||
set(EXPORT_TARGETS yaml-cpp::yaml-cpp)
|
||||
configure_package_config_file(
|
||||
"${PROJECT_SOURCE_DIR}/yaml-cpp-config.cmake.in"
|
||||
"${PROJECT_BINARY_DIR}/yaml-cpp-config.cmake"
|
||||
INSTALL_DESTINATION "${CONFIG_EXPORT_DIR}"
|
||||
PATH_VARS CMAKE_INSTALL_INCLUDEDIR CMAKE_INSTALL_LIBDIR CONFIG_EXPORT_DIR YAML_BUILD_SHARED_LIBS)
|
||||
INSTALL_DESTINATION "${YAML_CPP_INSTALL_CMAKEDIR}"
|
||||
PATH_VARS CMAKE_INSTALL_INCLUDEDIR CMAKE_INSTALL_LIBDIR)
|
||||
unset(EXPORT_TARGETS)
|
||||
|
||||
write_basic_package_version_file(
|
||||
@@ -169,15 +175,14 @@ if (YAML_CPP_INSTALL)
|
||||
FILES_MATCHING PATTERN "*.h")
|
||||
install(EXPORT yaml-cpp-targets
|
||||
NAMESPACE yaml-cpp::
|
||||
DESTINATION "${CONFIG_EXPORT_DIR}")
|
||||
DESTINATION "${YAML_CPP_INSTALL_CMAKEDIR}")
|
||||
install(FILES
|
||||
"${PROJECT_BINARY_DIR}/yaml-cpp-config.cmake"
|
||||
"${PROJECT_BINARY_DIR}/yaml-cpp-config-version.cmake"
|
||||
DESTINATION "${CONFIG_EXPORT_DIR}")
|
||||
DESTINATION "${YAML_CPP_INSTALL_CMAKEDIR}")
|
||||
install(FILES "${PROJECT_BINARY_DIR}/yaml-cpp.pc"
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
|
||||
endif()
|
||||
unset(CONFIG_EXPORT_DIR)
|
||||
|
||||
if(YAML_CPP_BUILD_TESTS)
|
||||
add_subdirectory(test)
|
||||
@@ -192,11 +197,12 @@ if (YAML_CPP_FORMAT_SOURCE AND YAML_CPP_CLANG_FORMAT_EXE)
|
||||
COMMAND clang-format --style=file -i $<TARGET_PROPERTY:yaml-cpp,SOURCES>
|
||||
COMMAND_EXPAND_LISTS
|
||||
COMMENT "Running clang-format"
|
||||
WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}"
|
||||
VERBATIM)
|
||||
endif()
|
||||
|
||||
# uninstall target
|
||||
if(NOT TARGET uninstall)
|
||||
if(YAML_CPP_INSTALL AND NOT YAML_CPP_DISABLE_UNINSTALL AND NOT TARGET uninstall)
|
||||
configure_file(
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake"
|
||||
|
@@ -17,9 +17,9 @@ Commit messages should be in the imperative mood, as described in the [Git contr
|
||||
|
||||
# Tests
|
||||
|
||||
Please verify the tests pass by running the target `test/yaml-cpp-tests`.
|
||||
Please verify the tests pass by configuring CMake with `-D YAML_CPP_BUILD_TESTS=ON` and running the target `test/yaml-cpp-tests`.
|
||||
|
||||
If you are adding functionality, add tests accordingly.
|
||||
If you are adding functionality, add tests accordingly. Note that the "spec tests" are reserved for examples directly from the YAML spec, so if you have new examples, put them in other test files.
|
||||
|
||||
# Pull request process
|
||||
|
||||
|
14
MODULE.bazel
Normal file
14
MODULE.bazel
Normal file
@@ -0,0 +1,14 @@
|
||||
"""
|
||||
yaml-cpp is a YAML parser and emitter in c++ matching the YAML specification.
|
||||
"""
|
||||
|
||||
module(
|
||||
name = "yaml-cpp",
|
||||
compatibility_level = 1,
|
||||
version = "0.8.0",
|
||||
)
|
||||
|
||||
bazel_dep(name = "platforms", version = "0.0.7")
|
||||
bazel_dep(name = "rules_cc", version = "0.0.8")
|
||||
|
||||
bazel_dep(name = "googletest", version = "1.14.0", dev_dependency = True)
|
114
MODULE.bazel.lock
generated
Normal file
114
MODULE.bazel.lock
generated
Normal file
@@ -0,0 +1,114 @@
|
||||
{
|
||||
"lockFileVersion": 11,
|
||||
"registryFileHashes": {
|
||||
"https://bcr.bazel.build/bazel_registry.json": "8a28e4aff06ee60aed2a8c281907fb8bcbf3b753c91fb5a5c57da3215d5b3497",
|
||||
"https://bcr.bazel.build/modules/abseil-cpp/20210324.2/MODULE.bazel": "7cd0312e064fde87c8d1cd79ba06c876bd23630c83466e9500321be55c96ace2",
|
||||
"https://bcr.bazel.build/modules/abseil-cpp/20211102.0/MODULE.bazel": "70390338f7a5106231d20620712f7cccb659cd0e9d073d1991c038eb9fc57589",
|
||||
"https://bcr.bazel.build/modules/abseil-cpp/20230125.1/MODULE.bazel": "89047429cb0207707b2dface14ba7f8df85273d484c2572755be4bab7ce9c3a0",
|
||||
"https://bcr.bazel.build/modules/abseil-cpp/20230125.1/source.json": "06cc0842d241da0c5edc755edb3c7d0d008d304330e57ecf2d6449fb0b633a82",
|
||||
"https://bcr.bazel.build/modules/apple_support/1.5.0/MODULE.bazel": "50341a62efbc483e8a2a6aec30994a58749bd7b885e18dd96aa8c33031e558ef",
|
||||
"https://bcr.bazel.build/modules/apple_support/1.5.0/source.json": "eb98a7627c0bc486b57f598ad8da50f6625d974c8f723e9ea71bd39f709c9862",
|
||||
"https://bcr.bazel.build/modules/bazel_features/1.11.0/MODULE.bazel": "f9382337dd5a474c3b7d334c2f83e50b6eaedc284253334cf823044a26de03e8",
|
||||
"https://bcr.bazel.build/modules/bazel_features/1.11.0/source.json": "c9320aa53cd1c441d24bd6b716da087ad7e4ff0d9742a9884587596edfe53015",
|
||||
"https://bcr.bazel.build/modules/bazel_skylib/1.0.3/MODULE.bazel": "bcb0fd896384802d1ad283b4e4eb4d718eebd8cb820b0a2c3a347fb971afd9d8",
|
||||
"https://bcr.bazel.build/modules/bazel_skylib/1.2.1/MODULE.bazel": "f35baf9da0efe45fa3da1696ae906eea3d615ad41e2e3def4aeb4e8bc0ef9a7a",
|
||||
"https://bcr.bazel.build/modules/bazel_skylib/1.3.0/MODULE.bazel": "20228b92868bf5cfc41bda7afc8a8ba2a543201851de39d990ec957b513579c5",
|
||||
"https://bcr.bazel.build/modules/bazel_skylib/1.4.1/MODULE.bazel": "a0dcb779424be33100dcae821e9e27e4f2901d9dfd5333efe5ac6a8d7ab75e1d",
|
||||
"https://bcr.bazel.build/modules/bazel_skylib/1.6.1/MODULE.bazel": "8fdee2dbaace6c252131c00e1de4b165dc65af02ea278476187765e1a617b917",
|
||||
"https://bcr.bazel.build/modules/bazel_skylib/1.6.1/source.json": "082ed5f9837901fada8c68c2f3ddc958bb22b6d654f71dd73f3df30d45d4b749",
|
||||
"https://bcr.bazel.build/modules/buildozer/7.1.2/MODULE.bazel": "2e8dd40ede9c454042645fd8d8d0cd1527966aa5c919de86661e62953cd73d84",
|
||||
"https://bcr.bazel.build/modules/buildozer/7.1.2/source.json": "c9028a501d2db85793a6996205c8de120944f50a0d570438fcae0457a5f9d1f8",
|
||||
"https://bcr.bazel.build/modules/googletest/1.11.0/MODULE.bazel": "3a83f095183f66345ca86aa13c58b59f9f94a2f81999c093d4eeaa2d262d12f4",
|
||||
"https://bcr.bazel.build/modules/googletest/1.14.0/MODULE.bazel": "cfbcbf3e6eac06ef9d85900f64424708cc08687d1b527f0ef65aa7517af8118f",
|
||||
"https://bcr.bazel.build/modules/googletest/1.14.0/source.json": "2478949479000fdd7de9a3d0107ba2c85bb5f961c3ecb1aa448f52549ce310b5",
|
||||
"https://bcr.bazel.build/modules/platforms/0.0.4/MODULE.bazel": "9b328e31ee156f53f3c416a64f8491f7eb731742655a47c9eec4703a71644aee",
|
||||
"https://bcr.bazel.build/modules/platforms/0.0.5/MODULE.bazel": "5733b54ea419d5eaf7997054bb55f6a1d0b5ff8aedf0176fef9eea44f3acda37",
|
||||
"https://bcr.bazel.build/modules/platforms/0.0.6/MODULE.bazel": "ad6eeef431dc52aefd2d77ed20a4b353f8ebf0f4ecdd26a807d2da5aa8cd0615",
|
||||
"https://bcr.bazel.build/modules/platforms/0.0.7/MODULE.bazel": "72fd4a0ede9ee5c021f6a8dd92b503e089f46c227ba2813ff183b71616034814",
|
||||
"https://bcr.bazel.build/modules/platforms/0.0.9/MODULE.bazel": "4a87a60c927b56ddd67db50c89acaa62f4ce2a1d2149ccb63ffd871d5ce29ebc",
|
||||
"https://bcr.bazel.build/modules/platforms/0.0.9/source.json": "cd74d854bf16a9e002fb2ca7b1a421f4403cda29f824a765acd3a8c56f8d43e6",
|
||||
"https://bcr.bazel.build/modules/protobuf/21.7/MODULE.bazel": "a5a29bb89544f9b97edce05642fac225a808b5b7be74038ea3640fae2f8e66a7",
|
||||
"https://bcr.bazel.build/modules/protobuf/21.7/source.json": "bbe500720421e582ff2d18b0802464205138c06056f443184de39fbb8187b09b",
|
||||
"https://bcr.bazel.build/modules/protobuf/3.19.0/MODULE.bazel": "6b5fbb433f760a99a22b18b6850ed5784ef0e9928a72668b66e4d7ccd47db9b0",
|
||||
"https://bcr.bazel.build/modules/protobuf/3.19.6/MODULE.bazel": "9233edc5e1f2ee276a60de3eaa47ac4132302ef9643238f23128fea53ea12858",
|
||||
"https://bcr.bazel.build/modules/rules_cc/0.0.1/MODULE.bazel": "cb2aa0747f84c6c3a78dad4e2049c154f08ab9d166b1273835a8174940365647",
|
||||
"https://bcr.bazel.build/modules/rules_cc/0.0.2/MODULE.bazel": "6915987c90970493ab97393024c156ea8fb9f3bea953b2f3ec05c34f19b5695c",
|
||||
"https://bcr.bazel.build/modules/rules_cc/0.0.6/MODULE.bazel": "abf360251023dfe3efcef65ab9d56beefa8394d4176dd29529750e1c57eaa33f",
|
||||
"https://bcr.bazel.build/modules/rules_cc/0.0.8/MODULE.bazel": "964c85c82cfeb6f3855e6a07054fdb159aced38e99a5eecf7bce9d53990afa3e",
|
||||
"https://bcr.bazel.build/modules/rules_cc/0.0.9/MODULE.bazel": "836e76439f354b89afe6a911a7adf59a6b2518fafb174483ad78a2a2fde7b1c5",
|
||||
"https://bcr.bazel.build/modules/rules_cc/0.0.9/source.json": "1f1ba6fea244b616de4a554a0f4983c91a9301640c8fe0dd1d410254115c8430",
|
||||
"https://bcr.bazel.build/modules/rules_java/4.0.0/MODULE.bazel": "5a78a7ae82cd1a33cef56dc578c7d2a46ed0dca12643ee45edbb8417899e6f74",
|
||||
"https://bcr.bazel.build/modules/rules_java/7.6.5/MODULE.bazel": "481164be5e02e4cab6e77a36927683263be56b7e36fef918b458d7a8a1ebadb1",
|
||||
"https://bcr.bazel.build/modules/rules_java/7.6.5/source.json": "a805b889531d1690e3c72a7a7e47a870d00323186a9904b36af83aa3d053ee8d",
|
||||
"https://bcr.bazel.build/modules/rules_jvm_external/4.4.2/MODULE.bazel": "a56b85e418c83eb1839819f0b515c431010160383306d13ec21959ac412d2fe7",
|
||||
"https://bcr.bazel.build/modules/rules_jvm_external/4.4.2/source.json": "a075731e1b46bc8425098512d038d416e966ab19684a10a34f4741295642fc35",
|
||||
"https://bcr.bazel.build/modules/rules_license/0.0.3/MODULE.bazel": "627e9ab0247f7d1e05736b59dbb1b6871373de5ad31c3011880b4133cafd4bd0",
|
||||
"https://bcr.bazel.build/modules/rules_license/0.0.7/MODULE.bazel": "088fbeb0b6a419005b89cf93fe62d9517c0a2b8bb56af3244af65ecfe37e7d5d",
|
||||
"https://bcr.bazel.build/modules/rules_license/0.0.7/source.json": "355cc5737a0f294e560d52b1b7a6492d4fff2caf0bef1a315df5a298fca2d34a",
|
||||
"https://bcr.bazel.build/modules/rules_pkg/0.7.0/MODULE.bazel": "df99f03fc7934a4737122518bb87e667e62d780b610910f0447665a7e2be62dc",
|
||||
"https://bcr.bazel.build/modules/rules_pkg/0.7.0/source.json": "c2557066e0c0342223ba592510ad3d812d4963b9024831f7f66fd0584dd8c66c",
|
||||
"https://bcr.bazel.build/modules/rules_proto/4.0.0/MODULE.bazel": "a7a7b6ce9bee418c1a760b3d84f83a299ad6952f9903c67f19e4edd964894e06",
|
||||
"https://bcr.bazel.build/modules/rules_proto/5.3.0-21.7/MODULE.bazel": "e8dff86b0971688790ae75528fe1813f71809b5afd57facb44dad9e8eca631b7",
|
||||
"https://bcr.bazel.build/modules/rules_proto/5.3.0-21.7/source.json": "d57902c052424dfda0e71646cb12668d39c4620ee0544294d9d941e7d12bc3a9",
|
||||
"https://bcr.bazel.build/modules/rules_python/0.10.2/MODULE.bazel": "cc82bc96f2997baa545ab3ce73f196d040ffb8756fd2d66125a530031cd90e5f",
|
||||
"https://bcr.bazel.build/modules/rules_python/0.22.1/MODULE.bazel": "26114f0c0b5e93018c0c066d6673f1a2c3737c7e90af95eff30cfee38d0bbac7",
|
||||
"https://bcr.bazel.build/modules/rules_python/0.22.1/source.json": "57226905e783bae7c37c2dd662be078728e48fa28ee4324a7eabcafb5a43d014",
|
||||
"https://bcr.bazel.build/modules/rules_python/0.4.0/MODULE.bazel": "9208ee05fd48bf09ac60ed269791cf17fb343db56c8226a720fbb1cdf467166c",
|
||||
"https://bcr.bazel.build/modules/stardoc/0.5.1/MODULE.bazel": "1a05d92974d0c122f5ccf09291442580317cdd859f07a8655f1db9a60374f9f8",
|
||||
"https://bcr.bazel.build/modules/stardoc/0.5.1/source.json": "a96f95e02123320aa015b956f29c00cb818fa891ef823d55148e1a362caacf29",
|
||||
"https://bcr.bazel.build/modules/upb/0.0.0-20220923-a547704/MODULE.bazel": "7298990c00040a0e2f121f6c32544bab27d4452f80d9ce51349b1a28f3005c43",
|
||||
"https://bcr.bazel.build/modules/upb/0.0.0-20220923-a547704/source.json": "f1ef7d3f9e0e26d4b23d1c39b5f5de71f584dd7d1b4ef83d9bbba6ec7a6a6459",
|
||||
"https://bcr.bazel.build/modules/zlib/1.2.11/MODULE.bazel": "07b389abc85fdbca459b69e2ec656ae5622873af3f845e1c9d80fe179f3effa0",
|
||||
"https://bcr.bazel.build/modules/zlib/1.2.12/MODULE.bazel": "3b1a8834ada2a883674be8cbd36ede1b6ec481477ada359cd2d3ddc562340b27",
|
||||
"https://bcr.bazel.build/modules/zlib/1.3.1.bcr.3/MODULE.bazel": "af322bc08976524477c79d1e45e241b6efbeb918c497e8840b8ab116802dda79",
|
||||
"https://bcr.bazel.build/modules/zlib/1.3.1.bcr.3/source.json": "2be409ac3c7601245958cd4fcdff4288be79ed23bd690b4b951f500d54ee6e7d"
|
||||
},
|
||||
"selectedYankedVersions": {},
|
||||
"moduleExtensions": {
|
||||
"@@apple_support~//crosstool:setup.bzl%apple_cc_configure_extension": {
|
||||
"general": {
|
||||
"bzlTransitiveDigest": "PjIds3feoYE8SGbbIq2SFTZy3zmxeO2tQevJZNDo7iY=",
|
||||
"usagesDigest": "+hz7IHWN6A1oVJJWNDB6yZRG+RYhF76wAYItpAeIUIg=",
|
||||
"recordedFileInputs": {},
|
||||
"recordedDirentsInputs": {},
|
||||
"envVariables": {},
|
||||
"generatedRepoSpecs": {
|
||||
"local_config_apple_cc_toolchains": {
|
||||
"bzlFile": "@@apple_support~//crosstool:setup.bzl",
|
||||
"ruleClassName": "_apple_cc_autoconf_toolchains",
|
||||
"attributes": {}
|
||||
},
|
||||
"local_config_apple_cc": {
|
||||
"bzlFile": "@@apple_support~//crosstool:setup.bzl",
|
||||
"ruleClassName": "_apple_cc_autoconf",
|
||||
"attributes": {}
|
||||
}
|
||||
},
|
||||
"recordedRepoMappingEntries": [
|
||||
[
|
||||
"apple_support~",
|
||||
"bazel_tools",
|
||||
"bazel_tools"
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
"@@platforms//host:extension.bzl%host_platform": {
|
||||
"general": {
|
||||
"bzlTransitiveDigest": "xelQcPZH8+tmuOHVjL9vDxMnnQNMlwj0SlvgoqBkm4U=",
|
||||
"usagesDigest": "pCYpDQmqMbmiiPI1p2Kd3VLm5T48rRAht5WdW0X2GlA=",
|
||||
"recordedFileInputs": {},
|
||||
"recordedDirentsInputs": {},
|
||||
"envVariables": {},
|
||||
"generatedRepoSpecs": {
|
||||
"host_platform": {
|
||||
"bzlFile": "@@platforms//host:extension.bzl",
|
||||
"ruleClassName": "host_platform_repo",
|
||||
"attributes": {}
|
||||
}
|
||||
},
|
||||
"recordedRepoMappingEntries": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
32
README.md
32
README.md
@@ -31,6 +31,17 @@ cmake [-G generator] [-DYAML_BUILD_SHARED_LIBS=on|OFF] ..
|
||||
|
||||
* `yaml-cpp` builds a static library by default, you may want to build a shared library by specifying `-DYAML_BUILD_SHARED_LIBS=ON`.
|
||||
|
||||
* [Debug mode of the GNU standard C++
|
||||
library](https://gcc.gnu.org/onlinedocs/libstdc++/manual/debug_mode.html)
|
||||
can be used when both `yaml-cpp` and client code is compiled with the
|
||||
`_GLIBCXX_DEBUG` flag (e.g. by calling CMake with `-D
|
||||
CMAKE_CXX_FLAGS_DEBUG='-g -D_GLIBCXX_DEBUG'` option).
|
||||
|
||||
Note that for `yaml-cpp` unit tests to run successfully, the _GoogleTest_
|
||||
library also must be built with this flag, i.e. the system one cannot be
|
||||
used (the _YAML_USE_SYSTEM_GTEST_ CMake option must be _OFF_, which is the
|
||||
default).
|
||||
|
||||
* For more options on customizing the build, see the [CMakeLists.txt](https://github.com/jbeder/yaml-cpp/blob/master/CMakeLists.txt) file.
|
||||
|
||||
#### 2. Build it!
|
||||
@@ -38,13 +49,30 @@ cmake [-G generator] [-DYAML_BUILD_SHARED_LIBS=on|OFF] ..
|
||||
|
||||
**Note:** To clean up, just remove the `build` directory.
|
||||
|
||||
## How to Integrate it within your project using CMake
|
||||
|
||||
You can use for example FetchContent :
|
||||
|
||||
```cmake
|
||||
include(FetchContent)
|
||||
|
||||
FetchContent_Declare(
|
||||
yaml-cpp
|
||||
GIT_REPOSITORY https://github.com/jbeder/yaml-cpp.git
|
||||
GIT_TAG <tag_name> # Can be a tag (yaml-cpp-x.x.x), a commit hash, or a branch name (master)
|
||||
)
|
||||
FetchContent_MakeAvailable(yaml-cpp)
|
||||
|
||||
target_link_libraries(YOUR_LIBRARY PUBLIC yaml-cpp::yaml-cpp) # The library or executable that require yaml-cpp library
|
||||
```
|
||||
|
||||
## Recent Releases
|
||||
|
||||
[yaml-cpp 0.6.0](https://github.com/jbeder/yaml-cpp/releases/tag/yaml-cpp-0.6.0) released! This release requires C++11, and no longer depends on Boost.
|
||||
[yaml-cpp 0.8.0](https://github.com/jbeder/yaml-cpp/releases/tag/0.8.0) released!
|
||||
|
||||
[yaml-cpp 0.3.0](https://github.com/jbeder/yaml-cpp/releases/tag/release-0.3.0) is still available if you want the old API.
|
||||
|
||||
**The old API will continue to be supported, and will still receive bugfixes!** The 0.3.x and 0.4.x versions will be old API releases, and 0.5.x and above will all be new API releases.
|
||||
**The old API will stop receiving bugfixes in 2026.** The 0.3.x versions provide the old API, and 0.5.x and above all provide the new API.
|
||||
|
||||
# API Documentation
|
||||
|
||||
|
10
WORKSPACE
10
WORKSPACE
@@ -1,10 +0,0 @@
|
||||
workspace(name = "com_github_jbeder_yaml_cpp")
|
||||
|
||||
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
|
||||
|
||||
http_archive(
|
||||
name = "com_google_googletest",
|
||||
strip_prefix = "googletest-release-1.8.1",
|
||||
url = "https://github.com/google/googletest/archive/release-1.8.1.tar.gz",
|
||||
sha256 = "9bf1fe5182a604b4135edc1a425ae356c9ad15e9b23f9f12a02e80184c3a249c",
|
||||
)
|
@@ -154,16 +154,11 @@ produces
|
||||
# STL Containers, and Other Overloads #
|
||||
We overload `operator <<` for `std::vector`, `std::list`, and `std::map`, so you can write stuff like:
|
||||
|
||||
{% raw %}
|
||||
```cpp
|
||||
std::vector <int> squares;
|
||||
squares.push_back(1);
|
||||
squares.push_back(4);
|
||||
squares.push_back(9);
|
||||
squares.push_back(16);
|
||||
std::vector <int> squares = {1, 4, 9, 16};
|
||||
|
||||
std::map <std::string, int> ages;
|
||||
ages["Daniel"] = 26;
|
||||
ages["Jesse"] = 24;
|
||||
std::map <std::string, int> ages = {{"Daniel", 26}, {"Jesse", 24}};
|
||||
|
||||
YAML::Emitter out;
|
||||
out << YAML::BeginSeq;
|
||||
@@ -171,6 +166,7 @@ out << YAML::Flow << squares;
|
||||
out << ages;
|
||||
out << YAML::EndSeq;
|
||||
```
|
||||
{% endraw %}
|
||||
|
||||
produces
|
||||
|
||||
@@ -227,4 +223,4 @@ assert(out.good());
|
||||
out << YAML::Key;
|
||||
assert(!out.good());
|
||||
std::cout << "Emitter error: " << out.GetLastError() << "\n";
|
||||
```
|
||||
```
|
||||
|
@@ -15,11 +15,9 @@
|
||||
# ifndef YAML_CPP_API
|
||||
# ifdef yaml_cpp_EXPORTS
|
||||
/* We are building this library */
|
||||
# pragma message( "Defining YAML_CPP_API for DLL export" )
|
||||
# define YAML_CPP_API __declspec(dllexport)
|
||||
# else
|
||||
/* We are using this library */
|
||||
# pragma message( "Defining YAML_CPP_API for DLL import" )
|
||||
# define YAML_CPP_API __declspec(dllimport)
|
||||
# endif
|
||||
# endif
|
||||
|
@@ -23,6 +23,7 @@ class Emitter;
|
||||
class EmitFromEvents : public EventHandler {
|
||||
public:
|
||||
EmitFromEvents(Emitter& emitter);
|
||||
~EmitFromEvents() override = default;
|
||||
|
||||
void OnDocumentStart(const Mark& mark) override;
|
||||
void OnDocumentEnd() override;
|
||||
|
@@ -9,18 +9,24 @@
|
||||
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L)
|
||||
#include <string_view>
|
||||
#endif
|
||||
|
||||
#include "yaml-cpp/binary.h"
|
||||
#include "yaml-cpp/dll.h"
|
||||
#include "yaml-cpp/emitterdef.h"
|
||||
#include "yaml-cpp/emittermanip.h"
|
||||
#include "yaml-cpp/null.h"
|
||||
#include "yaml-cpp/ostream_wrapper.h"
|
||||
#include "yaml-cpp/fptostring.h"
|
||||
|
||||
namespace YAML {
|
||||
class Binary;
|
||||
@@ -67,6 +73,7 @@ class YAML_CPP_API Emitter {
|
||||
Emitter& SetLocalPrecision(const _Precision& precision);
|
||||
|
||||
// overloads of write
|
||||
Emitter& Write(const char* str, std::size_t size);
|
||||
Emitter& Write(const std::string& str);
|
||||
Emitter& Write(bool b);
|
||||
Emitter& Write(char ch);
|
||||
@@ -141,6 +148,7 @@ inline Emitter& Emitter::WriteIntegralType(T value) {
|
||||
PrepareNode(EmitterNodeType::Scalar);
|
||||
|
||||
std::stringstream stream;
|
||||
stream.imbue(std::locale("C"));
|
||||
PrepareIntegralStream(stream);
|
||||
stream << value;
|
||||
m_stream << stream.str();
|
||||
@@ -158,6 +166,7 @@ inline Emitter& Emitter::WriteStreamable(T value) {
|
||||
PrepareNode(EmitterNodeType::Scalar);
|
||||
|
||||
std::stringstream stream;
|
||||
stream.imbue(std::locale("C"));
|
||||
SetStreamablePrecision<T>(stream);
|
||||
|
||||
bool special = false;
|
||||
@@ -178,7 +187,7 @@ inline Emitter& Emitter::WriteStreamable(T value) {
|
||||
}
|
||||
|
||||
if (!special) {
|
||||
stream << value;
|
||||
stream << FpToString(value, stream.precision());
|
||||
}
|
||||
m_stream << stream.str();
|
||||
|
||||
@@ -198,8 +207,13 @@ inline void Emitter::SetStreamablePrecision<double>(std::stringstream& stream) {
|
||||
}
|
||||
|
||||
// overloads of insertion
|
||||
#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L)
|
||||
inline Emitter& operator<<(Emitter& emitter, const std::string_view& v) {
|
||||
return emitter.Write(v.data(), v.size());
|
||||
}
|
||||
#endif
|
||||
inline Emitter& operator<<(Emitter& emitter, const std::string& v) {
|
||||
return emitter.Write(v);
|
||||
return emitter.Write(v.data(), v.size());
|
||||
}
|
||||
inline Emitter& operator<<(Emitter& emitter, bool v) {
|
||||
return emitter.Write(v);
|
||||
@@ -230,7 +244,7 @@ inline Emitter& operator<<(Emitter& emitter, const Binary& b) {
|
||||
}
|
||||
|
||||
inline Emitter& operator<<(Emitter& emitter, const char* v) {
|
||||
return emitter.Write(std::string(v));
|
||||
return emitter.Write(v, std::strlen(v));
|
||||
}
|
||||
|
||||
inline Emitter& operator<<(Emitter& emitter, int v) {
|
||||
|
@@ -8,9 +8,10 @@
|
||||
#endif
|
||||
|
||||
namespace YAML {
|
||||
struct EmitterStyle {
|
||||
enum value { Default, Block, Flow };
|
||||
};
|
||||
namespace EmitterStyle {
|
||||
enum value { Default, Block, Flow };
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // EMITTERSTYLE_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
@@ -48,6 +48,8 @@ const char* const UNKNOWN_TOKEN = "unknown token";
|
||||
const char* const DOC_IN_SCALAR = "illegal document indicator in scalar";
|
||||
const char* const EOF_IN_SCALAR = "illegal EOF in scalar";
|
||||
const char* const CHAR_IN_SCALAR = "illegal character in scalar";
|
||||
const char* const UNEXPECTED_SCALAR = "unexpected scalar";
|
||||
const char* const UNEXPECTED_FLOW = "plain value cannot start with flow indicator character";
|
||||
const char* const TAB_IN_INDENTATION =
|
||||
"illegal tab when looking for indentation";
|
||||
const char* const FLOW_END = "illegal flow end";
|
||||
|
15
include/yaml-cpp/fptostring.h
Normal file
15
include/yaml-cpp/fptostring.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#ifndef YAML_H_FPTOSTRING
|
||||
#define YAML_H_FPTOSTRING
|
||||
|
||||
#include "yaml-cpp/dll.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace YAML {
|
||||
// "precision = 0" refers to shortest known unique representation of the value
|
||||
YAML_CPP_API std::string FpToString(float v, size_t precision = 0);
|
||||
YAML_CPP_API std::string FpToString(double v, size_t precision = 0);
|
||||
YAML_CPP_API std::string FpToString(long double v, size_t precision = 0);
|
||||
}
|
||||
|
||||
#endif
|
@@ -18,7 +18,7 @@
|
||||
#include <valarray>
|
||||
#include <vector>
|
||||
|
||||
#if __cplusplus >= 201703L
|
||||
#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L)
|
||||
#include <string_view>
|
||||
#endif
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "yaml-cpp/node/node.h"
|
||||
#include "yaml-cpp/node/type.h"
|
||||
#include "yaml-cpp/null.h"
|
||||
#include "yaml-cpp/fptostring.h"
|
||||
|
||||
|
||||
namespace YAML {
|
||||
@@ -93,7 +94,7 @@ struct convert<char[N]> {
|
||||
static Node encode(const char* rhs) { return Node(rhs); }
|
||||
};
|
||||
|
||||
#if __cplusplus >= 201703L
|
||||
#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L)
|
||||
template <>
|
||||
struct convert<std::string_view> {
|
||||
static Node encode(std::string_view rhs) { return Node(std::string(rhs)); }
|
||||
@@ -129,7 +130,7 @@ inner_encode(const T& rhs, std::stringstream& stream){
|
||||
stream << ".inf";
|
||||
}
|
||||
} else {
|
||||
stream << rhs;
|
||||
stream << FpToString(rhs, stream.precision());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,6 +172,7 @@ ConvertStreamTo(std::stringstream& stream, T& rhs) {
|
||||
\
|
||||
static Node encode(const type& rhs) { \
|
||||
std::stringstream stream; \
|
||||
stream.imbue(std::locale("C")); \
|
||||
stream.precision(std::numeric_limits<type>::max_digits10); \
|
||||
conversion::inner_encode(rhs, stream); \
|
||||
return Node(stream.str()); \
|
||||
@@ -182,6 +184,7 @@ ConvertStreamTo(std::stringstream& stream, T& rhs) {
|
||||
} \
|
||||
const std::string& input = node.Scalar(); \
|
||||
std::stringstream stream(input); \
|
||||
stream.imbue(std::locale("C")); \
|
||||
stream.unsetf(std::ios::dec); \
|
||||
if ((stream.peek() == '-') && std::is_unsigned<type>::value) { \
|
||||
return false; \
|
||||
|
@@ -41,7 +41,7 @@ class iterator_base {
|
||||
using value_type = V;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = V*;
|
||||
using reference = V;
|
||||
using reference = V&;
|
||||
|
||||
public:
|
||||
iterator_base() : m_iterator(), m_pMemory() {}
|
||||
|
@@ -25,6 +25,7 @@ class YAML_CPP_API memory {
|
||||
memory() : m_nodes{} {}
|
||||
node& create_node();
|
||||
void merge(const memory& rhs);
|
||||
size_t size() const;
|
||||
|
||||
private:
|
||||
using Nodes = std::set<shared_node>;
|
||||
|
@@ -69,7 +69,7 @@ class node_iterator_base {
|
||||
using value_type = node_iterator_value<V>;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = node_iterator_value<V>*;
|
||||
using reference = node_iterator_value<V>;
|
||||
using reference = node_iterator_value<V>&;
|
||||
using SeqIter = typename node_iterator_type<V>::seq;
|
||||
using MapIter = typename node_iterator_type<V>::map;
|
||||
|
||||
|
@@ -97,7 +97,7 @@ struct as_if {
|
||||
if (!node.m_pNode)
|
||||
return fallback;
|
||||
|
||||
T t;
|
||||
T t = fallback;
|
||||
if (convert<T>::decode(node, t))
|
||||
return t;
|
||||
return fallback;
|
||||
@@ -124,8 +124,8 @@ struct as_if<T, void> {
|
||||
const Node& node;
|
||||
|
||||
T operator()() const {
|
||||
if (!node.m_pNode)
|
||||
throw TypedBadConversion<T>(node.Mark());
|
||||
if (!node.m_pNode) // no fallback
|
||||
throw InvalidNode(node.m_invalidKey);
|
||||
|
||||
T t;
|
||||
if (convert<T>::decode(node, t))
|
||||
@@ -140,6 +140,8 @@ struct as_if<std::string, void> {
|
||||
const Node& node;
|
||||
|
||||
std::string operator()() const {
|
||||
if (node.Type() == NodeType::Undefined) // no fallback
|
||||
throw InvalidNode(node.m_invalidKey);
|
||||
if (node.Type() == NodeType::Null)
|
||||
return "null";
|
||||
if (node.Type() != NodeType::Scalar)
|
||||
|
@@ -8,9 +8,10 @@
|
||||
#endif
|
||||
|
||||
namespace YAML {
|
||||
struct NodeType {
|
||||
enum value { Undefined, Null, Scalar, Sequence, Map };
|
||||
};
|
||||
namespace NodeType {
|
||||
enum value { Undefined, Null, Scalar, Sequence, Map };
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // VALUE_TYPE_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
@@ -8,7 +8,7 @@
|
||||
#endif
|
||||
|
||||
#include "yaml-cpp/dll.h"
|
||||
#include <string>
|
||||
#include <cstddef>
|
||||
|
||||
namespace YAML {
|
||||
class Node;
|
||||
@@ -18,7 +18,7 @@ inline bool operator==(const _Null&, const _Null&) { return true; }
|
||||
inline bool operator!=(const _Null&, const _Null&) { return false; }
|
||||
|
||||
YAML_CPP_API bool IsNull(const Node& node); // old API only
|
||||
YAML_CPP_API bool IsNullString(const std::string& str);
|
||||
YAML_CPP_API bool IsNullString(const char* str, std::size_t size);
|
||||
|
||||
extern YAML_CPP_API _Null Null;
|
||||
}
|
||||
|
@@ -121,6 +121,7 @@ template<typename Key, bool Streamable>
|
||||
struct streamable_to_string {
|
||||
static std::string impl(const Key& key) {
|
||||
std::stringstream ss;
|
||||
ss.imbue(std::locale("C"));
|
||||
ss << key;
|
||||
return ss.str();
|
||||
}
|
||||
|
4196
src/contrib/dragonbox.h
Normal file
4196
src/contrib/dragonbox.h
Normal file
File diff suppressed because it is too large
Load Diff
@@ -116,8 +116,13 @@ void EmitFromEvents::BeginNode() {
|
||||
}
|
||||
|
||||
void EmitFromEvents::EmitProps(const std::string& tag, anchor_t anchor) {
|
||||
if (!tag.empty() && tag != "?" && tag != "!")
|
||||
m_emitter << VerbatimTag(tag);
|
||||
if (!tag.empty() && tag != "?" && tag != "!"){
|
||||
if (tag[0] == '!') {
|
||||
m_emitter << LocalTag(std::string(tag.begin()+1, tag.end()));
|
||||
} else {
|
||||
m_emitter << VerbatimTag(tag);
|
||||
}
|
||||
}
|
||||
if (anchor)
|
||||
m_emitter << Anchor(ToString(anchor));
|
||||
}
|
||||
|
@@ -213,7 +213,8 @@ void Emitter::EmitEndSeq() {
|
||||
if (m_pState->CurGroupFlowType() == FlowType::Flow) {
|
||||
if (m_stream.comment())
|
||||
m_stream << "\n";
|
||||
m_stream << IndentTo(m_pState->CurIndent());
|
||||
if (originalType == FlowType::Block || m_pState->HasBegunNode())
|
||||
m_stream << IndentTo(m_pState->CurIndent());
|
||||
if (originalType == FlowType::Block) {
|
||||
m_stream << "[";
|
||||
} else {
|
||||
@@ -715,33 +716,33 @@ StringEscaping::value GetStringEscapingStyle(const EMITTER_MANIP emitterManip) {
|
||||
}
|
||||
}
|
||||
|
||||
Emitter& Emitter::Write(const std::string& str) {
|
||||
Emitter& Emitter::Write(const char* str, std::size_t size) {
|
||||
if (!good())
|
||||
return *this;
|
||||
|
||||
StringEscaping::value stringEscaping = GetStringEscapingStyle(m_pState->GetOutputCharset());
|
||||
|
||||
const StringFormat::value strFormat =
|
||||
Utils::ComputeStringFormat(str, m_pState->GetStringFormat(),
|
||||
Utils::ComputeStringFormat(str, size, m_pState->GetStringFormat(),
|
||||
m_pState->CurGroupFlowType(), stringEscaping == StringEscaping::NonAscii);
|
||||
|
||||
if (strFormat == StringFormat::Literal || str.size() > 1024)
|
||||
if (strFormat == StringFormat::Literal || size > 1024)
|
||||
m_pState->SetMapKeyFormat(YAML::LongKey, FmtScope::Local);
|
||||
|
||||
PrepareNode(EmitterNodeType::Scalar);
|
||||
|
||||
switch (strFormat) {
|
||||
case StringFormat::Plain:
|
||||
m_stream << str;
|
||||
m_stream.write(str, size);
|
||||
break;
|
||||
case StringFormat::SingleQuoted:
|
||||
Utils::WriteSingleQuotedString(m_stream, str);
|
||||
Utils::WriteSingleQuotedString(m_stream, str, size);
|
||||
break;
|
||||
case StringFormat::DoubleQuoted:
|
||||
Utils::WriteDoubleQuotedString(m_stream, str, stringEscaping);
|
||||
Utils::WriteDoubleQuotedString(m_stream, str, size, stringEscaping);
|
||||
break;
|
||||
case StringFormat::Literal:
|
||||
Utils::WriteLiteralString(m_stream, str,
|
||||
Utils::WriteLiteralString(m_stream, str, size,
|
||||
m_pState->CurIndent() + m_pState->GetIndent());
|
||||
break;
|
||||
}
|
||||
@@ -751,6 +752,10 @@ Emitter& Emitter::Write(const std::string& str) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
Emitter& Emitter::Write(const std::string& str) {
|
||||
return Write(str.data(), str.size());
|
||||
}
|
||||
|
||||
std::size_t Emitter::GetFloatPrecision() const {
|
||||
return m_pState->GetFloatPrecision();
|
||||
}
|
||||
@@ -864,7 +869,7 @@ Emitter& Emitter::Write(const _Alias& alias) {
|
||||
|
||||
PrepareNode(EmitterNodeType::Scalar);
|
||||
|
||||
if (!Utils::WriteAlias(m_stream, alias.content)) {
|
||||
if (!Utils::WriteAlias(m_stream, alias.content.data(), alias.content.size())) {
|
||||
m_pState->SetError(ErrorMsg::INVALID_ALIAS);
|
||||
return *this;
|
||||
}
|
||||
@@ -887,7 +892,7 @@ Emitter& Emitter::Write(const _Anchor& anchor) {
|
||||
|
||||
PrepareNode(EmitterNodeType::Property);
|
||||
|
||||
if (!Utils::WriteAnchor(m_stream, anchor.content)) {
|
||||
if (!Utils::WriteAnchor(m_stream, anchor.content.data(), anchor.content.size())) {
|
||||
m_pState->SetError(ErrorMsg::INVALID_ANCHOR);
|
||||
return *this;
|
||||
}
|
||||
@@ -936,7 +941,7 @@ Emitter& Emitter::Write(const _Comment& comment) {
|
||||
|
||||
if (m_stream.col() > 0)
|
||||
m_stream << Indentation(m_pState->GetPreCommentIndent());
|
||||
Utils::WriteComment(m_stream, comment.content,
|
||||
Utils::WriteComment(m_stream, comment.content.data(), comment.content.size(),
|
||||
m_pState->GetPostCommentIndent());
|
||||
|
||||
m_pState->SetNonContent();
|
||||
|
@@ -1,4 +1,5 @@
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
|
||||
@@ -88,8 +89,8 @@ int Utf8BytesIndicated(char ch) {
|
||||
bool IsTrailingByte(char ch) { return (ch & 0xC0) == 0x80; }
|
||||
|
||||
bool GetNextCodePointAndAdvance(int& codePoint,
|
||||
std::string::const_iterator& first,
|
||||
std::string::const_iterator last) {
|
||||
const char*& first,
|
||||
const char* last) {
|
||||
if (first == last)
|
||||
return false;
|
||||
|
||||
@@ -152,39 +153,39 @@ void WriteCodePoint(ostream_wrapper& out, int codePoint) {
|
||||
}
|
||||
}
|
||||
|
||||
bool IsValidPlainScalar(const std::string& str, FlowType::value flowType,
|
||||
bool IsValidPlainScalar(const char* str, std::size_t size, FlowType::value flowType,
|
||||
bool allowOnlyAscii) {
|
||||
// check against null
|
||||
if (IsNullString(str)) {
|
||||
if (IsNullString(str, size)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// check the start
|
||||
const RegEx& start = (flowType == FlowType::Flow ? Exp::PlainScalarInFlow()
|
||||
: Exp::PlainScalar());
|
||||
if (!start.Matches(str)) {
|
||||
if (!start.Matches(StringCharSource(str, size))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// and check the end for plain whitespace (which can't be faithfully kept in a
|
||||
// plain scalar)
|
||||
if (!str.empty() && *str.rbegin() == ' ') {
|
||||
if (size != 0 && str[size - 1] == ' ') {
|
||||
return false;
|
||||
}
|
||||
|
||||
// then check until something is disallowed
|
||||
static const RegEx& disallowed_flow =
|
||||
static const RegEx disallowed_flow =
|
||||
Exp::EndScalarInFlow() | (Exp::BlankOrBreak() + Exp::Comment()) |
|
||||
Exp::NotPrintable() | Exp::Utf8_ByteOrderMark() | Exp::Break() |
|
||||
Exp::Tab() | Exp::Ampersand();
|
||||
static const RegEx& disallowed_block =
|
||||
static const RegEx disallowed_block =
|
||||
Exp::EndScalar() | (Exp::BlankOrBreak() + Exp::Comment()) |
|
||||
Exp::NotPrintable() | Exp::Utf8_ByteOrderMark() | Exp::Break() |
|
||||
Exp::Tab() | Exp::Ampersand();
|
||||
const RegEx& disallowed =
|
||||
flowType == FlowType::Flow ? disallowed_flow : disallowed_block;
|
||||
|
||||
StringCharSource buffer(str.c_str(), str.size());
|
||||
StringCharSource buffer(str, size);
|
||||
while (buffer) {
|
||||
if (disallowed.Matches(buffer)) {
|
||||
return false;
|
||||
@@ -198,22 +199,22 @@ bool IsValidPlainScalar(const std::string& str, FlowType::value flowType,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IsValidSingleQuotedScalar(const std::string& str, bool escapeNonAscii) {
|
||||
bool IsValidSingleQuotedScalar(const char* str, std::size_t size, bool escapeNonAscii) {
|
||||
// TODO: check for non-printable characters?
|
||||
return std::none_of(str.begin(), str.end(), [=](char ch) {
|
||||
return std::none_of(str, str + size, [=](char ch) {
|
||||
return (escapeNonAscii && (0x80 <= static_cast<unsigned char>(ch))) ||
|
||||
(ch == '\n');
|
||||
});
|
||||
}
|
||||
|
||||
bool IsValidLiteralScalar(const std::string& str, FlowType::value flowType,
|
||||
bool IsValidLiteralScalar(const char* str, std::size_t size, FlowType::value flowType,
|
||||
bool escapeNonAscii) {
|
||||
if (flowType == FlowType::Flow) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: check for non-printable characters?
|
||||
return std::none_of(str.begin(), str.end(), [=](char ch) {
|
||||
return std::none_of(str, str + size, [=](char ch) {
|
||||
return (escapeNonAscii && (0x80 <= static_cast<unsigned char>(ch)));
|
||||
});
|
||||
}
|
||||
@@ -253,10 +254,10 @@ void WriteDoubleQuoteEscapeSequence(ostream_wrapper& out, int codePoint, StringE
|
||||
out << hexDigits[(codePoint >> (4 * (digits - 1))) & 0xF];
|
||||
}
|
||||
|
||||
bool WriteAliasName(ostream_wrapper& out, const std::string& str) {
|
||||
bool WriteAliasName(ostream_wrapper& out, const char* str, std::size_t size) {
|
||||
int codePoint;
|
||||
for (std::string::const_iterator i = str.begin();
|
||||
GetNextCodePointAndAdvance(codePoint, i, str.end());) {
|
||||
for (const char* i = str;
|
||||
GetNextCodePointAndAdvance(codePoint, i, str + size);) {
|
||||
if (!IsAnchorChar(codePoint)) {
|
||||
return false;
|
||||
}
|
||||
@@ -267,25 +268,25 @@ bool WriteAliasName(ostream_wrapper& out, const std::string& str) {
|
||||
}
|
||||
} // namespace
|
||||
|
||||
StringFormat::value ComputeStringFormat(const std::string& str,
|
||||
StringFormat::value ComputeStringFormat(const char* str, std::size_t size,
|
||||
EMITTER_MANIP strFormat,
|
||||
FlowType::value flowType,
|
||||
bool escapeNonAscii) {
|
||||
switch (strFormat) {
|
||||
case Auto:
|
||||
if (IsValidPlainScalar(str, flowType, escapeNonAscii)) {
|
||||
if (IsValidPlainScalar(str, size, flowType, escapeNonAscii)) {
|
||||
return StringFormat::Plain;
|
||||
}
|
||||
return StringFormat::DoubleQuoted;
|
||||
case SingleQuoted:
|
||||
if (IsValidSingleQuotedScalar(str, escapeNonAscii)) {
|
||||
if (IsValidSingleQuotedScalar(str, size, escapeNonAscii)) {
|
||||
return StringFormat::SingleQuoted;
|
||||
}
|
||||
return StringFormat::DoubleQuoted;
|
||||
case DoubleQuoted:
|
||||
return StringFormat::DoubleQuoted;
|
||||
case Literal:
|
||||
if (IsValidLiteralScalar(str, flowType, escapeNonAscii)) {
|
||||
if (IsValidLiteralScalar(str, size, flowType, escapeNonAscii)) {
|
||||
return StringFormat::Literal;
|
||||
}
|
||||
return StringFormat::DoubleQuoted;
|
||||
@@ -296,11 +297,11 @@ StringFormat::value ComputeStringFormat(const std::string& str,
|
||||
return StringFormat::DoubleQuoted;
|
||||
}
|
||||
|
||||
bool WriteSingleQuotedString(ostream_wrapper& out, const std::string& str) {
|
||||
bool WriteSingleQuotedString(ostream_wrapper& out, const char* str, std::size_t size) {
|
||||
out << "'";
|
||||
int codePoint;
|
||||
for (std::string::const_iterator i = str.begin();
|
||||
GetNextCodePointAndAdvance(codePoint, i, str.end());) {
|
||||
for (const char* i = str;
|
||||
GetNextCodePointAndAdvance(codePoint, i, str + size);) {
|
||||
if (codePoint == '\n') {
|
||||
return false; // We can't handle a new line and the attendant indentation
|
||||
// yet
|
||||
@@ -316,12 +317,12 @@ bool WriteSingleQuotedString(ostream_wrapper& out, const std::string& str) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteDoubleQuotedString(ostream_wrapper& out, const std::string& str,
|
||||
bool WriteDoubleQuotedString(ostream_wrapper& out, const char* str, std::size_t size,
|
||||
StringEscaping::value stringEscaping) {
|
||||
out << "\"";
|
||||
int codePoint;
|
||||
for (std::string::const_iterator i = str.begin();
|
||||
GetNextCodePointAndAdvance(codePoint, i, str.end());) {
|
||||
for (const char* i = str;
|
||||
GetNextCodePointAndAdvance(codePoint, i, str + size);) {
|
||||
switch (codePoint) {
|
||||
case '\"':
|
||||
out << "\\\"";
|
||||
@@ -363,12 +364,12 @@ bool WriteDoubleQuotedString(ostream_wrapper& out, const std::string& str,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteLiteralString(ostream_wrapper& out, const std::string& str,
|
||||
bool WriteLiteralString(ostream_wrapper& out, const char* str, std::size_t size,
|
||||
std::size_t indent) {
|
||||
out << "|\n";
|
||||
int codePoint;
|
||||
for (std::string::const_iterator i = str.begin();
|
||||
GetNextCodePointAndAdvance(codePoint, i, str.end());) {
|
||||
for (const char* i = str;
|
||||
GetNextCodePointAndAdvance(codePoint, i, str + size);) {
|
||||
if (codePoint == '\n') {
|
||||
out << "\n";
|
||||
} else {
|
||||
@@ -406,14 +407,14 @@ bool WriteChar(ostream_wrapper& out, char ch, StringEscaping::value stringEscapi
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteComment(ostream_wrapper& out, const std::string& str,
|
||||
bool WriteComment(ostream_wrapper& out, const char* str, std::size_t size,
|
||||
std::size_t postCommentIndent) {
|
||||
const std::size_t curIndent = out.col();
|
||||
out << "#" << Indentation(postCommentIndent);
|
||||
out.set_comment();
|
||||
int codePoint;
|
||||
for (std::string::const_iterator i = str.begin();
|
||||
GetNextCodePointAndAdvance(codePoint, i, str.end());) {
|
||||
for (const char* i = str;
|
||||
GetNextCodePointAndAdvance(codePoint, i, str + size);) {
|
||||
if (codePoint == '\n') {
|
||||
out << "\n"
|
||||
<< IndentTo(curIndent) << "#" << Indentation(postCommentIndent);
|
||||
@@ -425,14 +426,14 @@ bool WriteComment(ostream_wrapper& out, const std::string& str,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteAlias(ostream_wrapper& out, const std::string& str) {
|
||||
bool WriteAlias(ostream_wrapper& out, const char* str, std::size_t size) {
|
||||
out << "*";
|
||||
return WriteAliasName(out, str);
|
||||
return WriteAliasName(out, str, size);
|
||||
}
|
||||
|
||||
bool WriteAnchor(ostream_wrapper& out, const std::string& str) {
|
||||
bool WriteAnchor(ostream_wrapper& out, const char* str, std::size_t size) {
|
||||
out << "&";
|
||||
return WriteAliasName(out, str);
|
||||
return WriteAliasName(out, str, size);
|
||||
}
|
||||
|
||||
bool WriteTag(ostream_wrapper& out, const std::string& str, bool verbatim) {
|
||||
@@ -489,7 +490,8 @@ bool WriteTagWithPrefix(ostream_wrapper& out, const std::string& prefix,
|
||||
}
|
||||
|
||||
bool WriteBinary(ostream_wrapper& out, const Binary& binary) {
|
||||
WriteDoubleQuotedString(out, EncodeBase64(binary.data(), binary.size()),
|
||||
std::string encoded = EncodeBase64(binary.data(), binary.size());
|
||||
WriteDoubleQuotedString(out, encoded.data(), encoded.size(),
|
||||
StringEscaping::None);
|
||||
return true;
|
||||
}
|
||||
|
@@ -29,22 +29,22 @@ struct StringEscaping {
|
||||
};
|
||||
|
||||
namespace Utils {
|
||||
StringFormat::value ComputeStringFormat(const std::string& str,
|
||||
StringFormat::value ComputeStringFormat(const char* str, std::size_t size,
|
||||
EMITTER_MANIP strFormat,
|
||||
FlowType::value flowType,
|
||||
bool escapeNonAscii);
|
||||
|
||||
bool WriteSingleQuotedString(ostream_wrapper& out, const std::string& str);
|
||||
bool WriteDoubleQuotedString(ostream_wrapper& out, const std::string& str,
|
||||
bool WriteSingleQuotedString(ostream_wrapper& out, const char* str, std::size_t size);
|
||||
bool WriteDoubleQuotedString(ostream_wrapper& out, const char* str, std::size_t size,
|
||||
StringEscaping::value stringEscaping);
|
||||
bool WriteLiteralString(ostream_wrapper& out, const std::string& str,
|
||||
bool WriteLiteralString(ostream_wrapper& out, const char* str, std::size_t size,
|
||||
std::size_t indent);
|
||||
bool WriteChar(ostream_wrapper& out, char ch,
|
||||
StringEscaping::value stringEscapingStyle);
|
||||
bool WriteComment(ostream_wrapper& out, const std::string& str,
|
||||
bool WriteComment(ostream_wrapper& out, const char* str, std::size_t size,
|
||||
std::size_t postCommentIndent);
|
||||
bool WriteAlias(ostream_wrapper& out, const std::string& str);
|
||||
bool WriteAnchor(ostream_wrapper& out, const std::string& str);
|
||||
bool WriteAlias(ostream_wrapper& out, const char* str, std::size_t size);
|
||||
bool WriteAnchor(ostream_wrapper& out, const char* str, std::size_t size);
|
||||
bool WriteTag(ostream_wrapper& out, const std::string& str, bool verbatim);
|
||||
bool WriteTagWithPrefix(ostream_wrapper& out, const std::string& prefix,
|
||||
const std::string& tag);
|
||||
|
238
src/fptostring.cpp
Normal file
238
src/fptostring.cpp
Normal file
@@ -0,0 +1,238 @@
|
||||
#include "yaml-cpp/fptostring.h"
|
||||
#include "contrib/dragonbox.h"
|
||||
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
#include <sstream>
|
||||
#include <tuple>
|
||||
|
||||
namespace YAML {
|
||||
namespace detail {
|
||||
namespace fp_formatting {
|
||||
|
||||
/**
|
||||
* Converts a integer into its ASCII digits.
|
||||
*
|
||||
* @param begin/end - a buffer, must be at least 20bytes long.
|
||||
* @param value - input value.
|
||||
* @param width - minimum number of digits, fill with '0' to the left. Must be equal or smaller than the buffer size.
|
||||
* @return - number of digits filled into the buffer (or -1 if preconditions are not meet)
|
||||
*
|
||||
* Example:
|
||||
* std::array<char, 20> buffer;
|
||||
* auto ct = ConvertToChars(buffer.begin(), buffer.end(), 23, 3);
|
||||
* assert(ct = 3);
|
||||
* assert(buffer[0] == '0');
|
||||
* assert(buffer[1] == '2');
|
||||
* assert(buffer[2] == '3');
|
||||
*/
|
||||
int ConvertToChars(char* begin, char* end, size_t value, int width=1) {
|
||||
// precondition of this function (will trigger in debug build)
|
||||
assert(width >= 1);
|
||||
assert(end >= begin); // end must be after begin
|
||||
assert(end-begin >= width); // Buffer must be large enough
|
||||
assert(end-begin >= 20); // 2^64 has 20digits, so at least 20 digits must be available
|
||||
|
||||
// defensive programming, abort if precondition are not met (will trigger in release build)
|
||||
if (width < 1) {
|
||||
return -1;
|
||||
}
|
||||
if (end < begin) {
|
||||
return -1;
|
||||
}
|
||||
if (end-begin < width) {
|
||||
return -1;
|
||||
}
|
||||
if (end-begin < 20) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// count number of digits, and fill digits array accordingly
|
||||
int digits_ct{};
|
||||
while (value > 0) {
|
||||
char c = value % 10 + '0';
|
||||
value = value / 10;
|
||||
digits_ct += 1;
|
||||
*(end-digits_ct) = c;
|
||||
}
|
||||
while(digits_ct < width) {
|
||||
assert(digits_ct < 64);
|
||||
digits_ct += 1;
|
||||
*(end-digits_ct) = '0';
|
||||
}
|
||||
// move data to the front of the array
|
||||
std::memmove(begin, end-digits_ct, digits_ct);
|
||||
return digits_ct;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a float or double to a string.
|
||||
*
|
||||
* converts a value 'v' to a string. Uses dragonbox for formatting.
|
||||
*/
|
||||
template <typename T>
|
||||
std::string FpToString(T v, int precision = 0) {
|
||||
// hard coded constant, at which exponent should switch to a scientific notation
|
||||
int const lowerExponentThreshold = -5;
|
||||
int const upperExponentThreshold = (precision==0)?6:precision;
|
||||
if (precision == 0) {
|
||||
precision = 6;
|
||||
}
|
||||
|
||||
// dragonbox/to_decimal does not handle value 0, inf, NaN
|
||||
if (v == 0 || std::isinf(v) || std::isnan(v)) {
|
||||
std::stringstream ss;
|
||||
ss.imbue(std::locale("C"));
|
||||
ss << v;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
auto r = jkj::dragonbox::to_decimal(v);
|
||||
|
||||
auto digits = std::array<char, 20>{}; // max digits of size_t is 20.
|
||||
auto digits_ct = ConvertToChars(digits.data(), digits.data() + digits.size(), r.significand);
|
||||
|
||||
// defensive programming, ConvertToChars arguments are invalid
|
||||
if (digits_ct == -1) {
|
||||
std::stringstream ss;
|
||||
ss.imbue(std::locale("C"));
|
||||
ss << v;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
// check if requested precision is lower than
|
||||
// required digits for exact representation
|
||||
if (digits_ct > precision) {
|
||||
auto diff = digits_ct - precision;
|
||||
r.exponent += diff;
|
||||
digits_ct = precision;
|
||||
|
||||
// round numbers if required
|
||||
if (digits[digits_ct] >= '5') {
|
||||
int i{digits_ct-1};
|
||||
digits[i] += 1;
|
||||
while (digits[i] == '9'+1) {
|
||||
digits_ct -= 1;
|
||||
r.exponent += 1;
|
||||
if (i > 0) {
|
||||
digits[i-1] += 1;
|
||||
i -= 1;
|
||||
} else {
|
||||
digits_ct = 1;
|
||||
digits[0] = '1';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::array<char, 28> output_buffer; // max digits of size_t plus sign, a dot and 2 letters for 'e+' or 'e-' and 4 letters for the exponent
|
||||
auto output_ptr = &output_buffer[0];
|
||||
|
||||
// print '-' symbol for negative numbers
|
||||
if (r.is_negative) {
|
||||
*(output_ptr++) = '-';
|
||||
}
|
||||
|
||||
// exponent if only a single non-zero digit is before the decimal point
|
||||
int const exponent = r.exponent + digits_ct - 1;
|
||||
|
||||
// case 1: scientific notation
|
||||
if (exponent >= upperExponentThreshold || exponent <= lowerExponentThreshold) {
|
||||
// print first digit
|
||||
*(output_ptr++) = digits[0];
|
||||
|
||||
// print digits after decimal point
|
||||
if (digits_ct > 1) {
|
||||
*(output_ptr++) = '.';
|
||||
// print significant numbers after decimal point
|
||||
for (int i{1}; i < digits_ct; ++i) {
|
||||
*(output_ptr++) = digits[i];
|
||||
}
|
||||
}
|
||||
*(output_ptr++) = 'e';
|
||||
*(output_ptr++) = (exponent>=0)?'+':'-';
|
||||
auto exp_digits = std::array<char, 20>{};
|
||||
auto exp_digits_ct = ConvertToChars(exp_digits.data(), exp_digits.data() + exp_digits.size(), std::abs(exponent), /*.precision=*/ 2);
|
||||
|
||||
// defensive programming, ConvertToChars arguments are invalid
|
||||
if (exp_digits_ct == -1) {
|
||||
std::stringstream ss;
|
||||
ss.imbue(std::locale("C"));
|
||||
ss << v;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
for (int i{0}; i < exp_digits_ct; ++i) {
|
||||
*(output_ptr++) = exp_digits[i];
|
||||
}
|
||||
|
||||
// case 2: default notation
|
||||
} else {
|
||||
auto const digits_end = digits.begin() + digits_ct;
|
||||
auto digits_iter = digits.begin();
|
||||
|
||||
// print digits before point
|
||||
int const before_decimal_digits = digits_ct + r.exponent;
|
||||
if (before_decimal_digits > 0) {
|
||||
// print digits before point
|
||||
for (int i{0}; i < std::min(before_decimal_digits, digits_ct); ++i) {
|
||||
*(output_ptr++) = *(digits_iter++);
|
||||
}
|
||||
// print trailing zeros before point
|
||||
for (int i{0}; i < before_decimal_digits - digits_ct; ++i) {
|
||||
*(output_ptr++) = '0';
|
||||
}
|
||||
|
||||
// print 0 before point if none where printed before
|
||||
} else {
|
||||
*(output_ptr++) = '0';
|
||||
}
|
||||
|
||||
if (digits_iter != digits_end) {
|
||||
*(output_ptr++) = '.';
|
||||
// print 0 after decimal point, to fill until first digits
|
||||
int const after_decimal_zeros = -digits_ct - r.exponent;
|
||||
for (int i{0}; i < after_decimal_zeros; ++i) {
|
||||
*(output_ptr++) = '0';
|
||||
}
|
||||
|
||||
// print significant numbers after decimal point
|
||||
for (;digits_iter < digits_end; ++digits_iter) {
|
||||
*(output_ptr++) = *digits_iter;
|
||||
}
|
||||
}
|
||||
}
|
||||
*output_ptr = '\0';
|
||||
return std::string{&output_buffer[0], output_ptr};
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
std::string FpToString(float v, size_t precision) {
|
||||
return detail::fp_formatting::FpToString(v, precision);
|
||||
}
|
||||
|
||||
std::string FpToString(double v, size_t precision) {
|
||||
return detail::fp_formatting::FpToString(v, precision);
|
||||
}
|
||||
|
||||
/**
|
||||
* dragonbox only works for floats/doubles not long double
|
||||
*/
|
||||
std::string FpToString(long double v, size_t precision) {
|
||||
std::stringstream ss;
|
||||
ss.imbue(std::locale("C"));
|
||||
if (precision == 0) {
|
||||
precision = std::numeric_limits<long double>::max_digits10;
|
||||
}
|
||||
ss.precision(precision);
|
||||
ss << v;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
}
|
@@ -7,7 +7,6 @@
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
#include <cstddef>
|
||||
|
||||
#include "yaml-cpp/ostream_wrapper.h"
|
||||
|
@@ -9,6 +9,10 @@ void memory_holder::merge(memory_holder& rhs) {
|
||||
if (m_pMemory == rhs.m_pMemory)
|
||||
return;
|
||||
|
||||
if (m_pMemory->size() < rhs.m_pMemory->size()) {
|
||||
std::swap(m_pMemory, rhs.m_pMemory);
|
||||
}
|
||||
|
||||
m_pMemory->merge(*rhs.m_pMemory);
|
||||
rhs.m_pMemory = m_pMemory;
|
||||
}
|
||||
@@ -22,5 +26,9 @@ node& memory::create_node() {
|
||||
void memory::merge(const memory& rhs) {
|
||||
m_nodes.insert(rhs.m_nodes.begin(), rhs.m_nodes.end());
|
||||
}
|
||||
|
||||
size_t memory::size() const {
|
||||
return m_nodes.size();
|
||||
}
|
||||
} // namespace detail
|
||||
} // namespace YAML
|
||||
|
@@ -310,6 +310,7 @@ void node_data::convert_sequence_to_map(const shared_memory_holder& pMemory) {
|
||||
reset_map();
|
||||
for (std::size_t i = 0; i < m_sequence.size(); i++) {
|
||||
std::stringstream stream;
|
||||
stream.imbue(std::locale("C"));
|
||||
stream << i;
|
||||
|
||||
node& key = pMemory->create_node();
|
||||
|
13
src/null.cpp
13
src/null.cpp
@@ -1,10 +1,17 @@
|
||||
#include "yaml-cpp/null.h"
|
||||
#include <cstring>
|
||||
|
||||
namespace YAML {
|
||||
_Null Null;
|
||||
|
||||
bool IsNullString(const std::string& str) {
|
||||
return str.empty() || str == "~" || str == "null" || str == "Null" ||
|
||||
str == "NULL";
|
||||
template <std::size_t N>
|
||||
static bool same(const char* str, std::size_t size, const char (&literal)[N]) {
|
||||
constexpr int literalSize = N - 1; // minus null terminator
|
||||
return size == literalSize && std::strncmp(str, literal, literalSize) == 0;
|
||||
}
|
||||
|
||||
bool IsNullString(const char* str, std::size_t size) {
|
||||
return size == 0 || same(str, size, "~") || same(str, size, "null") ||
|
||||
same(str, size, "Null") || same(str, size, "NULL");
|
||||
}
|
||||
} // namespace YAML
|
||||
|
@@ -2,7 +2,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <ostream>
|
||||
|
||||
namespace YAML {
|
||||
ostream_wrapper::ostream_wrapper()
|
||||
|
@@ -53,7 +53,7 @@ std::vector<Node> LoadAll(std::istream& input) {
|
||||
Parser parser(input);
|
||||
while (true) {
|
||||
NodeBuilder builder;
|
||||
if (!parser.HandleNextDocument(builder)) {
|
||||
if (!parser.HandleNextDocument(builder) || builder.Root().IsNull()) {
|
||||
break;
|
||||
}
|
||||
docs.push_back(builder.Root());
|
||||
|
@@ -77,6 +77,7 @@ void Parser::HandleYamlDirective(const Token& token) {
|
||||
}
|
||||
|
||||
std::stringstream str(token.params[0]);
|
||||
str.imbue(std::locale("C"));
|
||||
str >> m_pDirectives->version.major;
|
||||
str.get();
|
||||
str >> m_pDirectives->version.minor;
|
||||
|
@@ -27,6 +27,10 @@ inline bool RegEx::Matches(const Stream& in) const { return Match(in) >= 0; }
|
||||
|
||||
template <typename Source>
|
||||
inline bool RegEx::Matches(const Source& source) const {
|
||||
#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201103L) || __cplusplus >= 201103L)
|
||||
static_assert(!std::is_same<Source, const char*>::value,
|
||||
#endif
|
||||
"Must use StringCharSource instead of plain C-string");
|
||||
return Match(source) >= 0;
|
||||
}
|
||||
|
||||
|
@@ -13,6 +13,7 @@ Scanner::Scanner(std::istream& in)
|
||||
m_startedStream(false),
|
||||
m_endedStream(false),
|
||||
m_simpleKeyAllowed(false),
|
||||
m_scalarValueAllowed(false),
|
||||
m_canBeJSONFlow(false),
|
||||
m_simpleKeys{},
|
||||
m_indents{},
|
||||
@@ -127,6 +128,17 @@ void Scanner::ScanNextToken() {
|
||||
}
|
||||
|
||||
if (INPUT.peek() == Keys::FlowEntry) {
|
||||
// values starting with `,` are not allowed.
|
||||
// eg: reject `,foo`
|
||||
if (INPUT.column() == 0) {
|
||||
throw ParserException(INPUT.mark(), ErrorMsg::UNEXPECTED_FLOW);
|
||||
}
|
||||
// if we already parsed a quoted scalar value and we are not in a flow,
|
||||
// then `,` is not a valid character.
|
||||
// eg: reject `"foo",`
|
||||
if (!m_scalarValueAllowed) {
|
||||
throw ParserException(INPUT.mark(), ErrorMsg::UNEXPECTED_SCALAR);
|
||||
}
|
||||
return ScanFlowEntry();
|
||||
}
|
||||
|
||||
@@ -159,6 +171,13 @@ void Scanner::ScanNextToken() {
|
||||
return ScanBlockScalar();
|
||||
}
|
||||
|
||||
// if we already parsed a quoted scalar value in this line,
|
||||
// another scalar value is an error.
|
||||
// eg: reject `"foo" "bar"`
|
||||
if (!m_scalarValueAllowed) {
|
||||
throw ParserException(INPUT.mark(), ErrorMsg::UNEXPECTED_SCALAR);
|
||||
}
|
||||
|
||||
if (INPUT.peek() == '\'' || INPUT.peek() == '\"') {
|
||||
return ScanQuotedScalar();
|
||||
}
|
||||
@@ -203,6 +222,9 @@ void Scanner::ScanToNextToken() {
|
||||
// oh yeah, and let's get rid of that simple key
|
||||
InvalidateSimpleKey();
|
||||
|
||||
// new line - we accept a scalar value now
|
||||
m_scalarValueAllowed = true;
|
||||
|
||||
// new line - we may be able to accept a simple key now
|
||||
if (InBlockContext()) {
|
||||
m_simpleKeyAllowed = true;
|
||||
@@ -245,6 +267,7 @@ const RegEx& Scanner::GetValueRegex() const {
|
||||
void Scanner::StartStream() {
|
||||
m_startedStream = true;
|
||||
m_simpleKeyAllowed = true;
|
||||
m_scalarValueAllowed = true;
|
||||
std::unique_ptr<IndentMarker> pIndent(
|
||||
new IndentMarker(-1, IndentMarker::NONE));
|
||||
m_indentRefs.push_back(std::move(pIndent));
|
||||
@@ -261,6 +284,7 @@ void Scanner::EndStream() {
|
||||
PopAllSimpleKeys();
|
||||
|
||||
m_simpleKeyAllowed = false;
|
||||
m_scalarValueAllowed = false;
|
||||
m_endedStream = true;
|
||||
}
|
||||
|
||||
|
@@ -177,6 +177,7 @@ class Scanner {
|
||||
// state info
|
||||
bool m_startedStream, m_endedStream;
|
||||
bool m_simpleKeyAllowed;
|
||||
bool m_scalarValueAllowed;
|
||||
bool m_canBeJSONFlow;
|
||||
std::stack<SimpleKey> m_simpleKeys;
|
||||
std::stack<IndentMarker *> m_indents;
|
||||
|
@@ -211,6 +211,9 @@ void Scanner::ScanValue() {
|
||||
m_simpleKeyAllowed = InBlockContext();
|
||||
}
|
||||
|
||||
// we are parsing a `key: value` pair; scalars are always allowed
|
||||
m_scalarValueAllowed = true;
|
||||
|
||||
// eat
|
||||
Mark mark = INPUT.mark();
|
||||
INPUT.eat(1);
|
||||
@@ -360,6 +363,10 @@ void Scanner::ScanQuotedScalar() {
|
||||
// and scan
|
||||
scalar = ScanScalar(INPUT, params);
|
||||
m_simpleKeyAllowed = false;
|
||||
// we just scanned a quoted scalar;
|
||||
// we can only have another scalar in this line
|
||||
// if we are in a flow, eg: `[ "foo", "bar" ]` is ok, but `"foo", "bar"` isn't.
|
||||
m_scalarValueAllowed = InFlowContext();
|
||||
m_canBeJSONFlow = true;
|
||||
|
||||
Token token(Token::NON_PLAIN_SCALAR, mark);
|
||||
|
@@ -1,4 +1,3 @@
|
||||
#include <algorithm>
|
||||
#include <cstdio>
|
||||
#include <sstream>
|
||||
|
||||
@@ -93,9 +92,9 @@ void SingleDocParser::HandleNode(EventHandler& eventHandler) {
|
||||
// add non-specific tags
|
||||
if (tag.empty())
|
||||
tag = (token.type == Token::NON_PLAIN_SCALAR ? "!" : "?");
|
||||
|
||||
if (token.type == Token::PLAIN_SCALAR
|
||||
&& tag.compare("?") == 0 && IsNullString(token.value)) {
|
||||
|
||||
if (token.type == Token::PLAIN_SCALAR
|
||||
&& tag.compare("?") == 0 && IsNullString(token.value.data(), token.value.size())) {
|
||||
eventHandler.OnNull(mark, anchor);
|
||||
m_scanner.pop();
|
||||
return;
|
||||
|
@@ -1,4 +1,4 @@
|
||||
#include <iostream>
|
||||
#include <istream>
|
||||
|
||||
#include "stream.h"
|
||||
|
||||
@@ -262,7 +262,24 @@ char Stream::get() {
|
||||
AdvanceCurrent();
|
||||
m_mark.column++;
|
||||
|
||||
if (ch == '\n') {
|
||||
// if line ending symbol is unknown, set it to the first
|
||||
// encountered line ending.
|
||||
// if line ending '\r' set ending symbol to '\r'
|
||||
// other wise set it to '\n'
|
||||
if (!m_lineEndingSymbol) {
|
||||
if (ch == '\n') { // line ending is '\n'
|
||||
m_lineEndingSymbol = '\n';
|
||||
} else if (ch == '\r') {
|
||||
auto ch2 = peek();
|
||||
if (ch2 == '\n') { // line ending is '\r\n'
|
||||
m_lineEndingSymbol = '\n';
|
||||
} else { // line ending is '\r'
|
||||
m_lineEndingSymbol = '\r';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ch == m_lineEndingSymbol) {
|
||||
m_mark.column = 0;
|
||||
m_mark.line++;
|
||||
}
|
||||
|
@@ -11,7 +11,7 @@
|
||||
#include <cstddef>
|
||||
#include <deque>
|
||||
#include <ios>
|
||||
#include <iostream>
|
||||
#include <istream>
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
@@ -53,6 +53,7 @@ class Stream {
|
||||
Mark m_mark;
|
||||
|
||||
CharacterSet m_charSet;
|
||||
char m_lineEndingSymbol{}; // 0 means it is not determined yet, must be '\n' or '\r'
|
||||
mutable std::deque<char> m_readahead;
|
||||
unsigned char* const m_pPrefetched;
|
||||
mutable size_t m_nPrefetchedAvailable;
|
||||
|
@@ -8,17 +8,18 @@
|
||||
#endif
|
||||
|
||||
#include "yaml-cpp/mark.h"
|
||||
#include <iostream>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace YAML {
|
||||
const std::string TokenNames[] = {
|
||||
constexpr const char* TokenNames[] = {
|
||||
"DIRECTIVE", "DOC_START", "DOC_END", "BLOCK_SEQ_START",
|
||||
"BLOCK_MAP_START", "BLOCK_SEQ_END", "BLOCK_MAP_END", "BLOCK_ENTRY",
|
||||
"FLOW_SEQ_START", "FLOW_MAP_START", "FLOW_SEQ_END", "FLOW_MAP_END",
|
||||
"FLOW_MAP_COMPACT", "FLOW_ENTRY", "KEY", "VALUE",
|
||||
"ANCHOR", "ALIAS", "TAG", "SCALAR"};
|
||||
"ANCHOR", "ALIAS", "TAG", "SCALAR",
|
||||
"NON_PLAIN_SCALAR"};
|
||||
|
||||
struct Token {
|
||||
// enums
|
||||
|
@@ -1,14 +1,28 @@
|
||||
package(default_visibility = ["//test:__subpackages__"])
|
||||
|
||||
cc_library(
|
||||
name = "mock_event_handler",
|
||||
hdrs = ["mock_event_handler.h"],
|
||||
strip_include_prefix = "//test",
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "specexamples",
|
||||
hdrs = ["specexamples.h"],
|
||||
strip_include_prefix = "//test",
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "test",
|
||||
srcs = glob([
|
||||
"*.cpp",
|
||||
"*.h",
|
||||
"integrations/*.cpp",
|
||||
"node/*.cpp",
|
||||
]),
|
||||
deps = [
|
||||
":mock_event_handler",
|
||||
":specexamples",
|
||||
"//:yaml-cpp",
|
||||
"//:yaml-cpp_internal",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
"@googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
@@ -2,13 +2,19 @@ find_package(Threads REQUIRED)
|
||||
|
||||
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
|
||||
set(BUILD_MOCK ON CACHE BOOL "" FORCE)
|
||||
set(CMAKE_POLICY_DEFAULT_CMP0048 NEW)
|
||||
set(INSTALL_GTEST OFF CACHE BOOL "" FORCE)
|
||||
|
||||
add_subdirectory(
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/gtest-1.11.0"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/prefix")
|
||||
|
||||
include_directories(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/gtest-1.11.0/googletest/include")
|
||||
if(YAML_USE_SYSTEM_GTEST)
|
||||
find_package(GTest)
|
||||
if (NOT GTEST_FOUND)
|
||||
message(FATAL_ERROR "system googletest was requested but not found")
|
||||
endif()
|
||||
else()
|
||||
add_subdirectory(
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/googletest-1.13.0"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/prefix")
|
||||
include_directories(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/googletest-1.13.0/googletest/include")
|
||||
endif()
|
||||
|
||||
set(test-new-api-pattern "new-api/*.cpp")
|
||||
set(test-source-pattern "*.cpp" "integration/*.cpp" "node/*.cpp")
|
||||
@@ -33,11 +39,12 @@ target_include_directories(yaml-cpp-tests
|
||||
target_compile_options(yaml-cpp-tests
|
||||
PRIVATE
|
||||
$<$<CXX_COMPILER_ID:Clang>:-Wno-c99-extensions -Wno-variadic-macros -Wno-sign-compare>
|
||||
$<$<CXX_COMPILER_ID:GNU>:-Wno-variadic-macros -Wno-sign-compare>)
|
||||
$<$<CXX_COMPILER_ID:GNU>:-Wno-variadic-macros -Wno-sign-compare -Wno-narrowing>)
|
||||
target_link_libraries(yaml-cpp-tests
|
||||
PRIVATE
|
||||
Threads::Threads
|
||||
yaml-cpp
|
||||
gtest
|
||||
gmock)
|
||||
|
||||
set_property(TARGET yaml-cpp-tests PROPERTY CXX_STANDARD_REQUIRED ON)
|
||||
|
21
test/cmake/CMakeLists.txt
Normal file
21
test/cmake/CMakeLists.txt
Normal file
@@ -0,0 +1,21 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
project(yaml-cpp-consumer LANGUAGES CXX)
|
||||
|
||||
find_package(yaml-cpp CONFIG REQUIRED)
|
||||
get_target_property(LIBRARY_TYPE yaml-cpp::yaml-cpp TYPE)
|
||||
|
||||
if(LIBRARY_TYPE STREQUAL "SHARED_LIBRARY")
|
||||
if(NOT YAML_CPP_SHARED_LIBS_BUILT)
|
||||
message(FATAL_ERROR "Library type (${LIBRARY_TYPE}) contradicts config: ${YAML_CPP_SHARED_LIBS_BUILT}")
|
||||
endif()
|
||||
else()
|
||||
if(YAML_CPP_SHARED_LIBS_BUILT)
|
||||
message(FATAL_ERROR "Library type (${LIBRARY_TYPE}) contradicts config: ${YAML_CPP_SHARED_LIBS_BUILT}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
add_executable(main main.cpp)
|
||||
if (NOT DEFINED CMAKE_CXX_STANDARD)
|
||||
set_target_properties(main PROPERTIES CXX_STANDARD 11)
|
||||
endif()
|
||||
target_link_libraries(main PRIVATE ${YAML_CPP_LIBRARIES})
|
3
test/cmake/main.cpp
Normal file
3
test/cmake/main.cpp
Normal file
@@ -0,0 +1,3 @@
|
||||
#include "yaml-cpp/yaml.h"
|
||||
|
||||
int main(int, char**) { YAML::Parser foo{}; }
|
242
test/fptostring_test.cpp
Normal file
242
test/fptostring_test.cpp
Normal file
@@ -0,0 +1,242 @@
|
||||
#include "yaml-cpp/fptostring.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace YAML {
|
||||
namespace {
|
||||
|
||||
/**
|
||||
* Helper function, that converts double to string as std::stringstream would do
|
||||
*/
|
||||
template <typename T>
|
||||
static std::string convert_with_stringstream(T v, size_t precision = 0) {
|
||||
std::stringstream ss;
|
||||
if (precision > 0) {
|
||||
ss << std::setprecision(precision);
|
||||
}
|
||||
ss << v;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
// Caution: Test involving 'convert_with_stringstream' are based on std::stringstream
|
||||
// having certain printing behavior, if these changes, the unit test might fail.
|
||||
// This is not a fault of FpToString just a weakness of the way these
|
||||
// tests are constructed
|
||||
|
||||
TEST(FpToStringTest, conversion_double) {
|
||||
// Issue motivating FpToString function,
|
||||
// https://github.com/jbeder/yaml-cpp/issues/1289
|
||||
// Original problem at hand:
|
||||
EXPECT_EQ("34.34", FpToString(34.34));
|
||||
EXPECT_EQ("56.56", FpToString(56.56));
|
||||
EXPECT_EQ("12.12", FpToString(12.12));
|
||||
EXPECT_EQ("78.78", FpToString(78.78));
|
||||
|
||||
// Special challenge with rounding
|
||||
// https://github.com/jbeder/yaml-cpp/issues/1289#issuecomment-2211705536
|
||||
EXPECT_EQ("1.54743e+26", FpToString(1.5474250491e+26f));
|
||||
EXPECT_EQ(convert_with_stringstream(1.5474250491e+26f), FpToString(1.5474250491e+26f));
|
||||
EXPECT_EQ("1.5474251e+26", FpToString(1.5474250491e+26f, 8));
|
||||
|
||||
// prints the same way as std::stringstream
|
||||
EXPECT_EQ(convert_with_stringstream(1.), FpToString(1.));
|
||||
EXPECT_EQ(convert_with_stringstream(1e0), FpToString(1e0));
|
||||
EXPECT_EQ(convert_with_stringstream(1e1), FpToString(1e1));
|
||||
EXPECT_EQ(convert_with_stringstream(1e2), FpToString(1e2));
|
||||
EXPECT_EQ(convert_with_stringstream(1e3), FpToString(1e3));
|
||||
EXPECT_EQ(convert_with_stringstream(1e4), FpToString(1e4));
|
||||
EXPECT_EQ(convert_with_stringstream(1e5), FpToString(1e5));
|
||||
EXPECT_EQ(convert_with_stringstream(1e6), FpToString(1e6));
|
||||
EXPECT_EQ(convert_with_stringstream(1e7), FpToString(1e7));
|
||||
EXPECT_EQ(convert_with_stringstream(1e8), FpToString(1e8));
|
||||
EXPECT_EQ(convert_with_stringstream(1e9), FpToString(1e9));
|
||||
|
||||
// Print by default values below 1e6 without scientific notation
|
||||
EXPECT_EQ("1", FpToString(1.));
|
||||
EXPECT_EQ("1", FpToString(1e0));
|
||||
EXPECT_EQ("10", FpToString(1e1));
|
||||
EXPECT_EQ("100", FpToString(1e2));
|
||||
EXPECT_EQ("1000", FpToString(1e3));
|
||||
EXPECT_EQ("10000", FpToString(1e4));
|
||||
EXPECT_EQ("100000", FpToString(1e5));
|
||||
EXPECT_EQ("1e+06", FpToString(1e6));
|
||||
EXPECT_EQ("1e+07", FpToString(1e7));
|
||||
EXPECT_EQ("1e+08", FpToString(1e8));
|
||||
EXPECT_EQ("1e+09", FpToString(1e9));
|
||||
|
||||
// prints the same way as std::stringstream
|
||||
EXPECT_EQ(convert_with_stringstream(1.), FpToString(1.));
|
||||
EXPECT_EQ(convert_with_stringstream(1e-0), FpToString(1e-0));
|
||||
EXPECT_EQ(convert_with_stringstream(1e-1), FpToString(1e-1));
|
||||
EXPECT_EQ(convert_with_stringstream(1e-2), FpToString(1e-2));
|
||||
EXPECT_EQ(convert_with_stringstream(1e-3), FpToString(1e-3));
|
||||
EXPECT_EQ(convert_with_stringstream(1e-4), FpToString(1e-4));
|
||||
EXPECT_EQ(convert_with_stringstream(1e-5), FpToString(1e-5));
|
||||
EXPECT_EQ(convert_with_stringstream(1e-6), FpToString(1e-6));
|
||||
EXPECT_EQ(convert_with_stringstream(1e-7), FpToString(1e-7));
|
||||
EXPECT_EQ(convert_with_stringstream(1e-8), FpToString(1e-8));
|
||||
EXPECT_EQ(convert_with_stringstream(1e-9), FpToString(1e-9));
|
||||
|
||||
// Print by default values above 1e-5 without scientific notation
|
||||
EXPECT_EQ("1", FpToString(1.));
|
||||
EXPECT_EQ("1", FpToString(1e-0));
|
||||
EXPECT_EQ("0.1", FpToString(1e-1));
|
||||
EXPECT_EQ("0.01", FpToString(1e-2));
|
||||
EXPECT_EQ("0.001", FpToString(1e-3));
|
||||
EXPECT_EQ("0.0001", FpToString(1e-4));
|
||||
EXPECT_EQ("1e-05", FpToString(1e-5));
|
||||
EXPECT_EQ("1e-06", FpToString(1e-6));
|
||||
EXPECT_EQ("1e-07", FpToString(1e-7));
|
||||
EXPECT_EQ("1e-08", FpToString(1e-8));
|
||||
EXPECT_EQ("1e-09", FpToString(1e-9));
|
||||
|
||||
// changing precision has the same effect as std::stringstream
|
||||
EXPECT_EQ(convert_with_stringstream(123., 1), FpToString(123., 1));
|
||||
EXPECT_EQ(convert_with_stringstream(1234567., 7), FpToString(1234567., 7));
|
||||
EXPECT_EQ(convert_with_stringstream(12345.67, 7), FpToString(12345.67, 7));
|
||||
EXPECT_EQ(convert_with_stringstream(1234567e-9, 7), FpToString(1234567e-9, 7));
|
||||
EXPECT_EQ(convert_with_stringstream(1234567e-9, 1), FpToString(1234567e-9, 1));
|
||||
|
||||
// known example that is difficult to round
|
||||
EXPECT_EQ("1", FpToString(0.9999, 2));
|
||||
EXPECT_EQ("-1", FpToString(-0.9999, 2));
|
||||
|
||||
// some more random tests
|
||||
EXPECT_EQ("1.25", FpToString(1.25));
|
||||
EXPECT_EQ("34.34", FpToString(34.34));
|
||||
EXPECT_EQ("1e+20", FpToString(1e+20));
|
||||
EXPECT_EQ("1.1e+20", FpToString(1.1e+20));
|
||||
EXPECT_EQ("1e-20", FpToString(1e-20));
|
||||
EXPECT_EQ("1.1e-20", FpToString(1.1e-20));
|
||||
EXPECT_EQ("1e-20", FpToString(0.1e-19));
|
||||
EXPECT_EQ("1.1e-20", FpToString(0.11e-19));
|
||||
|
||||
EXPECT_EQ("19", FpToString(18.9, 2));
|
||||
EXPECT_EQ("20", FpToString(19.9, 2));
|
||||
EXPECT_EQ("2e+01", FpToString(19.9, 1));
|
||||
EXPECT_EQ("1.2e-05", FpToString(1.234e-5, 2));
|
||||
EXPECT_EQ("1.3e-05", FpToString(1.299e-5, 2));
|
||||
|
||||
EXPECT_EQ("-1", FpToString(-1.));
|
||||
EXPECT_EQ("-1.25", FpToString(-1.25));
|
||||
EXPECT_EQ("-34.34", FpToString(-34.34));
|
||||
EXPECT_EQ("-1e+20", FpToString(-1e+20));
|
||||
EXPECT_EQ("-1.1e+20", FpToString(-1.1e+20));
|
||||
EXPECT_EQ("-1e-20", FpToString(-1e-20));
|
||||
EXPECT_EQ("-1.1e-20", FpToString(-1.1e-20));
|
||||
EXPECT_EQ("-1e-20", FpToString(-0.1e-19));
|
||||
EXPECT_EQ("-1.1e-20", FpToString(-0.11e-19));
|
||||
|
||||
EXPECT_EQ("-19", FpToString(-18.9, 2));
|
||||
EXPECT_EQ("-20", FpToString(-19.9, 2));
|
||||
EXPECT_EQ("-2e+01", FpToString(-19.9, 1));
|
||||
EXPECT_EQ("-1.2e-05", FpToString(-1.234e-5, 2));
|
||||
EXPECT_EQ("-1.3e-05", FpToString(-1.299e-5, 2));
|
||||
}
|
||||
|
||||
TEST(FpToStringTest, conversion_float) {
|
||||
// Issue motivating FpToString function,
|
||||
// https://github.com/jbeder/yaml-cpp/issues/1289
|
||||
// Original problem at hand:
|
||||
EXPECT_EQ("34.34", FpToString(34.34f));
|
||||
EXPECT_EQ("56.56", FpToString(56.56f));
|
||||
EXPECT_EQ("12.12", FpToString(12.12f));
|
||||
EXPECT_EQ("78.78", FpToString(78.78f));
|
||||
|
||||
// prints the same way as std::stringstream
|
||||
EXPECT_EQ(convert_with_stringstream(1.f), FpToString(1.f));
|
||||
EXPECT_EQ(convert_with_stringstream(1e0f), FpToString(1e0f));
|
||||
EXPECT_EQ(convert_with_stringstream(1e1f), FpToString(1e1f));
|
||||
EXPECT_EQ(convert_with_stringstream(1e2f), FpToString(1e2f));
|
||||
EXPECT_EQ(convert_with_stringstream(1e3f), FpToString(1e3f));
|
||||
EXPECT_EQ(convert_with_stringstream(1e4f), FpToString(1e4f));
|
||||
EXPECT_EQ(convert_with_stringstream(1e5f), FpToString(1e5f));
|
||||
EXPECT_EQ(convert_with_stringstream(1e6f), FpToString(1e6f));
|
||||
EXPECT_EQ(convert_with_stringstream(1e7f), FpToString(1e7f));
|
||||
EXPECT_EQ(convert_with_stringstream(1e8f), FpToString(1e8f));
|
||||
EXPECT_EQ(convert_with_stringstream(1e9f), FpToString(1e9f));
|
||||
|
||||
// Print by default values below 1e6 without scientific notation
|
||||
EXPECT_EQ("1", FpToString(1.f));
|
||||
EXPECT_EQ("1", FpToString(1e0f));
|
||||
EXPECT_EQ("10", FpToString(1e1f));
|
||||
EXPECT_EQ("100", FpToString(1e2f));
|
||||
EXPECT_EQ("1000", FpToString(1e3f));
|
||||
EXPECT_EQ("10000", FpToString(1e4f));
|
||||
EXPECT_EQ("100000", FpToString(1e5f));
|
||||
EXPECT_EQ("1e+06", FpToString(1e6f));
|
||||
EXPECT_EQ("1e+07", FpToString(1e7f));
|
||||
EXPECT_EQ("1e+08", FpToString(1e8f));
|
||||
EXPECT_EQ("1e+09", FpToString(1e9f));
|
||||
|
||||
// prints the same way as std::stringstream
|
||||
EXPECT_EQ(convert_with_stringstream(1.f), FpToString(1.f));
|
||||
EXPECT_EQ(convert_with_stringstream(1e-0f), FpToString(1e-0f));
|
||||
EXPECT_EQ(convert_with_stringstream(1e-1f), FpToString(1e-1f));
|
||||
EXPECT_EQ(convert_with_stringstream(1e-2f), FpToString(1e-2f));
|
||||
EXPECT_EQ(convert_with_stringstream(1e-3f), FpToString(1e-3f));
|
||||
EXPECT_EQ(convert_with_stringstream(1e-4f), FpToString(1e-4f));
|
||||
EXPECT_EQ(convert_with_stringstream(1e-5f), FpToString(1e-5f));
|
||||
EXPECT_EQ(convert_with_stringstream(1e-6f), FpToString(1e-6f));
|
||||
EXPECT_EQ(convert_with_stringstream(1e-7f), FpToString(1e-7f));
|
||||
EXPECT_EQ(convert_with_stringstream(1e-8f), FpToString(1e-8f));
|
||||
EXPECT_EQ(convert_with_stringstream(1e-9f), FpToString(1e-9f));
|
||||
|
||||
// Print by default values above 1e-5 without scientific notation
|
||||
EXPECT_EQ("1", FpToString(1.f));
|
||||
EXPECT_EQ("1", FpToString(1e-0f));
|
||||
EXPECT_EQ("0.1", FpToString(1e-1f));
|
||||
EXPECT_EQ("0.01", FpToString(1e-2f));
|
||||
EXPECT_EQ("0.001", FpToString(1e-3f));
|
||||
EXPECT_EQ("0.0001", FpToString(1e-4f));
|
||||
EXPECT_EQ("1e-05", FpToString(1e-5f));
|
||||
EXPECT_EQ("1e-06", FpToString(1e-6f));
|
||||
EXPECT_EQ("1e-07", FpToString(1e-7f));
|
||||
EXPECT_EQ("1e-08", FpToString(1e-8f));
|
||||
EXPECT_EQ("1e-09", FpToString(1e-9f));
|
||||
|
||||
// changing precision has the same effect as std::stringstream
|
||||
EXPECT_EQ(convert_with_stringstream(123.f, 1), FpToString(123.f, 1));
|
||||
EXPECT_EQ(convert_with_stringstream(1234567.f, 7), FpToString(1234567.f, 7));
|
||||
EXPECT_EQ(convert_with_stringstream(12345.67f, 7), FpToString(12345.67f, 7));
|
||||
EXPECT_EQ(convert_with_stringstream(1234567e-9f, 7), FpToString(1234567e-9f, 7));
|
||||
EXPECT_EQ(convert_with_stringstream(1234567e-9f, 1), FpToString(1234567e-9f, 1));
|
||||
|
||||
// known example that is difficult to round
|
||||
EXPECT_EQ("1", FpToString(0.9999f, 2));
|
||||
EXPECT_EQ("-1", FpToString(-0.9999f, 2));
|
||||
|
||||
// some more random tests
|
||||
EXPECT_EQ("1.25", FpToString(1.25f));
|
||||
EXPECT_EQ("34.34", FpToString(34.34f));
|
||||
EXPECT_EQ("1e+20", FpToString(1e+20f));
|
||||
EXPECT_EQ("1.1e+20", FpToString(1.1e+20f));
|
||||
EXPECT_EQ("1e-20", FpToString(1e-20f));
|
||||
EXPECT_EQ("1.1e-20", FpToString(1.1e-20f));
|
||||
EXPECT_EQ("1e-20", FpToString(0.1e-19f));
|
||||
EXPECT_EQ("1.1e-20", FpToString(0.11e-19f));
|
||||
|
||||
EXPECT_EQ("19", FpToString(18.9f, 2));
|
||||
EXPECT_EQ("20", FpToString(19.9f, 2));
|
||||
EXPECT_EQ("2e+01", FpToString(19.9f, 1));
|
||||
EXPECT_EQ("1.2e-05", FpToString(1.234e-5f, 2));
|
||||
EXPECT_EQ("1.3e-05", FpToString(1.299e-5f, 2));
|
||||
|
||||
EXPECT_EQ("-1", FpToString(-1.f));
|
||||
EXPECT_EQ("-1.25", FpToString(-1.25f));
|
||||
EXPECT_EQ("-34.34", FpToString(-34.34f));
|
||||
EXPECT_EQ("-1e+20", FpToString(-1e+20f));
|
||||
EXPECT_EQ("-1.1e+20", FpToString(-1.1e+20f));
|
||||
EXPECT_EQ("-1e-20", FpToString(-1e-20f));
|
||||
EXPECT_EQ("-1.1e-20", FpToString(-1.1e-20f));
|
||||
EXPECT_EQ("-1e-20", FpToString(-0.1e-19f));
|
||||
EXPECT_EQ("-1.1e-20", FpToString(-0.11e-19f));
|
||||
|
||||
EXPECT_EQ("-19", FpToString(-18.9f, 2));
|
||||
EXPECT_EQ("-20", FpToString(-19.9f, 2));
|
||||
EXPECT_EQ("-2e+01", FpToString(-19.9f, 1));
|
||||
EXPECT_EQ("-1.2e-05", FpToString(-1.234e-5f, 2));
|
||||
EXPECT_EQ("-1.3e-05", FpToString(-1.299e-5f, 2));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace YAML
|
53
test/googletest-1.13.0/.github/ISSUE_TEMPLATE/00-bug_report.yml
vendored
Normal file
53
test/googletest-1.13.0/.github/ISSUE_TEMPLATE/00-bug_report.yml
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
name: Bug Report
|
||||
description: Let us know that something does not work as expected.
|
||||
title: "[Bug]: Please title this bug report"
|
||||
body:
|
||||
- type: textarea
|
||||
id: what-happened
|
||||
attributes:
|
||||
label: Describe the issue
|
||||
description: What happened, and what did you expect to happen?
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: steps
|
||||
attributes:
|
||||
label: Steps to reproduce the problem
|
||||
description: It is important that we are able to reproduce the problem that you are experiencing. Please provide all code and relevant steps to reproduce the problem, including your `BUILD`/`CMakeLists.txt` file and build commands. Links to a GitHub branch or [godbolt.org](https://godbolt.org/) that demonstrate the problem are also helpful.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: version
|
||||
attributes:
|
||||
label: What version of GoogleTest are you using?
|
||||
description: Please include the output of `git rev-parse HEAD` or the GoogleTest release version number that you are using.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: os
|
||||
attributes:
|
||||
label: What operating system and version are you using?
|
||||
description: If you are using a Linux distribution please include the name and version of the distribution as well.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: compiler
|
||||
attributes:
|
||||
label: What compiler and version are you using?
|
||||
description: Please include the output of `gcc -v` or `clang -v`, or the equivalent for your compiler.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: buildsystem
|
||||
attributes:
|
||||
label: What build system are you using?
|
||||
description: Please include the output of `bazel --version` or `cmake --version`, or the equivalent for your build system.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: additional
|
||||
attributes:
|
||||
label: Additional context
|
||||
description: Add any other context about the problem here.
|
||||
validations:
|
||||
required: false
|
33
test/googletest-1.13.0/.github/ISSUE_TEMPLATE/10-feature_request.yml
vendored
Normal file
33
test/googletest-1.13.0/.github/ISSUE_TEMPLATE/10-feature_request.yml
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
name: Feature request
|
||||
description: Propose a new feature.
|
||||
title: "[FR]: Please title this feature request"
|
||||
labels: "enhancement"
|
||||
body:
|
||||
- type: textarea
|
||||
id: version
|
||||
attributes:
|
||||
label: Does the feature exist in the most recent commit?
|
||||
description: We recommend using the latest commit from GitHub in your projects.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: why
|
||||
attributes:
|
||||
label: Why do we need this feature?
|
||||
description: Ideally, explain why a combination of existing features cannot be used instead.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: proposal
|
||||
attributes:
|
||||
label: Describe the proposal.
|
||||
description: Include a detailed description of the feature, with usage examples.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: platform
|
||||
attributes:
|
||||
label: Is the feature specific to an operating system, compiler, or build system version?
|
||||
description: If it is, please specify which versions.
|
||||
validations:
|
||||
required: true
|
5
test/googletest-1.13.0/.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
5
test/googletest-1.13.0/.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Get Help
|
||||
url: https://github.com/google/googletest/discussions
|
||||
about: Please ask and answer questions here.
|
43
test/googletest-1.13.0/.github/workflows/gtest-ci.yml
vendored
Normal file
43
test/googletest-1.13.0/.github/workflows/gtest-ci.yml
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
name: ci
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
|
||||
env:
|
||||
BAZEL_CXXOPTS: -std=c++14
|
||||
|
||||
jobs:
|
||||
Linux:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Tests
|
||||
run: bazel test --cxxopt=-std=c++14 --features=external_include_paths --test_output=errors ...
|
||||
|
||||
macOS:
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Tests
|
||||
run: bazel test --cxxopt=-std=c++14 --features=external_include_paths --test_output=errors ...
|
||||
|
||||
|
||||
Windows:
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Tests
|
||||
run: bazel test --cxxopt=/std:c++14 --features=external_include_paths --test_output=errors ...
|
@@ -30,19 +30,32 @@
|
||||
#
|
||||
# Bazel Build for Google C++ Testing Framework(Google Test)
|
||||
|
||||
load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test")
|
||||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
exports_files(["LICENSE"])
|
||||
|
||||
config_setting(
|
||||
name = "qnx",
|
||||
constraint_values = ["@platforms//os:qnx"],
|
||||
)
|
||||
|
||||
config_setting(
|
||||
name = "windows",
|
||||
constraint_values = ["@platforms//os:windows"],
|
||||
)
|
||||
|
||||
config_setting(
|
||||
name = "freebsd",
|
||||
constraint_values = ["@platforms//os:freebsd"],
|
||||
)
|
||||
|
||||
config_setting(
|
||||
name = "openbsd",
|
||||
constraint_values = ["@platforms//os:openbsd"],
|
||||
)
|
||||
|
||||
config_setting(
|
||||
name = "msvc_compiler",
|
||||
flag_values = {
|
||||
@@ -86,6 +99,7 @@ cc_library(
|
||||
"googlemock/include/gmock/*.h",
|
||||
]),
|
||||
copts = select({
|
||||
":qnx": [],
|
||||
":windows": [],
|
||||
"//conditions:default": ["-pthread"],
|
||||
}),
|
||||
@@ -104,7 +118,16 @@ cc_library(
|
||||
"googletest/include",
|
||||
],
|
||||
linkopts = select({
|
||||
":qnx": ["-lregex"],
|
||||
":windows": [],
|
||||
":freebsd": [
|
||||
"-lm",
|
||||
"-pthread",
|
||||
],
|
||||
":openbsd": [
|
||||
"-lm",
|
||||
"-pthread",
|
||||
],
|
||||
"//conditions:default": ["-pthread"],
|
||||
}),
|
||||
deps = select({
|
||||
@@ -112,10 +135,15 @@ cc_library(
|
||||
"@com_google_absl//absl/debugging:failure_signal_handler",
|
||||
"@com_google_absl//absl/debugging:stacktrace",
|
||||
"@com_google_absl//absl/debugging:symbolize",
|
||||
"@com_google_absl//absl/flags:flag",
|
||||
"@com_google_absl//absl/flags:parse",
|
||||
"@com_google_absl//absl/flags:reflection",
|
||||
"@com_google_absl//absl/flags:usage",
|
||||
"@com_google_absl//absl/strings",
|
||||
"@com_google_absl//absl/types:any",
|
||||
"@com_google_absl//absl/types:optional",
|
||||
"@com_google_absl//absl/types:variant",
|
||||
"@com_googlesource_code_re2//:re2",
|
||||
],
|
||||
"//conditions:default": [],
|
||||
}),
|
@@ -1,19 +1,25 @@
|
||||
# Note: CMake support is community-based. The maintainers do not use CMake
|
||||
# internally.
|
||||
|
||||
cmake_minimum_required(VERSION 2.8.12)
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
if (POLICY CMP0048)
|
||||
cmake_policy(SET CMP0048 NEW)
|
||||
endif (POLICY CMP0048)
|
||||
|
||||
project(googletest-distribution)
|
||||
set(GOOGLETEST_VERSION 1.11.0)
|
||||
if (POLICY CMP0069)
|
||||
cmake_policy(SET CMP0069 NEW)
|
||||
endif (POLICY CMP0069)
|
||||
|
||||
if (CMAKE_VERSION VERSION_GREATER "3.0.2")
|
||||
if(NOT CYGWIN AND NOT MSYS AND NOT ${CMAKE_SYSTEM_NAME} STREQUAL QNX)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
endif()
|
||||
if (POLICY CMP0077)
|
||||
cmake_policy(SET CMP0077 NEW)
|
||||
endif (POLICY CMP0077)
|
||||
|
||||
project(googletest-distribution)
|
||||
set(GOOGLETEST_VERSION 1.13.0)
|
||||
|
||||
if(NOT CYGWIN AND NOT MSYS AND NOT ${CMAKE_SYSTEM_NAME} STREQUAL QNX)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
endif()
|
||||
|
||||
enable_testing()
|
||||
@@ -24,6 +30,7 @@ include(GNUInstallDirs)
|
||||
#Note that googlemock target already builds googletest
|
||||
option(BUILD_GMOCK "Builds the googlemock subproject" ON)
|
||||
option(INSTALL_GTEST "Enable installation of googletest. (Projects embedding googletest may want to turn this OFF.)" ON)
|
||||
option(GTEST_HAS_ABSL "Use Abseil and RE2. Requires Abseil and RE2 to be separately added to the build." OFF)
|
||||
|
||||
if(BUILD_GMOCK)
|
||||
add_subdirectory( googlemock )
|
@@ -21,8 +21,8 @@ accept your pull requests.
|
||||
|
||||
## Are you a Googler?
|
||||
|
||||
If you are a Googler, please make an attempt to submit an internal change rather
|
||||
than a GitHub Pull Request. If you are not able to submit an internal change a
|
||||
If you are a Googler, please make an attempt to submit an internal contribution
|
||||
rather than a GitHub Pull Request. If you are not able to submit internally, a
|
||||
PR is acceptable as an alternative.
|
||||
|
||||
## Contributing A Patch
|
||||
@@ -36,7 +36,8 @@ PR is acceptable as an alternative.
|
||||
This ensures that work isn't being duplicated and communicating your plan
|
||||
early also generally leads to better patches.
|
||||
4. If your proposed change is accepted, and you haven't already done so, sign a
|
||||
Contributor License Agreement (see details above).
|
||||
Contributor License Agreement
|
||||
([see details above](#contributor-license-agreements)).
|
||||
5. Fork the desired repo, develop and test your code changes.
|
||||
6. Ensure that your code adheres to the existing style in the sample to which
|
||||
you are contributing.
|
||||
@@ -79,8 +80,8 @@ 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://google.github.io/styleguide/cppguide.html). Use
|
||||
[.clang-format](https://github.com/google/googletest/blob/master/.clang-format)
|
||||
to check your formatting.
|
||||
[.clang-format](https://github.com/google/googletest/blob/main/.clang-format) to
|
||||
check your formatting.
|
||||
|
||||
## Requirements for Contributors
|
||||
|
@@ -34,6 +34,7 @@ Manuel Klimek <klimek@google.com>
|
||||
Mario Tanev <radix@google.com>
|
||||
Mark Paskin
|
||||
Markus Heule <markus.heule@gmail.com>
|
||||
Martijn Vels <mvels@google.com>
|
||||
Matthew Simmons <simmonmt@acm.org>
|
||||
Mika Raento <mikie@iki.fi>
|
||||
Mike Bland <mbland@google.com>
|
||||
@@ -55,6 +56,7 @@ Russ Rufer <russ@pentad.com>
|
||||
Sean Mcafee <eefacm@gmail.com>
|
||||
Sigurður Ásgeirsson <siggi@google.com>
|
||||
Sverre Sundsdal <sundsdal@gmail.com>
|
||||
Szymon Sobik <sobik.szymon@gmail.com>
|
||||
Takeshi Yoshino <tyoshino@google.com>
|
||||
Tracy Bialik <tracy@pentad.com>
|
||||
Vadim Berman <vadimb@google.com>
|
@@ -6,7 +6,8 @@
|
||||
|
||||
GoogleTest now follows the
|
||||
[Abseil Live at Head philosophy](https://abseil.io/about/philosophy#upgrade-support).
|
||||
We recommend using the latest commit in the `master` branch in your projects.
|
||||
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).
|
||||
|
||||
#### Documentation Updates
|
||||
|
||||
@@ -14,11 +15,14 @@ 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.
|
||||
|
||||
#### Release 1.10.x
|
||||
#### Release 1.12.1
|
||||
|
||||
[Release 1.10.x](https://github.com/google/googletest/releases/tag/release-1.10.0)
|
||||
[Release 1.12.1](https://github.com/google/googletest/releases/tag/release-1.12.1)
|
||||
is now available.
|
||||
|
||||
The 1.12.x branch will be the last to support C++11. Future releases will
|
||||
require at least C++14.
|
||||
|
||||
#### Coming Soon
|
||||
|
||||
* We are planning to take a dependency on
|
||||
@@ -55,39 +59,12 @@ More information about building GoogleTest can be found at
|
||||
|
||||
## Supported Platforms
|
||||
|
||||
GoogleTest requires a codebase and compiler compliant with the C++11 standard or
|
||||
newer.
|
||||
|
||||
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!
|
||||
|
||||
### Operating Systems
|
||||
|
||||
* Linux
|
||||
* macOS
|
||||
* Windows
|
||||
|
||||
### Compilers
|
||||
|
||||
* gcc 5.0+
|
||||
* clang 5.0+
|
||||
* MSVC 2015+
|
||||
|
||||
**macOS users:** Xcode 9.3+ provides clang 5.0+.
|
||||
|
||||
### Build Systems
|
||||
|
||||
* [Bazel](https://bazel.build/)
|
||||
* [CMake](https://cmake.org/)
|
||||
|
||||
**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.
|
||||
GoogleTest follows Google's
|
||||
[Foundational C++ Support Policy](https://opensource.google/documentation/policies/cplusplus-support).
|
||||
See
|
||||
[this table](https://github.com/google/oss-policies-info/blob/main/foundational-cxx-support-matrix.md)
|
||||
for a list of currently supported versions compilers, platforms, and build
|
||||
tools.
|
||||
|
||||
## Who Is Using GoogleTest?
|
||||
|
||||
@@ -109,8 +86,8 @@ 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. Google
|
||||
Test UI is written in C#.
|
||||
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
|
||||
@@ -121,11 +98,11 @@ result output. If your test runner understands TAP, you may find it useful.
|
||||
runs tests from your binary in parallel to provide significant speed-up.
|
||||
|
||||
[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
|
||||
is a VS Code extension allowing to view GoogleTest in a tree view and run/debug
|
||||
your tests.
|
||||
|
||||
[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
|
||||
Code extension allowing to view GoogleTest in a tree view and run/debug your
|
||||
tests.
|
||||
|
||||
[Cornichon](https://pypi.org/project/cornichon/) is a small Gherkin DSL parser
|
||||
@@ -134,7 +111,7 @@ that generates stub code for GoogleTest.
|
||||
## Contributing Changes
|
||||
|
||||
Please read
|
||||
[`CONTRIBUTING.md`](https://github.com/google/googletest/blob/master/CONTRIBUTING.md)
|
||||
[`CONTRIBUTING.md`](https://github.com/google/googletest/blob/main/CONTRIBUTING.md)
|
||||
for details on how to contribute to this project.
|
||||
|
||||
Happy testing!
|
40
test/googletest-1.13.0/WORKSPACE
Normal file
40
test/googletest-1.13.0/WORKSPACE
Normal file
@@ -0,0 +1,40 @@
|
||||
workspace(name = "com_google_googletest")
|
||||
|
||||
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
|
||||
|
||||
http_archive(
|
||||
name = "com_google_absl", # 2023-01-10T21:08:25Z
|
||||
sha256 = "f9a4e749f42c386a32a90fddf0e2913ed408d10c42f7f33ccf4c59ac4f0d1d05",
|
||||
strip_prefix = "abseil-cpp-52835439ca90d86b27bf8cd1708296e95604d724",
|
||||
urls = ["https://github.com/abseil/abseil-cpp/archive/52835439ca90d86b27bf8cd1708296e95604d724.zip"],
|
||||
)
|
||||
|
||||
# Note this must use a commit from the `abseil` branch of the RE2 project.
|
||||
# https://github.com/google/re2/tree/abseil
|
||||
http_archive(
|
||||
name = "com_googlesource_code_re2", # 2022-12-21T14:29:10Z
|
||||
sha256 = "b9ce3a51beebb38534d11d40f8928d40509b9e18a735f6a4a97ad3d014c87cb5",
|
||||
strip_prefix = "re2-d0b1f8f2ecc2ea74956c7608b6f915175314ff0e",
|
||||
urls = ["https://github.com/google/re2/archive/d0b1f8f2ecc2ea74956c7608b6f915175314ff0e.zip"],
|
||||
)
|
||||
|
||||
http_archive(
|
||||
name = "rules_python", # 2023-01-10T22:00:51Z
|
||||
sha256 = "5de54486a60ad8948dabe49605bb1c08053e04001a431ab3e96745b4d97a4419",
|
||||
strip_prefix = "rules_python-70cce26432187a60b4e950118791385e6fb3c26f",
|
||||
urls = ["https://github.com/bazelbuild/rules_python/archive/70cce26432187a60b4e950118791385e6fb3c26f.zip"],
|
||||
)
|
||||
|
||||
http_archive(
|
||||
name = "bazel_skylib", # 2022-11-16T18:29:32Z
|
||||
sha256 = "a22290c26d29d3ecca286466f7f295ac6cbe32c0a9da3a91176a90e0725e3649",
|
||||
strip_prefix = "bazel-skylib-5bfcb1a684550626ce138fe0fe8f5f702b3764c3",
|
||||
urls = ["https://github.com/bazelbuild/bazel-skylib/archive/5bfcb1a684550626ce138fe0fe8f5f702b3764c3.zip"],
|
||||
)
|
||||
|
||||
http_archive(
|
||||
name = "platforms", # 2022-11-09T19:18:22Z
|
||||
sha256 = "b4a3b45dc4202e2b3e34e3bc49d2b5b37295fc23ea58d88fb9e01f3642ad9b55",
|
||||
strip_prefix = "platforms-3fbc687756043fb58a407c2ea8c944bc2fe1d922",
|
||||
urls = ["https://github.com/bazelbuild/platforms/archive/3fbc687756043fb58a407c2ea8c944bc2fe1d922.zip"],
|
||||
)
|
@@ -31,15 +31,15 @@
|
||||
|
||||
set -euox pipefail
|
||||
|
||||
readonly LINUX_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_hybrid-latest:20210525"
|
||||
readonly LINUX_GCC_FLOOR_CONTAINER="gcr.io/google.com/absl-177019/linux_gcc-floor:20201015"
|
||||
readonly LINUX_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_hybrid-latest:20220217"
|
||||
readonly LINUX_GCC_FLOOR_CONTAINER="gcr.io/google.com/absl-177019/linux_gcc-floor:20220621"
|
||||
|
||||
if [[ -z ${GTEST_ROOT:-} ]]; then
|
||||
GTEST_ROOT="$(realpath $(dirname ${0})/..)"
|
||||
fi
|
||||
|
||||
if [[ -z ${STD:-} ]]; then
|
||||
STD="c++11 c++14 c++17 c++20"
|
||||
STD="c++14 c++17 c++20"
|
||||
fi
|
||||
|
||||
# Test the CMake build
|
||||
@@ -55,7 +55,7 @@ for cc in /usr/local/bin/gcc /opt/llvm/clang/bin/clang; do
|
||||
${LINUX_LATEST_CONTAINER} \
|
||||
/bin/bash -c "
|
||||
cmake /src \
|
||||
-DCMAKE_CXX_STANDARD=11 \
|
||||
-DCMAKE_CXX_STANDARD=14 \
|
||||
-Dgtest_build_samples=ON \
|
||||
-Dgtest_build_tests=ON \
|
||||
-Dgmock_build_tests=ON \
|
||||
@@ -72,11 +72,15 @@ time docker run \
|
||||
--workdir="/src" \
|
||||
--rm \
|
||||
--env="CC=/usr/local/bin/gcc" \
|
||||
--env="BAZEL_CXXOPTS=-std=c++14" \
|
||||
${LINUX_GCC_FLOOR_CONTAINER} \
|
||||
/usr/local/bin/bazel test ... \
|
||||
--copt="-Wall" \
|
||||
--copt="-Werror" \
|
||||
--copt="-Wuninitialized" \
|
||||
--copt="-Wno-error=pragmas" \
|
||||
--distdir="/bazel-distdir" \
|
||||
--features=external_include_paths \
|
||||
--keep_going \
|
||||
--show_timestamps \
|
||||
--test_output=errors
|
||||
@@ -94,8 +98,10 @@ for std in ${STD}; do
|
||||
/usr/local/bin/bazel test ... \
|
||||
--copt="-Wall" \
|
||||
--copt="-Werror" \
|
||||
--copt="-Wuninitialized" \
|
||||
--define="absl=${absl}" \
|
||||
--distdir="/bazel-distdir" \
|
||||
--features=external_include_paths \
|
||||
--keep_going \
|
||||
--show_timestamps \
|
||||
--test_output=errors
|
||||
@@ -116,8 +122,10 @@ for std in ${STD}; do
|
||||
--copt="--gcc-toolchain=/usr/local" \
|
||||
--copt="-Wall" \
|
||||
--copt="-Werror" \
|
||||
--copt="-Wuninitialized" \
|
||||
--define="absl=${absl}" \
|
||||
--distdir="/bazel-distdir" \
|
||||
--features=external_include_paths \
|
||||
--keep_going \
|
||||
--linkopt="--gcc-toolchain=/usr/local" \
|
||||
--show_timestamps \
|
@@ -40,7 +40,7 @@ for cmake_off_on in OFF ON; do
|
||||
BUILD_DIR=$(mktemp -d build_dir.XXXXXXXX)
|
||||
cd ${BUILD_DIR}
|
||||
time cmake ${GTEST_ROOT} \
|
||||
-DCMAKE_CXX_STANDARD=11 \
|
||||
-DCMAKE_CXX_STANDARD=14 \
|
||||
-Dgtest_build_samples=ON \
|
||||
-Dgtest_build_tests=ON \
|
||||
-Dgmock_build_tests=ON \
|
||||
@@ -53,7 +53,7 @@ done
|
||||
# Test the Bazel build
|
||||
|
||||
# If we are running on Kokoro, check for a versioned Bazel binary.
|
||||
KOKORO_GFILE_BAZEL_BIN="bazel-3.7.0-darwin-x86_64"
|
||||
KOKORO_GFILE_BAZEL_BIN="bazel-5.1.1-darwin-x86_64"
|
||||
if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -f ${KOKORO_GFILE_DIR}/${KOKORO_GFILE_BAZEL_BIN} ]]; then
|
||||
BAZEL_BIN="${KOKORO_GFILE_DIR}/${KOKORO_GFILE_BAZEL_BIN}"
|
||||
chmod +x ${BAZEL_BIN}
|
||||
@@ -66,7 +66,9 @@ for absl in 0 1; do
|
||||
${BAZEL_BIN} test ... \
|
||||
--copt="-Wall" \
|
||||
--copt="-Werror" \
|
||||
--cxxopt="-std=c++14" \
|
||||
--define="absl=${absl}" \
|
||||
--features=external_include_paths \
|
||||
--keep_going \
|
||||
--show_timestamps \
|
||||
--test_output=errors
|
56
test/googletest-1.13.0/ci/windows-presubmit.bat
Normal file
56
test/googletest-1.13.0/ci/windows-presubmit.bat
Normal file
@@ -0,0 +1,56 @@
|
||||
SETLOCAL ENABLEDELAYEDEXPANSION
|
||||
|
||||
SET BAZEL_EXE=%KOKORO_GFILE_DIR%\bazel-5.1.1-windows-x86_64.exe
|
||||
|
||||
SET PATH=C:\Python37;%PATH%
|
||||
SET BAZEL_PYTHON=C:\python37\python.exe
|
||||
SET BAZEL_SH=C:\tools\msys64\usr\bin\bash.exe
|
||||
SET CMAKE_BIN="C:\Program Files\CMake\bin\cmake.exe"
|
||||
SET CTEST_BIN="C:\Program Files\CMake\bin\ctest.exe"
|
||||
SET CTEST_OUTPUT_ON_FAILURE=1
|
||||
|
||||
IF EXIST git\googletest (
|
||||
CD git\googletest
|
||||
) ELSE IF EXIST github\googletest (
|
||||
CD github\googletest
|
||||
)
|
||||
|
||||
IF %errorlevel% neq 0 EXIT /B 1
|
||||
|
||||
:: ----------------------------------------------------------------------------
|
||||
:: CMake Visual Studio 15 2017 Win64
|
||||
MKDIR cmake_msvc2017
|
||||
CD cmake_msvc2017
|
||||
|
||||
%CMAKE_BIN% .. ^
|
||||
-G "Visual Studio 15 2017 Win64" ^
|
||||
-DPYTHON_EXECUTABLE:FILEPATH=c:\python37\python.exe ^
|
||||
-DPYTHON_INCLUDE_DIR:PATH=c:\python37\include ^
|
||||
-DPYTHON_LIBRARY:FILEPATH=c:\python37\lib\site-packages\pip ^
|
||||
-Dgtest_build_samples=ON ^
|
||||
-Dgtest_build_tests=ON ^
|
||||
-Dgmock_build_tests=ON
|
||||
IF %errorlevel% neq 0 EXIT /B 1
|
||||
|
||||
%CMAKE_BIN% --build . --target ALL_BUILD --config Debug -- -maxcpucount
|
||||
IF %errorlevel% neq 0 EXIT /B 1
|
||||
|
||||
%CTEST_BIN% -C Debug --timeout 600
|
||||
IF %errorlevel% neq 0 EXIT /B 1
|
||||
|
||||
CD ..
|
||||
RMDIR /S /Q cmake_msvc2017
|
||||
|
||||
:: ----------------------------------------------------------------------------
|
||||
:: Bazel Visual Studio 15 2017 Win64
|
||||
|
||||
SET BAZEL_VC=C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC
|
||||
%BAZEL_EXE% test ... ^
|
||||
--compilation_mode=dbg ^
|
||||
--copt=/std:c++14 ^
|
||||
--copt=/WX ^
|
||||
--features=external_include_paths ^
|
||||
--keep_going ^
|
||||
--test_output=errors ^
|
||||
--test_tag_filters=-no_test_msvc2017
|
||||
IF %errorlevel% neq 0 EXIT /B 1
|
@@ -48,7 +48,7 @@
|
||||
<div class="footer">
|
||||
GoogleTest ·
|
||||
<a href="https://github.com/google/googletest">GitHub Repository</a> ·
|
||||
<a href="https://github.com/google/googletest/blob/master/LICENSE">License</a> ·
|
||||
<a href="https://github.com/google/googletest/blob/main/LICENSE">License</a> ·
|
||||
<a href="https://policies.google.com/privacy">Privacy Policy</a>
|
||||
</div>
|
||||
</div>
|
@@ -157,8 +157,11 @@ that can be used in the predicate assertion macro
|
||||
example:
|
||||
|
||||
```c++
|
||||
EXPECT_PRED_FORMAT2(testing::FloatLE, val1, val2);
|
||||
EXPECT_PRED_FORMAT2(testing::DoubleLE, val1, val2);
|
||||
using ::testing::FloatLE;
|
||||
using ::testing::DoubleLE;
|
||||
...
|
||||
EXPECT_PRED_FORMAT2(FloatLE, val1, val2);
|
||||
EXPECT_PRED_FORMAT2(DoubleLE, val1, val2);
|
||||
```
|
||||
|
||||
The above code verifies that `val1` is less than, or approximately equal to,
|
||||
@@ -202,10 +205,9 @@ You can call the function
|
||||
|
||||
to assert that types `T1` and `T2` are the same. The function does nothing if
|
||||
the assertion is satisfied. If the types are different, the function call will
|
||||
fail to compile, the compiler error message will say that
|
||||
`T1 and T2 are not the same type` and most likely (depending on the compiler)
|
||||
show you the actual values of `T1` and `T2`. This is mainly useful inside
|
||||
template code.
|
||||
fail to compile, the compiler error message will say that `T1 and T2 are not the
|
||||
same type` and most likely (depending on the compiler) show you the actual
|
||||
values of `T1` and `T2`. This is mainly useful inside template code.
|
||||
|
||||
**Caveat**: When used inside a member function of a class template or a function
|
||||
template, `StaticAssertTypeEq<T1, T2>()` is effective only if the function is
|
||||
@@ -383,10 +385,10 @@ EXPECT_TRUE(IsCorrectBarIntVector(bar_ints))
|
||||
## Death Tests
|
||||
|
||||
In many applications, there are assertions that can cause application failure if
|
||||
a condition is not met. These sanity checks, which ensure that the program is in
|
||||
a known good state, are there to fail at the earliest possible time after some
|
||||
program state is corrupted. If the assertion checks the wrong condition, then
|
||||
the program may proceed in an erroneous state, which could lead to memory
|
||||
a condition is not met. These consistency checks, which ensure that the program
|
||||
is in a known good state, are there to fail at the earliest possible time after
|
||||
some program state is corrupted. If the assertion checks the wrong condition,
|
||||
then the program may proceed in an erroneous state, which could lead to memory
|
||||
corruption, security holes, or worse. Hence it is vitally important to test that
|
||||
such assertion statements work as expected.
|
||||
|
||||
@@ -480,10 +482,12 @@ TEST_F(FooDeathTest, DoesThat) {
|
||||
|
||||
### Regular Expression Syntax
|
||||
|
||||
On POSIX systems (e.g. Linux, Cygwin, and Mac), googletest uses the
|
||||
When built with Bazel and using Abseil, googletest uses the
|
||||
[RE2](https://github.com/google/re2/wiki/Syntax) syntax. Otherwise, for POSIX
|
||||
systems (Linux, Cygwin, Mac), googletest uses the
|
||||
[POSIX extended regular expression](http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap09.html#tag_09_04)
|
||||
syntax. To learn about this syntax, you may want to read this
|
||||
[Wikipedia entry](http://en.wikipedia.org/wiki/Regular_expression#POSIX_Extended_Regular_Expressions).
|
||||
syntax. To learn about POSIX syntax, you may want to read this
|
||||
[Wikipedia entry](http://en.wikipedia.org/wiki/Regular_expression#POSIX_extended).
|
||||
|
||||
On Windows, googletest uses its own simple regular expression implementation. It
|
||||
lacks many features. For example, we don't support union (`"x|y"`), grouping
|
||||
@@ -558,7 +562,7 @@ The automated testing framework does not set the style flag. You can choose a
|
||||
particular style of death tests by setting the flag programmatically:
|
||||
|
||||
```c++
|
||||
testing::FLAGS_gtest_death_test_style="threadsafe"
|
||||
GTEST_FLAG_SET(death_test_style, "threadsafe")
|
||||
```
|
||||
|
||||
You can do this in `main()` to set the style for all death tests in the binary,
|
||||
@@ -568,12 +572,12 @@ restored afterwards, so you need not do that yourself. For example:
|
||||
```c++
|
||||
int main(int argc, char** argv) {
|
||||
testing::InitGoogleTest(&argc, argv);
|
||||
testing::FLAGS_gtest_death_test_style = "fast";
|
||||
GTEST_FLAG_SET(death_test_style, "fast");
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
|
||||
TEST(MyDeathTest, TestOne) {
|
||||
testing::FLAGS_gtest_death_test_style = "threadsafe";
|
||||
GTEST_FLAG_SET(death_test_style, "threadsafe");
|
||||
// This test is run in the "threadsafe" style:
|
||||
ASSERT_DEATH(ThisShouldDie(), "");
|
||||
}
|
||||
@@ -610,15 +614,14 @@ Despite the improved thread safety afforded by the "threadsafe" style of death
|
||||
test, thread problems such as deadlock are still possible in the presence of
|
||||
handlers registered with `pthread_atfork(3)`.
|
||||
|
||||
|
||||
## Using Assertions in Sub-routines
|
||||
|
||||
{: .callout .note}
|
||||
Note: If you want to put a series of test assertions in a subroutine to check
|
||||
for a complex condition, consider using
|
||||
[a custom GMock matcher](gmock_cook_book.md#NewMatchers)
|
||||
instead. This lets you provide a more readable error message in case of failure
|
||||
and avoid all of the issues described below.
|
||||
[a custom GMock matcher](gmock_cook_book.md#NewMatchers) instead. This lets you
|
||||
provide a more readable error message in case of failure and avoid all of the
|
||||
issues described below.
|
||||
|
||||
### Adding Traces to Assertions
|
||||
|
||||
@@ -631,6 +634,7 @@ the `SCOPED_TRACE` macro or the `ScopedTrace` utility:
|
||||
```c++
|
||||
SCOPED_TRACE(message);
|
||||
```
|
||||
|
||||
```c++
|
||||
ScopedTrace trace("file_path", line_number, message);
|
||||
```
|
||||
@@ -837,7 +841,7 @@ will output XML like this:
|
||||
|
||||
```xml
|
||||
...
|
||||
<testcase name="MinAndMaxWidgets" status="run" time="0.006" classname="WidgetUsageTest" MaximumWidgets="12" MinimumWidgets="9" />
|
||||
<testcase name="MinAndMaxWidgets" file="test.cpp" line="1" status="run" time="0.006" classname="WidgetUsageTest" MaximumWidgets="12" MinimumWidgets="9" />
|
||||
...
|
||||
```
|
||||
|
||||
@@ -888,6 +892,12 @@ preceding or following another. Also, the tests must either not modify the state
|
||||
of any shared resource, or, if they do modify the state, they must restore the
|
||||
state to its original value before passing control to the next test.
|
||||
|
||||
Note that `SetUpTestSuite()` may be called multiple times for a test fixture
|
||||
class that has derived classes, so you should not expect code in the function
|
||||
body to be run only once. Also, derived classes still have access to shared
|
||||
resources defined as static members, so careful consideration is needed when
|
||||
managing shared resources to avoid memory leaks.
|
||||
|
||||
Here's an example of per-test-suite set-up and tear-down:
|
||||
|
||||
```c++
|
||||
@@ -897,7 +907,10 @@ class FooTest : public testing::Test {
|
||||
// Called before the first test in this test suite.
|
||||
// Can be omitted if not needed.
|
||||
static void SetUpTestSuite() {
|
||||
shared_resource_ = new ...;
|
||||
// Avoid reallocating static objects if called in subclasses of FooTest.
|
||||
if (shared_resource_ == nullptr) {
|
||||
shared_resource_ = new ...;
|
||||
}
|
||||
}
|
||||
|
||||
// Per-test-suite tear-down.
|
||||
@@ -1082,6 +1095,11 @@ instantiation of the test suite. The next argument is the name of the test
|
||||
pattern, and the last is the
|
||||
[parameter generator](reference/testing.md#param-generators).
|
||||
|
||||
The parameter generator expression is not evaluated until GoogleTest is
|
||||
initialized (via `InitGoogleTest()`). Any prior initialization done in the
|
||||
`main` function will be accessible from the parameter generator, for example,
|
||||
the results of flag parsing.
|
||||
|
||||
You can instantiate a test pattern more than once, so to distinguish different
|
||||
instances of the pattern, the instantiation name is added as a prefix to the
|
||||
actual test suite name. Remember to pick unique prefixes for different
|
||||
@@ -1129,8 +1147,8 @@ GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(FooTest);
|
||||
|
||||
You can see [sample7_unittest.cc] and [sample8_unittest.cc] for more examples.
|
||||
|
||||
[sample7_unittest.cc]: https://github.com/google/googletest/blob/master/googletest/samples/sample7_unittest.cc "Parameterized Test example"
|
||||
[sample8_unittest.cc]: https://github.com/google/googletest/blob/master/googletest/samples/sample8_unittest.cc "Parameterized Test example with multiple parameters"
|
||||
[sample7_unittest.cc]: https://github.com/google/googletest/blob/main/googletest/samples/sample7_unittest.cc "Parameterized Test example"
|
||||
[sample8_unittest.cc]: https://github.com/google/googletest/blob/main/googletest/samples/sample8_unittest.cc "Parameterized Test example with multiple parameters"
|
||||
|
||||
### Creating Value-Parameterized Abstract Tests
|
||||
|
||||
@@ -1281,7 +1299,7 @@ TYPED_TEST(FooTest, HasPropertyA) { ... }
|
||||
|
||||
You can see [sample6_unittest.cc] for a complete example.
|
||||
|
||||
[sample6_unittest.cc]: https://github.com/google/googletest/blob/master/googletest/samples/sample6_unittest.cc "Typed Test example"
|
||||
[sample6_unittest.cc]: https://github.com/google/googletest/blob/main/googletest/samples/sample6_unittest.cc "Typed Test example"
|
||||
|
||||
## Type-Parameterized Tests
|
||||
|
||||
@@ -1302,6 +1320,7 @@ First, define a fixture class template, as we did with typed tests:
|
||||
```c++
|
||||
template <typename T>
|
||||
class FooTest : public testing::Test {
|
||||
void DoSomethingInteresting();
|
||||
...
|
||||
};
|
||||
```
|
||||
@@ -1319,6 +1338,9 @@ this as many times as you want:
|
||||
TYPED_TEST_P(FooTest, DoesBlah) {
|
||||
// Inside a test, refer to TypeParam to get the type parameter.
|
||||
TypeParam n = 0;
|
||||
|
||||
// You will need to use `this` explicitly to refer to fixture members.
|
||||
this->DoSomethingInteresting()
|
||||
...
|
||||
}
|
||||
|
||||
@@ -1481,8 +1503,8 @@ In frameworks that report a failure by throwing an exception, you could catch
|
||||
the exception and assert on it. But googletest doesn't use exceptions, so how do
|
||||
we test that a piece of code generates an expected failure?
|
||||
|
||||
`"gtest/gtest-spi.h"` contains some constructs to do this. After #including this header,
|
||||
you can use
|
||||
`"gtest/gtest-spi.h"` contains some constructs to do this.
|
||||
After #including this header, you can use
|
||||
|
||||
```c++
|
||||
EXPECT_FATAL_FAILURE(statement, substring);
|
||||
@@ -1586,12 +1608,14 @@ void RegisterMyTests(const std::vector<int>& values) {
|
||||
}
|
||||
...
|
||||
int main(int argc, char** argv) {
|
||||
testing::InitGoogleTest(&argc, argv);
|
||||
std::vector<int> values_to_test = LoadValuesFromConfig();
|
||||
RegisterMyTests(values_to_test);
|
||||
...
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
```
|
||||
|
||||
## Getting the Current Test's Name
|
||||
|
||||
Sometimes a function may need to know the name of the currently running test.
|
||||
@@ -1714,7 +1738,7 @@ You can do so by adding one line:
|
||||
Now, sit back and enjoy a completely different output from your tests. For more
|
||||
details, see [sample9_unittest.cc].
|
||||
|
||||
[sample9_unittest.cc]: https://github.com/google/googletest/blob/master/googletest/samples/sample9_unittest.cc "Event listener example"
|
||||
[sample9_unittest.cc]: https://github.com/google/googletest/blob/main/googletest/samples/sample9_unittest.cc "Event listener example"
|
||||
|
||||
You may append more than one listener to the list. When an `On*Start()` or
|
||||
`OnTestPartResult()` event is fired, the listeners will receive it in the order
|
||||
@@ -1741,7 +1765,7 @@ by the former.
|
||||
|
||||
See [sample10_unittest.cc] for an example of a failure-raising listener.
|
||||
|
||||
[sample10_unittest.cc]: https://github.com/google/googletest/blob/master/googletest/samples/sample10_unittest.cc "Failure-raising listener example"
|
||||
[sample10_unittest.cc]: https://github.com/google/googletest/blob/main/googletest/samples/sample10_unittest.cc "Failure-raising listener example"
|
||||
|
||||
## Running Test Programs: Advanced Options
|
||||
|
||||
@@ -1816,8 +1840,7 @@ By default, a googletest program runs all tests the user has defined. In some
|
||||
cases (e.g. iterative test development & execution) it may be desirable stop
|
||||
test execution upon first failure (trading improved latency for completeness).
|
||||
If `GTEST_FAIL_FAST` environment variable or `--gtest_fail_fast` flag is set,
|
||||
the test runner will stop execution as soon as the first test failure is
|
||||
found.
|
||||
the test runner will stop execution as soon as the first test failure is found.
|
||||
|
||||
#### Temporarily Disabling Tests
|
||||
|
||||
@@ -1890,8 +1913,12 @@ Repeat the tests whose name matches the filter 1000 times.
|
||||
|
||||
If your test program contains
|
||||
[global set-up/tear-down](#global-set-up-and-tear-down) code, it will be
|
||||
repeated in each iteration as well, as the flakiness may be in it. You can also
|
||||
specify the repeat count by setting the `GTEST_REPEAT` environment variable.
|
||||
repeated in each iteration as well, as the flakiness may be in it. To avoid
|
||||
repeating global set-up/tear-down, specify
|
||||
`--gtest_recreate_environments_when_repeating=false`{.nowrap}.
|
||||
|
||||
You can also specify the repeat count by setting the `GTEST_REPEAT` environment
|
||||
variable.
|
||||
|
||||
### Shuffling the Tests
|
||||
|
||||
@@ -1911,6 +1938,58 @@ time.
|
||||
If you combine this with `--gtest_repeat=N`, googletest will pick a different
|
||||
random seed and re-shuffle the tests in each iteration.
|
||||
|
||||
### Distributing Test Functions to Multiple Machines
|
||||
|
||||
If you have more than one machine you can use to run a test program, you might
|
||||
want to run the test functions in parallel and get the result faster. We call
|
||||
this technique *sharding*, where each machine is called a *shard*.
|
||||
|
||||
GoogleTest is compatible with test sharding. To take advantage of this feature,
|
||||
your test runner (not part of GoogleTest) needs to do the following:
|
||||
|
||||
1. Allocate a number of machines (shards) to run the tests.
|
||||
1. On each shard, set the `GTEST_TOTAL_SHARDS` environment variable to the total
|
||||
number of shards. It must be the same for all shards.
|
||||
1. On each shard, set the `GTEST_SHARD_INDEX` environment variable to the index
|
||||
of the shard. Different shards must be assigned different indices, which
|
||||
must be in the range `[0, GTEST_TOTAL_SHARDS - 1]`.
|
||||
1. Run the same test program on all shards. When GoogleTest sees the above two
|
||||
environment variables, it will select a subset of the test functions to run.
|
||||
Across all shards, each test function in the program will be run exactly
|
||||
once.
|
||||
1. Wait for all shards to finish, then collect and report the results.
|
||||
|
||||
Your project may have tests that were written without GoogleTest and thus don't
|
||||
understand this protocol. In order for your test runner to figure out which test
|
||||
supports sharding, it can set the environment variable `GTEST_SHARD_STATUS_FILE`
|
||||
to a non-existent file path. If a test program supports sharding, it will create
|
||||
this file to acknowledge that fact; otherwise it will not create it. The actual
|
||||
contents of the file are not important at this time, although we may put some
|
||||
useful information in it in the future.
|
||||
|
||||
Here's an example to make it clear. Suppose you have a test program `foo_test`
|
||||
that contains the following 5 test functions:
|
||||
|
||||
```
|
||||
TEST(A, V)
|
||||
TEST(A, W)
|
||||
TEST(B, X)
|
||||
TEST(B, Y)
|
||||
TEST(B, Z)
|
||||
```
|
||||
|
||||
Suppose you have 3 machines at your disposal. To run the test functions in
|
||||
parallel, you would set `GTEST_TOTAL_SHARDS` to 3 on all machines, and set
|
||||
`GTEST_SHARD_INDEX` to 0, 1, and 2 on the machines respectively. Then you would
|
||||
run the same `foo_test` on each machine.
|
||||
|
||||
GoogleTest reserves the right to change how the work is distributed across the
|
||||
shards, but here's one possible scenario:
|
||||
|
||||
* Machine #0 runs `A.V` and `B.X`.
|
||||
* Machine #1 runs `A.W` and `B.Y`.
|
||||
* Machine #2 runs `B.Z`.
|
||||
|
||||
### Controlling Test Output
|
||||
|
||||
#### Colored Terminal Output
|
||||
@@ -1965,8 +2044,6 @@ text because, for example, you don't have an UTF-8 compatible output medium, run
|
||||
the test program with `--gtest_print_utf8=0` or set the `GTEST_PRINT_UTF8`
|
||||
environment variable to `0`.
|
||||
|
||||
|
||||
|
||||
#### Generating an XML Report
|
||||
|
||||
googletest can emit a detailed XML report to a file in addition to its normal
|
||||
@@ -2020,15 +2097,15 @@ could generate this report:
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<testsuites tests="3" failures="1" errors="0" time="0.035" timestamp="2011-10-31T18:52:42" name="AllTests">
|
||||
<testsuite name="MathTest" tests="2" failures="1" errors="0" time="0.015">
|
||||
<testcase name="Addition" status="run" time="0.007" classname="">
|
||||
<testcase name="Addition" file="test.cpp" line="1" status="run" time="0.007" classname="">
|
||||
<failure message="Value of: add(1, 1)
 Actual: 3
Expected: 2" type="">...</failure>
|
||||
<failure message="Value of: add(1, -1)
 Actual: 1
Expected: 0" type="">...</failure>
|
||||
</testcase>
|
||||
<testcase name="Subtraction" status="run" time="0.005" classname="">
|
||||
<testcase name="Subtraction" file="test.cpp" line="2" status="run" time="0.005" classname="">
|
||||
</testcase>
|
||||
</testsuite>
|
||||
<testsuite name="LogicTest" tests="1" failures="0" errors="0" time="0.005">
|
||||
<testcase name="NonContradiction" status="run" time="0.005" classname="">
|
||||
<testcase name="NonContradiction" file="test.cpp" line="3" status="run" time="0.005" classname="">
|
||||
</testcase>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
@@ -2046,6 +2123,9 @@ Things to note:
|
||||
* The `timestamp` attribute records the local date and time of the test
|
||||
execution.
|
||||
|
||||
* The `file` and `line` attributes record the source file location, where the
|
||||
test was defined.
|
||||
|
||||
* Each `<failure>` element corresponds to a single failed googletest
|
||||
assertion.
|
||||
|
||||
@@ -2085,6 +2165,8 @@ The report format conforms to the following JSON Schema:
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": { "type": "string" },
|
||||
"file": { "type": "string" },
|
||||
"line": { "type": "integer" },
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": ["RUN", "NOTRUN"]
|
||||
@@ -2162,6 +2244,8 @@ message TestCase {
|
||||
|
||||
message TestInfo {
|
||||
string name = 1;
|
||||
string file = 6;
|
||||
int32 line = 7;
|
||||
enum Status {
|
||||
RUN = 0;
|
||||
NOTRUN = 1;
|
||||
@@ -2205,6 +2289,8 @@ could generate this report:
|
||||
"testsuite": [
|
||||
{
|
||||
"name": "Addition",
|
||||
"file": "test.cpp",
|
||||
"line": 1,
|
||||
"status": "RUN",
|
||||
"time": "0.007s",
|
||||
"classname": "",
|
||||
@@ -2221,6 +2307,8 @@ could generate this report:
|
||||
},
|
||||
{
|
||||
"name": "Subtraction",
|
||||
"file": "test.cpp",
|
||||
"line": 2,
|
||||
"status": "RUN",
|
||||
"time": "0.005s",
|
||||
"classname": ""
|
||||
@@ -2236,6 +2324,8 @@ could generate this report:
|
||||
"testsuite": [
|
||||
{
|
||||
"name": "NonContradiction",
|
||||
"file": "test.cpp",
|
||||
"line": 3,
|
||||
"status": "RUN",
|
||||
"time": "0.005s",
|
||||
"classname": ""
|
||||
@@ -2253,12 +2343,11 @@ IMPORTANT: The exact format of the JSON document is subject to change.
|
||||
|
||||
#### Detecting Test Premature Exit
|
||||
|
||||
Google Test implements the _premature-exit-file_ protocol for test runners
|
||||
to catch any kind of unexpected exits of test programs. Upon start,
|
||||
Google Test creates the file which will be automatically deleted after
|
||||
all work has been finished. Then, the test runner can check if this file
|
||||
exists. In case the file remains undeleted, the inspected test has exited
|
||||
prematurely.
|
||||
Google Test implements the _premature-exit-file_ protocol for test runners to
|
||||
catch any kind of unexpected exits of test programs. Upon start, Google Test
|
||||
creates the file which will be automatically deleted after all work has been
|
||||
finished. Then, the test runner can check if this file exists. In case the file
|
||||
remains undeleted, the inspected test has exited prematurely.
|
||||
|
||||
This feature is enabled only if the `TEST_PREMATURE_EXIT_FILE` environment
|
||||
variable has been set.
|
@@ -1,9 +1,9 @@
|
||||
# Googletest FAQ
|
||||
# GoogleTest FAQ
|
||||
|
||||
## Why should test suite names and test names not contain underscore?
|
||||
|
||||
{: .callout .note}
|
||||
Note: Googletest reserves underscore (`_`) for special purpose keywords, such as
|
||||
Note: GoogleTest reserves underscore (`_`) for special purpose keywords, such as
|
||||
[the `DISABLED_` prefix](advanced.md#temporarily-disabling-tests), in addition
|
||||
to the following rationale.
|
||||
|
||||
@@ -50,15 +50,15 @@ Now, the two `TEST`s will both generate the same class
|
||||
|
||||
So for simplicity, we just ask the users to avoid `_` in `TestSuiteName` and
|
||||
`TestName`. The rule is more constraining than necessary, but it's simple and
|
||||
easy to remember. It also gives googletest some wiggle room in case its
|
||||
easy to remember. It also gives GoogleTest some wiggle room in case its
|
||||
implementation needs to change in the future.
|
||||
|
||||
If you violate the rule, there may not be immediate consequences, but your test
|
||||
may (just may) break with a new compiler (or a new version of the compiler you
|
||||
are using) or with a new version of googletest. Therefore it's best to follow
|
||||
are using) or with a new version of GoogleTest. Therefore it's best to follow
|
||||
the rule.
|
||||
|
||||
## Why does googletest support `EXPECT_EQ(NULL, ptr)` and `ASSERT_EQ(NULL, ptr)` but not `EXPECT_NE(NULL, ptr)` and `ASSERT_NE(NULL, ptr)`?
|
||||
## Why does GoogleTest support `EXPECT_EQ(NULL, ptr)` and `ASSERT_EQ(NULL, ptr)` but not `EXPECT_NE(NULL, ptr)` and `ASSERT_NE(NULL, ptr)`?
|
||||
|
||||
First of all, you can use `nullptr` with each of these macros, e.g.
|
||||
`EXPECT_EQ(ptr, nullptr)`, `EXPECT_NE(ptr, nullptr)`, `ASSERT_EQ(ptr, nullptr)`,
|
||||
@@ -68,7 +68,7 @@ because `nullptr` does not have the type problems that `NULL` does.
|
||||
Due to some peculiarity of C++, it requires some non-trivial template meta
|
||||
programming tricks to support using `NULL` as an argument of the `EXPECT_XX()`
|
||||
and `ASSERT_XX()` macros. Therefore we only do it where it's most needed
|
||||
(otherwise we make the implementation of googletest harder to maintain and more
|
||||
(otherwise we make the implementation of GoogleTest harder to maintain and more
|
||||
error-prone than necessary).
|
||||
|
||||
Historically, the `EXPECT_EQ()` macro took the *expected* value as its first
|
||||
@@ -162,7 +162,7 @@ methods, the parent process will think the calls have never occurred. Therefore,
|
||||
you may want to move your `EXPECT_CALL` statements inside the `EXPECT_DEATH`
|
||||
macro.
|
||||
|
||||
## EXPECT_EQ(htonl(blah), blah_blah) generates weird compiler errors in opt mode. Is this a googletest bug?
|
||||
## EXPECT_EQ(htonl(blah), blah_blah) generates weird compiler errors in opt mode. Is this a GoogleTest bug?
|
||||
|
||||
Actually, the bug is in `htonl()`.
|
||||
|
||||
@@ -199,7 +199,7 @@ const int Foo::kBar; // No initializer here.
|
||||
```
|
||||
|
||||
Otherwise your code is **invalid C++**, and may break in unexpected ways. In
|
||||
particular, using it in googletest comparison assertions (`EXPECT_EQ`, etc) will
|
||||
particular, using it in GoogleTest comparison assertions (`EXPECT_EQ`, etc) will
|
||||
generate an "undefined reference" linker error. The fact that "it used to work"
|
||||
doesn't mean it's valid. It just means that you were lucky. :-)
|
||||
|
||||
@@ -225,7 +225,7 @@ cases may want to use the same or slightly different fixtures. For example, you
|
||||
may want to make sure that all of a GUI library's test suites don't leak
|
||||
important system resources like fonts and brushes.
|
||||
|
||||
In googletest, you share a fixture among test suites by putting the shared logic
|
||||
In GoogleTest, you share a fixture among test suites by putting the shared logic
|
||||
in a base test fixture, then deriving from that base a separate fixture for each
|
||||
test suite that wants to use this common logic. You then use `TEST_F()` to write
|
||||
tests using each derived fixture.
|
||||
@@ -264,10 +264,10 @@ TEST_F(FooTest, Baz) { ... }
|
||||
```
|
||||
|
||||
If necessary, you can continue to derive test fixtures from a derived fixture.
|
||||
googletest has no limit on how deep the hierarchy can be.
|
||||
GoogleTest has no limit on how deep the hierarchy can be.
|
||||
|
||||
For a complete example using derived test fixtures, see
|
||||
[sample5_unittest.cc](https://github.com/google/googletest/blob/master/googletest/samples/sample5_unittest.cc).
|
||||
[sample5_unittest.cc](https://github.com/google/googletest/blob/main/googletest/samples/sample5_unittest.cc).
|
||||
|
||||
## My compiler complains "void value not ignored as it ought to be." What does this mean?
|
||||
|
||||
@@ -278,7 +278,7 @@ disabled by our build system. Please see more details
|
||||
|
||||
## My death test hangs (or seg-faults). How do I fix it?
|
||||
|
||||
In googletest, death tests are run in a child process and the way they work is
|
||||
In GoogleTest, death tests are run in a child process and the way they work is
|
||||
delicate. To write death tests you really need to understand how they work—see
|
||||
the details at [Death Assertions](reference/assertions.md#death) in the
|
||||
Assertions Reference.
|
||||
@@ -305,8 +305,8 @@ bullet - sorry!
|
||||
|
||||
## Should I use the constructor/destructor of the test fixture or SetUp()/TearDown()? {#CtorVsSetUp}
|
||||
|
||||
The first thing to remember is that googletest does **not** reuse the same test
|
||||
fixture object across multiple tests. For each `TEST_F`, googletest will create
|
||||
The first thing to remember is that GoogleTest does **not** reuse the same test
|
||||
fixture object across multiple tests. For each `TEST_F`, GoogleTest will create
|
||||
a **fresh** test fixture object, immediately call `SetUp()`, run the test body,
|
||||
call `TearDown()`, and then delete the test fixture object.
|
||||
|
||||
@@ -328,7 +328,7 @@ You may still want to use `SetUp()/TearDown()` in the following cases:
|
||||
|
||||
* C++ does not allow virtual function calls in constructors and destructors.
|
||||
You can call a method declared as virtual, but it will not use dynamic
|
||||
dispatch, it will use the definition from the class the constructor of which
|
||||
dispatch. It will use the definition from the class the constructor of which
|
||||
is currently executing. This is because calling a virtual method before the
|
||||
derived class constructor has a chance to run is very dangerous - the
|
||||
virtual method might operate on uninitialized data. Therefore, if you need
|
||||
@@ -345,11 +345,11 @@ You may still want to use `SetUp()/TearDown()` in the following cases:
|
||||
that many standard libraries (like STL) may throw when exceptions are
|
||||
enabled in the compiler. Therefore you should prefer `TearDown()` if you
|
||||
want to write portable tests that work with or without exceptions.
|
||||
* The googletest team is considering making the assertion macros throw on
|
||||
* The GoogleTest team is considering making the assertion macros throw on
|
||||
platforms where exceptions are enabled (e.g. Windows, Mac OS, and Linux
|
||||
client-side), which will eliminate the need for the user to propagate
|
||||
failures from a subroutine to its caller. Therefore, you shouldn't use
|
||||
googletest assertions in a destructor if your code could run on such a
|
||||
GoogleTest assertions in a destructor if your code could run on such a
|
||||
platform.
|
||||
|
||||
## The compiler complains "no matching function to call" when I use ASSERT_PRED*. How do I fix it?
|
||||
@@ -375,7 +375,7 @@ they write
|
||||
This is **wrong and dangerous**. The testing services needs to see the return
|
||||
value of `RUN_ALL_TESTS()` in order to determine if a test has passed. If your
|
||||
`main()` function ignores it, your test will be considered successful even if it
|
||||
has a googletest assertion failure. Very bad.
|
||||
has a GoogleTest assertion failure. Very bad.
|
||||
|
||||
We have decided to fix this (thanks to Michael Chastain for the idea). Now, your
|
||||
code will no longer be able to ignore `RUN_ALL_TESTS()` when compiled with
|
||||
@@ -410,7 +410,6 @@ C++ is case-sensitive. Did you spell it as `Setup()`?
|
||||
Similarly, sometimes people spell `SetUpTestSuite()` as `SetupTestSuite()` and
|
||||
wonder why it's never called.
|
||||
|
||||
|
||||
## I have several test suites which share the same test fixture logic, do I have to define a new test fixture class for each of them? This seems pretty tedious.
|
||||
|
||||
You don't have to. Instead of
|
||||
@@ -441,14 +440,14 @@ TEST_F(BarTest, Abc) { ... }
|
||||
TEST_F(BarTest, Def) { ... }
|
||||
```
|
||||
|
||||
## googletest output is buried in a whole bunch of LOG messages. What do I do?
|
||||
## GoogleTest output is buried in a whole bunch of LOG messages. What do I do?
|
||||
|
||||
The googletest output is meant to be a concise and human-friendly report. If
|
||||
your test generates textual output itself, it will mix with the googletest
|
||||
The GoogleTest output is meant to be a concise and human-friendly report. If
|
||||
your test generates textual output itself, it will mix with the GoogleTest
|
||||
output, making it hard to read. However, there is an easy solution to this
|
||||
problem.
|
||||
|
||||
Since `LOG` messages go to stderr, we decided to let googletest output go to
|
||||
Since `LOG` messages go to stderr, we decided to let GoogleTest output go to
|
||||
stdout. This way, you can easily separate the two using redirection. For
|
||||
example:
|
||||
|
||||
@@ -521,7 +520,7 @@ TEST(MyDeathTest, CompoundStatement) {
|
||||
|
||||
## I have a fixture class `FooTest`, but `TEST_F(FooTest, Bar)` gives me error ``"no matching function for call to `FooTest::FooTest()'"``. Why?
|
||||
|
||||
Googletest needs to be able to create objects of your test fixture class, so it
|
||||
GoogleTest needs to be able to create objects of your test fixture class, so it
|
||||
must have a default constructor. Normally the compiler will define one for you.
|
||||
However, there are cases where you have to define your own:
|
||||
|
||||
@@ -546,11 +545,11 @@ The new NPTL thread library doesn't suffer from this problem, as it doesn't
|
||||
create a manager thread. However, if you don't control which machine your test
|
||||
runs on, you shouldn't depend on this.
|
||||
|
||||
## Why does googletest require the entire test suite, instead of individual tests, to be named *DeathTest when it uses ASSERT_DEATH?
|
||||
## Why does GoogleTest require the entire test suite, instead of individual tests, to be named *DeathTest when it uses ASSERT_DEATH?
|
||||
|
||||
googletest does not interleave tests from different test suites. That is, it
|
||||
GoogleTest does not interleave tests from different test suites. That is, it
|
||||
runs all tests in one test suite first, and then runs all tests in the next test
|
||||
suite, and so on. googletest does this because it needs to set up a test suite
|
||||
suite, and so on. GoogleTest does this because it needs to set up a test suite
|
||||
before the first test in it is run, and tear it down afterwards. Splitting up
|
||||
the test case would require multiple set-up and tear-down processes, which is
|
||||
inefficient and makes the semantics unclean.
|
||||
@@ -589,11 +588,11 @@ TEST_F(FooDeathTest, Uvw) { ... EXPECT_DEATH(...) ... }
|
||||
TEST_F(FooDeathTest, Xyz) { ... ASSERT_DEATH(...) ... }
|
||||
```
|
||||
|
||||
## googletest prints the LOG messages in a death test's child process only when the test fails. How can I see the LOG messages when the death test succeeds?
|
||||
## GoogleTest prints the LOG messages in a death test's child process only when the test fails. How can I see the LOG messages when the death test succeeds?
|
||||
|
||||
Printing the LOG messages generated by the statement inside `EXPECT_DEATH()`
|
||||
makes it harder to search for real problems in the parent's log. Therefore,
|
||||
googletest only prints them when the death test has failed.
|
||||
GoogleTest only prints them when the death test has failed.
|
||||
|
||||
If you really need to see such LOG messages, a workaround is to temporarily
|
||||
break the death test (e.g. by changing the regex pattern it is expected to
|
||||
@@ -612,7 +611,7 @@ needs to be defined in the *same* name space. See
|
||||
|
||||
## How do I suppress the memory leak messages on Windows?
|
||||
|
||||
Since the statically initialized googletest singleton requires allocations on
|
||||
Since the statically initialized GoogleTest singleton requires allocations on
|
||||
the heap, the Visual C++ memory leak detector will report memory leaks at the
|
||||
end of the program run. The easiest way to avoid this is to use the
|
||||
`_CrtMemCheckpoint` and `_CrtMemDumpAllObjectsSince` calls to not report any
|
||||
@@ -626,7 +625,7 @@ things accordingly, you are leaking test-only logic into production code and
|
||||
there is no easy way to ensure that the test-only code paths aren't run by
|
||||
mistake in production. Such cleverness also leads to
|
||||
[Heisenbugs](https://en.wikipedia.org/wiki/Heisenbug). Therefore we strongly
|
||||
advise against the practice, and googletest doesn't provide a way to do it.
|
||||
advise against the practice, and GoogleTest doesn't provide a way to do it.
|
||||
|
||||
In general, the recommended way to cause the code to behave differently under
|
||||
test is [Dependency Injection](http://en.wikipedia.org/wiki/Dependency_injection). You can inject
|
||||
@@ -673,7 +672,7 @@ TEST(CoolTest, DoSomething) {
|
||||
```
|
||||
|
||||
However, the following code is **not allowed** and will produce a runtime error
|
||||
from googletest because the test methods are using different test fixture
|
||||
from GoogleTest because the test methods are using different test fixture
|
||||
classes with the same test suite name.
|
||||
|
||||
```c++
|
@@ -8,7 +8,7 @@ Given
|
||||
|
||||
```cpp
|
||||
class Foo {
|
||||
...
|
||||
public:
|
||||
virtual ~Foo();
|
||||
virtual int GetSize() const = 0;
|
||||
virtual string Describe(const char* name) = 0;
|
||||
@@ -23,7 +23,7 @@ class Foo {
|
||||
#include "gmock/gmock.h"
|
||||
|
||||
class MockFoo : public Foo {
|
||||
...
|
||||
public:
|
||||
MOCK_METHOD(int, GetSize, (), (const, override));
|
||||
MOCK_METHOD(string, Describe, (const char* name), (override));
|
||||
MOCK_METHOD(string, Describe, (int type), (override));
|
||||
@@ -58,7 +58,7 @@ To mock
|
||||
```cpp
|
||||
template <typename Elem>
|
||||
class StackInterface {
|
||||
...
|
||||
public:
|
||||
virtual ~StackInterface();
|
||||
virtual int GetSize() const = 0;
|
||||
virtual void Push(const Elem& x) = 0;
|
||||
@@ -71,7 +71,7 @@ class StackInterface {
|
||||
```cpp
|
||||
template <typename Elem>
|
||||
class MockStack : public StackInterface<Elem> {
|
||||
...
|
||||
public:
|
||||
MOCK_METHOD(int, GetSize, (), (const, override));
|
||||
MOCK_METHOD(void, Push, (const Elem& x), (override));
|
||||
};
|
||||
@@ -140,7 +140,7 @@ To customize the default action for functions with return type `T`, use
|
||||
// Sets the default action for return type std::unique_ptr<Buzz> to
|
||||
// creating a new Buzz every time.
|
||||
DefaultValue<std::unique_ptr<Buzz>>::SetFactory(
|
||||
[] { return MakeUnique<Buzz>(AccessLevel::kInternal); });
|
||||
[] { return std::make_unique<Buzz>(AccessLevel::kInternal); });
|
||||
|
||||
// When this fires, the default action of MakeBuzz() will run, which
|
||||
// will return a new Buzz object.
|
||||
@@ -230,7 +230,7 @@ class MockFunction<R(A1, ..., An)> {
|
||||
};
|
||||
```
|
||||
|
||||
See this [recipe](gmock_cook_book.md#using-check-points) for one application of
|
||||
See this [recipe](gmock_cook_book.md#UsingCheckPoints) for one application of
|
||||
it.
|
||||
|
||||
## Flags
|
@@ -392,8 +392,7 @@ Old macros and their new equivalents:
|
||||
If a mock method has no `EXPECT_CALL` spec but is called, we say that it's an
|
||||
"uninteresting call", and the default action (which can be specified using
|
||||
`ON_CALL()`) of the method will be taken. Currently, an uninteresting call will
|
||||
also by default cause gMock to print a warning. (In the future, we might remove
|
||||
this warning by default.)
|
||||
also by default cause gMock to print a warning.
|
||||
|
||||
However, sometimes you may want to ignore these uninteresting calls, and
|
||||
sometimes you may want to treat them as errors. gMock lets you make the decision
|
||||
@@ -905,7 +904,7 @@ using ::testing::Contains;
|
||||
using ::testing::Property;
|
||||
|
||||
inline constexpr auto HasFoo = [](const auto& f) {
|
||||
return Property(&MyClass::foo, Contains(f));
|
||||
return Property("foo", &MyClass::foo, Contains(f));
|
||||
};
|
||||
...
|
||||
EXPECT_THAT(x, HasFoo("blah"));
|
||||
@@ -1084,7 +1083,7 @@ using ::testing::Lt;
|
||||
```
|
||||
|
||||
says that `Blah` will be called with arguments `x`, `y`, and `z` where `x < y <
|
||||
z`. Note that in this example, it wasn't necessary specify the positional
|
||||
z`. Note that in this example, it wasn't necessary to specify the positional
|
||||
matchers.
|
||||
|
||||
As a convenience and example, gMock provides some matchers for 2-tuples,
|
||||
@@ -1159,7 +1158,7 @@ int IsEven(int n) { return (n % 2) == 0 ? 1 : 0; }
|
||||
```
|
||||
|
||||
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 in statement
|
||||
works as long as the return value can be used as the condition in the statement
|
||||
`if (condition) ...`.
|
||||
|
||||
### Matching Arguments that Are Not Copyable
|
||||
@@ -1300,23 +1299,27 @@ What if you have a pointer to pointer? You guessed it - you can use nested
|
||||
`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
|
||||
### Defining a Custom Matcher Class {#CustomMatcherClass}
|
||||
|
||||
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](#NewMatchers). If you want to do it
|
||||
quick and dirty, you could get away with writing an ordinary function.
|
||||
Most matchers can be simply defined using [the MATCHER* macros](#NewMatchers),
|
||||
which are terse and flexible, and produce good error messages. However, these
|
||||
macros are not very explicit about the interfaces they create and are not always
|
||||
suitable, especially for matchers that will be widely reused.
|
||||
|
||||
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:
|
||||
For more advanced cases, you may need to define your own matcher class. A custom
|
||||
matcher allows you to test a specific invariant property of that object. Let's
|
||||
take a look at how to do so.
|
||||
|
||||
Imagine you have a mock function that takes an object of type `Foo`, which has
|
||||
an `int bar()` method and an `int baz()` method. You want to constrain that the
|
||||
argument's `bar()` value plus its `baz()` value is a given number. (This is an
|
||||
invariant.) Here's how we can write and use a matcher class to do so:
|
||||
|
||||
```cpp
|
||||
using ::testing::Matcher;
|
||||
|
||||
class BarPlusBazEqMatcher {
|
||||
public:
|
||||
using is_gtest_matcher = void;
|
||||
|
||||
explicit BarPlusBazEqMatcher(int expected_sum)
|
||||
: expected_sum_(expected_sum) {}
|
||||
|
||||
@@ -1325,23 +1328,24 @@ class BarPlusBazEqMatcher {
|
||||
return (foo.bar() + foo.baz()) == expected_sum_;
|
||||
}
|
||||
|
||||
void DescribeTo(std::ostream& os) const {
|
||||
os << "bar() + baz() equals " << expected_sum_;
|
||||
void DescribeTo(std::ostream* os) const {
|
||||
*os << "bar() + baz() equals " << expected_sum_;
|
||||
}
|
||||
|
||||
void DescribeNegationTo(std::ostream& os) const {
|
||||
os << "bar() + baz() does not equal " << expected_sum_;
|
||||
void DescribeNegationTo(std::ostream* os) const {
|
||||
*os << "bar() + baz() does not equal " << expected_sum_;
|
||||
}
|
||||
private:
|
||||
const int expected_sum_;
|
||||
};
|
||||
|
||||
Matcher<const Foo&> BarPlusBazEq(int expected_sum) {
|
||||
::testing::Matcher<const Foo&> BarPlusBazEq(int expected_sum) {
|
||||
return BarPlusBazEqMatcher(expected_sum);
|
||||
}
|
||||
|
||||
...
|
||||
EXPECT_CALL(..., DoThis(BarPlusBazEq(5)))...;
|
||||
Foo foo;
|
||||
EXPECT_THAT(foo, BarPlusBazEq(5))...;
|
||||
```
|
||||
|
||||
### Matching Containers
|
||||
@@ -1420,11 +1424,12 @@ Use `Pair` when comparing maps or other associative containers.
|
||||
{% raw %}
|
||||
|
||||
```cpp
|
||||
using testing::ElementsAre;
|
||||
using testing::Pair;
|
||||
using ::testing::UnorderedElementsAre;
|
||||
using ::testing::Pair;
|
||||
...
|
||||
std::map<string, int> m = {{"a", 1}, {"b", 2}, {"c", 3}};
|
||||
EXPECT_THAT(m, ElementsAre(Pair("a", 1), Pair("b", 2), Pair("c", 3)));
|
||||
absl::flat_hash_map<string, int> m = {{"a", 1}, {"b", 2}, {"c", 3}};
|
||||
EXPECT_THAT(m, UnorderedElementsAre(
|
||||
Pair("a", 1), Pair("b", 2), Pair("c", 3)));
|
||||
```
|
||||
|
||||
{% endraw %}
|
||||
@@ -1441,8 +1446,8 @@ using testing::Pair;
|
||||
* If the container is passed by pointer instead of by reference, just write
|
||||
`Pointee(ElementsAre*(...))`.
|
||||
* The order of elements *matters* for `ElementsAre*()`. If you are using it
|
||||
with containers whose element order are undefined (e.g. `hash_map`) you
|
||||
should use `WhenSorted` around `ElementsAre`.
|
||||
with containers whose element order are undefined (such as a
|
||||
`std::unordered_map`) you should use `UnorderedElementsAre`.
|
||||
|
||||
### Sharing Matchers
|
||||
|
||||
@@ -1452,7 +1457,7 @@ 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
|
||||
again, there is no need to build it every time. Just assign it to a matcher
|
||||
variable and use that variable repeatedly! For example,
|
||||
|
||||
```cpp
|
||||
@@ -1754,7 +1759,7 @@ specifies the following DAG (where `s1` is `A -> B`, and `s2` is `A -> C -> D`):
|
||||
|
|
||||
A ---|
|
||||
|
|
||||
+---> C ---> D
|
||||
+---> C ---> D
|
||||
```
|
||||
|
||||
This means that A must occur before B and C, and C must occur before D. There's
|
||||
@@ -1899,7 +1904,7 @@ using testing::ReturnPointee;
|
||||
### 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
|
||||
allows you to do a sequence of actions every time. Only the return value of the
|
||||
last action in the sequence will be used.
|
||||
|
||||
```cpp
|
||||
@@ -1980,6 +1985,7 @@ If the mock method also needs to return a value as well, you can chain
|
||||
|
||||
```cpp
|
||||
using ::testing::_;
|
||||
using ::testing::DoAll;
|
||||
using ::testing::Return;
|
||||
using ::testing::SetArgPointee;
|
||||
|
||||
@@ -2033,10 +2039,7 @@ class MockRolodex : public Rolodex {
|
||||
}
|
||||
...
|
||||
MockRolodex rolodex;
|
||||
vector<string> names;
|
||||
names.push_back("George");
|
||||
names.push_back("John");
|
||||
names.push_back("Thomas");
|
||||
vector<string> names = {"George", "John", "Thomas"};
|
||||
EXPECT_CALL(rolodex, GetNames(_))
|
||||
.WillOnce(SetArrayArgument<0>(names.begin(), names.end()));
|
||||
```
|
||||
@@ -2604,7 +2607,7 @@ 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
|
||||
not have to build it from scratch every time. 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:
|
||||
@@ -2781,7 +2784,7 @@ If you just need to return a pre-defined move-only value, you can use the
|
||||
// When this fires, the unique_ptr<> specified by ByMove(...) will
|
||||
// be returned.
|
||||
EXPECT_CALL(mock_buzzer_, MakeBuzz("world"))
|
||||
.WillOnce(Return(ByMove(MakeUnique<Buzz>(AccessLevel::kInternal))));
|
||||
.WillOnce(Return(ByMove(std::make_unique<Buzz>(AccessLevel::kInternal))));
|
||||
|
||||
EXPECT_NE(nullptr, mock_buzzer_.MakeBuzz("world"));
|
||||
```
|
||||
@@ -2802,7 +2805,7 @@ pretty much anything you want:
|
||||
```cpp
|
||||
EXPECT_CALL(mock_buzzer_, MakeBuzz("x"))
|
||||
.WillRepeatedly([](StringPiece text) {
|
||||
return MakeUnique<Buzz>(AccessLevel::kInternal);
|
||||
return std::make_unique<Buzz>(AccessLevel::kInternal);
|
||||
});
|
||||
|
||||
EXPECT_NE(nullptr, mock_buzzer_.MakeBuzz("x"));
|
||||
@@ -2821,7 +2824,7 @@ can always use `Return`, or a [lambda or functor](#FunctionsAsActions):
|
||||
using ::testing::Unused;
|
||||
|
||||
EXPECT_CALL(mock_buzzer_, ShareBuzz(NotNull(), _)).WillOnce(Return(true));
|
||||
EXPECT_TRUE(mock_buzzer_.ShareBuzz(MakeUnique<Buzz>(AccessLevel::kInternal)),
|
||||
EXPECT_TRUE(mock_buzzer_.ShareBuzz(std::make_unique<Buzz>(AccessLevel::kInternal)),
|
||||
0);
|
||||
|
||||
EXPECT_CALL(mock_buzzer_, ShareBuzz(_, _)).WillOnce(
|
||||
@@ -2865,7 +2868,7 @@ method:
|
||||
// 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), 0);
|
||||
mock_buzzer_.ShareBuzz(std::make_unique<Buzz>(AccessLevel::kInternal), 0);
|
||||
```
|
||||
|
||||
### Making the Compilation Faster
|
||||
@@ -3809,22 +3812,19 @@ Cardinality EvenNumber() {
|
||||
.Times(EvenNumber());
|
||||
```
|
||||
|
||||
### Writing New Actions Quickly {#QuickNewActions}
|
||||
### Writing New Actions {#QuickNewActions}
|
||||
|
||||
If the built-in actions don't work for you, you can easily define your own one.
|
||||
Just define a functor class with a (possibly templated) call operator, matching
|
||||
the signature of your action.
|
||||
All you need is a call operator with a signature compatible with the mocked
|
||||
function. So you can use a lambda:
|
||||
|
||||
```cpp
|
||||
struct Increment {
|
||||
template <typename T>
|
||||
T operator()(T* arg) {
|
||||
return ++(*arg);
|
||||
}
|
||||
}
|
||||
```
|
||||
MockFunction<int(int)> mock;
|
||||
EXPECT_CALL(mock, Call).WillOnce([](const int input) { return input * 7; });
|
||||
EXPECT_EQ(14, mock.AsStdFunction()(2));
|
||||
```
|
||||
|
||||
The same approach works with stateful functors (or any callable, really):
|
||||
Or a struct with a call operator (even a templated one):
|
||||
|
||||
```
|
||||
struct MultiplyBy {
|
||||
@@ -3832,12 +3832,54 @@ struct MultiplyBy {
|
||||
T operator()(T arg) { return arg * multiplier; }
|
||||
|
||||
int multiplier;
|
||||
}
|
||||
};
|
||||
|
||||
// Then use:
|
||||
// EXPECT_CALL(...).WillOnce(MultiplyBy{7});
|
||||
```
|
||||
|
||||
It's also fine for the callable to take no arguments, ignoring the arguments
|
||||
supplied to the mock function:
|
||||
|
||||
```
|
||||
MockFunction<int(int)> mock;
|
||||
EXPECT_CALL(mock, Call).WillOnce([] { return 17; });
|
||||
EXPECT_EQ(17, mock.AsStdFunction()(0));
|
||||
```
|
||||
|
||||
When used with `WillOnce`, the callable can assume it will be called at most
|
||||
once and is allowed to be a move-only type:
|
||||
|
||||
```
|
||||
// An action that contains move-only types and has an &&-qualified operator,
|
||||
// demanding in the type system that it be called at most once. This can be
|
||||
// used with WillOnce, but the compiler will reject it if handed to
|
||||
// WillRepeatedly.
|
||||
struct MoveOnlyAction {
|
||||
std::unique_ptr<int> move_only_state;
|
||||
std::unique_ptr<int> operator()() && { return std::move(move_only_state); }
|
||||
};
|
||||
|
||||
MockFunction<std::unique_ptr<int>()> mock;
|
||||
EXPECT_CALL(mock, Call).WillOnce(MoveOnlyAction{std::make_unique<int>(17)});
|
||||
EXPECT_THAT(mock.AsStdFunction()(), Pointee(Eq(17)));
|
||||
```
|
||||
|
||||
More generally, to use with a mock function whose signature is `R(Args...)` the
|
||||
object can be anything convertible to `OnceAction<R(Args...)>` or
|
||||
`Action<R(Args...)`>. The difference between the two is that `OnceAction` has
|
||||
weaker requirements (`Action` requires a copy-constructible input that can be
|
||||
called repeatedly whereas `OnceAction` requires only move-constructible and
|
||||
supports `&&`-qualified call operators), but can be used only with `WillOnce`.
|
||||
`OnceAction` is typically relevant only when supporting move-only types or
|
||||
actions that want a type-system guarantee that they will be called at most once.
|
||||
|
||||
Typically the `OnceAction` and `Action` templates need not be referenced
|
||||
directly in your actions: a struct or class with a call operator is sufficient,
|
||||
as in the examples above. But fancier polymorphic actions that need to know the
|
||||
specific return type of the mock function can define templated conversion
|
||||
operators to make that possible. See `gmock-actions.h` for examples.
|
||||
|
||||
#### Legacy macro-based Actions
|
||||
|
||||
Before C++11, the functor-based actions were not supported; the old way of
|
||||
@@ -4191,7 +4233,7 @@ 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
|
||||
but must be invocable with exactly one template argument, which is the result
|
||||
type. In other words, you must be able to call `Perform<R>(args)` where `R` is
|
||||
the mock function's return type and `args` is its arguments in a tuple.
|
||||
|
@@ -369,8 +369,8 @@ Usually, if your action is for a particular function type, defining it using
|
||||
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
|
||||
`testing/base/public/gmock-actions.h` for an example.
|
||||
is the way to go here. See the implementation of `Return()` in `gmock-actions.h`
|
||||
for an example.
|
||||
|
||||
### I use SetArgPointee() in WillOnce(), but gcc complains about "conflicting return type specified". What does it mean?
|
||||
|
@@ -190,10 +190,10 @@ Some people put it in a `_test.cc`. This is fine when the interface being mocked
|
||||
`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), put
|
||||
it in a `.h` and a `cc_library`. Then everyone can reference them from their
|
||||
Generally, you should not mock classes you don't own. If you must mock such a
|
||||
class owned by others, define the mock class in `Foo`'s Bazel package (usually
|
||||
the same directory or a `testing` sub-directory), and put it in a `.h` and a
|
||||
`cc_library` with `testonly=True`. Then everyone can reference them 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.
|
||||
|
||||
@@ -480,8 +480,8 @@ 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](gmock_cook_book.md#using-actions).
|
||||
reference using `ReturnRef(`*`variable`*`)`, or invoke a pre-defined function,
|
||||
among [others](gmock_cook_book.md#using-actions).
|
||||
|
||||
**Important note:** The `EXPECT_CALL()` statement evaluates the action clause
|
||||
only once, even though the action may be performed many times. Therefore you
|
@@ -105,7 +105,7 @@ includedir=/usr/include
|
||||
|
||||
Name: gtest
|
||||
Description: GoogleTest (without main() function)
|
||||
Version: 1.10.0
|
||||
Version: 1.11.0
|
||||
URL: https://github.com/google/googletest
|
||||
Libs: -L${libdir} -lgtest -lpthread
|
||||
Cflags: -I${includedir} -DGTEST_HAS_PTHREAD=1 -lpthread
|
@@ -162,9 +162,9 @@ TEST(TestSuiteName, TestName) {
|
||||
|
||||
`TEST()` arguments go from general to specific. The *first* argument is the name
|
||||
of the test suite, and the *second* argument is the test's name within the test
|
||||
suite. Both names must be valid C++ identifiers, and they should not contain
|
||||
any underscores (`_`). A test's *full name* consists of its containing test suite and
|
||||
its individual name. Tests from different test suites can have the same
|
||||
suite. Both names must be valid C++ identifiers, and they should not contain any
|
||||
underscores (`_`). A test's *full name* consists of its containing test suite
|
||||
and its individual name. Tests from different test suites can have the same
|
||||
individual name.
|
||||
|
||||
For example, let's take a simple integer function:
|
||||
@@ -245,8 +245,8 @@ Also, you must first define a test fixture class before using it in a
|
||||
declaration`".
|
||||
|
||||
For each test defined with `TEST_F()`, googletest will create a *fresh* test
|
||||
fixture at runtime, immediately initialize it via `SetUp()`, run the test,
|
||||
clean up by calling `TearDown()`, and then delete the test fixture. Note that
|
||||
fixture at runtime, immediately initialize it via `SetUp()`, run the test, clean
|
||||
up by calling `TearDown()`, and then delete the test fixture. Note that
|
||||
different tests in the same test suite have different test fixture objects, and
|
||||
googletest always deletes a test fixture before it creates the next one.
|
||||
googletest does **not** reuse the same test fixture for multiple tests. Any
|
||||
@@ -274,6 +274,7 @@ First, define a fixture class. By convention, you should give it the name
|
||||
class QueueTest : public ::testing::Test {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
// q0_ remains empty
|
||||
q1_.Enqueue(1);
|
||||
q2_.Enqueue(2);
|
||||
q2_.Enqueue(3);
|
||||
@@ -342,8 +343,8 @@ your defined tests in order to run them.
|
||||
|
||||
After defining your tests, you can run them with `RUN_ALL_TESTS()`, which
|
||||
returns `0` if all the tests are successful, or `1` otherwise. Note that
|
||||
`RUN_ALL_TESTS()` runs *all tests* in your link unit--they can be from
|
||||
different test suites, or even different source files.
|
||||
`RUN_ALL_TESTS()` runs *all tests* in your link unit--they can be from different
|
||||
test suites, or even different source files.
|
||||
|
||||
When invoked, the `RUN_ALL_TESTS()` macro:
|
||||
|
||||
@@ -456,8 +457,8 @@ int main(int argc, char **argv) {
|
||||
|
||||
The `::testing::InitGoogleTest()` function parses the command line for
|
||||
googletest flags, and removes all recognized flags. This allows the user to
|
||||
control a test program's behavior via various flags, which we'll cover in
|
||||
the [AdvancedGuide](advanced.md). You **must** call this function before calling
|
||||
control a test program's behavior via various flags, which we'll cover in the
|
||||
[AdvancedGuide](advanced.md). You **must** call this function before calling
|
||||
`RUN_ALL_TESTS()`, or the flags won't be properly initialized.
|
||||
|
||||
On Windows, `InitGoogleTest()` also works with wide strings, so it can be used
|
@@ -9,7 +9,7 @@ we recommend this tutorial as a starting point.
|
||||
To complete this tutorial, you'll need:
|
||||
|
||||
* A compatible operating system (e.g. Linux, macOS, Windows).
|
||||
* A compatible C++ compiler that supports at least C++11.
|
||||
* A compatible C++ compiler that supports at least C++14.
|
||||
* [Bazel](https://bazel.build/), the preferred build system used by the
|
||||
GoogleTest team.
|
||||
|
||||
@@ -17,16 +17,15 @@ See [Supported Platforms](platforms.md) for more information about platforms
|
||||
compatible with GoogleTest.
|
||||
|
||||
If you don't already have Bazel installed, see the
|
||||
[Bazel installation guide](https://docs.bazel.build/versions/master/install.html).
|
||||
[Bazel installation guide](https://bazel.build/install).
|
||||
|
||||
{: .callout .note}
|
||||
Note: The terminal commands in this tutorial show a Unix shell prompt, but the
|
||||
commands work on the Windows command line as well.
|
||||
{: .callout .note} Note: The terminal commands in this tutorial show a Unix
|
||||
shell prompt, but the commands work on the Windows command line as well.
|
||||
|
||||
## Set up a Bazel workspace
|
||||
|
||||
A
|
||||
[Bazel workspace](https://docs.bazel.build/versions/master/build-ref.html#workspace)
|
||||
[Bazel workspace](https://docs.bazel.build/versions/main/build-ref.html#workspace)
|
||||
is a directory on your filesystem that you use to manage source files for the
|
||||
software you want to build. Each workspace directory has a text file named
|
||||
`WORKSPACE` which may be empty, or may contain references to external
|
||||
@@ -40,9 +39,9 @@ $ mkdir my_workspace && cd my_workspace
|
||||
|
||||
Next, you’ll create the `WORKSPACE` file to specify dependencies. A common and
|
||||
recommended way to depend on GoogleTest is to use a
|
||||
[Bazel external dependency](https://docs.bazel.build/versions/master/external.html)
|
||||
[Bazel external dependency](https://docs.bazel.build/versions/main/external.html)
|
||||
via the
|
||||
[`http_archive` rule](https://docs.bazel.build/versions/master/repo/http.html#http_archive).
|
||||
[`http_archive` rule](https://docs.bazel.build/versions/main/repo/http.html#http_archive).
|
||||
To do this, in the root directory of your workspace (`my_workspace/`), create a
|
||||
file named `WORKSPACE` with the following contents:
|
||||
|
||||
@@ -51,28 +50,16 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
|
||||
|
||||
http_archive(
|
||||
name = "com_google_googletest",
|
||||
urls = ["https://github.com/google/googletest/archive/609281088cfefc76f9d0ce82e1ff6c30cc3591e5.zip"],
|
||||
strip_prefix = "googletest-609281088cfefc76f9d0ce82e1ff6c30cc3591e5",
|
||||
urls = ["https://github.com/google/googletest/archive/5ab508a01f9eb089207ee87fd547d290da39d015.zip"],
|
||||
strip_prefix = "googletest-5ab508a01f9eb089207ee87fd547d290da39d015",
|
||||
)
|
||||
```
|
||||
|
||||
The above configuration declares a dependency on GoogleTest which is downloaded
|
||||
as a ZIP archive from GitHub. In the above example,
|
||||
`609281088cfefc76f9d0ce82e1ff6c30cc3591e5` is the Git commit hash of the
|
||||
`5ab508a01f9eb089207ee87fd547d290da39d015` is the Git commit hash of the
|
||||
GoogleTest version to use; we recommend updating the hash often to point to the
|
||||
latest version.
|
||||
|
||||
Bazel also needs a dependency on the
|
||||
[`rules_cc` repository](https://github.com/bazelbuild/rules_cc) to build C++
|
||||
code, so add the following to the `WORKSPACE` file:
|
||||
|
||||
```
|
||||
http_archive(
|
||||
name = "rules_cc",
|
||||
urls = ["https://github.com/bazelbuild/rules_cc/archive/40548a2974f1aea06215272d9c2b47a14a24e556.zip"],
|
||||
strip_prefix = "rules_cc-40548a2974f1aea06215272d9c2b47a14a24e556",
|
||||
)
|
||||
```
|
||||
latest version. Use a recent hash on the `main` branch.
|
||||
|
||||
Now you're ready to build C++ code that uses GoogleTest.
|
||||
|
||||
@@ -104,8 +91,6 @@ To build the code, create a file named `BUILD` in the same directory with the
|
||||
following contents:
|
||||
|
||||
```
|
||||
load("@rules_cc//cc:defs.bzl", "cc_test")
|
||||
|
||||
cc_test(
|
||||
name = "hello_test",
|
||||
size = "small",
|
||||
@@ -118,7 +103,7 @@ This `cc_test` rule declares the C++ test binary you want to build, and links to
|
||||
GoogleTest (`//:gtest_main`) using the prefix you specified in the `WORKSPACE`
|
||||
file (`@com_google_googletest`). For more information about Bazel `BUILD` files,
|
||||
see the
|
||||
[Bazel C++ Tutorial](https://docs.bazel.build/versions/master/tutorial/cpp.html).
|
||||
[Bazel C++ Tutorial](https://docs.bazel.build/versions/main/tutorial/cpp.html).
|
||||
|
||||
Now you can build and run your test:
|
||||
|
@@ -10,7 +10,7 @@ this tutorial as a starting point. If your project uses Bazel, see the
|
||||
To complete this tutorial, you'll need:
|
||||
|
||||
* A compatible operating system (e.g. Linux, macOS, Windows).
|
||||
* A compatible C++ compiler that supports at least C++11.
|
||||
* A compatible C++ compiler that supports at least C++14.
|
||||
* [CMake](https://cmake.org/) and a compatible build tool for building the
|
||||
project.
|
||||
* Compatible build tools include
|
||||
@@ -52,13 +52,13 @@ To do this, in your project directory (`my_project`), create a file named
|
||||
cmake_minimum_required(VERSION 3.14)
|
||||
project(my_project)
|
||||
|
||||
# GoogleTest requires at least C++11
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
# GoogleTest requires at least C++14
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
|
||||
include(FetchContent)
|
||||
FetchContent_Declare(
|
||||
googletest
|
||||
URL https://github.com/google/googletest/archive/609281088cfefc76f9d0ce82e1ff6c30cc3591e5.zip
|
||||
URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip
|
||||
)
|
||||
# For Windows: Prevent overriding the parent project's compiler/linker settings
|
||||
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
|
||||
@@ -66,7 +66,7 @@ FetchContent_MakeAvailable(googletest)
|
||||
```
|
||||
|
||||
The above configuration declares a dependency on GoogleTest which is downloaded
|
||||
from GitHub. In the above example, `609281088cfefc76f9d0ce82e1ff6c30cc3591e5` is
|
||||
from GitHub. In the above example, `03597a01ee50ed33e9dfd640b249b4be3799d395` is
|
||||
the Git commit hash of the GoogleTest version to use; we recommend updating the
|
||||
hash often to point to the latest version.
|
||||
|
||||
@@ -108,7 +108,7 @@ add_executable(
|
||||
)
|
||||
target_link_libraries(
|
||||
hello_test
|
||||
gtest_main
|
||||
GTest::gtest_main
|
||||
)
|
||||
|
||||
include(GoogleTest)
|
@@ -6,7 +6,7 @@ provided by GoogleTest. All actions are defined in the `::testing` namespace.
|
||||
|
||||
## Returning a Value
|
||||
|
||||
| | |
|
||||
| Action | Description |
|
||||
| :-------------------------------- | :-------------------------------------------- |
|
||||
| `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 <i>at the time the expectation is set</i>, not when the action is executed. |
|
||||
@@ -20,7 +20,7 @@ provided by GoogleTest. All actions are defined in the `::testing` namespace.
|
||||
|
||||
## Side Effects
|
||||
|
||||
| | |
|
||||
| Action | Description |
|
||||
| :--------------------------------- | :-------------------------------------- |
|
||||
| `Assign(&variable, value)` | Assign `value` to variable. |
|
||||
| `DeleteArg<N>()` | Delete the `N`-th (0-based) argument, which must be a pointer. |
|
||||
@@ -38,9 +38,9 @@ provided by GoogleTest. All actions are defined in the `::testing` namespace.
|
||||
In the following, by "callable" we mean a free function, `std::function`,
|
||||
functor, or lambda.
|
||||
|
||||
| | |
|
||||
| Action | Description |
|
||||
| :---------------------------------- | :------------------------------------- |
|
||||
| `f` | Invoke f with the arguments passed to the mock function, where f is a callable. |
|
||||
| `f` | Invoke `f` with the arguments passed to the mock function, where `f` is a callable. |
|
||||
| `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. |
|
||||
@@ -86,7 +86,7 @@ value, and `foo` by reference.
|
||||
|
||||
## Default Action
|
||||
|
||||
| Matcher | Description |
|
||||
| Action | Description |
|
||||
| :------------ | :----------------------------------------------------- |
|
||||
| `DoDefault()` | Do the default action (specified by `ON_CALL()` or the built-in one). |
|
||||
|
||||
@@ -96,7 +96,7 @@ composite action - trying to do so will result in a run-time error.
|
||||
|
||||
## Composite Actions
|
||||
|
||||
| | |
|
||||
| Action | Description |
|
||||
| :----------------------------- | :------------------------------------------ |
|
||||
| `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 and will receive a readonly view of the arguments. |
|
||||
| `IgnoreResult(a)` | Perform action `a` and ignore its result. `a` must not return void. |
|
||||
@@ -106,7 +106,7 @@ composite action - trying to do so will result in a run-time error.
|
||||
|
||||
## Defining Actions
|
||||
|
||||
| | |
|
||||
| Macro | Description |
|
||||
| :--------------------------------- | :-------------------------------------- |
|
||||
| `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`. |
|
@@ -8,9 +8,13 @@ A **matcher** matches a *single* argument. You can use it inside `ON_CALL()` or
|
||||
| `EXPECT_THAT(actual_value, matcher)` | Asserts that `actual_value` matches `matcher`. |
|
||||
| `ASSERT_THAT(actual_value, matcher)` | The same as `EXPECT_THAT(actual_value, matcher)`, except that it generates a **fatal** failure. |
|
||||
|
||||
{: .callout .note}
|
||||
**Note:** Although equality matching via `EXPECT_THAT(actual_value,
|
||||
expected_value)` is supported, prefer to make the comparison explicit via
|
||||
{: .callout .warning}
|
||||
**WARNING:** Equality matching via `EXPECT_THAT(actual_value, expected_value)`
|
||||
is supported, however note that implicit conversions can cause surprising
|
||||
results. For example, `EXPECT_THAT(some_bool, "some string")` will compile and
|
||||
may pass unintentionally.
|
||||
|
||||
**BEST PRACTICE:** Prefer to make the comparison explicit via
|
||||
`EXPECT_THAT(actual_value, Eq(expected_value))` or `EXPECT_EQ(actual_value,
|
||||
expected_value)`.
|
||||
|
||||
@@ -88,16 +92,17 @@ The `argument` can be either a C string or a C++ string object:
|
||||
|
||||
| Matcher | Description |
|
||||
| :---------------------- | :------------------------------------------------- |
|
||||
| `ContainsRegex(string)` | `argument` matches the given regular expression. |
|
||||
| `EndsWith(suffix)` | `argument` ends with string `suffix`. |
|
||||
| `HasSubstr(string)` | `argument` contains `string` as a sub-string. |
|
||||
| `IsEmpty()` | `argument` is an empty 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(string)` | `argument` matches the given regular expression. |
|
||||
| `EndsWith(suffix)` | `argument` ends with string `suffix`. |
|
||||
| `HasSubstr(string)` | `argument` contains `string` as a sub-string. |
|
||||
| `IsEmpty()` | `argument` is an empty 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`. |
|
||||
| `WhenBase64Unescaped(m)` | `argument` is a base-64 escaped string whose unescaped string matches `m`. |
|
||||
|
||||
`ContainsRegex()` and `MatchesRegex()` take ownership of the `RE` object. They
|
||||
use the regular expression syntax defined
|
||||
@@ -116,6 +121,7 @@ messages, you can use:
|
||||
| `BeginEndDistanceIs(m)` | `argument` is a container whose `begin()` and `end()` iterators are separated by a number of increments matching `m`. E.g. `BeginEndDistanceIs(2)` or `BeginEndDistanceIs(Lt(2))`. For containers that define a `size()` method, `SizeIs(m)` may be more efficient. |
|
||||
| `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. |
|
||||
| `Contains(e).Times(n)` | `argument` contains elements that match `e`, which can be either a value or a matcher, and the number of matches is `n`, which can be either a value or a matcher. Unlike the plain `Contains` and `Each` this allows to check for arbitrary occurrences including testing for absence with `Contains(e).Times(0)`. |
|
||||
| `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. |
|
||||
| `ElementsAreArray({e0, e1, ..., en})`, `ElementsAreArray(a_container)`, `ElementsAreArray(begin, end)`, `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, iterator range, or C-style array. |
|
||||
@@ -146,7 +152,6 @@ messages, you can use:
|
||||
one might write:
|
||||
|
||||
```cpp
|
||||
using ::std::get;
|
||||
MATCHER(FooEq, "") {
|
||||
return std::get<0>(arg).Equals(std::get<1>(arg));
|
||||
}
|
||||
@@ -193,6 +198,7 @@ messages, you can use:
|
||||
| Matcher | Description |
|
||||
| :--------------- | :------------------------------------------------ |
|
||||
| `ResultOf(f, m)` | `f(argument)` matches matcher `m`, where `f` is a function or functor. |
|
||||
| `ResultOf(result_description, f, m)` | The same as the two-parameter version, but provides a better error message.
|
||||
|
||||
## Pointer Matchers
|
||||
|
||||
@@ -237,6 +243,7 @@ You can make a matcher from one or more other matchers:
|
||||
| `AnyOf(m1, m2, ..., mn)` | `argument` matches at least one of the matchers `m1` to `mn`. |
|
||||
| `AnyOfArray({m0, m1, ..., mn})`, `AnyOfArray(a_container)`, `AnyOfArray(begin, end)`, `AnyOfArray(array)`, or `AnyOfArray(array, count)` | The same as `AnyOf()` except that the matchers come from an initializer list, STL-style container, iterator range, or C-style array. |
|
||||
| `Not(m)` | `argument` doesn't match matcher `m`. |
|
||||
| `Conditional(cond, m1, m2)` | Matches matcher `m1` if `cond` evaluates to true, else matches `m2`.|
|
||||
|
||||
## Adapters for Matchers
|
||||
|
||||
@@ -259,7 +266,7 @@ which must be a permanent callback.
|
||||
|
||||
## Defining Matchers
|
||||
|
||||
| Matcher | Description |
|
||||
| Macro | Description |
|
||||
| :----------------------------------- | :------------------------------------ |
|
||||
| `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 matcher `IsDivisibleBy(n)` to match a number divisible by `n`. |
|
@@ -248,7 +248,9 @@ EXPECT_CALL(my_mock, GetNumber())
|
||||
.WillOnce(Return(3));
|
||||
```
|
||||
|
||||
The `WillOnce` clause can be used any number of times on an expectation.
|
||||
The `WillOnce` clause can be used any number of times on an expectation. Unlike
|
||||
`WillRepeatedly`, the action fed to each `WillOnce` call will be called at most
|
||||
once, so may be a move-only type and/or have an `&&`-qualified call operator.
|
||||
|
||||
#### WillRepeatedly {#EXPECT_CALL.WillRepeatedly}
|
||||
|
@@ -109,7 +109,7 @@ namespace:
|
||||
| `ValuesIn(container)` or `ValuesIn(begin,end)` | Yields values from a C-style array, an STL-style container, or an iterator range `[begin, end)`. |
|
||||
| `Bool()` | Yields sequence `{false, true}`. |
|
||||
| `Combine(g1, g2, ..., gN)` | Yields as `std::tuple` *n*-tuples all combinations (Cartesian product) of the values generated by the given *n* generators `g1`, `g2`, ..., `gN`. |
|
||||
|
||||
| `ConvertGenerator<T>(g)` | Yields values generated by generator `g`, `static_cast` to `T`. |
|
||||
The optional last argument *`name_generator`* is a function or functor that
|
||||
generates custom test name suffixes based on the test parameters. The function
|
||||
must accept an argument of type
|
||||
@@ -518,8 +518,8 @@ Logs a property for the current test, test suite, or entire invocation of the
|
||||
test program. Only the last value for a given key is logged.
|
||||
|
||||
The key must be a valid XML attribute name, and cannot conflict with the ones
|
||||
already used by GoogleTest (`name`, `status`, `time`, `classname`, `type_param`,
|
||||
and `value_param`).
|
||||
already used by GoogleTest (`name`, `file`, `line`, `status`, `time`,
|
||||
`classname`, `type_param`, and `value_param`).
|
||||
|
||||
`RecordProperty` is `public static` so it can be called from utility functions
|
||||
that are not members of the test fixture.
|
@@ -1,7 +1,7 @@
|
||||
# Googletest Samples
|
||||
|
||||
If you're like us, you'd like to look at
|
||||
[googletest samples.](https://github.com/google/googletest/tree/master/googletest/samples)
|
||||
[googletest samples.](https://github.com/google/googletest/blob/main/googletest/samples)
|
||||
The sample directory has a number of well-commented samples showing how to use a
|
||||
variety of googletest features.
|
||||
|
@@ -36,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 (CMAKE_VERSION VERSION_LESS 3.0)
|
||||
project(gmock CXX C)
|
||||
else()
|
||||
cmake_policy(SET CMP0048 NEW)
|
||||
project(gmock VERSION ${GOOGLETEST_VERSION} LANGUAGES CXX C)
|
||||
endif()
|
||||
cmake_minimum_required(VERSION 2.8.12)
|
||||
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()
|
||||
@@ -109,11 +105,12 @@ endif()
|
||||
# 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")
|
||||
string(REPLACE ";" "$<SEMICOLON>" dirs "${gmock_build_include_dirs}")
|
||||
target_include_directories(gmock SYSTEM INTERFACE
|
||||
"$<BUILD_INTERFACE:${gmock_build_include_dirs}>"
|
||||
"$<BUILD_INTERFACE:${dirs}>"
|
||||
"$<INSTALL_INTERFACE:$<INSTALL_PREFIX>/${CMAKE_INSTALL_INCLUDEDIR}>")
|
||||
target_include_directories(gmock_main SYSTEM INTERFACE
|
||||
"$<BUILD_INTERFACE:${gmock_build_include_dirs}>"
|
||||
"$<BUILD_INTERFACE:${dirs}>"
|
||||
"$<INSTALL_INTERFACE:$<INSTALL_PREFIX>/${CMAKE_INSTALL_INCLUDEDIR}>")
|
||||
endif()
|
||||
|
||||
@@ -154,7 +151,10 @@ if (gmock_build_tests)
|
||||
cxx_test(gmock_ex_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)
|
@@ -35,10 +35,6 @@ Details and examples can be found here:
|
||||
* [gMock Cookbook](https://google.github.io/googletest/gmock_cook_book.html)
|
||||
* [gMock Cheat Sheet](https://google.github.io/googletest/gmock_cheat_sheet.html)
|
||||
|
||||
Please note that code under scripts/generator/ is from the
|
||||
[cppclean project](http://code.google.com/p/cppclean/) and under the Apache
|
||||
License, which is different from GoogleMock's license.
|
||||
|
||||
GoogleMock is a part of
|
||||
[GoogleTest C++ testing framework](http://github.com/google/googletest/) and a
|
||||
subject to the same requirements.
|
File diff suppressed because it is too large
Load Diff
@@ -27,21 +27,23 @@
|
||||
// (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 cardinalities. More
|
||||
// cardinalities can be defined by the user implementing the
|
||||
// CardinalityInterface interface if necessary.
|
||||
|
||||
// GOOGLETEST_CM0002 DO NOT DELETE
|
||||
// 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 <limits.h>
|
||||
|
||||
#include <memory>
|
||||
#include <ostream> // NOLINT
|
||||
|
||||
#include "gmock/internal/gmock-port.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
@@ -116,7 +118,7 @@ class GTEST_API_ Cardinality {
|
||||
// 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
|
@@ -31,10 +31,11 @@
|
||||
//
|
||||
// This file implements MOCK_METHOD.
|
||||
|
||||
// GOOGLETEST_CM0002 DO NOT DELETE
|
||||
// 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
|
||||
#ifndef GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_FUNCTION_MOCKER_H_
|
||||
#define GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_FUNCTION_MOCKER_H_
|
||||
|
||||
#include <type_traits> // IWYU pragma: keep
|
||||
#include <utility> // IWYU pragma: keep
|
||||
@@ -64,6 +65,39 @@ struct ThisRefAdjuster {
|
||||
}
|
||||
};
|
||||
|
||||
constexpr bool PrefixOf(const char* a, const char* b) {
|
||||
return *a == 0 || (*a == *b && internal::PrefixOf(a + 1, b + 1));
|
||||
}
|
||||
|
||||
template <int N, int M>
|
||||
constexpr bool StartsWith(const char (&prefix)[N], const char (&str)[M]) {
|
||||
return N <= M && internal::PrefixOf(prefix, str);
|
||||
}
|
||||
|
||||
template <int N, int M>
|
||||
constexpr bool EndsWith(const char (&suffix)[N], const char (&str)[M]) {
|
||||
return N <= M && internal::PrefixOf(suffix, str + M - N);
|
||||
}
|
||||
|
||||
template <int N, int M>
|
||||
constexpr bool Equals(const char (&a)[N], const char (&b)[M]) {
|
||||
return N == M && internal::PrefixOf(a, b);
|
||||
}
|
||||
|
||||
template <int N>
|
||||
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
|
||||
@@ -74,8 +108,11 @@ struct ThisRefAdjuster {
|
||||
using internal::FunctionMocker;
|
||||
} // namespace testing
|
||||
|
||||
#define MOCK_METHOD(...) \
|
||||
GMOCK_PP_VARIADIC_CALL(GMOCK_INTERNAL_MOCK_METHOD_ARG_, __VA_ARGS__)
|
||||
#define MOCK_METHOD(...) \
|
||||
GMOCK_INTERNAL_WARNING_PUSH() \
|
||||
GMOCK_INTERNAL_WARNING_CLANG(ignored, "-Wunused-member-function") \
|
||||
GMOCK_PP_VARIADIC_CALL(GMOCK_INTERNAL_MOCK_METHOD_ARG_, __VA_ARGS__) \
|
||||
GMOCK_INTERNAL_WARNING_POP()
|
||||
|
||||
#define GMOCK_INTERNAL_MOCK_METHOD_ARG_1(...) \
|
||||
GMOCK_INTERNAL_WRONG_ARITY(__VA_ARGS__)
|
||||
@@ -86,17 +123,18 @@ using internal::FunctionMocker;
|
||||
#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), GMOCK_INTERNAL_GET_REF_SPEC(_Spec), \
|
||||
#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(...) \
|
||||
@@ -166,11 +204,11 @@ using internal::FunctionMocker;
|
||||
GMOCK_INTERNAL_A_MATCHER_ARGUMENT, _Signature, _N)); \
|
||||
} \
|
||||
mutable ::testing::FunctionMocker<GMOCK_PP_REMOVE_PARENS(_Signature)> \
|
||||
GMOCK_MOCKER_(_N, _Constness, _MethodName)
|
||||
GMOCK_MOCKER_(_N, _Constness, _MethodName)
|
||||
|
||||
#define GMOCK_INTERNAL_EXPAND(...) __VA_ARGS__
|
||||
|
||||
// Five Valid modifiers.
|
||||
// Valid modifiers.
|
||||
#define GMOCK_INTERNAL_HAS_CONST(_Tuple) \
|
||||
GMOCK_PP_HAS_COMMA(GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_DETECT_CONST, ~, _Tuple))
|
||||
|
||||
@@ -189,6 +227,14 @@ using internal::FunctionMocker;
|
||||
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)
|
||||
|
||||
@@ -196,19 +242,25 @@ using internal::FunctionMocker;
|
||||
GMOCK_PP_IF(GMOCK_PP_HAS_COMMA(GMOCK_INTERNAL_DETECT_REF(_i, _, _elem)), \
|
||||
GMOCK_PP_CAT(GMOCK_INTERNAL_UNPACK_, _elem), )
|
||||
|
||||
#define GMOCK_INTERNAL_GET_CALLTYPE(_Tuple) \
|
||||
GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_GET_CALLTYPE_IMPL, ~, _Tuple)
|
||||
|
||||
#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_INTERNAL_IS_CALLTYPE(_elem)) == 1, \
|
||||
GMOCK_PP_STRINGIZE( \
|
||||
#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) \
|
||||
@@ -238,26 +290,12 @@ using internal::FunctionMocker;
|
||||
|
||||
#define GMOCK_INTERNAL_UNPACK_ref(x) x
|
||||
|
||||
#define GMOCK_INTERNAL_GET_CALLTYPE_IMPL(_i, _, _elem) \
|
||||
GMOCK_PP_IF(GMOCK_INTERNAL_IS_CALLTYPE(_elem), \
|
||||
GMOCK_INTERNAL_GET_VALUE_CALLTYPE, GMOCK_PP_EMPTY) \
|
||||
(_elem)
|
||||
#define GMOCK_INTERNAL_DETECT_CALLTYPE(_i, _, _elem) \
|
||||
GMOCK_PP_CAT(GMOCK_INTERNAL_DETECT_CALLTYPE_I_, _elem)
|
||||
|
||||
// TODO(iserna): GMOCK_INTERNAL_IS_CALLTYPE and
|
||||
// GMOCK_INTERNAL_GET_VALUE_CALLTYPE needed more expansions to work on windows
|
||||
// maybe they can be simplified somehow.
|
||||
#define GMOCK_INTERNAL_IS_CALLTYPE(_arg) \
|
||||
GMOCK_INTERNAL_IS_CALLTYPE_I( \
|
||||
GMOCK_PP_CAT(GMOCK_INTERNAL_IS_CALLTYPE_HELPER_, _arg))
|
||||
#define GMOCK_INTERNAL_IS_CALLTYPE_I(_arg) GMOCK_PP_IS_ENCLOSED_PARENS(_arg)
|
||||
#define GMOCK_INTERNAL_DETECT_CALLTYPE_I_Calltype ,
|
||||
|
||||
#define GMOCK_INTERNAL_GET_VALUE_CALLTYPE(_arg) \
|
||||
GMOCK_INTERNAL_GET_VALUE_CALLTYPE_I( \
|
||||
GMOCK_PP_CAT(GMOCK_INTERNAL_IS_CALLTYPE_HELPER_, _arg))
|
||||
#define GMOCK_INTERNAL_GET_VALUE_CALLTYPE_I(_arg) \
|
||||
GMOCK_PP_IDENTITY _arg
|
||||
|
||||
#define GMOCK_INTERNAL_IS_CALLTYPE_HELPER_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
|
||||
@@ -476,4 +514,4 @@ using internal::FunctionMocker;
|
||||
#define GMOCK_MOCKER_(arity, constness, Method) \
|
||||
GTEST_CONCAT_TOKEN_(gmock##constness##arity##_##Method##_, __LINE__)
|
||||
|
||||
#endif // GOOGLEMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_FUNCTION_MOCKER_H_
|
||||
#endif // GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_FUNCTION_MOCKER_H_
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user