├── cppformat
├── ignore.bii
├── doc
│ ├── _static
│ │ ├── cppformat.css
│ │ └── breathe.css
│ ├── index.rst
│ ├── CMakeLists.txt
│ ├── _templates
│ │ └── layout.html
│ ├── Doxyfile
│ ├── usage.rst
│ ├── reference.rst
│ ├── LICENSE.python
│ └── syntax.rst
├── .gitmodules
├── .gitignore
├── cmake
│ ├── FindSetEnv.cmake
│ └── run-cmake.bat
├── Android.mk
├── biicode.conf
├── biicode
│ ├── samples
│ │ └── basic.cc
│ ├── cmake
│ │ └── biicode.cmake
│ └── support
│ │ └── travis-build.sh
├── .travis.yml
├── test
│ ├── header-only-test.cc
│ ├── header-only-test2.cc
│ ├── compile-test
│ │ └── CMakeLists.txt
│ ├── util.h
│ ├── util.cc
│ ├── test-main.cc
│ ├── posix-test.h
│ ├── mock-allocator.h
│ ├── CMakeLists.txt
│ ├── gtest-extra.cc
│ ├── macro-test.cc
│ ├── format-impl-test.cc
│ ├── gtest-extra.h
│ ├── posix-test.cc
│ ├── printf-test.cc
│ └── gtest-extra-test.cc
├── appveyor.yml
├── CMakeLists.txt
├── posix.cc
├── posix.h
├── gmock
│ └── gtest
│ │ └── gtest-spi.h
└── README.rst
├── example
├── jni
│ ├── Application.mk
│ ├── Android.mk
│ └── hello-jni.cpp
├── res
│ └── values
│ │ └── strings.xml
├── default.properties
├── project.properties
├── AndroidManifest.xml
└── src
│ └── com
│ └── example
│ └── hellojni
│ └── HelloJni.java
├── screenshot.png
├── README.rst
└── run
/cppformat/ignore.bii:
--------------------------------------------------------------------------------
1 | doc/*
2 | breathe/*
3 | gmock/*
4 |
--------------------------------------------------------------------------------
/example/jni/Application.mk:
--------------------------------------------------------------------------------
1 | APP_ABI := all
2 | APP_STL := gnustl_static
--------------------------------------------------------------------------------
/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vitaut-archive/android-ndk-example/HEAD/screenshot.png
--------------------------------------------------------------------------------
/cppformat/doc/_static/cppformat.css:
--------------------------------------------------------------------------------
1 | .class dd, .define dd, .function dd {
2 | margin-left: 30px;
3 | }
4 |
5 | .public-func dd {
6 | margin-left: 0px;
7 | }
8 |
--------------------------------------------------------------------------------
/example/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | C++ Format Example
4 |
5 |
--------------------------------------------------------------------------------
/cppformat/doc/index.rst:
--------------------------------------------------------------------------------
1 | ##########
2 | C++ Format
3 | ##########
4 |
5 | .. toctree::
6 | :maxdepth: 2
7 |
8 | usage
9 | reference
10 | syntax
11 |
--------------------------------------------------------------------------------
/cppformat/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "breathe"]
2 | path = breathe
3 | url = https://github.com/michaeljones/breathe.git
4 | [submodule "doc/sphinx-bootstrap-theme"]
5 | path = doc/sphinx-bootstrap-theme
6 | url = https://github.com/cppformat/sphinx-bootstrap-theme.git
7 |
--------------------------------------------------------------------------------
/cppformat/.gitignore:
--------------------------------------------------------------------------------
1 | /_CPack_Packages
2 | /doc/conf.py
3 | /doc/doxyxml
4 | /doc/html
5 | /Testing
6 | /*-test
7 | /install_manifest.txt
8 | /tinyformat_speed_test
9 | *~
10 | *.a
11 | *.zip
12 | cmake_install.cmake
13 | CPack*Config.cmake
14 | CTestTestfile.cmake
15 | CMakeCache.txt
16 | CMakeFiles
17 | Makefile
18 |
--------------------------------------------------------------------------------
/README.rst:
--------------------------------------------------------------------------------
1 | Using fmt with Android NDK
2 | ==========================
3 |
4 | Building the example::
5 |
6 | $ git clone https://github.com/fmtlib/android-ndk-example.git
7 | $ cd android-ndk-example/example
8 | $ ndk-build
9 |
10 | .. image:: https://raw.githubusercontent.com/fmtlib/android-ndk-example/master/screenshot.png
11 |
--------------------------------------------------------------------------------
/example/jni/Android.mk:
--------------------------------------------------------------------------------
1 | LOCAL_PATH := $(call my-dir)
2 | include $(CLEAR_VARS)
3 |
4 | $(call import-add-path,$(LOCAL_PATH))
5 |
6 | LOCAL_MODULE := hello-jni
7 | LOCAL_SRC_FILES := hello-jni.cpp
8 | LOCAL_WHOLE_STATIC_LIBRARIES := cppformat_static
9 |
10 | include $(BUILD_SHARED_LIBRARY)
11 |
12 | $(call import-module,../../cppformat)
--------------------------------------------------------------------------------
/cppformat/cmake/FindSetEnv.cmake:
--------------------------------------------------------------------------------
1 | # A CMake script to find SetEnv.cmd.
2 |
3 | find_program(WINSDK_SETENV NAMES SetEnv.cmd
4 | PATHS "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows;CurrentInstallFolder]/bin")
5 | if (WINSDK_SETENV AND PRINT_PATH)
6 | execute_process(COMMAND ${CMAKE_COMMAND} -E echo "${WINSDK_SETENV}")
7 | endif ()
8 |
--------------------------------------------------------------------------------
/run:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | ANDROID_NDK=
4 | ANDROID_SDK=
5 |
6 | PATH=$PATH:$ANDROID_NDK:$ANDROID_SDK/tools:$ANDROID_SDK/platform-tools
7 | cd example
8 | ndk-build
9 | android update project --name android-ndk-example --path . --target android-21
10 | ant debug
11 | emulator -avd Nexus_5_API_21_x86
12 | # adb install bin/android-ndk-example-debug.apk
13 |
--------------------------------------------------------------------------------
/cppformat/doc/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | foreach (program doxygen sphinx-build)
2 | find_program(${program} ${program})
3 | if (NOT ${program})
4 | message(STATUS "Target 'doc' disabled (requires ${program})")
5 | return ()
6 | endif ()
7 | endforeach ()
8 |
9 | add_custom_target(doc
10 | COMMAND ${doxygen}
11 | COMMAND ${sphinx-build} -b html . html)
12 |
--------------------------------------------------------------------------------
/cppformat/Android.mk:
--------------------------------------------------------------------------------
1 | LOCAL_PATH := $(call my-dir)
2 | include $(CLEAR_VARS)
3 |
4 | LOCAL_MODULE := cppformat_static
5 | LOCAL_MODULE_FILENAME := libcppformat
6 |
7 | LOCAL_SRC_FILES := format.cc
8 |
9 | LOCAL_C_INCLUDES := $(LOCAL_PATH)
10 | LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)
11 |
12 | LOCAL_CFLAGS += -std=c++11 -fexceptions
13 |
14 | include $(BUILD_STATIC_LIBRARY)
15 |
--------------------------------------------------------------------------------
/example/default.properties:
--------------------------------------------------------------------------------
1 | # This file is automatically generated by Android Tools.
2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3 | #
4 | # This file must be checked in Version Control Systems.
5 | #
6 | # To customize properties used by the Ant build system use,
7 | # "build.properties", and override values to adapt the script to your
8 | # project structure.
9 |
10 | # Project target.
11 | target=android-4
12 |
--------------------------------------------------------------------------------
/cppformat/doc/_static/breathe.css:
--------------------------------------------------------------------------------
1 |
2 | /* -- breathe specific styles ----------------------------------------------- */
3 |
4 | /* So enum value descriptions are displayed inline to the item */
5 | .breatheenumvalues li tt + p {
6 | display: inline;
7 | }
8 |
9 | /* So parameter descriptions are displayed inline to the item */
10 | .breatheparameterlist li tt + p {
11 | display: inline;
12 | }
13 |
14 | .container .breathe-sectiondef {
15 | width: inherit;
16 | }
17 |
--------------------------------------------------------------------------------
/cppformat/cmake/run-cmake.bat:
--------------------------------------------------------------------------------
1 | @echo on
2 | rem This scripts configures build environment and runs CMake.
3 | rem Use it instead of running CMake directly when building with
4 | rem the Microsoft SDK toolchain rather than Visual Studio.
5 | rem It is used in the same way as cmake, for example:
6 | rem
7 | rem run-cmake -G "Visual Studio 10 Win64" .
8 |
9 | for /F "delims=" %%i IN ('cmake "-DPRINT_PATH=1" -P %~dp0/FindSetEnv.cmake') DO set setenv=%%i
10 | if NOT "%setenv%" == "" call "%setenv%"
11 | cmake %*
12 |
--------------------------------------------------------------------------------
/cppformat/biicode.conf:
--------------------------------------------------------------------------------
1 | # Biicode configuration file
2 |
3 | [paths]
4 | # Local directories to look for headers (within block)
5 | /
6 |
7 | [dependencies]
8 | # Manual adjust file implicit dependencies, add (+), remove (-), or overwrite (=)
9 | CMakeLists.txt + cmake/FindSetEnv.cmake
10 | format.h = format.cc
11 | format.cc - test/* posix.cc
12 | biicode/samples/basic.cpp - test/*
13 |
14 | [mains]
15 | # Manual adjust of files that define an executable
16 | !test/test-main.cc
17 |
--------------------------------------------------------------------------------
/cppformat/doc/_templates/layout.html:
--------------------------------------------------------------------------------
1 | {% extends "!layout.html" %}
2 |
3 | {% block footer %}
4 | {{ super() }}
5 |
6 |
14 | {% endblock %}
15 |
--------------------------------------------------------------------------------
/example/project.properties:
--------------------------------------------------------------------------------
1 | # This file is automatically generated by Android Tools.
2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3 | #
4 | # This file must be checked in Version Control Systems.
5 | #
6 | # To customize properties used by the Ant build system edit
7 | # "ant.properties", and override values to adapt the script to your
8 | # project structure.
9 | #
10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
12 |
13 | # Project target.
14 | target=android-10
15 |
--------------------------------------------------------------------------------
/cppformat/biicode/samples/basic.cc:
--------------------------------------------------------------------------------
1 | #include "vitaut/cppformat/format.h"
2 |
3 | class Date {
4 | int year_, month_, day_;
5 | public:
6 | Date(int year, int month, int day) : year_(year), month_(month), day_(day) {}
7 |
8 | friend std::ostream &operator<<(std::ostream &os, const Date &d) {
9 | return os << d.year_ << '-' << d.month_ << '-' << d.day_;
10 | }
11 | };
12 |
13 | int main(int argc, char *argv[]){
14 | std::string s = fmt::format("The date is {}", Date(2012, 12, 9));
15 | fmt::print("Hello, {}!", "world"); // uses Python-like format string syntax
16 | fmt::printf("\n%s", s); // uses printf format string syntax
17 | }
18 |
--------------------------------------------------------------------------------
/cppformat/biicode/cmake/biicode.cmake:
--------------------------------------------------------------------------------
1 | # Initializes block variables
2 | INIT_BIICODE_BLOCK()
3 |
4 | # Actually create targets: EXEcutables and libraries.
5 | ADD_BIICODE_TARGETS()
6 |
7 | target_include_directories(${BII_BLOCK_TARGET} INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
8 |
9 | if (HAVE_OPEN)
10 | target_compile_definitions(${BII_BLOCK_TARGET} INTERFACE -DFMT_USE_FILE_DESCRIPTORS=1)
11 | endif ()
12 |
13 | if (CMAKE_COMPILER_IS_GNUCXX)
14 | target_compile_options(${BII_BLOCK_TARGET} INTERFACE -Wall -Wextra -Wshadow -pedantic)
15 | endif ()
16 | if (CPP11_FLAG AND FMT_EXTRA_TESTS)
17 | target_compile_options(${BII_BLOCK_TARGET} INTERFACE ${CPP11_FLAG})
18 | endif ()
19 |
--------------------------------------------------------------------------------
/cppformat/doc/Doxyfile:
--------------------------------------------------------------------------------
1 | PROJECT_NAME = C++ Format
2 | GENERATE_LATEX = NO
3 | GENERATE_MAN = NO
4 | GENERATE_RTF = NO
5 | CASE_SENSE_NAMES = NO
6 | INPUT = ../format.h
7 | QUIET = YES
8 | JAVADOC_AUTOBRIEF = YES
9 | AUTOLINK_SUPPORT = NO
10 | GENERATE_HTML = NO
11 | GENERATE_XML = YES
12 | XML_OUTPUT = doxyxml
13 | ALIASES = "rst=\verbatim embed:rst"
14 | ALIASES += "endrst=\endverbatim"
15 | PREDEFINED = _WIN32=1 \
16 | FMT_NO_DEPRECATED=1 \
17 | FMT_USE_VARIADIC_TEMPLATES=1 \
18 | FMT_USE_RVALUE_REFERENCES=1
19 | EXCLUDE_SYMBOLS = fmt::internal::* BasicArg FormatParser StringValue \
20 | write_str
21 |
--------------------------------------------------------------------------------
/example/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
9 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/cppformat/.travis.yml:
--------------------------------------------------------------------------------
1 | language: cpp
2 |
3 | os:
4 | - linux
5 | - osx
6 |
7 | before_install:
8 | - if [ $TRAVIS_OS_NAME == osx ]; then curl http://www.cmake.org/files/v3.0/cmake-3.0.2-Darwin64-universal.tar.gz -o cmake.tar.gz; fi
9 | - if [ $TRAVIS_OS_NAME == osx ]; then tar xzf cmake.tar.gz; fi
10 | - if [ $TRAVIS_OS_NAME == osx ]; then export PATH=$PATH:"cmake-3.0.2-Darwin64-universal/CMake.app/Contents/bin"; fi
11 | - git submodule update --init
12 |
13 | env:
14 | - BUILD_TYPE=Debug
15 | - BUILD_TYPE=Release
16 |
17 | script:
18 | - mkdir build && cd build
19 | - cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DFMT_EXTRA_TESTS=ON ..
20 | - make -j4
21 | - CTEST_OUTPUT_ON_FAILURE=1 make test
22 | - cd .. && rm -rf build/
23 | # Building with biicode
24 | - biicode/support/travis-build.sh
25 |
26 | after_failure:
27 | - cat Testing/Temporary/LastTest.log
28 |
--------------------------------------------------------------------------------
/cppformat/biicode/support/travis-build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | if [ $TRAVIS_OS_NAME == linux ]; then
4 | sudo apt-get install libglu1-mesa-dev xorg-dev
5 | wget http://www.biicode.com/downloads/latest/ubuntu64
6 | mv ubuntu64 bii-ubuntu64.deb
7 | (sudo dpkg -i bii-ubuntu64.deb) && sudo apt-get -f install
8 | rm bii-ubuntu64.deb
9 | wget https://s3.amazonaws.com/biibinaries/thirdparty/cmake-3.0.2-Linux-64.tar.gz
10 | tar -xzf cmake-3.0.2-Linux-64.tar.gz
11 | sudo cp -fR cmake-3.0.2-Linux-64/* /usr
12 | rm -rf cmake-3.0.2-Linux-64
13 | rm cmake-3.0.2-Linux-64.tar.gz
14 | elif [ $TRAVIS_OS_NAME == osx ]; then
15 | wget http://www.biicode.com/downloads/latest/macos
16 | mv macos macos.pkg
17 | sudo installer -pkg macos.pkg -target /
18 | rm macos.pkg
19 | fi
20 |
21 | cmake --version
22 | bii init biicode_project
23 | mkdir -p ./biicode_project/blocks/vitaut/cppformat
24 | shopt -s extglob
25 | mv !(biicode_project|cmake-3.0.2-Darwin64-universal) ./biicode_project/blocks/vitaut/cppformat
26 | cd biicode_project
27 | bii cpp:build
28 | ls bin/*
29 | ./bin/vitaut_cppformat_biicode_samples_basic
30 |
31 |
--------------------------------------------------------------------------------
/example/jni/hello-jni.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2009 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 | #include
18 | #include
19 | #include "format.h"
20 |
21 | /* This is a trivial JNI example where we use a native method
22 | * to return a new VM String. See the corresponding Java source
23 | * file located at:
24 | *
25 | * apps/samples/hello-jni/project/src/com/example/hellojni/HelloJni.java
26 | */
27 |
28 | extern "C" {
29 |
30 | JNIEXPORT jstring JNICALL Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv * env, jobject obj )
31 | {
32 | std::string hello = fmt::format(
33 | "Hello from C++ Format! GCC version: {}.{}", __GNUC__, __GNUC_MINOR__);
34 | return env->NewStringUTF(hello.c_str());
35 | }
36 |
37 | }
--------------------------------------------------------------------------------
/cppformat/test/header-only-test.cc:
--------------------------------------------------------------------------------
1 | /*
2 | Header-only configuration test
3 |
4 | Copyright (c) 2014, Victor Zverovich
5 | All rights reserved.
6 |
7 | Redistribution and use in source and binary forms, with or without
8 | modification, are permitted provided that the following conditions are met:
9 |
10 | 1. Redistributions of source code must retain the above copyright notice, this
11 | list of conditions and the following disclaimer.
12 | 2. Redistributions in binary form must reproduce the above copyright notice,
13 | this list of conditions and the following disclaimer in the documentation
14 | and/or other materials provided with the distribution.
15 |
16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
20 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 | */
27 |
28 | #include "format.h"
29 |
--------------------------------------------------------------------------------
/cppformat/test/header-only-test2.cc:
--------------------------------------------------------------------------------
1 | /*
2 | Additional translation unit for the header-only configuration test
3 |
4 | Copyright (c) 2014, Victor Zverovich
5 | All rights reserved.
6 |
7 | Redistribution and use in source and binary forms, with or without
8 | modification, are permitted provided that the following conditions are met:
9 |
10 | 1. Redistributions of source code must retain the above copyright notice, this
11 | list of conditions and the following disclaimer.
12 | 2. Redistributions in binary form must reproduce the above copyright notice,
13 | this list of conditions and the following disclaimer in the documentation
14 | and/or other materials provided with the distribution.
15 |
16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
20 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 | */
27 |
28 | #include "format.h"
29 |
--------------------------------------------------------------------------------
/cppformat/test/compile-test/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # Test if compile errors are produced where necessary.
2 |
3 | cmake_minimum_required(VERSION 2.8)
4 |
5 | include(CheckCXXSourceCompiles)
6 | set(CMAKE_REQUIRED_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}/../..)
7 |
8 | function (expect_compile_error code)
9 | check_cxx_source_compiles("
10 | #include \"format.cc\"
11 | #include \"posix.h\"
12 | int main() {
13 | ${code}
14 | }
15 | " compiles)
16 | set (does_compile ${compiles})
17 | # Unset the CMake cache variable compiles. Otherwise the compile test will
18 | # just use cached information next time it runs.
19 | unset(compiles CACHE)
20 | if (does_compile)
21 | message(FATAL_ERROR "No compile error for: ${code}")
22 | endif ()
23 | endfunction ()
24 |
25 | # MakeArg doesn't accept [const] volatile char *.
26 | expect_compile_error("volatile char s[] = \"test\"; (fmt::internal::MakeArg)(s);")
27 | expect_compile_error("const volatile char s[] = \"test\"; (fmt::internal::MakeArg)(s);")
28 |
29 | # MakeArg doesn't accept wchar_t.
30 | expect_compile_error("fmt::internal::MakeArg(L'a');")
31 | expect_compile_error("fmt::internal::MakeArg(L\"test\");")
32 |
33 | # Writing a wide character to a character stream Writer is forbidden.
34 | expect_compile_error("fmt::Writer() << L'a';")
35 | expect_compile_error("fmt::Writer() << fmt::pad(\"abc\", 5, L' ');")
36 | expect_compile_error("fmt::Writer() << fmt::pad(42, 5, L' ');")
37 |
38 | # Formatting a wide character with a narrow format string is forbidden.
39 | expect_compile_error("fmt::format(\"{}\", L'a';")
40 |
41 | expect_compile_error("FMT_STATIC_ASSERT(0 > 1, \"oops\");")
42 |
--------------------------------------------------------------------------------
/cppformat/appveyor.yml:
--------------------------------------------------------------------------------
1 | environment:
2 | CTEST_OUTPUT_ON_FAILURE: 1
3 | matrix:
4 | - Build: msvc
5 | Config: Debug
6 | - Build: msvc
7 | Config: Release
8 | - Build: mingw
9 | Config: Debug
10 | - Build: mingw
11 | Config: Release
12 |
13 | install:
14 | - ps: |
15 | if ($env:Build -eq "mingw") {
16 | # Install MinGW.
17 | $url = "http://sourceforge.net/projects/mingw-w64/files/"
18 | $url += "Toolchains%20targetting%20Win64/Personal%20Builds/"
19 | $url += "mingw-builds/4.9.0/threads-win32/seh/"
20 | $url += "x86_64-4.9.0-release-win32-seh-rt_v3-rev2.7z/download"
21 | Invoke-WebRequest -UserAgent wget -Uri $url -OutFile mingw.7z
22 | &7z x -oC:\ mingw.7z > $null
23 | }
24 | - set PATH=C:\Program Files (x86)\MSBuild\12.0\bin\;%PATH%;C:\mingw64\bin
25 |
26 | before_build:
27 | - ps: |
28 | if ($env:Build -eq "mingw") {
29 | # Remove path to Git bin directory from PATH because it breaks MinGW config.
30 | $env:PATH = $env:PATH -replace "C:\\Program Files \(x86\)\\Git\\bin",""
31 | $generator = "-GMinGW Makefiles"
32 | }
33 | - echo "-DCMAKE_BUILD_TYPE=$env:Config"
34 | - cmake -DFMT_EXTRA_TESTS=ON "-DCMAKE_BUILD_TYPE=$env:Config" "$generator" .
35 |
36 | build_script:
37 | - ps: |
38 | if ($env:Build -eq "mingw") {
39 | mingw32-make -j4
40 | } else {
41 | msbuild /m:4 /p:Config=$env:Config FORMAT.sln
42 | }
43 |
44 | test_script:
45 | - ps: |
46 | if ($env:Build -eq "mingw") {
47 | mingw32-make test
48 | } else {
49 | msbuild RUN_TESTS.vcxproj
50 | }
51 |
52 | on_failure:
53 | - appveyor PushArtifact Testing/Temporary/LastTest.log
54 | - appveyor AddTest test
55 |
--------------------------------------------------------------------------------
/cppformat/test/util.h:
--------------------------------------------------------------------------------
1 | /*
2 | Test utilities.
3 |
4 | Copyright (c) 2012-2014, Victor Zverovich
5 | All rights reserved.
6 |
7 | Redistribution and use in source and binary forms, with or without
8 | modification, are permitted provided that the following conditions are met:
9 |
10 | 1. Redistributions of source code must retain the above copyright notice, this
11 | list of conditions and the following disclaimer.
12 | 2. Redistributions in binary form must reproduce the above copyright notice,
13 | this list of conditions and the following disclaimer in the documentation
14 | and/or other materials provided with the distribution.
15 |
16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
20 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 | */
27 |
28 | #include
29 | #include
30 | #include
31 |
32 | enum {BUFFER_SIZE = 256};
33 |
34 | #ifdef _MSC_VER
35 | # define FMT_VSNPRINTF vsprintf_s
36 | #else
37 | # define FMT_VSNPRINTF vsnprintf
38 | #endif
39 |
40 | template
41 | void safe_sprintf(char (&buffer)[SIZE], const char *format, ...) {
42 | std::va_list args;
43 | va_start(args, format);
44 | FMT_VSNPRINTF(buffer, SIZE, format, args);
45 | va_end(args);
46 | }
47 |
48 | // Increment a number in a string.
49 | void increment(char *s);
50 |
51 | std::string get_system_error(int error_code);
52 |
--------------------------------------------------------------------------------
/cppformat/test/util.cc:
--------------------------------------------------------------------------------
1 | /*
2 | Test utilities.
3 |
4 | Copyright (c) 2012-2014, Victor Zverovich
5 | All rights reserved.
6 |
7 | Redistribution and use in source and binary forms, with or without
8 | modification, are permitted provided that the following conditions are met:
9 |
10 | 1. Redistributions of source code must retain the above copyright notice, this
11 | list of conditions and the following disclaimer.
12 | 2. Redistributions in binary form must reproduce the above copyright notice,
13 | this list of conditions and the following disclaimer in the documentation
14 | and/or other materials provided with the distribution.
15 |
16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
20 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 | */
27 |
28 | #include "util.h"
29 | #include
30 |
31 | void increment(char *s) {
32 | for (int i = static_cast(std::strlen(s)) - 1; i >= 0; --i) {
33 | if (s[i] != '9') {
34 | ++s[i];
35 | break;
36 | }
37 | s[i] = '0';
38 | }
39 | }
40 |
41 | std::string get_system_error(int error_code) {
42 | #if defined(__MINGW32__) || !defined(_WIN32)
43 | return strerror(error_code);
44 | #else
45 | enum { BUFFER_SIZE = 200 };
46 | char buffer[BUFFER_SIZE];
47 | if (strerror_s(buffer, BUFFER_SIZE, error_code))
48 | throw std::exception("strerror_s failed");
49 | return buffer;
50 | #endif
51 | }
52 |
--------------------------------------------------------------------------------
/cppformat/doc/usage.rst:
--------------------------------------------------------------------------------
1 | *****
2 | Usage
3 | *****
4 |
5 | To use the C++ Format library, add :file:`format.h` and :file:`format.cc` from
6 | a `release archive `_
7 | or the `Git repository `_ to your project.
8 | Alternatively, you can :ref:`build the library with CMake `.
9 |
10 | If you are using Visual C++ with precompiled headers, you might need to add
11 | the line ::
12 |
13 | #include "stdafx.h"
14 |
15 | before other includes in :file:`format.cc`.
16 |
17 | .. _building:
18 |
19 | Building the library
20 | ====================
21 |
22 | The included `CMake build script`__ can be used to build the C++ Format
23 | library on a wide range of platforms. CMake is freely available for
24 | download from http://www.cmake.org/download/.
25 |
26 | __ https://github.com/cppformat/cppformat/blob/master/CMakeLists.txt
27 |
28 | CMake works by generating native makefiles or project files that can
29 | be used in the compiler environment of your choice. The typical
30 | workflow starts with::
31 |
32 | mkdir build # Create a directory to hold the build output.
33 | cd build
34 | cmake # Generate native build scripts.
35 |
36 | where :file:`{}` is a path to the ``cppformat`` repository.
37 |
38 | If you are on a \*nix system, you should now see a Makefile in the
39 | current directory. Now you can build C++ Format by running :command:`make`.
40 |
41 | Once the library has been built you can invoke :command:`make test` to run
42 | the tests.
43 |
44 | If you use Windows and have Vistual Studio installed, a :file:`FORMAT.sln`
45 | file and several :file:`.vcproj` files will be created. You can then build them
46 | using Visual Studio or msbuild.
47 |
48 | On Mac OS X with Xcode installed, an :file:`.xcodeproj` file will be generated.
49 |
50 | To build a `shared library`__ set the ``BUILD_SHARED_LIBS`` CMake variable to
51 | ``TRUE``::
52 |
53 | cmake -DBUILD_SHARED_LIBS=TRUE ...
54 |
55 | __ http://en.wikipedia.org/wiki/Library_%28computing%29#Shared_libraries
56 |
--------------------------------------------------------------------------------
/cppformat/test/test-main.cc:
--------------------------------------------------------------------------------
1 | /*
2 | Tests of additional gtest macros.
3 |
4 | Copyright (c) 2012-2014, Victor Zverovich
5 | All rights reserved.
6 |
7 | Redistribution and use in source and binary forms, with or without
8 | modification, are permitted provided that the following conditions are met:
9 |
10 | 1. Redistributions of source code must retain the above copyright notice, this
11 | list of conditions and the following disclaimer.
12 | 2. Redistributions in binary form must reproduce the above copyright notice,
13 | this list of conditions and the following disclaimer in the documentation
14 | and/or other materials provided with the distribution.
15 |
16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
20 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 | */
27 |
28 | #include
29 |
30 | #ifdef _WIN32
31 | # include
32 | # include
33 | #endif
34 |
35 | int main(int argc, char **argv) {
36 | #ifdef _WIN32
37 | // Don't display any error dialogs. This also suppresses message boxes
38 | // on assertion failures in MinGW where _set_error_mode/CrtSetReportMode
39 | // doesn't help.
40 | SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX |
41 | SEM_NOOPENFILEERRORBOX);
42 | // Disable message boxes on assertion failures.
43 | _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
44 | _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
45 | _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
46 | _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
47 | #endif
48 | testing::InitGoogleTest(&argc, argv);
49 | return RUN_ALL_TESTS();
50 | }
51 |
--------------------------------------------------------------------------------
/example/src/com/example/hellojni/HelloJni.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2009 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.example.hellojni;
17 |
18 | import android.app.Activity;
19 | import android.widget.TextView;
20 | import android.os.Bundle;
21 |
22 |
23 | public class HelloJni extends Activity
24 | {
25 | /** Called when the activity is first created. */
26 | @Override
27 | public void onCreate(Bundle savedInstanceState)
28 | {
29 | super.onCreate(savedInstanceState);
30 |
31 | /* Create a TextView and set its content.
32 | * the text is retrieved by calling a native
33 | * function.
34 | */
35 | TextView tv = new TextView(this);
36 | tv.setText( stringFromJNI() );
37 | setContentView(tv);
38 | }
39 |
40 | /* A native method that is implemented by the
41 | * 'hello-jni' native library, which is packaged
42 | * with this application.
43 | */
44 | public native String stringFromJNI();
45 |
46 | /* This is another native method declaration that is *not*
47 | * implemented by 'hello-jni'. This is simply to show that
48 | * you can declare as many native methods in your Java code
49 | * as you want, their implementation is searched in the
50 | * currently loaded native libraries only the first time
51 | * you call them.
52 | *
53 | * Trying to call this function will result in a
54 | * java.lang.UnsatisfiedLinkError exception !
55 | */
56 | public native String unimplementedStringFromJNI();
57 |
58 | /* this is used to load the 'hello-jni' library on application
59 | * startup. The library has already been unpacked into
60 | * /data/data/com.example.hellojni/lib/libhello-jni.so at
61 | * installation time by the package manager.
62 | */
63 | static {
64 | System.loadLibrary("hello-jni");
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/cppformat/test/posix-test.h:
--------------------------------------------------------------------------------
1 | /*
2 | Test wrappers around POSIX functions.
3 |
4 | Copyright (c) 2012-2014, Victor Zverovich
5 | All rights reserved.
6 |
7 | Redistribution and use in source and binary forms, with or without
8 | modification, are permitted provided that the following conditions are met:
9 |
10 | 1. Redistributions of source code must retain the above copyright notice, this
11 | list of conditions and the following disclaimer.
12 | 2. Redistributions in binary form must reproduce the above copyright notice,
13 | this list of conditions and the following disclaimer in the documentation
14 | and/or other materials provided with the distribution.
15 |
16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
20 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 | */
27 |
28 | #ifndef FMT_POSIX_TEST_H
29 | #define FMT_POSIX_TEST_H
30 |
31 | #include
32 | #include
33 |
34 | #ifndef _WIN32
35 | struct stat;
36 | #else
37 | # include
38 | #endif
39 |
40 | namespace test {
41 |
42 | #ifndef _WIN32
43 | // Size type for read and write.
44 | typedef size_t size_t;
45 | typedef ssize_t ssize_t;
46 | int open(const char *path, int oflag, int mode);
47 | int fstat(int fd, struct stat *buf);
48 | long sysconf(int name);
49 | #else
50 | typedef unsigned size_t;
51 | typedef int ssize_t;
52 | errno_t sopen_s(
53 | int* pfh, const char *filename, int oflag, int shflag, int pmode);
54 | BOOL GetFileSizeEx(HANDLE hFile, PLARGE_INTEGER lpFileSize);
55 | #endif
56 |
57 | int close(int fildes);
58 |
59 | int dup(int fildes);
60 | int dup2(int fildes, int fildes2);
61 |
62 | FILE *fdopen(int fildes, const char *mode);
63 |
64 | ssize_t read(int fildes, void *buf, size_t nbyte);
65 | ssize_t write(int fildes, const void *buf, size_t nbyte);
66 |
67 | #ifndef _WIN32
68 | int pipe(int fildes[2]);
69 | #else
70 | int pipe(int *pfds, unsigned psize, int textmode);
71 | #endif
72 |
73 | FILE *fopen(const char *filename, const char *mode);
74 | int fclose(FILE *stream);
75 | int fileno(FILE *stream);
76 |
77 | } // namespace test
78 |
79 | #define FMT_SYSTEM(call) test::call
80 |
81 | #endif // FMT_POSIX_TEST_H
82 |
--------------------------------------------------------------------------------
/cppformat/test/mock-allocator.h:
--------------------------------------------------------------------------------
1 | /*
2 | Mock allocator.
3 |
4 | Copyright (c) 2014, Victor Zverovich
5 | All rights reserved.
6 |
7 | Redistribution and use in source and binary forms, with or without
8 | modification, are permitted provided that the following conditions are met:
9 |
10 | 1. Redistributions of source code must retain the above copyright notice, this
11 | list of conditions and the following disclaimer.
12 | 2. Redistributions in binary form must reproduce the above copyright notice,
13 | this list of conditions and the following disclaimer in the documentation
14 | and/or other materials provided with the distribution.
15 |
16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
20 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 | */
27 |
28 | #ifndef FMT_MOCK_ALLOCATOR_H_
29 | #define FMT_MOCK_ALLOCATOR_H_
30 |
31 | #include "gmock/gmock.h"
32 |
33 | template
34 | class MockAllocator {
35 | public:
36 | MockAllocator() {}
37 | MockAllocator(const MockAllocator &) {}
38 | typedef T value_type;
39 | MOCK_METHOD1_T(allocate, T* (std::size_t n));
40 | MOCK_METHOD2_T(deallocate, void (T* p, std::size_t n));
41 | };
42 |
43 | template
44 | class AllocatorRef {
45 | private:
46 | Allocator *alloc_;
47 |
48 | public:
49 | typedef typename Allocator::value_type value_type;
50 |
51 | explicit AllocatorRef(Allocator *alloc = 0) : alloc_(alloc) {}
52 |
53 | AllocatorRef(const AllocatorRef &other) : alloc_(other.alloc_) {}
54 |
55 | AllocatorRef& operator=(const AllocatorRef &other) {
56 | alloc_ = other.alloc_;
57 | return *this;
58 | }
59 |
60 | #if FMT_USE_RVALUE_REFERENCES
61 | private:
62 | void move(AllocatorRef &other) {
63 | alloc_ = other.alloc_;
64 | other.alloc_ = 0;
65 | }
66 |
67 | public:
68 | AllocatorRef(AllocatorRef &&other) {
69 | move(other);
70 | }
71 |
72 | AllocatorRef& operator=(AllocatorRef &&other) {
73 | assert(this != &other);
74 | move(other);
75 | return *this;
76 | }
77 | #endif
78 |
79 | Allocator *get() const { return alloc_; }
80 |
81 | value_type* allocate(std::size_t n) { return alloc_->allocate(n); }
82 | void deallocate(value_type* p, std::size_t n) { alloc_->deallocate(p, n); }
83 | };
84 |
85 | #endif // FMT_MOCK_ALLOCATOR_H_
86 |
--------------------------------------------------------------------------------
/cppformat/test/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | set(TEST_MAIN_SRC test-main.cc gtest-extra.cc gtest-extra.h util.cc)
2 | add_library(test-main STATIC ${TEST_MAIN_SRC})
3 | target_link_libraries(test-main format gmock)
4 |
5 | # Adds a test.
6 | # Usage: add_fmt_test(name [CUSTOM_LINK] srcs...)
7 | function(add_fmt_test name)
8 | cmake_parse_arguments(add_fmt_test CUSTOM_LINK "" "" ${ARGN})
9 | add_executable(${name} ${name}.cc ${add_fmt_test_UNPARSED_ARGUMENTS})
10 | target_link_libraries(${name} test-main)
11 | if (NOT add_fmt_test_CUSTOM_LINK)
12 | target_link_libraries(${name} format)
13 | endif ()
14 | add_test(${name} ${name})
15 | endfunction()
16 |
17 | add_fmt_test(gtest-extra-test)
18 | add_fmt_test(format-test)
19 | add_fmt_test(format-impl-test CUSTOM_LINK)
20 | add_fmt_test(printf-test)
21 | foreach (target format-test printf-test)
22 | if (CMAKE_COMPILER_IS_GNUCXX)
23 | set_target_properties(${target} PROPERTIES COMPILE_FLAGS
24 | "-Wall -Wextra -pedantic -Wno-long-long -Wno-variadic-macros")
25 | endif ()
26 | if (CPP11_FLAG)
27 | set_target_properties(${target} PROPERTIES COMPILE_FLAGS ${CPP11_FLAG})
28 | endif ()
29 | endforeach ()
30 | add_fmt_test(util-test mock-allocator.h)
31 | if (CPP11_FLAG)
32 | set_target_properties(util-test PROPERTIES COMPILE_FLAGS ${CPP11_FLAG})
33 | endif ()
34 |
35 | foreach (src ${FMT_SOURCES})
36 | set(FMT_TEST_SOURCES ${FMT_TEST_SOURCES} ../${src})
37 | endforeach ()
38 |
39 | check_cxx_source_compiles("
40 | #include
41 | class C { void operator=(const C&); };
42 | int main() { static_assert(!std::is_copy_assignable::value, \"\"); }"
43 | HAVE_TYPE_TRAITS)
44 | if (HAVE_TYPE_TRAITS)
45 | add_definitions(-DFMT_USE_TYPE_TRAITS=1)
46 | endif ()
47 |
48 | add_executable(macro-test macro-test.cc ${FMT_TEST_SOURCES} ${TEST_MAIN_SRC})
49 | set_target_properties(macro-test
50 | PROPERTIES COMPILE_DEFINITIONS "FMT_USE_VARIADIC_TEMPLATES=0")
51 | target_link_libraries(macro-test gmock)
52 |
53 | if (HAVE_OPEN)
54 | add_executable(posix-test posix-test.cc ${FMT_TEST_SOURCES} ${TEST_MAIN_SRC})
55 | set_target_properties(posix-test
56 | PROPERTIES COMPILE_DEFINITIONS "FMT_INCLUDE_POSIX_TEST=1")
57 | target_link_libraries(posix-test gmock)
58 | add_test(posix-test posix-test)
59 | endif ()
60 |
61 | add_executable(header-only-test
62 | header-only-test.cc header-only-test2.cc test-main.cc)
63 | set_target_properties(header-only-test
64 | PROPERTIES COMPILE_DEFINITIONS "FMT_HEADER_ONLY=1")
65 | target_link_libraries(header-only-test gmock)
66 |
67 | # Test that the library can be compiled with exceptions disabled.
68 | check_cxx_compiler_flag(-fno-exceptions HAVE_FNO_EXCEPTIONS_FLAG)
69 | if (HAVE_FNO_EXCEPTIONS_FLAG)
70 | add_library(noexception-test STATIC ../format.cc)
71 | set_target_properties(noexception-test
72 | PROPERTIES COMPILE_FLAGS -fno-exceptions)
73 | endif ()
74 |
75 | add_test(compile-test ${CMAKE_CTEST_COMMAND}
76 | --build-and-test
77 | "${CMAKE_CURRENT_SOURCE_DIR}/compile-test"
78 | "${CMAKE_CURRENT_BINARY_DIR}/compile-test"
79 | --build-generator ${CMAKE_GENERATOR}
80 | --build-makeprogram ${CMAKE_MAKE_PROGRAM})
81 |
--------------------------------------------------------------------------------
/cppformat/doc/reference.rst:
--------------------------------------------------------------------------------
1 | .. cpp:namespace:: fmt
2 |
3 | .. _string-formatting-api:
4 |
5 | *************
6 | API Reference
7 | *************
8 |
9 | All functions and classes provided by the C++ Format library reside
10 | in namespace ``fmt`` and macros have prefix ``FMT_``. For brevity the
11 | namespace is usually omitted in examples.
12 |
13 | Formatting functions
14 | ====================
15 |
16 | The following functions use :ref:`format string syntax ` similar
17 | to the one used by Python's `str.format
18 | `_ function.
19 | They take *format_str* and *args* as arguments.
20 |
21 | *format_str* is a format string that contains literal text and replacement
22 | fields surrounded by braces ``{}``. The fields are replaced with formatted
23 | arguments in the resulting string.
24 |
25 | *args* is an argument list representing arbitrary arguments.
26 |
27 | .. _format:
28 |
29 | .. doxygenfunction:: format(StringRef, ArgList)
30 |
31 | .. _print:
32 |
33 | .. doxygenfunction:: print(StringRef, ArgList)
34 |
35 | .. doxygenfunction:: print(std::FILE *, StringRef, ArgList)
36 |
37 | .. doxygenfunction:: print(std::ostream &, StringRef, ArgList)
38 |
39 | Printf formatting functions
40 | ===========================
41 |
42 | The following functions use `printf format string syntax
43 | `_ with
44 | a POSIX extension for positional arguments.
45 |
46 | .. doxygenfunction:: printf(StringRef, ArgList)
47 |
48 | .. doxygenfunction:: fprintf(std::FILE *, StringRef, ArgList)
49 |
50 | .. doxygenfunction:: sprintf(StringRef, ArgList)
51 |
52 | Write API
53 | =========
54 |
55 | .. doxygenclass:: fmt::BasicWriter
56 | :members:
57 |
58 | .. doxygenclass:: fmt::BasicMemoryWriter
59 | :members:
60 |
61 | .. doxygenfunction:: bin
62 |
63 | .. doxygenfunction:: oct
64 |
65 | .. doxygenfunction:: hex
66 |
67 | .. doxygenfunction:: hexu
68 |
69 | .. doxygenfunction:: pad(int, unsigned, Char)
70 |
71 | Utilities
72 | =========
73 |
74 | .. doxygendefine:: FMT_VARIADIC
75 |
76 | .. doxygenclass:: fmt::ArgList
77 | :members:
78 |
79 | .. doxygenclass:: fmt::BasicStringRef
80 | :members:
81 |
82 | System Errors
83 | =============
84 |
85 | .. doxygenclass:: fmt::SystemError
86 | :members:
87 |
88 | .. doxygenclass:: fmt::WindowsError
89 | :members:
90 |
91 | .. _formatstrings:
92 |
93 | Custom allocators
94 | =================
95 |
96 | The C++ Format library supports custom dynamic memory allocators.
97 | A custom allocator class can be specified as a template argument to
98 | :class:`fmt::BasicMemoryWriter`::
99 |
100 | typedef fmt::BasicMemoryWriter CustomMemoryWriter;
101 |
102 | It is also possible to write a formatting function that uses a custom
103 | allocator::
104 |
105 | typedef std::basic_string, CustomAllocator> CustomString;
106 |
107 | CustomString format(CustomAllocator alloc, fmt::StringRef format_str,
108 | fmt::ArgList args) {
109 | CustomMemoryWriter writer(alloc);
110 | writer.write(format_str, args);
111 | return CustomString(writer.data(), writer.size(), alloc);
112 | }
113 | FMT_VARIADIC(CustomString, format, CustomAllocator, fmt::StringRef)
114 |
--------------------------------------------------------------------------------
/cppformat/test/gtest-extra.cc:
--------------------------------------------------------------------------------
1 | /*
2 | Custom Google Test assertions.
3 |
4 | Copyright (c) 2012-2014, Victor Zverovich
5 | All rights reserved.
6 |
7 | Redistribution and use in source and binary forms, with or without
8 | modification, are permitted provided that the following conditions are met:
9 |
10 | 1. Redistributions of source code must retain the above copyright notice, this
11 | list of conditions and the following disclaimer.
12 | 2. Redistributions in binary form must reproduce the above copyright notice,
13 | this list of conditions and the following disclaimer in the documentation
14 | and/or other materials provided with the distribution.
15 |
16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
20 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 | */
27 |
28 | #include "gtest-extra.h"
29 |
30 | #if FMT_USE_FILE_DESCRIPTORS
31 |
32 | using fmt::File;
33 |
34 | void OutputRedirect::flush() {
35 | #if EOF != -1
36 | # error "FMT_RETRY assumes return value of -1 indicating failure"
37 | #endif
38 | int result = 0;
39 | FMT_RETRY(result, fflush(file_));
40 | if (result != 0)
41 | throw fmt::SystemError(errno, "cannot flush stream");
42 | }
43 |
44 | void OutputRedirect::restore() {
45 | if (original_.descriptor() == -1)
46 | return; // Already restored.
47 | flush();
48 | // Restore the original file.
49 | original_.dup2(FMT_POSIX(fileno(file_)));
50 | original_.close();
51 | }
52 |
53 | OutputRedirect::OutputRedirect(FILE *file) : file_(file) {
54 | flush();
55 | int fd = FMT_POSIX(fileno(file));
56 | // Create a File object referring to the original file.
57 | original_ = File::dup(fd);
58 | // Create a pipe.
59 | File write_end;
60 | File::pipe(read_end_, write_end);
61 | // Connect the passed FILE object to the write end of the pipe.
62 | write_end.dup2(fd);
63 | }
64 |
65 | OutputRedirect::~OutputRedirect() FMT_NOEXCEPT(true) {
66 | try {
67 | restore();
68 | } catch (const std::exception &e) {
69 | std::fputs(e.what(), stderr);
70 | }
71 | }
72 |
73 | std::string OutputRedirect::restore_and_read() {
74 | // Restore output.
75 | restore();
76 |
77 | // Read everything from the pipe.
78 | std::string content;
79 | if (read_end_.descriptor() == -1)
80 | return content; // Already read.
81 | enum { BUFFER_SIZE = 4096 };
82 | char buffer[BUFFER_SIZE];
83 | std::streamsize count = 0;
84 | do {
85 | count = read_end_.read(buffer, BUFFER_SIZE);
86 | content.append(buffer, static_cast(count));
87 | } while (count != 0);
88 | read_end_.close();
89 | return content;
90 | }
91 |
92 | #endif // FMT_USE_FILE_DESCRIPTORS
93 |
94 | std::string format_system_error(int error_code, fmt::StringRef message) {
95 | fmt::MemoryWriter out;
96 | fmt::internal::format_system_error(out, error_code, message);
97 | return out.str();
98 | }
99 |
--------------------------------------------------------------------------------
/cppformat/test/macro-test.cc:
--------------------------------------------------------------------------------
1 | /*
2 | Tests of variadic function emulation macros.
3 |
4 | Copyright (c) 2012-2014, Victor Zverovich
5 | All rights reserved.
6 |
7 | Redistribution and use in source and binary forms, with or without
8 | modification, are permitted provided that the following conditions are met:
9 |
10 | 1. Redistributions of source code must retain the above copyright notice, this
11 | list of conditions and the following disclaimer.
12 | 2. Redistributions in binary form must reproduce the above copyright notice,
13 | this list of conditions and the following disclaimer in the documentation
14 | and/or other materials provided with the distribution.
15 |
16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
20 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 | */
27 |
28 | #include
29 | #include
30 | #include "format.h"
31 |
32 | #define IDENTITY(x) x
33 |
34 | TEST(UtilTest, Gen) {
35 | int values[] = {FMT_GEN(10, IDENTITY)};
36 | for (int i = 0; i < 10; ++i)
37 | EXPECT_EQ(i, values[i]);
38 | }
39 |
40 | #define MAKE_PAIR(x, y) std::make_pair(x, y)
41 |
42 | TEST(UtilTest, ForEach) {
43 | std::pair values[] = {
44 | FMT_FOR_EACH10(MAKE_PAIR, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j')
45 | };
46 | for (int i = 0; i < 10; ++i) {
47 | EXPECT_EQ('a' + i, values[i].first);
48 | EXPECT_EQ(i, values[i].second);
49 | }
50 | }
51 |
52 | TEST(UtilTest, NArg) {
53 | EXPECT_EQ(1, FMT_NARG(a));
54 | EXPECT_EQ(2, FMT_NARG(a, b));
55 | EXPECT_EQ(3, FMT_NARG(a, b, c));
56 | EXPECT_EQ(4, FMT_NARG(a, b, c, d));
57 | EXPECT_EQ(5, FMT_NARG(a, b, c, d, e));
58 | EXPECT_EQ(6, FMT_NARG(a, b, c, d, e, f));
59 | EXPECT_EQ(7, FMT_NARG(a, b, c, d, e, f, g));
60 | EXPECT_EQ(8, FMT_NARG(a, b, c, d, e, f, g, h));
61 | EXPECT_EQ(9, FMT_NARG(a, b, c, d, e, f, g, h, i));
62 | EXPECT_EQ(10, FMT_NARG(a, b, c, d, e, f, g, h, i, j));
63 | }
64 |
65 | int result;
66 |
67 | #define MAKE_TEST(func) \
68 | void func(const char *format, const fmt::ArgList &args) { \
69 | result = 0; \
70 | for (unsigned i = 0; args[i].type; ++i) \
71 | result += args[i].int_value; \
72 | }
73 |
74 | MAKE_TEST(test_func)
75 |
76 | typedef char Char;
77 | FMT_WRAP1(test_func, const char *, 1)
78 |
79 | TEST(UtilTest, Wrap1) {
80 | result = 0;
81 | test_func("", 42);
82 | EXPECT_EQ(42, result);
83 | }
84 |
85 | MAKE_TEST(test_variadic_void)
86 | FMT_VARIADIC_VOID(test_variadic_void, const char *)
87 |
88 | TEST(UtilTest, VariadicVoid) {
89 | result = 0;
90 | test_variadic_void("", 10, 20, 30, 40, 50, 60, 70, 80, 90, 100);
91 | EXPECT_EQ(550, result);
92 | }
93 |
94 | template
95 | struct S {};
96 |
97 | #define GET_TYPE(n) S
98 |
99 | int test_variadic(FMT_GEN(10, GET_TYPE), const fmt::ArgList &args) { \
100 | int result = 0; \
101 | for (std::size_t i = 0; args[i].type; ++i) \
102 | result += args[i].int_value; \
103 | return result;
104 | }
105 | FMT_VARIADIC(int, test_variadic,
106 | S<0>, S<1>, S<2>, S<3>, S<4>, S<5>, S<6>, S<7>, S<8>, S<9>)
107 |
108 | #define MAKE_ARG(n) S()
109 |
110 | TEST(UtilTest, Variadic) {
111 | EXPECT_EQ(550, test_variadic(FMT_GEN(10, MAKE_ARG),
112 | 10, 20, 30, 40, 50, 60, 70, 80, 90, 100));
113 | }
114 |
--------------------------------------------------------------------------------
/cppformat/test/format-impl-test.cc:
--------------------------------------------------------------------------------
1 | /*
2 | Formatting library implementation tests.
3 |
4 | Copyright (c) 2012-2014, Victor Zverovich
5 | All rights reserved.
6 |
7 | Redistribution and use in source and binary forms, with or without
8 | modification, are permitted provided that the following conditions are met:
9 |
10 | 1. Redistributions of source code must retain the above copyright notice, this
11 | list of conditions and the following disclaimer.
12 | 2. Redistributions in binary form must reproduce the above copyright notice,
13 | this list of conditions and the following disclaimer in the documentation
14 | and/or other materials provided with the distribution.
15 |
16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
20 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 | */
27 |
28 | // Include format.cc instead of format.h to test implementation-specific stuff.
29 | #include "format.cc"
30 |
31 | #include
32 |
33 | #include "gtest-extra.h"
34 | #include "util.h"
35 |
36 | #undef max
37 |
38 | TEST(FormatTest, ArgConverter) {
39 | using fmt::internal::Arg;
40 | Arg arg = Arg();
41 | arg.type = Arg::LONG_LONG;
42 | arg.long_long_value = std::numeric_limits::max();
43 | ArgConverter(arg, 'd').visit(arg);
44 | EXPECT_EQ(Arg::LONG_LONG, arg.type);
45 | }
46 |
47 | TEST(FormatTest, FormatNegativeNaN) {
48 | double nan = std::numeric_limits::quiet_NaN();
49 | if (fmt::internal::getsign(-nan))
50 | EXPECT_EQ("-nan", fmt::format("{}", -nan));
51 | else
52 | fmt::print("Warning: compiler doesn't handle negative NaN correctly");
53 | }
54 |
55 | TEST(FormatTest, StrError) {
56 | char *message = 0;
57 | char buffer[BUFFER_SIZE];
58 | #ifndef NDEBUG
59 | EXPECT_DEBUG_DEATH(safe_strerror(EDOM, message = 0, 0), "Assertion");
60 | EXPECT_DEBUG_DEATH(safe_strerror(EDOM, message = buffer, 0), "Assertion");
61 | #endif
62 | buffer[0] = 'x';
63 | #ifdef _GNU_SOURCE
64 | // Use invalid error code to make sure that safe_strerror returns an error
65 | // message in the buffer rather than a pointer to a static string.
66 | int error_code = -1;
67 | #else
68 | int error_code = EDOM;
69 | #endif
70 |
71 | int result = safe_strerror(error_code, message = buffer, BUFFER_SIZE);
72 | EXPECT_EQ(0, result);
73 | std::size_t message_size = std::strlen(message);
74 | EXPECT_GE(BUFFER_SIZE - 1u, message_size);
75 | EXPECT_EQ(get_system_error(error_code), message);
76 |
77 | // safe_strerror never uses buffer on MinGW.
78 | #ifndef __MINGW32__
79 | result = safe_strerror(error_code, message = buffer, message_size);
80 | EXPECT_EQ(ERANGE, result);
81 | result = safe_strerror(error_code, message = buffer, 1);
82 | EXPECT_EQ(buffer, message); // Message should point to buffer.
83 | EXPECT_EQ(ERANGE, result);
84 | EXPECT_STREQ("", message);
85 | #endif
86 | }
87 |
88 | TEST(FormatTest, FormatErrorCode) {
89 | std::string msg = "error 42", sep = ": ";
90 | {
91 | fmt::MemoryWriter w;
92 | w << "garbage";
93 | format_error_code(w, 42, "test");
94 | EXPECT_EQ("test: " + msg, w.str());
95 | }
96 | {
97 | fmt::MemoryWriter w;
98 | std::string prefix(
99 | fmt::internal::INLINE_BUFFER_SIZE - msg.size() - sep.size() + 1, 'x');
100 | format_error_code(w, 42, prefix);
101 | EXPECT_EQ(msg, w.str());
102 | }
103 | {
104 | fmt::MemoryWriter w;
105 | std::string prefix(
106 | fmt::internal::INLINE_BUFFER_SIZE - msg.size() - sep.size(), 'x');
107 | format_error_code(w, 42, prefix);
108 | EXPECT_EQ(prefix + sep + msg, w.str());
109 | std::size_t size = fmt::internal::INLINE_BUFFER_SIZE;
110 | EXPECT_EQ(size, w.size());
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/cppformat/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | message(STATUS "CMake version: ${CMAKE_VERSION}")
2 |
3 | if (POLICY CMP0054)
4 | # Only interpret `if` arguments as variables or keywords when unquoted.
5 | cmake_policy(SET CMP0054 NEW)
6 | endif ()
7 |
8 | cmake_minimum_required(VERSION 2.6)
9 |
10 | # Set the default CMAKE_BUILD_TYPE to Release.
11 | # This should be done before the project command since the latter can set
12 | # CMAKE_BUILD_TYPE itself (it does so for nmake).
13 | if (NOT CMAKE_BUILD_TYPE)
14 | set(CMAKE_BUILD_TYPE Release CACHE STRING
15 | "Choose the type of build, options are: None(CMAKE_CXX_FLAGS or CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel.")
16 | endif ()
17 |
18 | option(FMT_EXTRA_TESTS "Enable extra tests." OFF)
19 |
20 | project(FORMAT)
21 |
22 | message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
23 |
24 | include(CheckCXXCompilerFlag)
25 | check_cxx_compiler_flag(-std=c++11 HAVE_STD_CPP11_FLAG)
26 | if (HAVE_STD_CPP11_FLAG)
27 | set(CPP11_FLAG -std=c++11)
28 | else ()
29 | check_cxx_compiler_flag(-std=c++0x HAVE_STD_CPP0X_FLAG)
30 | if (HAVE_STD_CPP0X_FLAG)
31 | set(CPP11_FLAG -std=c++0x)
32 | endif ()
33 | endif ()
34 |
35 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH}
36 | "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
37 |
38 | if (CMAKE_GENERATOR MATCHES "Visual Studio")
39 | # If Microsoft SDK is installed create script run-msbuild.bat that
40 | # calls SetEnv.cmd to to set up build environment and runs msbuild.
41 | # It is useful when building Visual Studio projects with the SDK
42 | # toolchain rather than Visual Studio.
43 | include(FindSetEnv)
44 | if (WINSDK_SETENV)
45 | set(MSBUILD_SETUP "call \"${WINSDK_SETENV}\"")
46 | endif ()
47 | # Set FrameworkPathOverride to get rid of MSB3644 warnings.
48 | set(netfxpath "C:\\Program Files\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.0")
49 | file(WRITE run-msbuild.bat "
50 | ${MSBUILD_SETUP}
51 | ${CMAKE_MAKE_PROGRAM} -p:FrameworkPathOverride=\"${netfxpath}\" %*")
52 | endif ()
53 |
54 | set(FMT_SOURCES format.cc format.h)
55 |
56 | include(CheckSymbolExists)
57 | if (WIN32)
58 | check_symbol_exists(open io.h HAVE_OPEN)
59 | else ()
60 | check_symbol_exists(open fcntl.h HAVE_OPEN)
61 | endif ()
62 | if (HAVE_OPEN)
63 | add_definitions(-DFMT_USE_FILE_DESCRIPTORS=1)
64 | set(FMT_SOURCES ${FMT_SOURCES} posix.cc posix.h)
65 | endif ()
66 |
67 | if (CPP11_FLAG)
68 | set(CMAKE_REQUIRED_FLAGS ${CPP11_FLAG})
69 | endif ()
70 |
71 | if (BIICODE)
72 | include(biicode/cmake/biicode.cmake)
73 | return()
74 | endif ()
75 |
76 | add_library(format ${FMT_SOURCES})
77 | if (CMAKE_COMPILER_IS_GNUCXX)
78 | set_target_properties(format PROPERTIES COMPILE_FLAGS
79 | "-Wall -Wextra -Wshadow -pedantic")
80 | endif ()
81 | if (CPP11_FLAG AND FMT_EXTRA_TESTS)
82 | set_target_properties(format PROPERTIES COMPILE_FLAGS ${CPP11_FLAG})
83 | # Test compilation with default flags.
84 | file(GLOB src RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} test/*.cc test/*.h)
85 | add_library(testformat STATIC ${FMT_SOURCE_FILES} ${src})
86 | endif ()
87 |
88 | add_subdirectory(doc)
89 |
90 | include_directories(. gmock)
91 |
92 | # We compile Google Test ourselves instead of using pre-compiled libraries.
93 | # See the Google Test FAQ "Why is it not recommended to install a
94 | # pre-compiled copy of Google Test (for example, into /usr/local)?"
95 | # at http://code.google.com/p/googletest/wiki/FAQ for more details.
96 |
97 | add_library(gmock STATIC gmock/gmock-gtest-all.cc)
98 | find_package(Threads)
99 | target_link_libraries(gmock ${CMAKE_THREAD_LIBS_INIT})
100 |
101 | # Check if variadic templates are working and not affected by GCC bug 39653:
102 | # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=39653
103 | check_cxx_source_compiles("
104 | template
105 | struct S { typedef typename S::type type; };
106 | int main() {}" FMT_VARIADIC_TEMPLATES)
107 | if (NOT FMT_VARIADIC_TEMPLATES)
108 | add_definitions(-DGTEST_LANG_CXX11=0)
109 | endif ()
110 |
111 | # GTest doesn't detect with clang.
112 | if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
113 | target_compile_definitions(gmock PUBLIC GTEST_USE_OWN_TR1_TUPLE=1)
114 | endif ()
115 |
116 | enable_testing()
117 | add_subdirectory(test)
118 |
119 | if (EXISTS .gitignore)
120 | # Get the list of ignored files from .gitignore.
121 | file (STRINGS ".gitignore" lines)
122 | LIST(REMOVE_ITEM lines /doc/html)
123 | foreach (line ${lines})
124 | string(REPLACE "." "[.]" line "${line}")
125 | string(REPLACE "*" ".*" line "${line}")
126 | set(ignored_files ${ignored_files} "${line}$" "${line}/")
127 | endforeach ()
128 | set(ignored_files ${ignored_files} /.git /breathe /format-benchmark sphinx/)
129 |
130 | set(CPACK_SOURCE_GENERATOR ZIP)
131 | set(CPACK_SOURCE_IGNORE_FILES ${ignored_files})
132 | set(CPACK_PACKAGE_VERSION_MAJOR 1)
133 | set(CPACK_PACKAGE_VERSION_MINOR 0)
134 | set(CPACK_PACKAGE_VERSION_PATCH 1)
135 | set(CPPFORMAT_VERSION
136 | ${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH})
137 | set(CPACK_SOURCE_PACKAGE_FILE_NAME cppformat-${CPPFORMAT_VERSION})
138 | set(CPACK_RESOURCE_FILE_README ${FORMAT_SOURCE_DIR}/README.rst)
139 | include(CPack)
140 | endif ()
141 |
--------------------------------------------------------------------------------
/cppformat/test/gtest-extra.h:
--------------------------------------------------------------------------------
1 | /*
2 | Custom Google Test assertions.
3 |
4 | Copyright (c) 2012-2014, Victor Zverovich
5 | All rights reserved.
6 |
7 | Redistribution and use in source and binary forms, with or without
8 | modification, are permitted provided that the following conditions are met:
9 |
10 | 1. Redistributions of source code must retain the above copyright notice, this
11 | list of conditions and the following disclaimer.
12 | 2. Redistributions in binary form must reproduce the above copyright notice,
13 | this list of conditions and the following disclaimer in the documentation
14 | and/or other materials provided with the distribution.
15 |
16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
20 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 | */
27 |
28 | #ifndef FMT_GTEST_EXTRA_H_
29 | #define FMT_GTEST_EXTRA_H_
30 |
31 | #include
32 | #include
33 |
34 | #include "format.h"
35 |
36 | #ifndef FMT_USE_FILE_DESCRIPTORS
37 | # define FMT_USE_FILE_DESCRIPTORS 0
38 | #endif
39 |
40 | #if FMT_USE_FILE_DESCRIPTORS
41 | # include "posix.h"
42 | #endif
43 |
44 | #define FMT_TEST_THROW_(statement, expected_exception, expected_message, fail) \
45 | GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
46 | if (::testing::AssertionResult gtest_ar = ::testing::AssertionSuccess()) { \
47 | std::string gtest_expected_message = expected_message; \
48 | bool gtest_caught_expected = false; \
49 | try { \
50 | GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
51 | } \
52 | catch (expected_exception const& e) { \
53 | if (gtest_expected_message != e.what()) { \
54 | gtest_ar \
55 | << #statement " throws an exception with a different message.\n" \
56 | << "Expected: " << gtest_expected_message << "\n" \
57 | << " Actual: " << e.what(); \
58 | goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
59 | } \
60 | gtest_caught_expected = true; \
61 | } \
62 | catch (...) { \
63 | gtest_ar << \
64 | "Expected: " #statement " throws an exception of type " \
65 | #expected_exception ".\n Actual: it throws a different type."; \
66 | goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
67 | } \
68 | if (!gtest_caught_expected) { \
69 | gtest_ar << \
70 | "Expected: " #statement " throws an exception of type " \
71 | #expected_exception ".\n Actual: it throws nothing."; \
72 | goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
73 | } \
74 | } else \
75 | GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__): \
76 | fail(gtest_ar.failure_message())
77 |
78 | // Tests that the statement throws the expected exception and the exception's
79 | // what() method returns expected message.
80 | #define EXPECT_THROW_MSG(statement, expected_exception, expected_message) \
81 | FMT_TEST_THROW_(statement, expected_exception, \
82 | expected_message, GTEST_NONFATAL_FAILURE_)
83 |
84 | std::string format_system_error(int error_code, fmt::StringRef message);
85 |
86 | #define EXPECT_SYSTEM_ERROR(statement, error_code, message) \
87 | EXPECT_THROW_MSG(statement, fmt::SystemError, \
88 | format_system_error(error_code, message))
89 |
90 | #if FMT_USE_FILE_DESCRIPTORS
91 |
92 | // Captures file output by redirecting it to a pipe.
93 | // The output it can handle is limited by the pipe capacity.
94 | class OutputRedirect {
95 | private:
96 | FILE *file_;
97 | fmt::File original_; // Original file passed to redirector.
98 | fmt::File read_end_; // Read end of the pipe where the output is redirected.
99 |
100 | GTEST_DISALLOW_COPY_AND_ASSIGN_(OutputRedirect);
101 |
102 | void flush();
103 | void restore();
104 |
105 | public:
106 | explicit OutputRedirect(FILE *file);
107 | ~OutputRedirect() FMT_NOEXCEPT(true);
108 |
109 | // Restores the original file, reads output from the pipe into a string
110 | // and returns it.
111 | std::string restore_and_read();
112 | };
113 |
114 | #define FMT_TEST_WRITE_(statement, expected_output, file, fail) \
115 | GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
116 | if (::testing::AssertionResult gtest_ar = ::testing::AssertionSuccess()) { \
117 | std::string gtest_expected_output = expected_output; \
118 | OutputRedirect gtest_redir(file); \
119 | GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
120 | std::string gtest_output = gtest_redir.restore_and_read(); \
121 | if (gtest_output != gtest_expected_output) { \
122 | gtest_ar \
123 | << #statement " produces different output.\n" \
124 | << "Expected: " << gtest_expected_output << "\n" \
125 | << " Actual: " << gtest_output; \
126 | goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
127 | } \
128 | } else \
129 | GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__): \
130 | fail(gtest_ar.failure_message())
131 |
132 | // Tests that the statement writes the expected output to file.
133 | #define EXPECT_WRITE(file, statement, expected_output) \
134 | FMT_TEST_WRITE_(statement, expected_output, file, GTEST_NONFATAL_FAILURE_)
135 |
136 | #endif // FMT_USE_FILE_DESCRIPTORS
137 |
138 | #endif // FMT_GTEST_EXTRA_H_
139 |
--------------------------------------------------------------------------------
/cppformat/posix.cc:
--------------------------------------------------------------------------------
1 | /*
2 | A C++ interface to POSIX functions.
3 |
4 | Copyright (c) 2014, Victor Zverovich
5 | All rights reserved.
6 |
7 | Redistribution and use in source and binary forms, with or without
8 | modification, are permitted provided that the following conditions are met:
9 |
10 | 1. Redistributions of source code must retain the above copyright notice, this
11 | list of conditions and the following disclaimer.
12 | 2. Redistributions in binary form must reproduce the above copyright notice,
13 | this list of conditions and the following disclaimer in the documentation
14 | and/or other materials provided with the distribution.
15 |
16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
20 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 | */
27 |
28 | // Disable bogus MSVC warnings.
29 | #define _CRT_SECURE_NO_WARNINGS
30 |
31 | #include "posix.h"
32 |
33 | #include
34 | #include
35 | #include
36 |
37 | #ifndef _WIN32
38 | # include
39 | #else
40 | # include
41 | # include
42 |
43 | # define O_CREAT _O_CREAT
44 | # define O_TRUNC _O_TRUNC
45 |
46 | #ifndef S_IRUSR
47 | # define S_IRUSR _S_IREAD
48 | #endif
49 |
50 | #ifndef S_IWUSR
51 | # define S_IWUSR _S_IWRITE
52 | #endif
53 |
54 | # ifdef __MINGW32__
55 | # define _SH_DENYNO 0x40
56 | # endif
57 |
58 | #endif // _WIN32
59 |
60 | namespace {
61 | #ifdef _WIN32
62 | // Return type of read and write functions.
63 | typedef int RWResult;
64 |
65 | // On Windows the count argument to read and write is unsigned, so convert
66 | // it from size_t preventing integer overflow.
67 | inline unsigned convert_rwcount(std::size_t count) {
68 | return count <= UINT_MAX ? static_cast(count) : UINT_MAX;
69 | }
70 | #else
71 | // Return type of read and write functions.
72 | typedef ssize_t RWResult;
73 |
74 | inline std::size_t convert_rwcount(std::size_t count) { return count; }
75 | #endif
76 | }
77 |
78 | fmt::BufferedFile::~BufferedFile() FMT_NOEXCEPT(true) {
79 | if (file_ && FMT_SYSTEM(fclose(file_)) != 0)
80 | fmt::report_system_error(errno, "cannot close file");
81 | }
82 |
83 | fmt::BufferedFile::BufferedFile(fmt::StringRef filename, fmt::StringRef mode) {
84 | FMT_RETRY_VAL(file_, FMT_SYSTEM(fopen(filename.c_str(), mode.c_str())), 0);
85 | if (!file_)
86 | throw SystemError(errno, "cannot open file {}", filename);
87 | }
88 |
89 | void fmt::BufferedFile::close() {
90 | if (!file_)
91 | return;
92 | int result = FMT_SYSTEM(fclose(file_));
93 | file_ = 0;
94 | if (result != 0)
95 | throw SystemError(errno, "cannot close file");
96 | }
97 |
98 | int fmt::BufferedFile::fileno() const {
99 | int fd = FMT_POSIX_CALL(fileno(file_));
100 | if (fd == -1)
101 | throw SystemError(errno, "cannot get file descriptor");
102 | return fd;
103 | }
104 |
105 | fmt::File::File(fmt::StringRef path, int oflag) {
106 | int mode = S_IRUSR | S_IWUSR;
107 | #ifdef _WIN32
108 | fd_ = -1;
109 | FMT_POSIX_CALL(sopen_s(&fd_, path.c_str(), oflag, _SH_DENYNO, mode));
110 | #else
111 | FMT_RETRY(fd_, FMT_POSIX_CALL(open(path.c_str(), oflag, mode)));
112 | #endif
113 | if (fd_ == -1)
114 | throw SystemError(errno, "cannot open file {}", path);
115 | }
116 |
117 | fmt::File::~File() FMT_NOEXCEPT(true) {
118 | // Don't retry close in case of EINTR!
119 | // See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
120 | if (fd_ != -1 && FMT_POSIX_CALL(close(fd_)) != 0)
121 | fmt::report_system_error(errno, "cannot close file");
122 | }
123 |
124 | void fmt::File::close() {
125 | if (fd_ == -1)
126 | return;
127 | // Don't retry close in case of EINTR!
128 | // See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
129 | int result = FMT_POSIX_CALL(close(fd_));
130 | fd_ = -1;
131 | if (result != 0)
132 | throw SystemError(errno, "cannot close file");
133 | }
134 |
135 | fmt::LongLong fmt::File::size() const {
136 | #ifdef _WIN32
137 | LARGE_INTEGER size = {};
138 | HANDLE handle = reinterpret_cast(_get_osfhandle(fd_));
139 | if (!FMT_SYSTEM(GetFileSizeEx(handle, &size)))
140 | throw WindowsError(GetLastError(), "cannot get file size");
141 | FMT_STATIC_ASSERT(sizeof(fmt::LongLong) >= sizeof(size.QuadPart),
142 | "return type of File::size is not large enough");
143 | return size.QuadPart;
144 | #else
145 | typedef struct stat Stat;
146 | Stat file_stat = Stat();
147 | if (FMT_POSIX_CALL(fstat(fd_, &file_stat)) == -1)
148 | throw SystemError(errno, "cannot get file attributes");
149 | FMT_STATIC_ASSERT(sizeof(fmt::LongLong) >= sizeof(file_stat.st_size),
150 | "return type of File::size is not large enough");
151 | return file_stat.st_size;
152 | #endif
153 | }
154 |
155 | std::size_t fmt::File::read(void *buffer, std::size_t count) {
156 | RWResult result = 0;
157 | FMT_RETRY(result, FMT_POSIX_CALL(read(fd_, buffer, convert_rwcount(count))));
158 | if (result < 0)
159 | throw SystemError(errno, "cannot read from file");
160 | return result;
161 | }
162 |
163 | std::size_t fmt::File::write(const void *buffer, std::size_t count) {
164 | RWResult result = 0;
165 | FMT_RETRY(result, FMT_POSIX_CALL(write(fd_, buffer, convert_rwcount(count))));
166 | if (result < 0)
167 | throw SystemError(errno, "cannot write to file");
168 | return result;
169 | }
170 |
171 | fmt::File fmt::File::dup(int fd) {
172 | // Don't retry as dup doesn't return EINTR.
173 | // http://pubs.opengroup.org/onlinepubs/009695399/functions/dup.html
174 | int new_fd = FMT_POSIX_CALL(dup(fd));
175 | if (new_fd == -1)
176 | throw SystemError(errno, "cannot duplicate file descriptor {}", fd);
177 | return File(new_fd);
178 | }
179 |
180 | void fmt::File::dup2(int fd) {
181 | int result = 0;
182 | FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd)));
183 | if (result == -1) {
184 | throw SystemError(errno,
185 | "cannot duplicate file descriptor {} to {}", fd_, fd);
186 | }
187 | }
188 |
189 | void fmt::File::dup2(int fd, ErrorCode &ec) FMT_NOEXCEPT(true) {
190 | int result = 0;
191 | FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd)));
192 | if (result == -1)
193 | ec = ErrorCode(errno);
194 | }
195 |
196 | void fmt::File::pipe(File &read_end, File &write_end) {
197 | // Close the descriptors first to make sure that assignments don't throw
198 | // and there are no leaks.
199 | read_end.close();
200 | write_end.close();
201 | int fds[2] = {};
202 | #ifdef _WIN32
203 | // Make the default pipe capacity same as on Linux 2.6.11+.
204 | enum { DEFAULT_CAPACITY = 65536 };
205 | int result = FMT_POSIX_CALL(pipe(fds, DEFAULT_CAPACITY, _O_BINARY));
206 | #else
207 | // Don't retry as the pipe function doesn't return EINTR.
208 | // http://pubs.opengroup.org/onlinepubs/009696799/functions/pipe.html
209 | int result = FMT_POSIX_CALL(pipe(fds));
210 | #endif
211 | if (result != 0)
212 | throw SystemError(errno, "cannot create pipe");
213 | // The following assignments don't throw because read_fd and write_fd
214 | // are closed.
215 | read_end = File(fds[0]);
216 | write_end = File(fds[1]);
217 | }
218 |
219 | fmt::BufferedFile fmt::File::fdopen(const char *mode) {
220 | // Don't retry as fdopen doesn't return EINTR.
221 | FILE *f = FMT_POSIX_CALL(fdopen(fd_, mode));
222 | if (!f)
223 | throw SystemError(errno, "cannot associate stream with file descriptor");
224 | BufferedFile file(f);
225 | fd_ = -1;
226 | return file;
227 | }
228 |
229 | long fmt::getpagesize() {
230 | #ifdef _WIN32
231 | SYSTEM_INFO si = {};
232 | GetSystemInfo(&si);
233 | return si.dwPageSize;
234 | #else
235 | long size = FMT_POSIX_CALL(sysconf(_SC_PAGESIZE));
236 | if (size < 0)
237 | throw SystemError(errno, "cannot get memory page size");
238 | return size;
239 | #endif
240 | }
241 |
--------------------------------------------------------------------------------
/cppformat/posix.h:
--------------------------------------------------------------------------------
1 | /*
2 | A C++ interface to POSIX functions.
3 |
4 | Copyright (c) 2014, Victor Zverovich
5 | All rights reserved.
6 |
7 | Redistribution and use in source and binary forms, with or without
8 | modification, are permitted provided that the following conditions are met:
9 |
10 | 1. Redistributions of source code must retain the above copyright notice, this
11 | list of conditions and the following disclaimer.
12 | 2. Redistributions in binary form must reproduce the above copyright notice,
13 | this list of conditions and the following disclaimer in the documentation
14 | and/or other materials provided with the distribution.
15 |
16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
20 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 | */
27 |
28 | #ifndef FMT_POSIX_H_
29 | #define FMT_POSIX_H_
30 |
31 | #include
32 | #include // for O_RDONLY
33 | #include
34 |
35 | #include
36 |
37 | #include "format.h"
38 |
39 | #ifdef FMT_INCLUDE_POSIX_TEST
40 | # include "test/posix-test.h"
41 | #endif
42 |
43 | #ifndef FMT_POSIX
44 | # ifdef _WIN32
45 | // Fix warnings about deprecated symbols.
46 | # define FMT_POSIX(call) _##call
47 | # else
48 | # define FMT_POSIX(call) call
49 | # endif
50 | #endif
51 |
52 | // Calls to system functions are wrapped in FMT_SYSTEM for testability.
53 | #ifdef FMT_SYSTEM
54 | # define FMT_POSIX_CALL(call) FMT_SYSTEM(call)
55 | #else
56 | # define FMT_SYSTEM(call) call
57 | # ifdef _WIN32
58 | // Fix warnings about deprecated symbols.
59 | # define FMT_POSIX_CALL(call) ::_##call
60 | # else
61 | # define FMT_POSIX_CALL(call) ::call
62 | # endif
63 | #endif
64 |
65 | #if FMT_GCC_VERSION >= 407
66 | # define FMT_UNUSED __attribute__((unused))
67 | #else
68 | # define FMT_UNUSED
69 | #endif
70 |
71 | #if FMT_USE_STATIC_ASSERT
72 | # define FMT_STATIC_ASSERT(cond, message) static_assert(cond, message)
73 | #else
74 | # define FMT_CONCAT_(a, b) FMT_CONCAT(a, b)
75 | # define FMT_STATIC_ASSERT(cond, message) \
76 | typedef int FMT_CONCAT_(Assert, __LINE__)[(cond) ? 1 : -1] FMT_UNUSED
77 | #endif
78 |
79 | // Retries the expression while it evaluates to error_result and errno
80 | // equals to EINTR.
81 | #ifndef _WIN32
82 | # define FMT_RETRY_VAL(result, expression, error_result) \
83 | do { \
84 | result = (expression); \
85 | } while (result == error_result && errno == EINTR)
86 | #else
87 | # define FMT_RETRY_VAL(result, expression, error_result) result = (expression)
88 | #endif
89 |
90 | #define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1)
91 |
92 | namespace fmt {
93 |
94 | // An error code.
95 | class ErrorCode {
96 | private:
97 | int value_;
98 |
99 | public:
100 | explicit ErrorCode(int value = 0) FMT_NOEXCEPT(true) : value_(value) {}
101 |
102 | int get() const FMT_NOEXCEPT(true) { return value_; }
103 | };
104 |
105 | // A buffered file.
106 | class BufferedFile {
107 | private:
108 | FILE *file_;
109 |
110 | friend class File;
111 |
112 | explicit BufferedFile(FILE *f) : file_(f) {}
113 |
114 | public:
115 | // Constructs a BufferedFile object which doesn't represent any file.
116 | BufferedFile() FMT_NOEXCEPT(true) : file_(0) {}
117 |
118 | // Destroys the object closing the file it represents if any.
119 | ~BufferedFile() FMT_NOEXCEPT(true);
120 |
121 | #if !FMT_USE_RVALUE_REFERENCES
122 | // Emulate a move constructor and a move assignment operator if rvalue
123 | // references are not supported.
124 |
125 | private:
126 | // A proxy object to emulate a move constructor.
127 | // It is private to make it impossible call operator Proxy directly.
128 | struct Proxy {
129 | FILE *file;
130 | };
131 |
132 | public:
133 | // A "move constructor" for moving from a temporary.
134 | BufferedFile(Proxy p) FMT_NOEXCEPT(true) : file_(p.file) {}
135 |
136 | // A "move constructor" for for moving from an lvalue.
137 | BufferedFile(BufferedFile &f) FMT_NOEXCEPT(true) : file_(f.file_) {
138 | f.file_ = 0;
139 | }
140 |
141 | // A "move assignment operator" for moving from a temporary.
142 | BufferedFile &operator=(Proxy p) {
143 | close();
144 | file_ = p.file;
145 | return *this;
146 | }
147 |
148 | // A "move assignment operator" for moving from an lvalue.
149 | BufferedFile &operator=(BufferedFile &other) {
150 | close();
151 | file_ = other.file_;
152 | other.file_ = 0;
153 | return *this;
154 | }
155 |
156 | // Returns a proxy object for moving from a temporary:
157 | // BufferedFile file = BufferedFile(...);
158 | operator Proxy() FMT_NOEXCEPT(true) {
159 | Proxy p = {file_};
160 | file_ = 0;
161 | return p;
162 | }
163 |
164 | #else
165 | private:
166 | FMT_DISALLOW_COPY_AND_ASSIGN(BufferedFile);
167 |
168 | public:
169 | BufferedFile(BufferedFile &&other) FMT_NOEXCEPT(true) : file_(other.file_) {
170 | other.file_ = 0;
171 | }
172 |
173 | BufferedFile& operator=(BufferedFile &&other) {
174 | close();
175 | file_ = other.file_;
176 | other.file_ = 0;
177 | return *this;
178 | }
179 | #endif
180 |
181 | // Opens a file.
182 | BufferedFile(fmt::StringRef filename, fmt::StringRef mode);
183 |
184 | // Closes the file.
185 | void close();
186 |
187 | // Returns the pointer to a FILE object representing this file.
188 | FILE *get() const { return file_; }
189 |
190 | int fileno() const;
191 |
192 | void print(fmt::StringRef format_str, const ArgList &args) {
193 | fmt::print(file_, format_str, args);
194 | }
195 | FMT_VARIADIC(void, print, fmt::StringRef)
196 | };
197 |
198 | // A file. Closed file is represented by a File object with descriptor -1.
199 | // Methods that are not declared with FMT_NOEXCEPT(true) may throw
200 | // fmt::SystemError in case of failure. Note that some errors such as
201 | // closing the file multiple times will cause a crash on Windows rather
202 | // than an exception. You can get standard behavior by overriding the
203 | // invalid parameter handler with _set_invalid_parameter_handler.
204 | class File {
205 | private:
206 | int fd_; // File descriptor.
207 |
208 | // Constructs a File object with a given descriptor.
209 | explicit File(int fd) : fd_(fd) {}
210 |
211 | public:
212 | // Possible values for the oflag argument to the constructor.
213 | enum {
214 | RDONLY = FMT_POSIX(O_RDONLY), // Open for reading only.
215 | WRONLY = FMT_POSIX(O_WRONLY), // Open for writing only.
216 | RDWR = FMT_POSIX(O_RDWR) // Open for reading and writing.
217 | };
218 |
219 | // Constructs a File object which doesn't represent any file.
220 | File() FMT_NOEXCEPT(true) : fd_(-1) {}
221 |
222 | // Opens a file and constructs a File object representing this file.
223 | File(fmt::StringRef path, int oflag);
224 |
225 | #if !FMT_USE_RVALUE_REFERENCES
226 | // Emulate a move constructor and a move assignment operator if rvalue
227 | // references are not supported.
228 |
229 | private:
230 | // A proxy object to emulate a move constructor.
231 | // It is private to make it impossible call operator Proxy directly.
232 | struct Proxy {
233 | int fd;
234 | };
235 |
236 | public:
237 | // A "move constructor" for moving from a temporary.
238 | File(Proxy p) FMT_NOEXCEPT(true) : fd_(p.fd) {}
239 |
240 | // A "move constructor" for for moving from an lvalue.
241 | File(File &other) FMT_NOEXCEPT(true) : fd_(other.fd_) {
242 | other.fd_ = -1;
243 | }
244 |
245 | // A "move assignment operator" for moving from a temporary.
246 | File &operator=(Proxy p) {
247 | close();
248 | fd_ = p.fd;
249 | return *this;
250 | }
251 |
252 | // A "move assignment operator" for moving from an lvalue.
253 | File &operator=(File &other) {
254 | close();
255 | fd_ = other.fd_;
256 | other.fd_ = -1;
257 | return *this;
258 | }
259 |
260 | // Returns a proxy object for moving from a temporary:
261 | // File file = File(...);
262 | operator Proxy() FMT_NOEXCEPT(true) {
263 | Proxy p = {fd_};
264 | fd_ = -1;
265 | return p;
266 | }
267 |
268 | #else
269 | private:
270 | FMT_DISALLOW_COPY_AND_ASSIGN(File);
271 |
272 | public:
273 | File(File &&other) FMT_NOEXCEPT(true) : fd_(other.fd_) {
274 | other.fd_ = -1;
275 | }
276 |
277 | File& operator=(File &&other) {
278 | close();
279 | fd_ = other.fd_;
280 | other.fd_ = -1;
281 | return *this;
282 | }
283 | #endif
284 |
285 | // Destroys the object closing the file it represents if any.
286 | ~File() FMT_NOEXCEPT(true);
287 |
288 | // Returns the file descriptor.
289 | int descriptor() const FMT_NOEXCEPT(true) { return fd_; }
290 |
291 | // Closes the file.
292 | void close();
293 |
294 | // Returns the file size.
295 | fmt::LongLong size() const;
296 |
297 | // Attempts to read count bytes from the file into the specified buffer.
298 | std::size_t read(void *buffer, std::size_t count);
299 |
300 | // Attempts to write count bytes from the specified buffer to the file.
301 | std::size_t write(const void *buffer, std::size_t count);
302 |
303 | // Duplicates a file descriptor with the dup function and returns
304 | // the duplicate as a file object.
305 | static File dup(int fd);
306 |
307 | // Makes fd be the copy of this file descriptor, closing fd first if
308 | // necessary.
309 | void dup2(int fd);
310 |
311 | // Makes fd be the copy of this file descriptor, closing fd first if
312 | // necessary.
313 | void dup2(int fd, ErrorCode &ec) FMT_NOEXCEPT(true);
314 |
315 | // Creates a pipe setting up read_end and write_end file objects for reading
316 | // and writing respectively.
317 | static void pipe(File &read_end, File &write_end);
318 |
319 | // Creates a BufferedFile object associated with this file and detaches
320 | // this File object from the file.
321 | BufferedFile fdopen(const char *mode);
322 | };
323 |
324 | // Returns the memory page size.
325 | long getpagesize();
326 | } // namespace fmt
327 |
328 | #if !FMT_USE_RVALUE_REFERENCES
329 | namespace std {
330 | // For compatibility with C++98.
331 | inline fmt::BufferedFile &move(fmt::BufferedFile &f) { return f; }
332 | inline fmt::File &move(fmt::File &f) { return f; }
333 | }
334 | #endif
335 |
336 | #endif // FMT_POSIX_H_
337 |
--------------------------------------------------------------------------------
/cppformat/gmock/gtest/gtest-spi.h:
--------------------------------------------------------------------------------
1 | // Copyright 2007, Google Inc.
2 | // All rights reserved.
3 | //
4 | // Redistribution and use in source and binary forms, with or without
5 | // modification, are permitted provided that the following conditions are
6 | // met:
7 | //
8 | // * Redistributions of source code must retain the above copyright
9 | // notice, this list of conditions and the following disclaimer.
10 | // * Redistributions in binary form must reproduce the above
11 | // copyright notice, this list of conditions and the following disclaimer
12 | // in the documentation and/or other materials provided with the
13 | // distribution.
14 | // * Neither the name of Google Inc. nor the names of its
15 | // contributors may be used to endorse or promote products derived from
16 | // this software without specific prior written permission.
17 | //
18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 | //
30 | // Author: wan@google.com (Zhanyong Wan)
31 | //
32 | // Utilities for testing Google Test itself and code that uses Google Test
33 | // (e.g. frameworks built on top of Google Test).
34 |
35 | #ifndef GTEST_INCLUDE_GTEST_GTEST_SPI_H_
36 | #define GTEST_INCLUDE_GTEST_GTEST_SPI_H_
37 |
38 | #include "gtest/gtest.h"
39 |
40 | namespace testing {
41 |
42 | // This helper class can be used to mock out Google Test failure reporting
43 | // so that we can test Google Test or code that builds on Google Test.
44 | //
45 | // An object of this class appends a TestPartResult object to the
46 | // TestPartResultArray object given in the constructor whenever a Google Test
47 | // failure is reported. It can either intercept only failures that are
48 | // generated in the same thread that created this object or it can intercept
49 | // all generated failures. The scope of this mock object can be controlled with
50 | // the second argument to the two arguments constructor.
51 | class GTEST_API_ ScopedFakeTestPartResultReporter
52 | : public TestPartResultReporterInterface {
53 | public:
54 | // The two possible mocking modes of this object.
55 | enum InterceptMode {
56 | INTERCEPT_ONLY_CURRENT_THREAD, // Intercepts only thread local failures.
57 | INTERCEPT_ALL_THREADS // Intercepts all failures.
58 | };
59 |
60 | // The c'tor sets this object as the test part result reporter used
61 | // by Google Test. The 'result' parameter specifies where to report the
62 | // results. This reporter will only catch failures generated in the current
63 | // thread. DEPRECATED
64 | explicit ScopedFakeTestPartResultReporter(TestPartResultArray* result);
65 |
66 | // Same as above, but you can choose the interception scope of this object.
67 | ScopedFakeTestPartResultReporter(InterceptMode intercept_mode,
68 | TestPartResultArray* result);
69 |
70 | // The d'tor restores the previous test part result reporter.
71 | virtual ~ScopedFakeTestPartResultReporter();
72 |
73 | // Appends the TestPartResult object to the TestPartResultArray
74 | // received in the constructor.
75 | //
76 | // This method is from the TestPartResultReporterInterface
77 | // interface.
78 | virtual void ReportTestPartResult(const TestPartResult& result);
79 | private:
80 | void Init();
81 |
82 | const InterceptMode intercept_mode_;
83 | TestPartResultReporterInterface* old_reporter_;
84 | TestPartResultArray* const result_;
85 |
86 | GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedFakeTestPartResultReporter);
87 | };
88 |
89 | namespace internal {
90 |
91 | // A helper class for implementing EXPECT_FATAL_FAILURE() and
92 | // EXPECT_NONFATAL_FAILURE(). Its destructor verifies that the given
93 | // TestPartResultArray contains exactly one failure that has the given
94 | // type and contains the given substring. If that's not the case, a
95 | // non-fatal failure will be generated.
96 | class GTEST_API_ SingleFailureChecker {
97 | public:
98 | // The constructor remembers the arguments.
99 | SingleFailureChecker(const TestPartResultArray* results,
100 | TestPartResult::Type type,
101 | const string& substr);
102 | ~SingleFailureChecker();
103 | private:
104 | const TestPartResultArray* const results_;
105 | const TestPartResult::Type type_;
106 | const string substr_;
107 |
108 | GTEST_DISALLOW_COPY_AND_ASSIGN_(SingleFailureChecker);
109 | };
110 |
111 | } // namespace internal
112 |
113 | } // namespace testing
114 |
115 | // A set of macros for testing Google Test assertions or code that's expected
116 | // to generate Google Test fatal failures. It verifies that the given
117 | // statement will cause exactly one fatal Google Test failure with 'substr'
118 | // being part of the failure message.
119 | //
120 | // There are two different versions of this macro. EXPECT_FATAL_FAILURE only
121 | // affects and considers failures generated in the current thread and
122 | // EXPECT_FATAL_FAILURE_ON_ALL_THREADS does the same but for all threads.
123 | //
124 | // The verification of the assertion is done correctly even when the statement
125 | // throws an exception or aborts the current function.
126 | //
127 | // Known restrictions:
128 | // - 'statement' cannot reference local non-static variables or
129 | // non-static members of the current object.
130 | // - 'statement' cannot return a value.
131 | // - You cannot stream a failure message to this macro.
132 | //
133 | // Note that even though the implementations of the following two
134 | // macros are much alike, we cannot refactor them to use a common
135 | // helper macro, due to some peculiarity in how the preprocessor
136 | // works. The AcceptsMacroThatExpandsToUnprotectedComma test in
137 | // gtest_unittest.cc will fail to compile if we do that.
138 | #define EXPECT_FATAL_FAILURE(statement, substr) \
139 | do { \
140 | class GTestExpectFatalFailureHelper {\
141 | public:\
142 | static void Execute() { statement; }\
143 | };\
144 | ::testing::TestPartResultArray gtest_failures;\
145 | ::testing::internal::SingleFailureChecker gtest_checker(\
146 | >est_failures, ::testing::TestPartResult::kFatalFailure, (substr));\
147 | {\
148 | ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
149 | ::testing::ScopedFakeTestPartResultReporter:: \
150 | INTERCEPT_ONLY_CURRENT_THREAD, >est_failures);\
151 | GTestExpectFatalFailureHelper::Execute();\
152 | }\
153 | } while (::testing::internal::AlwaysFalse())
154 |
155 | #define EXPECT_FATAL_FAILURE_ON_ALL_THREADS(statement, substr) \
156 | do { \
157 | class GTestExpectFatalFailureHelper {\
158 | public:\
159 | static void Execute() { statement; }\
160 | };\
161 | ::testing::TestPartResultArray gtest_failures;\
162 | ::testing::internal::SingleFailureChecker gtest_checker(\
163 | >est_failures, ::testing::TestPartResult::kFatalFailure, (substr));\
164 | {\
165 | ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
166 | ::testing::ScopedFakeTestPartResultReporter:: \
167 | INTERCEPT_ALL_THREADS, >est_failures);\
168 | GTestExpectFatalFailureHelper::Execute();\
169 | }\
170 | } while (::testing::internal::AlwaysFalse())
171 |
172 | // A macro for testing Google Test assertions or code that's expected to
173 | // generate Google Test non-fatal failures. It asserts that the given
174 | // statement will cause exactly one non-fatal Google Test failure with 'substr'
175 | // being part of the failure message.
176 | //
177 | // There are two different versions of this macro. EXPECT_NONFATAL_FAILURE only
178 | // affects and considers failures generated in the current thread and
179 | // EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS does the same but for all threads.
180 | //
181 | // 'statement' is allowed to reference local variables and members of
182 | // the current object.
183 | //
184 | // The verification of the assertion is done correctly even when the statement
185 | // throws an exception or aborts the current function.
186 | //
187 | // Known restrictions:
188 | // - You cannot stream a failure message to this macro.
189 | //
190 | // Note that even though the implementations of the following two
191 | // macros are much alike, we cannot refactor them to use a common
192 | // helper macro, due to some peculiarity in how the preprocessor
193 | // works. If we do that, the code won't compile when the user gives
194 | // EXPECT_NONFATAL_FAILURE() a statement that contains a macro that
195 | // expands to code containing an unprotected comma. The
196 | // AcceptsMacroThatExpandsToUnprotectedComma test in gtest_unittest.cc
197 | // catches that.
198 | //
199 | // For the same reason, we have to write
200 | // if (::testing::internal::AlwaysTrue()) { statement; }
201 | // instead of
202 | // GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement)
203 | // to avoid an MSVC warning on unreachable code.
204 | #define EXPECT_NONFATAL_FAILURE(statement, substr) \
205 | do {\
206 | ::testing::TestPartResultArray gtest_failures;\
207 | ::testing::internal::SingleFailureChecker gtest_checker(\
208 | >est_failures, ::testing::TestPartResult::kNonFatalFailure, \
209 | (substr));\
210 | {\
211 | ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
212 | ::testing::ScopedFakeTestPartResultReporter:: \
213 | INTERCEPT_ONLY_CURRENT_THREAD, >est_failures);\
214 | if (::testing::internal::AlwaysTrue()) { statement; }\
215 | }\
216 | } while (::testing::internal::AlwaysFalse())
217 |
218 | #define EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(statement, substr) \
219 | do {\
220 | ::testing::TestPartResultArray gtest_failures;\
221 | ::testing::internal::SingleFailureChecker gtest_checker(\
222 | >est_failures, ::testing::TestPartResult::kNonFatalFailure, \
223 | (substr));\
224 | {\
225 | ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
226 | ::testing::ScopedFakeTestPartResultReporter::INTERCEPT_ALL_THREADS, \
227 | >est_failures);\
228 | if (::testing::internal::AlwaysTrue()) { statement; }\
229 | }\
230 | } while (::testing::internal::AlwaysFalse())
231 |
232 | #endif // GTEST_INCLUDE_GTEST_GTEST_SPI_H_
233 |
--------------------------------------------------------------------------------
/cppformat/test/posix-test.cc:
--------------------------------------------------------------------------------
1 | /*
2 | Test wrappers around POSIX functions.
3 |
4 | Copyright (c) 2012-2014, Victor Zverovich
5 | All rights reserved.
6 |
7 | Redistribution and use in source and binary forms, with or without
8 | modification, are permitted provided that the following conditions are met:
9 |
10 | 1. Redistributions of source code must retain the above copyright notice, this
11 | list of conditions and the following disclaimer.
12 | 2. Redistributions in binary form must reproduce the above copyright notice,
13 | this list of conditions and the following disclaimer in the documentation
14 | and/or other materials provided with the distribution.
15 |
16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
20 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 | */
27 |
28 | // Disable bogus MSVC warnings.
29 | #define _CRT_SECURE_NO_WARNINGS
30 |
31 | #include "posix-test.h"
32 |
33 | #include
34 | #include
35 | #include
36 |
37 | #ifdef _WIN32
38 | # include
39 | # undef max
40 | # undef ERROR
41 | #endif
42 |
43 | #include "gtest-extra.h"
44 |
45 | using fmt::BufferedFile;
46 | using fmt::ErrorCode;
47 | using fmt::File;
48 |
49 | namespace {
50 | int open_count;
51 | int close_count;
52 | int dup_count;
53 | int dup2_count;
54 | int fdopen_count;
55 | int read_count;
56 | int write_count;
57 | int pipe_count;
58 | int fopen_count;
59 | int fclose_count;
60 | int fileno_count;
61 | std::size_t read_nbyte;
62 | std::size_t write_nbyte;
63 | bool sysconf_error;
64 |
65 | enum FStatSimulation { NONE, MAX_SIZE, ERROR } fstat_sim;
66 | }
67 |
68 | #define EMULATE_EINTR(func, error_result) \
69 | if (func##_count != 0) { \
70 | if (func##_count++ != 3) { \
71 | errno = EINTR; \
72 | return error_result; \
73 | } \
74 | }
75 |
76 | #ifndef _WIN32
77 | int test::open(const char *path, int oflag, int mode) {
78 | EMULATE_EINTR(open, -1);
79 | return ::open(path, oflag, mode);
80 | }
81 |
82 | static off_t max_file_size() { return std::numeric_limits::max(); }
83 |
84 | int test::fstat(int fd, struct stat *buf) {
85 | int result = ::fstat(fd, buf);
86 | if (fstat_sim == MAX_SIZE)
87 | buf->st_size = max_file_size();
88 | return result;
89 | }
90 |
91 | long test::sysconf(int name) {
92 | long result = ::sysconf(name);
93 | if (!sysconf_error)
94 | return result;
95 | // Simulate an error.
96 | errno = EINVAL;
97 | return -1;
98 | }
99 | #else
100 | errno_t test::sopen_s(
101 | int* pfh, const char *filename, int oflag, int shflag, int pmode) {
102 | EMULATE_EINTR(open, EINTR);
103 | return _sopen_s(pfh, filename, oflag, shflag, pmode);
104 | }
105 |
106 | static LONGLONG max_file_size() { return std::numeric_limits::max(); }
107 |
108 | BOOL test::GetFileSizeEx(HANDLE hFile, PLARGE_INTEGER lpFileSize) {
109 | if (fstat_sim == ERROR) {
110 | SetLastError(ERROR_ACCESS_DENIED);
111 | return FALSE;
112 | }
113 | BOOL result = ::GetFileSizeEx(hFile, lpFileSize);
114 | if (fstat_sim == MAX_SIZE)
115 | lpFileSize->QuadPart = max_file_size();
116 | return result;
117 | }
118 | #endif
119 |
120 | int test::close(int fildes) {
121 | // Close the file first because close shouldn't be retried.
122 | int result = ::FMT_POSIX(close(fildes));
123 | EMULATE_EINTR(close, -1);
124 | return result;
125 | }
126 |
127 | int test::dup(int fildes) {
128 | EMULATE_EINTR(dup, -1);
129 | return ::FMT_POSIX(dup(fildes));
130 | }
131 |
132 | int test::dup2(int fildes, int fildes2) {
133 | EMULATE_EINTR(dup2, -1);
134 | return ::FMT_POSIX(dup2(fildes, fildes2));
135 | }
136 |
137 | FILE *test::fdopen(int fildes, const char *mode) {
138 | EMULATE_EINTR(fdopen, 0);
139 | return ::FMT_POSIX(fdopen(fildes, mode));
140 | }
141 |
142 | test::ssize_t test::read(int fildes, void *buf, test::size_t nbyte) {
143 | read_nbyte = nbyte;
144 | EMULATE_EINTR(read, -1);
145 | return ::FMT_POSIX(read(fildes, buf, nbyte));
146 | }
147 |
148 | test::ssize_t test::write(int fildes, const void *buf, test::size_t nbyte) {
149 | write_nbyte = nbyte;
150 | EMULATE_EINTR(write, -1);
151 | return ::FMT_POSIX(write(fildes, buf, nbyte));
152 | }
153 |
154 | #ifndef _WIN32
155 | int test::pipe(int fildes[2]) {
156 | EMULATE_EINTR(pipe, -1);
157 | return ::pipe(fildes);
158 | }
159 | #else
160 | int test::pipe(int *pfds, unsigned psize, int textmode) {
161 | EMULATE_EINTR(pipe, -1);
162 | return _pipe(pfds, psize, textmode);
163 | }
164 | #endif
165 |
166 | FILE *test::fopen(const char *filename, const char *mode) {
167 | EMULATE_EINTR(fopen, 0);
168 | return ::fopen(filename, mode);
169 | }
170 |
171 | int test::fclose(FILE *stream) {
172 | EMULATE_EINTR(fclose, EOF);
173 | return ::fclose(stream);
174 | }
175 |
176 | int test::fileno(FILE *stream) {
177 | EMULATE_EINTR(fileno, -1);
178 | return ::FMT_POSIX(fileno(stream));
179 | }
180 |
181 | #ifndef _WIN32
182 | # define EXPECT_RETRY(statement, func, message) \
183 | func##_count = 1; \
184 | statement; \
185 | EXPECT_EQ(4, func##_count); \
186 | func##_count = 0;
187 | # define EXPECT_EQ_POSIX(expected, actual) EXPECT_EQ(expected, actual)
188 | #else
189 | # define EXPECT_RETRY(statement, func, message) \
190 | func##_count = 1; \
191 | EXPECT_SYSTEM_ERROR(statement, EINTR, message); \
192 | func##_count = 0;
193 | # define EXPECT_EQ_POSIX(expected, actual)
194 | #endif
195 |
196 | void write_file(fmt::StringRef filename, fmt::StringRef content) {
197 | fmt::BufferedFile f(filename, "w");
198 | f.print("{}", content);
199 | }
200 |
201 | TEST(UtilTest, StaticAssert) {
202 | FMT_STATIC_ASSERT(true, "success");
203 | // Static assertion failure is tested in compile-test because it causes
204 | // a compile-time error.
205 | }
206 |
207 | TEST(UtilTest, GetPageSize) {
208 | #ifdef _WIN32
209 | SYSTEM_INFO si = {};
210 | GetSystemInfo(&si);
211 | EXPECT_EQ(si.dwPageSize, fmt::getpagesize());
212 | #else
213 | EXPECT_EQ(sysconf(_SC_PAGESIZE), fmt::getpagesize());
214 | sysconf_error = true;
215 | EXPECT_SYSTEM_ERROR(
216 | fmt::getpagesize(), EINVAL, "cannot get memory page size");
217 | sysconf_error = false;
218 | #endif
219 | }
220 |
221 | TEST(FileTest, OpenRetry) {
222 | write_file("test", "there must be something here");
223 | File *f = 0;
224 | EXPECT_RETRY(f = new File("test", File::RDONLY),
225 | open, "cannot open file test");
226 | #ifndef _WIN32
227 | char c = 0;
228 | f->read(&c, 1);
229 | #endif
230 | delete f;
231 | }
232 |
233 | TEST(FileTest, CloseNoRetryInDtor) {
234 | File read_end, write_end;
235 | File::pipe(read_end, write_end);
236 | File *f = new File(std::move(read_end));
237 | int saved_close_count = 0;
238 | EXPECT_WRITE(stderr, {
239 | close_count = 1;
240 | delete f;
241 | saved_close_count = close_count;
242 | close_count = 0;
243 | }, format_system_error(EINTR, "cannot close file") + "\n");
244 | EXPECT_EQ(2, saved_close_count);
245 | }
246 |
247 | TEST(FileTest, CloseNoRetry) {
248 | File read_end, write_end;
249 | File::pipe(read_end, write_end);
250 | close_count = 1;
251 | EXPECT_SYSTEM_ERROR(read_end.close(), EINTR, "cannot close file");
252 | EXPECT_EQ(2, close_count);
253 | close_count = 0;
254 | }
255 |
256 | TEST(FileTest, Size) {
257 | std::string content = "top secret, destroy before reading";
258 | write_file("test", content);
259 | File f("test", File::RDONLY);
260 | EXPECT_GE(f.size(), 0);
261 | fmt::ULongLong file_size = f.size();
262 | EXPECT_EQ(content.size(), file_size);
263 | #ifdef _WIN32
264 | fmt::MemoryWriter message;
265 | fmt::internal::format_windows_error(
266 | message, ERROR_ACCESS_DENIED, "cannot get file size");
267 | fstat_sim = ERROR;
268 | EXPECT_THROW_MSG(f.size(), fmt::WindowsError, message.str());
269 | fstat_sim = NONE;
270 | #else
271 | f.close();
272 | EXPECT_SYSTEM_ERROR(f.size(), EBADF, "cannot get file attributes");
273 | #endif
274 | }
275 |
276 | TEST(FileTest, MaxSize) {
277 | write_file("test", "");
278 | File f("test", File::RDONLY);
279 | fstat_sim = MAX_SIZE;
280 | EXPECT_GE(f.size(), 0);
281 | EXPECT_EQ(max_file_size(), f.size());
282 | fstat_sim = NONE;
283 | }
284 |
285 | TEST(FileTest, ReadRetry) {
286 | File read_end, write_end;
287 | File::pipe(read_end, write_end);
288 | enum { SIZE = 4 };
289 | write_end.write("test", SIZE);
290 | write_end.close();
291 | char buffer[SIZE];
292 | std::streamsize count = 0;
293 | EXPECT_RETRY(count = read_end.read(buffer, SIZE),
294 | read, "cannot read from file");
295 | EXPECT_EQ_POSIX(static_cast(SIZE), count);
296 | }
297 |
298 | TEST(FileTest, WriteRetry) {
299 | File read_end, write_end;
300 | File::pipe(read_end, write_end);
301 | enum { SIZE = 4 };
302 | std::streamsize count = 0;
303 | EXPECT_RETRY(count = write_end.write("test", SIZE),
304 | write, "cannot write to file");
305 | write_end.close();
306 | #ifndef _WIN32
307 | EXPECT_EQ(static_cast(SIZE), count);
308 | char buffer[SIZE + 1];
309 | read_end.read(buffer, SIZE);
310 | buffer[SIZE] = '\0';
311 | EXPECT_STREQ("test", buffer);
312 | #endif
313 | }
314 |
315 | #ifdef _WIN32
316 | TEST(FileTest, ConvertReadCount) {
317 | File read_end, write_end;
318 | File::pipe(read_end, write_end);
319 | char c;
320 | std::size_t size = UINT_MAX;
321 | if (sizeof(unsigned) != sizeof(std::size_t))
322 | ++size;
323 | read_count = 1;
324 | read_nbyte = 0;
325 | EXPECT_THROW(read_end.read(&c, size), fmt::SystemError);
326 | read_count = 0;
327 | EXPECT_EQ(UINT_MAX, read_nbyte);
328 | }
329 |
330 | TEST(FileTest, ConvertWriteCount) {
331 | File read_end, write_end;
332 | File::pipe(read_end, write_end);
333 | char c;
334 | std::size_t size = UINT_MAX;
335 | if (sizeof(unsigned) != sizeof(std::size_t))
336 | ++size;
337 | write_count = 1;
338 | write_nbyte = 0;
339 | EXPECT_THROW(write_end.write(&c, size), fmt::SystemError);
340 | write_count = 0;
341 | EXPECT_EQ(UINT_MAX, write_nbyte);
342 | }
343 | #endif
344 |
345 | TEST(FileTest, DupNoRetry) {
346 | int stdout_fd = FMT_POSIX(fileno(stdout));
347 | dup_count = 1;
348 | EXPECT_SYSTEM_ERROR(File::dup(stdout_fd), EINTR,
349 | fmt::format("cannot duplicate file descriptor {}", stdout_fd));
350 | dup_count = 0;
351 | }
352 |
353 | TEST(FileTest, Dup2Retry) {
354 | int stdout_fd = FMT_POSIX(fileno(stdout));
355 | File f1 = File::dup(stdout_fd), f2 = File::dup(stdout_fd);
356 | EXPECT_RETRY(f1.dup2(f2.descriptor()), dup2,
357 | fmt::format("cannot duplicate file descriptor {} to {}",
358 | f1.descriptor(), f2.descriptor()));
359 | }
360 |
361 | TEST(FileTest, Dup2NoExceptRetry) {
362 | int stdout_fd = FMT_POSIX(fileno(stdout));
363 | File f1 = File::dup(stdout_fd), f2 = File::dup(stdout_fd);
364 | ErrorCode ec;
365 | dup2_count = 1;
366 | f1.dup2(f2.descriptor(), ec);
367 | #ifndef _WIN32
368 | EXPECT_EQ(4, dup2_count);
369 | #else
370 | EXPECT_EQ(EINTR, ec.get());
371 | #endif
372 | dup2_count = 0;
373 | }
374 |
375 | TEST(FileTest, PipeNoRetry) {
376 | File read_end, write_end;
377 | pipe_count = 1;
378 | EXPECT_SYSTEM_ERROR(
379 | File::pipe(read_end, write_end), EINTR, "cannot create pipe");
380 | pipe_count = 0;
381 | }
382 |
383 | TEST(FileTest, FdopenNoRetry) {
384 | File read_end, write_end;
385 | File::pipe(read_end, write_end);
386 | fdopen_count = 1;
387 | EXPECT_SYSTEM_ERROR(read_end.fdopen("r"),
388 | EINTR, "cannot associate stream with file descriptor");
389 | fdopen_count = 0;
390 | }
391 |
392 | TEST(BufferedFileTest, OpenRetry) {
393 | write_file("test", "there must be something here");
394 | BufferedFile *f = 0;
395 | EXPECT_RETRY(f = new BufferedFile("test", "r"),
396 | fopen, "cannot open file test");
397 | #ifndef _WIN32
398 | char c = 0;
399 | if (fread(&c, 1, 1, f->get()) < 1)
400 | throw fmt::SystemError(errno, "fread failed");
401 | #endif
402 | delete f;
403 | }
404 |
405 | TEST(BufferedFileTest, CloseNoRetryInDtor) {
406 | File read_end, write_end;
407 | File::pipe(read_end, write_end);
408 | BufferedFile *f = new BufferedFile(read_end.fdopen("r"));
409 | int saved_fclose_count = 0;
410 | EXPECT_WRITE(stderr, {
411 | fclose_count = 1;
412 | delete f;
413 | saved_fclose_count = fclose_count;
414 | fclose_count = 0;
415 | }, format_system_error(EINTR, "cannot close file") + "\n");
416 | EXPECT_EQ(2, saved_fclose_count);
417 | }
418 |
419 | TEST(BufferedFileTest, CloseNoRetry) {
420 | File read_end, write_end;
421 | File::pipe(read_end, write_end);
422 | BufferedFile f = read_end.fdopen("r");
423 | fclose_count = 1;
424 | EXPECT_SYSTEM_ERROR(f.close(), EINTR, "cannot close file");
425 | EXPECT_EQ(2, fclose_count);
426 | fclose_count = 0;
427 | }
428 |
429 | TEST(BufferedFileTest, FilenoNoRetry) {
430 | File read_end, write_end;
431 | File::pipe(read_end, write_end);
432 | BufferedFile f = read_end.fdopen("r");
433 | fileno_count = 1;
434 | EXPECT_SYSTEM_ERROR(f.fileno(), EINTR, "cannot get file descriptor");
435 | EXPECT_EQ(2, fileno_count);
436 | fileno_count = 0;
437 | }
438 |
--------------------------------------------------------------------------------
/cppformat/doc/LICENSE.python:
--------------------------------------------------------------------------------
1 | A. HISTORY OF THE SOFTWARE
2 | ==========================
3 |
4 | Python was created in the early 1990s by Guido van Rossum at Stichting
5 | Mathematisch Centrum (CWI, see http://www.cwi.nl) in the Netherlands
6 | as a successor of a language called ABC. Guido remains Python's
7 | principal author, although it includes many contributions from others.
8 |
9 | In 1995, Guido continued his work on Python at the Corporation for
10 | National Research Initiatives (CNRI, see http://www.cnri.reston.va.us)
11 | in Reston, Virginia where he released several versions of the
12 | software.
13 |
14 | In May 2000, Guido and the Python core development team moved to
15 | BeOpen.com to form the BeOpen PythonLabs team. In October of the same
16 | year, the PythonLabs team moved to Digital Creations (now Zope
17 | Corporation, see http://www.zope.com). In 2001, the Python Software
18 | Foundation (PSF, see http://www.python.org/psf/) was formed, a
19 | non-profit organization created specifically to own Python-related
20 | Intellectual Property. Zope Corporation is a sponsoring member of
21 | the PSF.
22 |
23 | All Python releases are Open Source (see http://www.opensource.org for
24 | the Open Source Definition). Historically, most, but not all, Python
25 | releases have also been GPL-compatible; the table below summarizes
26 | the various releases.
27 |
28 | Release Derived Year Owner GPL-
29 | from compatible? (1)
30 |
31 | 0.9.0 thru 1.2 1991-1995 CWI yes
32 | 1.3 thru 1.5.2 1.2 1995-1999 CNRI yes
33 | 1.6 1.5.2 2000 CNRI no
34 | 2.0 1.6 2000 BeOpen.com no
35 | 1.6.1 1.6 2001 CNRI yes (2)
36 | 2.1 2.0+1.6.1 2001 PSF no
37 | 2.0.1 2.0+1.6.1 2001 PSF yes
38 | 2.1.1 2.1+2.0.1 2001 PSF yes
39 | 2.2 2.1.1 2001 PSF yes
40 | 2.1.2 2.1.1 2002 PSF yes
41 | 2.1.3 2.1.2 2002 PSF yes
42 | 2.2.1 2.2 2002 PSF yes
43 | 2.2.2 2.2.1 2002 PSF yes
44 | 2.2.3 2.2.2 2003 PSF yes
45 | 2.3 2.2.2 2002-2003 PSF yes
46 | 2.3.1 2.3 2002-2003 PSF yes
47 | 2.3.2 2.3.1 2002-2003 PSF yes
48 | 2.3.3 2.3.2 2002-2003 PSF yes
49 | 2.3.4 2.3.3 2004 PSF yes
50 | 2.3.5 2.3.4 2005 PSF yes
51 | 2.4 2.3 2004 PSF yes
52 | 2.4.1 2.4 2005 PSF yes
53 | 2.4.2 2.4.1 2005 PSF yes
54 | 2.4.3 2.4.2 2006 PSF yes
55 | 2.4.4 2.4.3 2006 PSF yes
56 | 2.5 2.4 2006 PSF yes
57 | 2.5.1 2.5 2007 PSF yes
58 | 2.5.2 2.5.1 2008 PSF yes
59 | 2.5.3 2.5.2 2008 PSF yes
60 | 2.6 2.5 2008 PSF yes
61 | 2.6.1 2.6 2008 PSF yes
62 | 2.6.2 2.6.1 2009 PSF yes
63 | 2.6.3 2.6.2 2009 PSF yes
64 | 2.6.4 2.6.3 2009 PSF yes
65 | 2.6.5 2.6.4 2010 PSF yes
66 | 3.0 2.6 2008 PSF yes
67 | 3.0.1 3.0 2009 PSF yes
68 | 3.1 3.0.1 2009 PSF yes
69 | 3.1.1 3.1 2009 PSF yes
70 | 3.1.2 3.1.1 2010 PSF yes
71 | 3.1.3 3.1.2 2010 PSF yes
72 | 3.1.4 3.1.3 2011 PSF yes
73 | 3.2 3.1 2011 PSF yes
74 | 3.2.1 3.2 2011 PSF yes
75 | 3.2.2 3.2.1 2011 PSF yes
76 | 3.2.3 3.2.2 2012 PSF yes
77 | 3.3.0 3.2 2012 PSF yes
78 |
79 | Footnotes:
80 |
81 | (1) GPL-compatible doesn't mean that we're distributing Python under
82 | the GPL. All Python licenses, unlike the GPL, let you distribute
83 | a modified version without making your changes open source. The
84 | GPL-compatible licenses make it possible to combine Python with
85 | other software that is released under the GPL; the others don't.
86 |
87 | (2) According to Richard Stallman, 1.6.1 is not GPL-compatible,
88 | because its license has a choice of law clause. According to
89 | CNRI, however, Stallman's lawyer has told CNRI's lawyer that 1.6.1
90 | is "not incompatible" with the GPL.
91 |
92 | Thanks to the many outside volunteers who have worked under Guido's
93 | direction to make these releases possible.
94 |
95 |
96 | B. TERMS AND CONDITIONS FOR ACCESSING OR OTHERWISE USING PYTHON
97 | ===============================================================
98 |
99 | PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
100 | --------------------------------------------
101 |
102 | 1. This LICENSE AGREEMENT is between the Python Software Foundation
103 | ("PSF"), and the Individual or Organization ("Licensee") accessing and
104 | otherwise using this software ("Python") in source or binary form and
105 | its associated documentation.
106 |
107 | 2. Subject to the terms and conditions of this License Agreement, PSF hereby
108 | grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce,
109 | analyze, test, perform and/or display publicly, prepare derivative works,
110 | distribute, and otherwise use Python alone or in any derivative version,
111 | provided, however, that PSF's License Agreement and PSF's notice of copyright,
112 | i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
113 | 2011, 2012 Python Software Foundation; All Rights Reserved" are retained in Python
114 | alone or in any derivative version prepared by Licensee.
115 |
116 | 3. In the event Licensee prepares a derivative work that is based on
117 | or incorporates Python or any part thereof, and wants to make
118 | the derivative work available to others as provided herein, then
119 | Licensee hereby agrees to include in any such work a brief summary of
120 | the changes made to Python.
121 |
122 | 4. PSF is making Python available to Licensee on an "AS IS"
123 | basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
124 | IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND
125 | DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
126 | FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT
127 | INFRINGE ANY THIRD PARTY RIGHTS.
128 |
129 | 5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
130 | FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
131 | A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON,
132 | OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
133 |
134 | 6. This License Agreement will automatically terminate upon a material
135 | breach of its terms and conditions.
136 |
137 | 7. Nothing in this License Agreement shall be deemed to create any
138 | relationship of agency, partnership, or joint venture between PSF and
139 | Licensee. This License Agreement does not grant permission to use PSF
140 | trademarks or trade name in a trademark sense to endorse or promote
141 | products or services of Licensee, or any third party.
142 |
143 | 8. By copying, installing or otherwise using Python, Licensee
144 | agrees to be bound by the terms and conditions of this License
145 | Agreement.
146 |
147 |
148 | BEOPEN.COM LICENSE AGREEMENT FOR PYTHON 2.0
149 | -------------------------------------------
150 |
151 | BEOPEN PYTHON OPEN SOURCE LICENSE AGREEMENT VERSION 1
152 |
153 | 1. This LICENSE AGREEMENT is between BeOpen.com ("BeOpen"), having an
154 | office at 160 Saratoga Avenue, Santa Clara, CA 95051, and the
155 | Individual or Organization ("Licensee") accessing and otherwise using
156 | this software in source or binary form and its associated
157 | documentation ("the Software").
158 |
159 | 2. Subject to the terms and conditions of this BeOpen Python License
160 | Agreement, BeOpen hereby grants Licensee a non-exclusive,
161 | royalty-free, world-wide license to reproduce, analyze, test, perform
162 | and/or display publicly, prepare derivative works, distribute, and
163 | otherwise use the Software alone or in any derivative version,
164 | provided, however, that the BeOpen Python License is retained in the
165 | Software, alone or in any derivative version prepared by Licensee.
166 |
167 | 3. BeOpen is making the Software available to Licensee on an "AS IS"
168 | basis. BEOPEN MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
169 | IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, BEOPEN MAKES NO AND
170 | DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
171 | FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE WILL NOT
172 | INFRINGE ANY THIRD PARTY RIGHTS.
173 |
174 | 4. BEOPEN SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF THE
175 | SOFTWARE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS
176 | AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY
177 | DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
178 |
179 | 5. This License Agreement will automatically terminate upon a material
180 | breach of its terms and conditions.
181 |
182 | 6. This License Agreement shall be governed by and interpreted in all
183 | respects by the law of the State of California, excluding conflict of
184 | law provisions. Nothing in this License Agreement shall be deemed to
185 | create any relationship of agency, partnership, or joint venture
186 | between BeOpen and Licensee. This License Agreement does not grant
187 | permission to use BeOpen trademarks or trade names in a trademark
188 | sense to endorse or promote products or services of Licensee, or any
189 | third party. As an exception, the "BeOpen Python" logos available at
190 | http://www.pythonlabs.com/logos.html may be used according to the
191 | permissions granted on that web page.
192 |
193 | 7. By copying, installing or otherwise using the software, Licensee
194 | agrees to be bound by the terms and conditions of this License
195 | Agreement.
196 |
197 |
198 | CNRI LICENSE AGREEMENT FOR PYTHON 1.6.1
199 | ---------------------------------------
200 |
201 | 1. This LICENSE AGREEMENT is between the Corporation for National
202 | Research Initiatives, having an office at 1895 Preston White Drive,
203 | Reston, VA 20191 ("CNRI"), and the Individual or Organization
204 | ("Licensee") accessing and otherwise using Python 1.6.1 software in
205 | source or binary form and its associated documentation.
206 |
207 | 2. Subject to the terms and conditions of this License Agreement, CNRI
208 | hereby grants Licensee a nonexclusive, royalty-free, world-wide
209 | license to reproduce, analyze, test, perform and/or display publicly,
210 | prepare derivative works, distribute, and otherwise use Python 1.6.1
211 | alone or in any derivative version, provided, however, that CNRI's
212 | License Agreement and CNRI's notice of copyright, i.e., "Copyright (c)
213 | 1995-2001 Corporation for National Research Initiatives; All Rights
214 | Reserved" are retained in Python 1.6.1 alone or in any derivative
215 | version prepared by Licensee. Alternately, in lieu of CNRI's License
216 | Agreement, Licensee may substitute the following text (omitting the
217 | quotes): "Python 1.6.1 is made available subject to the terms and
218 | conditions in CNRI's License Agreement. This Agreement together with
219 | Python 1.6.1 may be located on the Internet using the following
220 | unique, persistent identifier (known as a handle): 1895.22/1013. This
221 | Agreement may also be obtained from a proxy server on the Internet
222 | using the following URL: http://hdl.handle.net/1895.22/1013".
223 |
224 | 3. In the event Licensee prepares a derivative work that is based on
225 | or incorporates Python 1.6.1 or any part thereof, and wants to make
226 | the derivative work available to others as provided herein, then
227 | Licensee hereby agrees to include in any such work a brief summary of
228 | the changes made to Python 1.6.1.
229 |
230 | 4. CNRI is making Python 1.6.1 available to Licensee on an "AS IS"
231 | basis. CNRI MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
232 | IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, CNRI MAKES NO AND
233 | DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
234 | FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 1.6.1 WILL NOT
235 | INFRINGE ANY THIRD PARTY RIGHTS.
236 |
237 | 5. CNRI SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
238 | 1.6.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
239 | A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 1.6.1,
240 | OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
241 |
242 | 6. This License Agreement will automatically terminate upon a material
243 | breach of its terms and conditions.
244 |
245 | 7. This License Agreement shall be governed by the federal
246 | intellectual property law of the United States, including without
247 | limitation the federal copyright law, and, to the extent such
248 | U.S. federal law does not apply, by the law of the Commonwealth of
249 | Virginia, excluding Virginia's conflict of law provisions.
250 | Notwithstanding the foregoing, with regard to derivative works based
251 | on Python 1.6.1 that incorporate non-separable material that was
252 | previously distributed under the GNU General Public License (GPL), the
253 | law of the Commonwealth of Virginia shall govern this License
254 | Agreement only as to issues arising under or with respect to
255 | Paragraphs 4, 5, and 7 of this License Agreement. Nothing in this
256 | License Agreement shall be deemed to create any relationship of
257 | agency, partnership, or joint venture between CNRI and Licensee. This
258 | License Agreement does not grant permission to use CNRI trademarks or
259 | trade name in a trademark sense to endorse or promote products or
260 | services of Licensee, or any third party.
261 |
262 | 8. By clicking on the "ACCEPT" button where indicated, or by copying,
263 | installing or otherwise using Python 1.6.1, Licensee agrees to be
264 | bound by the terms and conditions of this License Agreement.
265 |
266 | ACCEPT
267 |
268 |
269 | CWI LICENSE AGREEMENT FOR PYTHON 0.9.0 THROUGH 1.2
270 | --------------------------------------------------
271 |
272 | Copyright (c) 1991 - 1995, Stichting Mathematisch Centrum Amsterdam,
273 | The Netherlands. All rights reserved.
274 |
275 | Permission to use, copy, modify, and distribute this software and its
276 | documentation for any purpose and without fee is hereby granted,
277 | provided that the above copyright notice appear in all copies and that
278 | both that copyright notice and this permission notice appear in
279 | supporting documentation, and that the name of Stichting Mathematisch
280 | Centrum or CWI not be used in advertising or publicity pertaining to
281 | distribution of the software without specific, written prior
282 | permission.
283 |
284 | STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
285 | THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
286 | FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
287 | FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
288 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
289 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
290 | OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
291 |
--------------------------------------------------------------------------------
/cppformat/test/printf-test.cc:
--------------------------------------------------------------------------------
1 | /*
2 | printf tests.
3 |
4 | Copyright (c) 2012-2014, Victor Zverovich
5 | All rights reserved.
6 |
7 | Redistribution and use in source and binary forms, with or without
8 | modification, are permitted provided that the following conditions are met:
9 |
10 | 1. Redistributions of source code must retain the above copyright notice, this
11 | list of conditions and the following disclaimer.
12 | 2. Redistributions in binary form must reproduce the above copyright notice,
13 | this list of conditions and the following disclaimer in the documentation
14 | and/or other materials provided with the distribution.
15 |
16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
20 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 | */
27 |
28 | #include
29 | #include
30 | #include
31 |
32 | #include "format.h"
33 | #include "gtest-extra.h"
34 | #include "util.h"
35 |
36 | using fmt::format;
37 | using fmt::FormatError;
38 |
39 | const unsigned BIG_NUM = INT_MAX + 1u;
40 |
41 | // Makes format string argument positional.
42 | std::string make_positional(fmt::StringRef format) {
43 | std::string s(format);
44 | s.replace(s.find('%'), 1, "%1$");
45 | return s;
46 | }
47 |
48 | #define EXPECT_PRINTF(expected_output, format, arg) \
49 | EXPECT_EQ(expected_output, fmt::sprintf(format, arg)) \
50 | << "format: " << format; \
51 | EXPECT_EQ(expected_output, fmt::sprintf(make_positional(format), arg))
52 |
53 | TEST(PrintfTest, NoArgs) {
54 | EXPECT_EQ("test", fmt::sprintf("test"));
55 | }
56 |
57 | TEST(PrintfTest, Escape) {
58 | EXPECT_EQ("%", fmt::sprintf("%%"));
59 | EXPECT_EQ("before %", fmt::sprintf("before %%"));
60 | EXPECT_EQ("% after", fmt::sprintf("%% after"));
61 | EXPECT_EQ("before % after", fmt::sprintf("before %% after"));
62 | EXPECT_EQ("%s", fmt::sprintf("%%s"));
63 | }
64 |
65 | TEST(PrintfTest, PositionalArgs) {
66 | EXPECT_EQ("42", fmt::sprintf("%1$d", 42));
67 | EXPECT_EQ("before 42", fmt::sprintf("before %1$d", 42));
68 | EXPECT_EQ("42 after", fmt::sprintf("%1$d after",42));
69 | EXPECT_EQ("before 42 after", fmt::sprintf("before %1$d after", 42));
70 | EXPECT_EQ("answer = 42", fmt::sprintf("%1$s = %2$d", "answer", 42));
71 | EXPECT_EQ("42 is the answer",
72 | fmt::sprintf("%2$d is the %1$s", "answer", 42));
73 | EXPECT_EQ("abracadabra", fmt::sprintf("%1$s%2$s%1$s", "abra", "cad"));
74 | }
75 |
76 | TEST(PrintfTest, AutomaticArgIndexing) {
77 | EXPECT_EQ("abc", fmt::sprintf("%c%c%c", 'a', 'b', 'c'));
78 | }
79 |
80 | TEST(PrintfTest, NumberIsTooBigInArgIndex) {
81 | EXPECT_THROW_MSG(fmt::sprintf(format("%{}$", BIG_NUM)),
82 | FormatError, "number is too big");
83 | EXPECT_THROW_MSG(fmt::sprintf(format("%{}$d", BIG_NUM)),
84 | FormatError, "number is too big");
85 | }
86 |
87 | TEST(PrintfTest, SwitchArgIndexing) {
88 | EXPECT_THROW_MSG(fmt::sprintf("%1$d%", 1, 2),
89 | FormatError, "invalid format string");
90 | EXPECT_THROW_MSG(fmt::sprintf(format("%1$d%{}d", BIG_NUM), 1, 2),
91 | FormatError, "number is too big");
92 | EXPECT_THROW_MSG(fmt::sprintf("%1$d%d", 1, 2),
93 | FormatError, "cannot switch from manual to automatic argument indexing");
94 |
95 | EXPECT_THROW_MSG(fmt::sprintf("%d%1$", 1, 2),
96 | FormatError, "invalid format string");
97 | EXPECT_THROW_MSG(fmt::sprintf(format("%d%{}$d", BIG_NUM), 1, 2),
98 | FormatError, "number is too big");
99 | EXPECT_THROW_MSG(fmt::sprintf("%d%1$d", 1, 2),
100 | FormatError, "cannot switch from automatic to manual argument indexing");
101 |
102 | // Indexing errors override width errors.
103 | EXPECT_THROW_MSG(fmt::sprintf(format("%d%1${}d", BIG_NUM), 1, 2),
104 | FormatError, "number is too big");
105 | EXPECT_THROW_MSG(fmt::sprintf(format("%1$d%{}d", BIG_NUM), 1, 2),
106 | FormatError, "number is too big");
107 | }
108 |
109 | TEST(PrintfTest, InvalidArgIndex) {
110 | EXPECT_THROW_MSG(fmt::sprintf("%0$d", 42), FormatError,
111 | "argument index out of range");
112 | EXPECT_THROW_MSG(fmt::sprintf("%2$d", 42), FormatError,
113 | "argument index out of range");
114 | EXPECT_THROW_MSG(fmt::sprintf(format("%{}$d", INT_MAX), 42),
115 | FormatError, "argument index out of range");
116 |
117 | EXPECT_THROW_MSG(fmt::sprintf("%2$", 42),
118 | FormatError, "invalid format string");
119 | EXPECT_THROW_MSG(fmt::sprintf(format("%{}$d", BIG_NUM), 42),
120 | FormatError, "number is too big");
121 | }
122 |
123 | TEST(PrintfTest, DefaultAlignRight) {
124 | EXPECT_PRINTF(" 42", "%5d", 42);
125 | EXPECT_PRINTF(" abc", "%5s", "abc");
126 | }
127 |
128 | TEST(PrintfTest, ZeroFlag) {
129 | EXPECT_PRINTF("00042", "%05d", 42);
130 | EXPECT_PRINTF("-0042", "%05d", -42);
131 |
132 | EXPECT_PRINTF("00042", "%05d", 42);
133 | EXPECT_PRINTF("-0042", "%05d", -42);
134 | EXPECT_PRINTF("-004.2", "%06g", -4.2);
135 |
136 | EXPECT_PRINTF("+00042", "%00+6d", 42);
137 |
138 | // '0' flag is ignored for non-numeric types.
139 | EXPECT_PRINTF(" x", "%05c", 'x');
140 | }
141 |
142 | TEST(PrintfTest, PlusFlag) {
143 | EXPECT_PRINTF("+42", "%+d", 42);
144 | EXPECT_PRINTF("-42", "%+d", -42);
145 | EXPECT_PRINTF("+0042", "%+05d", 42);
146 | EXPECT_PRINTF("+0042", "%0++5d", 42);
147 |
148 | // '+' flag is ignored for non-numeric types.
149 | EXPECT_PRINTF("x", "%+c", 'x');
150 | }
151 |
152 | TEST(PrintfTest, MinusFlag) {
153 | EXPECT_PRINTF("abc ", "%-5s", "abc");
154 | EXPECT_PRINTF("abc ", "%0--5s", "abc");
155 | }
156 |
157 | TEST(PrintfTest, SpaceFlag) {
158 | EXPECT_PRINTF(" 42", "% d", 42);
159 | EXPECT_PRINTF("-42", "% d", -42);
160 | EXPECT_PRINTF(" 0042", "% 05d", 42);
161 | EXPECT_PRINTF(" 0042", "%0 5d", 42);
162 |
163 | // ' ' flag is ignored for non-numeric types.
164 | EXPECT_PRINTF("x", "% c", 'x');
165 | }
166 |
167 | TEST(PrintfTest, HashFlag) {
168 | EXPECT_PRINTF("042", "%#o", 042);
169 | EXPECT_PRINTF(fmt::format("0{:o}", static_cast(-042)), "%#o", -042);
170 | EXPECT_PRINTF("0", "%#o", 0);
171 |
172 | EXPECT_PRINTF("0x42", "%#x", 0x42);
173 | EXPECT_PRINTF("0X42", "%#X", 0x42);
174 | EXPECT_PRINTF(
175 | fmt::format("0x{:x}", static_cast(-0x42)), "%#x", -0x42);
176 | EXPECT_PRINTF("0", "%#x", 0);
177 |
178 | EXPECT_PRINTF("0x0042", "%#06x", 0x42);
179 | EXPECT_PRINTF("0x0042", "%0##6x", 0x42);
180 |
181 | EXPECT_PRINTF("-42.000000", "%#f", -42.0);
182 | EXPECT_PRINTF("-42.000000", "%#F", -42.0);
183 |
184 | char buffer[BUFFER_SIZE];
185 | safe_sprintf(buffer, "%#e", -42.0);
186 | EXPECT_PRINTF(buffer, "%#e", -42.0);
187 | safe_sprintf(buffer, "%#E", -42.0);
188 | EXPECT_PRINTF(buffer, "%#E", -42.0);
189 |
190 | EXPECT_PRINTF("-42.0000", "%#g", -42.0);
191 | EXPECT_PRINTF("-42.0000", "%#G", -42.0);
192 |
193 | safe_sprintf(buffer, "%#a", 16.0);
194 | EXPECT_PRINTF(buffer, "%#a", 16.0);
195 | safe_sprintf(buffer, "%#A", 16.0);
196 | EXPECT_PRINTF(buffer, "%#A", 16.0);
197 |
198 | // '#' flag is ignored for non-numeric types.
199 | EXPECT_PRINTF("x", "%#c", 'x');
200 | }
201 |
202 | TEST(PrintfTest, Width) {
203 | EXPECT_PRINTF(" abc", "%5s", "abc");
204 |
205 | // Width cannot be specified twice.
206 | EXPECT_THROW_MSG(fmt::sprintf("%5-5d", 42), FormatError,
207 | "unknown format code '-' for integer");
208 |
209 | EXPECT_THROW_MSG(fmt::sprintf(format("%{}d", BIG_NUM), 42),
210 | FormatError, "number is too big");
211 | EXPECT_THROW_MSG(fmt::sprintf(format("%1${}d", BIG_NUM), 42),
212 | FormatError, "number is too big");
213 | }
214 |
215 | TEST(PrintfTest, DynamicWidth) {
216 | EXPECT_EQ(" 42", fmt::sprintf("%*d", 5, 42));
217 | EXPECT_EQ("42 ", fmt::sprintf("%*d", -5, 42));
218 | EXPECT_THROW_MSG(fmt::sprintf("%*d", 5.0, 42), FormatError,
219 | "width is not integer");
220 | EXPECT_THROW_MSG(fmt::sprintf("%*d"), FormatError,
221 | "argument index out of range");
222 | EXPECT_THROW_MSG(fmt::sprintf("%*d", BIG_NUM, 42), FormatError,
223 | "number is too big");
224 | }
225 |
226 | TEST(PrintfTest, IntPrecision) {
227 | EXPECT_PRINTF("00042", "%.5d", 42);
228 | EXPECT_PRINTF("-00042", "%.5d", -42);
229 | EXPECT_PRINTF("00042", "%.5x", 0x42);
230 | EXPECT_PRINTF("0x00042", "%#.5x", 0x42);
231 | EXPECT_PRINTF("00042", "%.5o", 042);
232 | EXPECT_PRINTF("00042", "%#.5o", 042);
233 |
234 | EXPECT_PRINTF(" 00042", "%7.5d", 42);
235 | EXPECT_PRINTF(" 00042", "%7.5x", 0x42);
236 | EXPECT_PRINTF(" 0x00042", "%#10.5x", 0x42);
237 | EXPECT_PRINTF(" 00042", "%7.5o", 042);
238 | EXPECT_PRINTF(" 00042", "%#10.5o", 042);
239 |
240 | EXPECT_PRINTF("00042 ", "%-7.5d", 42);
241 | EXPECT_PRINTF("00042 ", "%-7.5x", 0x42);
242 | EXPECT_PRINTF("0x00042 ", "%-#10.5x", 0x42);
243 | EXPECT_PRINTF("00042 ", "%-7.5o", 042);
244 | EXPECT_PRINTF("00042 ", "%-#10.5o", 042);
245 | }
246 |
247 | TEST(PrintfTest, FloatPrecision) {
248 | char buffer[BUFFER_SIZE];
249 | safe_sprintf(buffer, "%.3e", 1234.5678);
250 | EXPECT_PRINTF(buffer, "%.3e", 1234.5678);
251 | EXPECT_PRINTF("1234.568", "%.3f", 1234.5678);
252 | safe_sprintf(buffer, "%.3g", 1234.5678);
253 | EXPECT_PRINTF(buffer, "%.3g", 1234.5678);
254 | safe_sprintf(buffer, "%.3a", 1234.5678);
255 | EXPECT_PRINTF(buffer, "%.3a", 1234.5678);
256 | }
257 |
258 | TEST(PrintfTest, IgnorePrecisionForNonNumericArg) {
259 | EXPECT_PRINTF("abc", "%.5s", "abc");
260 | }
261 |
262 | TEST(PrintfTest, DynamicPrecision) {
263 | EXPECT_EQ("00042", fmt::sprintf("%.*d", 5, 42));
264 | EXPECT_EQ("42", fmt::sprintf("%.*d", -5, 42));
265 | EXPECT_THROW_MSG(fmt::sprintf("%.*d", 5.0, 42), FormatError,
266 | "precision is not integer");
267 | EXPECT_THROW_MSG(fmt::sprintf("%.*d"), FormatError,
268 | "argument index out of range");
269 | EXPECT_THROW_MSG(fmt::sprintf("%.*d", BIG_NUM, 42), FormatError,
270 | "number is too big");
271 | if (sizeof(fmt::LongLong) != sizeof(int)) {
272 | fmt::LongLong prec = static_cast(INT_MIN) - 1;
273 | EXPECT_THROW_MSG(fmt::sprintf("%.*d", prec, 42), FormatError,
274 | "number is too big");
275 | }
276 | }
277 |
278 | template
279 | struct MakeSigned { typedef T Type; };
280 |
281 | #define SPECIALIZE_MAKE_SIGNED(T, S) \
282 | template <> \
283 | struct MakeSigned { typedef S Type; }
284 |
285 | SPECIALIZE_MAKE_SIGNED(char, signed char);
286 | SPECIALIZE_MAKE_SIGNED(unsigned char, signed char);
287 | SPECIALIZE_MAKE_SIGNED(unsigned short, short);
288 | SPECIALIZE_MAKE_SIGNED(unsigned, int);
289 | SPECIALIZE_MAKE_SIGNED(unsigned long, long);
290 | SPECIALIZE_MAKE_SIGNED(fmt::ULongLong, fmt::LongLong);
291 |
292 | template
293 | void TestLength(const char *length_spec, U value) {
294 | fmt::LongLong signed_value = value;
295 | fmt::ULongLong unsigned_value = value;
296 | // Apply integer promotion to the argument.
297 | fmt::ULongLong max = std::numeric_limits::max();
298 | if (max <= static_cast(std::numeric_limits::max())) {
299 | signed_value = static_cast(value);
300 | unsigned_value = static_cast(value);
301 | } else if (max <= std::numeric_limits::max()) {
302 | signed_value = static_cast(value);
303 | unsigned_value = static_cast(value);
304 | }
305 | using fmt::internal::MakeUnsigned;
306 | if (sizeof(U) <= sizeof(int) && sizeof(int) < sizeof(T)) {
307 | signed_value = unsigned_value =
308 | static_cast::Type>(value);
309 | } else {
310 | signed_value = static_cast::Type>(value);
311 | unsigned_value = static_cast::Type>(value);
312 | }
313 | std::ostringstream os;
314 | os << signed_value;
315 | EXPECT_PRINTF(os.str(), fmt::format("%{}d", length_spec), value);
316 | EXPECT_PRINTF(os.str(), fmt::format("%{}i", length_spec), value);
317 | os.str("");
318 | os << unsigned_value;
319 | EXPECT_PRINTF(os.str(), fmt::format("%{}u", length_spec), value);
320 | os.str("");
321 | os << std::oct << unsigned_value;
322 | EXPECT_PRINTF(os.str(), fmt::format("%{}o", length_spec), value);
323 | os.str("");
324 | os << std::hex << unsigned_value;
325 | EXPECT_PRINTF(os.str(), fmt::format("%{}x", length_spec), value);
326 | os.str("");
327 | os << std::hex << std::uppercase << unsigned_value;
328 | EXPECT_PRINTF(os.str(), fmt::format("%{}X", length_spec), value);
329 | }
330 |
331 | template
332 | void TestLength(const char *length_spec) {
333 | T min = std::numeric_limits::min(), max = std::numeric_limits::max();
334 | TestLength(length_spec, 42);
335 | TestLength(length_spec, -42);
336 | TestLength(length_spec, min);
337 | TestLength(length_spec, max);
338 | if (min >= 0 || static_cast(min) >
339 | std::numeric_limits::min()) {
340 | TestLength(length_spec, fmt::LongLong(min) - 1);
341 | }
342 | fmt::ULongLong long_long_max = std::numeric_limits::max();
343 | if (max < 0 || static_cast(max) < long_long_max)
344 | TestLength(length_spec, fmt::LongLong(max) + 1);
345 | TestLength(length_spec, std::numeric_limits::min());
346 | TestLength(length_spec, std::numeric_limits::max());
347 | TestLength(length_spec, std::numeric_limits::min());
348 | TestLength(length_spec, std::numeric_limits::max());
349 | TestLength(length_spec, std::numeric_limits::min());
350 | TestLength(length_spec, std::numeric_limits::max());
351 | TestLength(length_spec, std::numeric_limits::min());
352 | TestLength(length_spec, std::numeric_limits::max());
353 | TestLength(length_spec, std::numeric_limits::min());
354 | TestLength(length_spec, std::numeric_limits::max());
355 | }
356 |
357 | TEST(PrintfTest, Length) {
358 | TestLength("hh");
359 | TestLength("hh");
360 | TestLength("hh");
361 | TestLength("h");
362 | TestLength("h");
363 | TestLength("l");
364 | TestLength("l");
365 | TestLength("ll");
366 | TestLength("ll");
367 | TestLength("j");
368 | TestLength("z");
369 | TestLength("t");
370 | long double max = std::numeric_limits::max();
371 | EXPECT_PRINTF(fmt::format("{}", max), "%g", max);
372 | EXPECT_PRINTF(fmt::format("{}", max), "%Lg", max);
373 | }
374 |
375 | TEST(PrintfTest, Int) {
376 | EXPECT_PRINTF("-42", "%d", -42);
377 | EXPECT_PRINTF("-42", "%i", -42);
378 | unsigned u = -42;
379 | EXPECT_PRINTF(fmt::format("{}", u), "%u", -42);
380 | EXPECT_PRINTF(fmt::format("{:o}", u), "%o", -42);
381 | EXPECT_PRINTF(fmt::format("{:x}", u), "%x", -42);
382 | EXPECT_PRINTF(fmt::format("{:X}", u), "%X", -42);
383 | }
384 |
385 | TEST(PrintfTest, Float) {
386 | EXPECT_PRINTF("392.650000", "%f", 392.65);
387 | EXPECT_PRINTF("392.650000", "%F", 392.65);
388 | char buffer[BUFFER_SIZE];
389 | safe_sprintf(buffer, "%e", 392.65);
390 | EXPECT_PRINTF(buffer, "%e", 392.65);
391 | safe_sprintf(buffer, "%E", 392.65);
392 | EXPECT_PRINTF(buffer, "%E", 392.65);
393 | EXPECT_PRINTF("392.65", "%g", 392.65);
394 | EXPECT_PRINTF("392.65", "%G", 392.65);
395 | safe_sprintf(buffer, "%a", -392.65);
396 | EXPECT_EQ(buffer, format("{:a}", -392.65));
397 | safe_sprintf(buffer, "%A", -392.65);
398 | EXPECT_EQ(buffer, format("{:A}", -392.65));
399 | }
400 |
401 | TEST(PrintfTest, Inf) {
402 | double inf = std::numeric_limits::infinity();
403 | for (const char* type = "fega"; *type; ++type) {
404 | EXPECT_PRINTF("inf", fmt::format("%{}", *type), inf);
405 | char upper = std::toupper(*type);
406 | EXPECT_PRINTF("INF", fmt::format("%{}", upper), inf);
407 | }
408 | }
409 |
410 | TEST(PrintfTest, Char) {
411 | EXPECT_PRINTF("x", "%c", 'x');
412 | int max = std::numeric_limits::max();
413 | EXPECT_PRINTF(fmt::format("{}", static_cast(max)), "%c", max);
414 | //EXPECT_PRINTF("x", "%lc", L'x');
415 | // TODO: test wchar_t
416 | }
417 |
418 | TEST(PrintfTest, String) {
419 | EXPECT_PRINTF("abc", "%s", "abc");
420 | // TODO: wide string
421 | }
422 |
423 | TEST(PrintfTest, Pointer) {
424 | int n;
425 | void *p = &n;
426 | EXPECT_PRINTF(fmt::format("{}", p), "%p", p);
427 | }
428 |
429 | TEST(PrintfTest, Location) {
430 | // TODO: test %n
431 | }
432 |
433 | #if FMT_USE_FILE_DESCRIPTORS
434 | TEST(PrintfTest, Examples) {
435 | const char *weekday = "Thursday";
436 | const char *month = "August";
437 | int day = 21;
438 | EXPECT_WRITE(stdout, fmt::printf("%1$s, %3$d %2$s", weekday, month, day),
439 | "Thursday, 21 August");
440 | }
441 |
442 | TEST(PrintfTest, PrintfError) {
443 | fmt::File read_end, write_end;
444 | fmt::File::pipe(read_end, write_end);
445 | int result = fmt::fprintf(read_end.fdopen("r").get(), "test");
446 | EXPECT_LT(result, 0);
447 | }
448 | #endif
449 |
--------------------------------------------------------------------------------
/cppformat/README.rst:
--------------------------------------------------------------------------------
1 | C++ Format
2 | ==========
3 |
4 | .. image:: https://travis-ci.org/cppformat/cppformat.png?branch=master
5 | :target: https://travis-ci.org/cppformat/cppformat
6 |
7 | .. image:: https://ci.appveyor.com/api/projects/status/qk0bhyhqp1ekpat8
8 | :target: https://ci.appveyor.com/project/vitaut/cppformat
9 |
10 | .. image:: https://readthedocs.org/projects/cppformat/badge/?version=stable
11 | :target: http://cppformat.readthedocs.org/en/stable/
12 | :alt: Documentation Status
13 |
14 | .. image:: https://webapi.biicode.com/v1/badges/vitaut/vitaut/cppformat/master
15 | :target: https://www.biicode.com/vitaut/cppformat
16 |
17 | C++ Format is an open-source formatting library for C++.
18 | It can be used as a safe alternative to printf or as a fast
19 | alternative to IOStreams.
20 |
21 | Features
22 | --------
23 |
24 | * Two APIs: faster concatenation-based write API and slower (but still
25 | very fast) replacement-based format API with positional arguments for
26 | localization.
27 | * Write API similar to the one used by IOStreams but much faster and more
28 | consistent.
29 | * Format API with `format string syntax
30 | `_
31 | similar to the one used by `str.format
32 | `_ in Python.
33 | * Support for user-defined types.
34 | * High speed: performance of the format API is close to that of
35 | glibc's `printf `_
36 | and better than performance of IOStreams. See `Speed tests`_ and
37 | `Fast integer to string conversion in C++
38 | `_.
39 | * Small code size both in terms of source code (format consists of a single
40 | header file and a single source file) and compiled code.
41 | See `Compile time and code bloat`_.
42 | * Reliability: the library has an extensive set of `unit tests
43 | `_.
44 | * Safety: the library is fully type safe, errors in format strings are
45 | reported using exceptions, automatic memory management prevents buffer
46 | overflow errors.
47 | * Ease of use: small self-contained code base, no external dependencies,
48 | permissive BSD `license`_.
49 | * `Portability `_ with consistent output
50 | across platforms and support for older compilers.
51 | * Clean warning-free codebase even on high warning levels
52 | (-Wall -Wextra -pedantic).
53 | * Support for wide strings.
54 |
55 | See the `documentation `_ for more details.
56 |
57 | Examples
58 | --------
59 |
60 | This prints ``Hello, world!`` to stdout:
61 |
62 | .. code:: c++
63 |
64 | fmt::print("Hello, {}!", "world"); // uses Python-like format string syntax
65 | fmt::printf("Hello, %s!", "world"); // uses printf format string syntax
66 |
67 | Arguments can be accessed by position and arguments' indices can be repeated:
68 |
69 | .. code:: c++
70 |
71 | std::string s = fmt::format("{0}{1}{0}", "abra", "cad");
72 | // s == "abracadabra"
73 |
74 | C++ Format can be used as a safe portable replacement for ``itoa``:
75 |
76 | .. code:: c++
77 |
78 | fmt::MemoryWriter w;
79 | w << 42; // replaces itoa(42, buffer, 10)
80 | w << fmt::hex(42); // replaces itoa(42, buffer, 16)
81 | // access the string using w.str() or w.c_str()
82 |
83 | An object of any user-defined type for which there is an overloaded
84 | :code:`std::ostream` insertion operator (``operator<<``) can be formatted:
85 |
86 | .. code:: c++
87 |
88 | class Date {
89 | int year_, month_, day_;
90 | public:
91 | Date(int year, int month, int day) : year_(year), month_(month), day_(day) {}
92 |
93 | friend std::ostream &operator<<(std::ostream &os, const Date &d) {
94 | return os << d.year_ << '-' << d.month_ << '-' << d.day_;
95 | }
96 | };
97 |
98 | std::string s = fmt::format("The date is {}", Date(2012, 12, 9));
99 | // s == "The date is 2012-12-9"
100 |
101 | You can use the `FMT_VARIADIC
102 | `_
103 | macro to create your own functions similar to `format
104 | `_ and
105 | `print `_
106 | which take arbitrary arguments:
107 |
108 | .. code:: c++
109 |
110 | // Prints formatted error message.
111 | void report_error(const char *format, fmt::ArgList args) {
112 | fmt::print("Error: ");
113 | fmt::print(format, args);
114 | }
115 | FMT_VARIADIC(void, report_error, const char *)
116 |
117 | report_error("file not found: {}", path);
118 |
119 | Note that you only need to define one function that takes ``fmt::ArgList``
120 | argument. ``FMT_VARIADIC`` automatically defines necessary wrappers that
121 | accept variable number of arguments.
122 |
123 | Projects using this library
124 | ---------------------------
125 |
126 | * `0 A.D. `_: A free, open-source, cross-platform real-time strategy game
127 |
128 | * `AMPL/MP `_:
129 | An open-source library for mathematical programming
130 |
131 | * `HarpyWar/pvpgn `_:
132 | Player vs Player Gaming Network with tweaks
133 |
134 | * `KBEngine `_: An open-source MMOG server engine
135 |
136 | * `Lifeline `_: A 2D game
137 |
138 | * `PenUltima Online (POL) `_:
139 | An MMO server, compatible with most Ultima Online clients
140 |
141 | * `readpe `_: Read Portable Executable
142 |
143 | * `Saddy `_:
144 | Small crossplatform 2D graphic engine
145 |
146 | * `Salesforce Analytics Cloud `_:
147 | Business intelligence software
148 |
149 | * `spdlog `_: Super fast C++ logging library
150 |
151 | `More... `_
152 |
153 | If you are aware of other projects using this library, please let me know
154 | by `email `_ or by submitting an
155 | `issue `_.
156 |
157 | Motivation
158 | ----------
159 |
160 | So why yet another formatting library?
161 |
162 | There are plenty of methods for doing this task, from standard ones like
163 | the printf family of function and IOStreams to Boost Format library and
164 | FastFormat. The reason for creating a new library is that every existing
165 | solution that I found either had serious issues or didn't provide
166 | all the features I needed.
167 |
168 | Printf
169 | ~~~~~~
170 |
171 | The good thing about printf is that it is very fast and readily available
172 | being a part of the C standard library. The main drawback is that it
173 | doesn't support user-defined types. Printf also has safety issues although
174 | they are mostly solved with `_attribute__ ((format (printf, ...))
175 | `_ in GCC.
176 | There is a POSIX extension that adds positional arguments required for
177 | `i18n `_
178 | to printf but it is not a part of C99 and may not be available on some
179 | platforms.
180 |
181 | IOStreams
182 | ~~~~~~~~~
183 |
184 | The main issue with IOStreams is best illustrated with an example:
185 |
186 | .. code:: c++
187 |
188 | std::cout << std::setprecision(2) << std::fixed << 1.23456 << "\n";
189 |
190 | which is a lot of typing compared to printf:
191 |
192 | .. code:: c++
193 |
194 | printf("%.2f\n", 1.23456);
195 |
196 | Matthew Wilson, the author of FastFormat, referred to this situation with
197 | IOStreams as "chevron hell". IOStreams doesn't support positional arguments
198 | by design.
199 |
200 | The good part is that IOStreams supports user-defined types and is safe
201 | although error reporting is awkward.
202 |
203 | Boost Format library
204 | ~~~~~~~~~~~~~~~~~~~~
205 |
206 | This is a very powerful library which supports both printf-like format
207 | strings and positional arguments. The main its drawback is performance.
208 | According to various benchmarks it is much slower than other methods
209 | considered here. Boost Format also has excessive build times and severe
210 | code bloat issues (see `Benchmarks`_).
211 |
212 | FastFormat
213 | ~~~~~~~~~~
214 |
215 | This is an interesting library which is fast, safe and has positional
216 | arguments. However it has significant limitations, citing its author:
217 |
218 | Three features that have no hope of being accommodated within the
219 | current design are:
220 |
221 | * Leading zeros (or any other non-space padding)
222 | * Octal/hexadecimal encoding
223 | * Runtime width/alignment specification
224 |
225 | It is also quite big and has a heavy dependency, STLSoft, which might be
226 | too restrictive for using it in some projects.
227 |
228 | Loki SafeFormat
229 | ~~~~~~~~~~~~~~~
230 |
231 | SafeFormat is a formatting library which uses printf-like format strings
232 | and is type safe. It doesn't support user-defined types or positional
233 | arguments. It makes unconventional use of ``operator()`` for passing
234 | format arguments.
235 |
236 | Tinyformat
237 | ~~~~~~~~~~
238 |
239 | This library supports printf-like format strings and is very small and
240 | fast. Unfortunately it doesn't support positional arguments and wrapping
241 | it in C++98 is somewhat difficult. However if you only need a type-safe
242 | printf replacement with support for user-defined types, I highly recommend
243 | this library.
244 |
245 | Boost Spirit.Karma
246 | ~~~~~~~~~~~~~~~~~~
247 |
248 | This is not really a formatting library but I decided to include it here
249 | for completeness. As IOStreams it suffers from the problem of mixing
250 | verbatim text with arguments. The library is pretty fast, but slower
251 | on integer formatting than ``fmt::Writer`` on Karma's own benchmark,
252 | see `Fast integer to string conversion in C++
253 | `_.
254 |
255 | Benchmarks
256 | ----------
257 |
258 | Speed tests
259 | ~~~~~~~~~~~
260 |
261 | The following speed tests results were generated by building
262 | ``tinyformat_test.cpp`` on Ubuntu GNU/Linux 14.04.1 with
263 | ``g++-4.8.2 -O3 -DSPEED_TEST -DHAVE_FORMAT``, and taking the best of three
264 | runs. In the test, the format string ``"%0.10f:%04d:%+g:%s:%p:%c:%%\n"`` or
265 | equivalent is filled 2000000 times with output sent to ``/dev/null``; for
266 | further details see the `source
267 | `_.
268 |
269 | ============== ========
270 | test name run time
271 | ============== ========
272 | libc printf 1.30s
273 | std::ostream 1.85s
274 | cppformat 1.42s
275 | tinyformat 2.25s
276 | boost::format 9.94s
277 | ============== ========
278 |
279 | As you can see boost::format is much slower than the alternative methods; this
280 | is confirmed by `other tests `_.
281 | Tinyformat is quite good coming close to IOStreams. Unfortunately tinyformat
282 | cannot be faster than the IOStreams because it uses them internally.
283 | Performance of cppformat is close to that of printf, being `faster than printf on integer
284 | formatting `_,
285 | but slower on floating-point formatting which dominates this benchmark.
286 |
287 | Compile time and code bloat
288 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~
289 |
290 | The script `bloat-test.py
291 | `_
292 | from `format-benchmark `_
293 | tests compile time and code bloat for nontrivial projects.
294 | It generates 100 translation units and uses ``printf()`` or its alternative
295 | five times in each to simulate a medium sized project. The resulting
296 | executable size and compile time (g++-4.8.1, Ubuntu GNU/Linux 13.10,
297 | best of three) is shown in the following tables.
298 |
299 | **Optimized build (-O3)**
300 |
301 | ============ =============== ==================== ==================
302 | Method Compile Time, s Executable size, KiB Stripped size, KiB
303 | ============ =============== ==================== ==================
304 | printf 2.6 41 30
305 | IOStreams 19.4 92 70
306 | C++ Format 46.8 46 34
307 | tinyformat 64.6 418 386
308 | Boost Format 222.8 990 923
309 | ============ =============== ==================== ==================
310 |
311 | As you can see, C++ Format has 80% less overhead in terms of resulting
312 | code size compared to IOStreams and comes pretty close to ``printf``.
313 | Boost Format has by far the largest overheads.
314 |
315 | **Non-optimized build**
316 |
317 | ============ =============== ==================== ==================
318 | Method Compile Time, s Executable size, KiB Stripped size, KiB
319 | ============ =============== ==================== ==================
320 | printf 2.1 41 30
321 | IOStreams 19.7 86 62
322 | C++ Format 47.9 108 86
323 | tinyformat 27.7 234 190
324 | Boost Format 122.6 884 763
325 | ============ =============== ==================== ==================
326 |
327 | ``libc``, ``libstdc++`` and ``libformat`` are all linked as shared
328 | libraries to compare formatting function overhead only. Boost Format
329 | and tinyformat are header-only libraries so they don't provide any
330 | linkage options.
331 |
332 | Running the tests
333 | ~~~~~~~~~~~~~~~~~
334 |
335 | Please refer to `Building the library`__ for the instructions on how to build
336 | the library and run the unit tests.
337 |
338 | __ http://cppformat.readthedocs.org/en/latest/usage.html#building-the-library
339 |
340 | Benchmarks reside in a separate repository,
341 | `format-benchmarks `_,
342 | so to run the benchmarks you first need to clone this repository and
343 | generate Makefiles with CMake::
344 |
345 | $ git clone --recursive https://github.com/cppformat/format-benchmark.git
346 | $ cd format-benchmark
347 | $ cmake .
348 |
349 | Then you can run the speed test::
350 |
351 | $ make speed-test
352 |
353 | or the bloat test::
354 |
355 | $ make bloat-test
356 |
357 | License
358 | -------
359 |
360 | Copyright (c) 2012, Victor Zverovich
361 |
362 | All rights reserved.
363 |
364 | Redistribution and use in source and binary forms, with or without
365 | modification, are permitted provided that the following conditions are met:
366 |
367 | 1. Redistributions of source code must retain the above copyright notice, this
368 | list of conditions and the following disclaimer.
369 | 2. Redistributions in binary form must reproduce the above copyright notice,
370 | this list of conditions and the following disclaimer in the documentation
371 | and/or other materials provided with the distribution.
372 |
373 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
374 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
375 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
376 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
377 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
378 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
379 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
380 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
381 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
382 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
383 |
384 | Documentation License
385 | ---------------------
386 |
387 | The `Format String Syntax
388 | `_
389 | section in the documentation is based on the one from Python `string module
390 | documentation `_
391 | adapted for the current library. For this reason the documentation is
392 | distributed under the Python Software Foundation license available in
393 | `doc/LICENSE.python
394 | `_.
395 |
396 | Acknowledgments
397 | ---------------
398 |
399 | The benchmark section of this readme file and the performance tests are taken
400 | from the excellent `tinyformat `_ library
401 | written by Chris Foster. Boost Format library is acknowledged transitively
402 | since it had some influence on tinyformat.
403 | Some ideas used in the implementation are borrowed from `Loki
404 | `_ SafeFormat and `Diagnostic API
405 | `_ in
406 | `Clang `_.
407 | Format string syntax and the documentation are based on Python's `str.format
408 | `_.
409 | Thanks `Doug Turnbull `_ for his valuable
410 | comments and contribution to the design of the type-safe API and
411 | `Gregory Czajkowski `_ for implementing binary
412 | formatting. Thanks `Ruslan Baratov `_ for comprehensive
413 | `comparison of integer formatting algorithms `_
414 | and useful comments regarding performance, `Boris Kaul `_ for
415 | `C++ counting digits benchmark `_.
416 |
--------------------------------------------------------------------------------
/cppformat/doc/syntax.rst:
--------------------------------------------------------------------------------
1 | .. _syntax:
2 |
3 | ********************
4 | Format String Syntax
5 | ********************
6 |
7 | Formatting functions such as :ref:`fmt::format() ` and :ref:`fmt::print() `
8 | use the same format string syntax described in this section.
9 |
10 | Format strings contain "replacement fields" surrounded by curly braces ``{}``.
11 | Anything that is not contained in braces is considered literal text, which is
12 | copied unchanged to the output. If you need to include a brace character in the
13 | literal text, it can be escaped by doubling: ``{{`` and ``}}``.
14 |
15 | The grammar for a replacement field is as follows:
16 |
17 | .. productionlist:: sf
18 | replacement_field: "{" [`arg_index`] [":" `format_spec`] "}"
19 | arg_index: `integer`
20 |
21 | In less formal terms, the replacement field can start with an *arg_index*
22 | that specifies the argument whose value is to be formatted and inserted into
23 | the output instead of the replacement field.
24 | The *arg_index* is optionally followed by a *format_spec*, which is preceded
25 | by a colon ``':'``. These specify a non-default format for the replacement value.
26 |
27 | See also the :ref:`formatspec` section.
28 |
29 | If the numerical arg_indexes in a format string are 0, 1, 2, ... in sequence,
30 | they can all be omitted (not just some) and the numbers 0, 1, 2, ... will be
31 | automatically inserted in that order.
32 |
33 | Some simple format string examples::
34 |
35 | "First, thou shalt count to {0}" // References the first argument
36 | "Bring me a {}" // Implicitly references the first argument
37 | "From {} to {}" // Same as "From {0} to {1}"
38 |
39 | The *format_spec* field contains a specification of how the value should be
40 | presented, including such details as field width, alignment, padding, decimal
41 | precision and so on. Each value type can define its own "formatting
42 | mini-language" or interpretation of the *format_spec*.
43 |
44 | Most built-in types support a common formatting mini-language, which is
45 | described in the next section.
46 |
47 | A *format_spec* field can also include nested replacement fields within it.
48 | These nested replacement fields can contain only an argument index;
49 | format specifications are not allowed. Formatting is performed as if the
50 | replacement fields within the format_spec are substituted before the
51 | *format_spec* string is interpreted. This allows the formatting of a value
52 | to be dynamically specified.
53 |
54 | See the :ref:`formatexamples` section for some examples.
55 |
56 | .. _formatspec:
57 |
58 | Format Specification Mini-Language
59 | ==================================
60 |
61 | "Format specifications" are used within replacement fields contained within a
62 | format string to define how individual values are presented (see
63 | :ref:`formatstrings`). Each formattable type may define how the format
64 | specification is to be interpreted.
65 |
66 | Most built-in types implement the following options for format specifications,
67 | although some of the formatting options are only supported by the numeric types.
68 |
69 | The general form of a *standard format specifier* is:
70 |
71 | .. productionlist:: sf
72 | format_spec: [[`fill`]`align`][`sign`]["#"]["0"][`width`]["." `precision`][`type`]
73 | fill:
74 | align: "<" | ">" | "=" | "^"
75 | sign: "+" | "-" | " "
76 | width: `integer`
77 | precision: `integer` | "{" `arg_index` "}"
78 | type: `int_type` | "c" | "e" | "E" | "f" | "F" | "g" | "G" | "p" | "s"
79 | int_type: "b" | "B" | "d" | "o" | "x" | "X"
80 |
81 | The *fill* character can be any character other than '{' or '}'. The presence
82 | of a fill character is signaled by the character following it, which must be
83 | one of the alignment options. If the second character of *format_spec* is not
84 | a valid alignment option, then it is assumed that both the fill character and
85 | the alignment option are absent.
86 |
87 | The meaning of the various alignment options is as follows:
88 |
89 | +---------+----------------------------------------------------------+
90 | | Option | Meaning |
91 | +=========+==========================================================+
92 | | ``'<'`` | Forces the field to be left-aligned within the available |
93 | | | space (this is the default for most objects). |
94 | +---------+----------------------------------------------------------+
95 | | ``'>'`` | Forces the field to be right-aligned within the |
96 | | | available space (this is the default for numbers). |
97 | +---------+----------------------------------------------------------+
98 | | ``'='`` | Forces the padding to be placed after the sign (if any) |
99 | | | but before the digits. This is used for printing fields |
100 | | | in the form '+000000120'. This alignment option is only |
101 | | | valid for numeric types. |
102 | +---------+----------------------------------------------------------+
103 | | ``'^'`` | Forces the field to be centered within the available |
104 | | | space. |
105 | +---------+----------------------------------------------------------+
106 |
107 | Note that unless a minimum field width is defined, the field width will always
108 | be the same size as the data to fill it, so that the alignment option has no
109 | meaning in this case.
110 |
111 | The *sign* option is only valid for number types, and can be one of the
112 | following:
113 |
114 | +---------+----------------------------------------------------------+
115 | | Option | Meaning |
116 | +=========+==========================================================+
117 | | ``'+'`` | indicates that a sign should be used for both |
118 | | | positive as well as negative numbers. |
119 | +---------+----------------------------------------------------------+
120 | | ``'-'`` | indicates that a sign should be used only for negative |
121 | | | numbers (this is the default behavior). |
122 | +---------+----------------------------------------------------------+
123 | | space | indicates that a leading space should be used on |
124 | | | positive numbers, and a minus sign on negative numbers. |
125 | +---------+----------------------------------------------------------+
126 |
127 | The ``'#'`` option causes the "alternate form" to be used for the
128 | conversion. The alternate form is defined differently for different
129 | types. This option is only valid for integer and floating-point types.
130 | For integers, when binary, octal, or hexadecimal output is used, this
131 | option adds the prefix respective ``"0b"`` (``"0B"``), ``"0"``, or
132 | ``"0x"`` (``"0X"``) to the output value. Whether the prefix is
133 | lower-case or upper-case is determined by the case of the type
134 | specifier, for example, the prefix ``"0x"`` is used for the type ``'x'``
135 | and ``"0X"`` is used for ``'X'``. For floating-point numbers the
136 | alternate form causes the result of the conversion to always contain a
137 | decimal-point character, even if no digits follow it. Normally, a
138 | decimal-point character appears in the result of these conversions
139 | only if a digit follows it. In addition, for ``'g'`` and ``'G'``
140 | conversions, trailing zeros are not removed from the result.
141 |
142 | .. ifconfig:: False
143 |
144 | The ``','`` option signals the use of a comma for a thousands separator.
145 | For a locale aware separator, use the ``'n'`` integer presentation type
146 | instead.
147 |
148 | *width* is a decimal integer defining the minimum field width. If not
149 | specified, then the field width will be determined by the content.
150 |
151 | Preceding the *width* field by a zero (``'0'``) character enables
152 | sign-aware zero-padding for numeric types. This is equivalent to a *fill*
153 | character of ``'0'`` with an *alignment* type of ``'='``.
154 |
155 | The *precision* is a decimal number indicating how many digits should be
156 | displayed after the decimal point for a floating-point value formatted with
157 | ``'f'`` and ``'F'``, or before and after the decimal point for a floating-point
158 | value formatted with ``'g'`` or ``'G'``. For non-number types the field
159 | indicates the maximum field size - in other words, how many characters will be
160 | used from the field content. The *precision* is not allowed for integer values
161 | or pointers.
162 |
163 | Finally, the *type* determines how the data should be presented.
164 |
165 | The available string presentation types are:
166 |
167 | +---------+----------------------------------------------------------+
168 | | Type | Meaning |
169 | +=========+==========================================================+
170 | | ``'s'`` | String format. This is the default type for strings and |
171 | | | may be omitted. |
172 | +---------+----------------------------------------------------------+
173 | | none | The same as ``'s'``. |
174 | +---------+----------------------------------------------------------+
175 |
176 | The available character presentation types are:
177 |
178 | +---------+----------------------------------------------------------+
179 | | Type | Meaning |
180 | +=========+==========================================================+
181 | | ``'c'`` | Character format. This is the default type for |
182 | | | characters and may be omitted. |
183 | +---------+----------------------------------------------------------+
184 | | none | The same as ``'c'``. |
185 | +---------+----------------------------------------------------------+
186 |
187 | The available integer presentation types are:
188 |
189 | +---------+----------------------------------------------------------+
190 | | Type | Meaning |
191 | +=========+==========================================================+
192 | | ``'b'`` | Binary format. Outputs the number in base 2. Using the |
193 | | | ``'#'`` option with this type adds the prefix ``"0b"`` |
194 | | | to the output value. |
195 | +---------+----------------------------------------------------------+
196 | | ``'B'`` | Binary format. Outputs the number in base 2. Using the |
197 | | | ``'#'`` option with this type adds the prefix ``"0B"`` |
198 | | | to the output value. |
199 | +---------+----------------------------------------------------------+
200 | | ``'d'`` | Decimal integer. Outputs the number in base 10. |
201 | +---------+----------------------------------------------------------+
202 | | ``'o'`` | Octal format. Outputs the number in base 8. |
203 | +---------+----------------------------------------------------------+
204 | | ``'x'`` | Hex format. Outputs the number in base 16, using |
205 | | | lower-case letters for the digits above 9. Using the |
206 | | | ``'#'`` option with this type adds the prefix ``"0x"`` |
207 | | | to the output value. |
208 | +---------+----------------------------------------------------------+
209 | | ``'X'`` | Hex format. Outputs the number in base 16, using |
210 | | | upper-case letters for the digits above 9. Using the |
211 | | | ``'#'`` option with this type adds the prefix ``"0X"`` |
212 | | | to the output value. |
213 | +---------+----------------------------------------------------------+
214 | | none | The same as ``'d'``. |
215 | +---------+----------------------------------------------------------+
216 |
217 | The available presentation types for floating-point values are:
218 |
219 | +---------+----------------------------------------------------------+
220 | | Type | Meaning |
221 | +=========+==========================================================+
222 | | ``'a'`` | Hexadecimal floating point format. Prints the number in |
223 | | | base 16 with prefix ``"0x"`` and lower-case letters for |
224 | | | digits above 9. Uses 'p' to indicate the exponent. |
225 | +---------+----------------------------------------------------------+
226 | | ``'A'`` | Same as ``'a'`` except it uses upper-case letters for |
227 | | | the prefix, digits above 9 and to indicate the exponent. |
228 | +---------+----------------------------------------------------------+
229 | | ``'e'`` | Exponent notation. Prints the number in scientific |
230 | | | notation using the letter 'e' to indicate the exponent. |
231 | +---------+----------------------------------------------------------+
232 | | ``'E'`` | Exponent notation. Same as ``'e'`` except it uses an |
233 | | | upper-case 'E' as the separator character. |
234 | +---------+----------------------------------------------------------+
235 | | ``'f'`` | Fixed point. Displays the number as a fixed-point |
236 | | | number. |
237 | +---------+----------------------------------------------------------+
238 | | ``'F'`` | Fixed point. Same as ``'f'``, but converts ``nan`` to |
239 | | | ``NAN`` and ``inf`` to ``INF``. |
240 | +---------+----------------------------------------------------------+
241 | | ``'g'`` | General format. For a given precision ``p >= 1``, |
242 | | | this rounds the number to ``p`` significant digits and |
243 | | | then formats the result in either fixed-point format |
244 | | | or in scientific notation, depending on its magnitude. |
245 | | | |
246 | | | A precision of ``0`` is treated as equivalent to a |
247 | | | precision of ``1``. |
248 | +---------+----------------------------------------------------------+
249 | | ``'G'`` | General format. Same as ``'g'`` except switches to |
250 | | | ``'E'`` if the number gets too large. The |
251 | | | representations of infinity and NaN are uppercased, too. |
252 | +---------+----------------------------------------------------------+
253 | | none | The same as ``'g'``. |
254 | +---------+----------------------------------------------------------+
255 |
256 | .. ifconfig:: False
257 |
258 | +---------+----------------------------------------------------------+
259 | | | The precise rules are as follows: suppose that the |
260 | | | result formatted with presentation type ``'e'`` and |
261 | | | precision ``p-1`` would have exponent ``exp``. Then |
262 | | | if ``-4 <= exp < p``, the number is formatted |
263 | | | with presentation type ``'f'`` and precision |
264 | | | ``p-1-exp``. Otherwise, the number is formatted |
265 | | | with presentation type ``'e'`` and precision ``p-1``. |
266 | | | In both cases insignificant trailing zeros are removed |
267 | | | from the significand, and the decimal point is also |
268 | | | removed if there are no remaining digits following it. |
269 | | | |
270 | | | Positive and negative infinity, positive and negative |
271 | | | zero, and nans, are formatted as ``inf``, ``-inf``, |
272 | | | ``0``, ``-0`` and ``nan`` respectively, regardless of |
273 | | | the precision. |
274 | | | |
275 | +---------+----------------------------------------------------------+
276 |
277 | The available presentation types for pointers are:
278 |
279 | +---------+----------------------------------------------------------+
280 | | Type | Meaning |
281 | +=========+==========================================================+
282 | | ``'p'`` | Pointer format. This is the default type for |
283 | | | pointers and may be omitted. |
284 | +---------+----------------------------------------------------------+
285 | | none | The same as ``'p'``. |
286 | +---------+----------------------------------------------------------+
287 |
288 | .. _formatexamples:
289 |
290 | Format examples
291 | ===============
292 |
293 | This section contains examples of the format syntax and comparison with
294 | the printf formatting.
295 |
296 | In most of the cases the syntax is similar to the printf formatting, with the
297 | addition of the ``{}`` and with ``:`` used instead of ``%``.
298 | For example, ``"%03.2f"`` can be translated to ``"{:03.2f}"``.
299 |
300 | The new format syntax also supports new and different options, shown in the
301 | following examples.
302 |
303 | Accessing arguments by position::
304 |
305 | format("{0}, {1}, {2}", 'a', 'b', 'c');
306 | // Result: "a, b, c"
307 | format("{}, {}, {}", 'a', 'b', 'c');
308 | // Result: "a, b, c"
309 | format("{2}, {1}, {0}", 'a', 'b', 'c');
310 | // Result: "c, b, a"
311 | format("{0}{1}{0}", "abra", "cad"); // arguments' indices can be repeated
312 | // Result: "abracadabra"
313 |
314 | Aligning the text and specifying a width::
315 |
316 | format("{:<30}", "left aligned");
317 | // Result: "left aligned "
318 | format("{:>30}", "right aligned");
319 | // Result: " right aligned"
320 | format("{:^30}", "centered");
321 | // Result: " centered "
322 | format("{:*^30}", "centered"); // use '*' as a fill char
323 | // Result: "***********centered***********"
324 |
325 | Replacing ``%+f``, ``%-f``, and ``% f`` and specifying a sign::
326 |
327 | format("{:+f}; {:+f}", 3.14, -3.14); // show it always
328 | // Result: "+3.140000; -3.140000"
329 | format("{: f}; {: f}", 3.14, -3.14); // show a space for positive numbers
330 | // Result: " 3.140000; -3.140000"
331 | format("{:-f}; {:-f}", 3.14, -3.14); // show only the minus -- same as '{:f}; {:f}'
332 | // Result: "3.140000; -3.140000"
333 |
334 | Replacing ``%x`` and ``%o`` and converting the value to different bases::
335 |
336 | format("int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}", 42);
337 | // Result: "int: 42; hex: 2a; oct: 52; bin: 101010"
338 | // with 0x or 0 or 0b as prefix:
339 | format("int: {0:d}; hex: {0:#x}; oct: {0:#o}; bin: {0:#b}", 42);
340 | // Result: "int: 42; hex: 0x2a; oct: 052; bin: 0b101010"
341 |
342 | .. ifconfig:: False
343 |
344 | Using the comma as a thousands separator::
345 |
346 | format("{:,}", 1234567890);
347 | '1,234,567,890'
348 |
349 | Expressing a percentage::
350 |
351 | >>> points = 19
352 | >>> total = 22
353 | Format("Correct answers: {:.2%}") << points/total)
354 | 'Correct answers: 86.36%'
355 |
356 | Using type-specific formatting::
357 |
358 | >>> import datetime
359 | >>> d = datetime.datetime(2010, 7, 4, 12, 15, 58)
360 | Format("{:%Y-%m-%d %H:%M:%S}") << d)
361 | '2010-07-04 12:15:58'
362 |
363 | Nesting arguments and more complex examples::
364 |
365 | >>> for align, text in zip('<^>', ['left', 'center', 'right']):
366 | ... '{0:{fill}{align}16}") << text, fill=align, align=align)
367 | ...
368 | 'left<<<<<<<<<<<<'
369 | '^^^^^center^^^^^'
370 | '>>>>>>>>>>>right'
371 | >>>
372 | >>> octets = [192, 168, 0, 1]
373 | Format("{:02X}{:02X}{:02X}{:02X}") << *octets)
374 | 'C0A80001'
375 | >>> int(_, 16)
376 | 3232235521
377 | >>>
378 | >>> width = 5
379 | >>> for num in range(5,12):
380 | ... for base in 'dXob':
381 | ... print('{0:{width}{base}}") << num, base=base, width=width), end=' ')
382 | ... print()
383 | ...
384 | 5 5 5 101
385 | 6 6 6 110
386 | 7 7 7 111
387 | 8 8 10 1000
388 | 9 9 11 1001
389 | 10 A 12 1010
390 | 11 B 13 1011
391 |
392 |
--------------------------------------------------------------------------------
/cppformat/test/gtest-extra-test.cc:
--------------------------------------------------------------------------------
1 | /*
2 | Tests of custom Google Test assertions.
3 |
4 | Copyright (c) 2012-2014, Victor Zverovich
5 | All rights reserved.
6 |
7 | Redistribution and use in source and binary forms, with or without
8 | modification, are permitted provided that the following conditions are met:
9 |
10 | 1. Redistributions of source code must retain the above copyright notice, this
11 | list of conditions and the following disclaimer.
12 | 2. Redistributions in binary form must reproduce the above copyright notice,
13 | this list of conditions and the following disclaimer in the documentation
14 | and/or other materials provided with the distribution.
15 |
16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
20 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 | */
27 |
28 | #include "gtest-extra.h"
29 |
30 | #include
31 | #include
32 | #include
33 | #include
34 |
35 | #if defined(_WIN32) && !defined(__MINGW32__)
36 | # include // for _CrtSetReportMode
37 | #endif // _WIN32
38 |
39 | namespace {
40 |
41 | #if defined(_WIN32) && !defined(__MINGW32__)
42 |
43 | // Suppresses Windows assertions on invalid file descriptors, making
44 | // POSIX functions return proper error codes instead of crashing on Windows.
45 | class SuppressAssert {
46 | private:
47 | _invalid_parameter_handler original_handler_;
48 | int original_report_mode_;
49 |
50 | static void handle_invalid_parameter(const wchar_t *,
51 | const wchar_t *, const wchar_t *, unsigned , uintptr_t) {}
52 |
53 | public:
54 | SuppressAssert()
55 | : original_handler_(_set_invalid_parameter_handler(handle_invalid_parameter)),
56 | original_report_mode_(_CrtSetReportMode(_CRT_ASSERT, 0)) {
57 | }
58 | ~SuppressAssert() {
59 | _set_invalid_parameter_handler(original_handler_);
60 | _CrtSetReportMode(_CRT_ASSERT, original_report_mode_);
61 | }
62 | };
63 |
64 | # define SUPPRESS_ASSERT(statement) { SuppressAssert sa; statement; }
65 |
66 | // Fix "secure" warning about using fopen without defining
67 | // _CRT_SECURE_NO_WARNINGS.
68 | FILE *safe_fopen(const char *filename, const char *mode) {
69 | FILE *f = 0;
70 | errno = fopen_s(&f, filename, mode);
71 | return f;
72 | }
73 | #define fopen safe_fopen
74 | #else
75 | # define SUPPRESS_ASSERT(statement) statement
76 | using std::fopen;
77 | #endif // _WIN32
78 |
79 | #define EXPECT_SYSTEM_ERROR_NOASSERT(statement, error_code, message) \
80 | EXPECT_SYSTEM_ERROR(SUPPRESS_ASSERT(statement), error_code, message)
81 |
82 | // Tests that assertion macros evaluate their arguments exactly once.
83 | class SingleEvaluationTest : public ::testing::Test {
84 | protected:
85 | SingleEvaluationTest() {
86 | p_ = s_;
87 | a_ = 0;
88 | b_ = 0;
89 | }
90 |
91 | static const char* const s_;
92 | static const char* p_;
93 |
94 | static int a_;
95 | static int b_;
96 | };
97 |
98 | const char* const SingleEvaluationTest::s_ = "01234";
99 | const char* SingleEvaluationTest::p_;
100 | int SingleEvaluationTest::a_;
101 | int SingleEvaluationTest::b_;
102 |
103 | void do_nothing() {}
104 |
105 | void throw_exception() {
106 | throw std::runtime_error("test");
107 | }
108 |
109 | void throw_system_error() {
110 | throw fmt::SystemError(EDOM, "test");
111 | }
112 |
113 | // Tests that when EXPECT_THROW_MSG fails, it evaluates its message argument
114 | // exactly once.
115 | TEST_F(SingleEvaluationTest, FailedEXPECT_THROW_MSG) {
116 | EXPECT_NONFATAL_FAILURE(
117 | EXPECT_THROW_MSG(throw_exception(), std::exception, p_++), "01234");
118 | EXPECT_EQ(s_ + 1, p_);
119 | }
120 |
121 | // Tests that when EXPECT_SYSTEM_ERROR fails, it evaluates its message argument
122 | // exactly once.
123 | TEST_F(SingleEvaluationTest, FailedEXPECT_SYSTEM_ERROR) {
124 | EXPECT_NONFATAL_FAILURE(
125 | EXPECT_SYSTEM_ERROR(throw_system_error(), EDOM, p_++), "01234");
126 | EXPECT_EQ(s_ + 1, p_);
127 | }
128 |
129 | // Tests that when EXPECT_WRITE fails, it evaluates its message argument
130 | // exactly once.
131 | TEST_F(SingleEvaluationTest, FailedEXPECT_WRITE) {
132 | EXPECT_NONFATAL_FAILURE(
133 | EXPECT_WRITE(stdout, std::printf("test"), p_++), "01234");
134 | EXPECT_EQ(s_ + 1, p_);
135 | }
136 |
137 | // Tests that assertion arguments are evaluated exactly once.
138 | TEST_F(SingleEvaluationTest, ExceptionTests) {
139 | // successful EXPECT_THROW_MSG
140 | EXPECT_THROW_MSG({ // NOLINT
141 | a_++;
142 | throw_exception();
143 | }, std::exception, (b_++, "test"));
144 | EXPECT_EQ(1, a_);
145 | EXPECT_EQ(1, b_);
146 |
147 | // failed EXPECT_THROW_MSG, throws different type
148 | EXPECT_NONFATAL_FAILURE(EXPECT_THROW_MSG({ // NOLINT
149 | a_++;
150 | throw_exception();
151 | }, std::logic_error, (b_++, "test")), "throws a different type");
152 | EXPECT_EQ(2, a_);
153 | EXPECT_EQ(2, b_);
154 |
155 | // failed EXPECT_THROW_MSG, throws an exception with different message
156 | EXPECT_NONFATAL_FAILURE(EXPECT_THROW_MSG({ // NOLINT
157 | a_++;
158 | throw_exception();
159 | }, std::exception, (b_++, "other")),
160 | "throws an exception with a different message");
161 | EXPECT_EQ(3, a_);
162 | EXPECT_EQ(3, b_);
163 |
164 | // failed EXPECT_THROW_MSG, throws nothing
165 | EXPECT_NONFATAL_FAILURE(
166 | EXPECT_THROW_MSG(a_++, std::exception, (b_++, "test")), "throws nothing");
167 | EXPECT_EQ(4, a_);
168 | EXPECT_EQ(4, b_);
169 | }
170 |
171 | TEST_F(SingleEvaluationTest, SystemErrorTests) {
172 | // successful EXPECT_SYSTEM_ERROR
173 | EXPECT_SYSTEM_ERROR({ // NOLINT
174 | a_++;
175 | throw_system_error();
176 | }, EDOM, (b_++, "test"));
177 | EXPECT_EQ(1, a_);
178 | EXPECT_EQ(1, b_);
179 |
180 | // failed EXPECT_SYSTEM_ERROR, throws different type
181 | EXPECT_NONFATAL_FAILURE(EXPECT_SYSTEM_ERROR({ // NOLINT
182 | a_++;
183 | throw_exception();
184 | }, EDOM, (b_++, "test")), "throws a different type");
185 | EXPECT_EQ(2, a_);
186 | EXPECT_EQ(2, b_);
187 |
188 | // failed EXPECT_SYSTEM_ERROR, throws an exception with different message
189 | EXPECT_NONFATAL_FAILURE(EXPECT_SYSTEM_ERROR({ // NOLINT
190 | a_++;
191 | throw_system_error();
192 | }, EDOM, (b_++, "other")),
193 | "throws an exception with a different message");
194 | EXPECT_EQ(3, a_);
195 | EXPECT_EQ(3, b_);
196 |
197 | // failed EXPECT_SYSTEM_ERROR, throws nothing
198 | EXPECT_NONFATAL_FAILURE(
199 | EXPECT_SYSTEM_ERROR(a_++, EDOM, (b_++, "test")), "throws nothing");
200 | EXPECT_EQ(4, a_);
201 | EXPECT_EQ(4, b_);
202 | }
203 |
204 | // Tests that assertion arguments are evaluated exactly once.
205 | TEST_F(SingleEvaluationTest, WriteTests) {
206 | // successful EXPECT_WRITE
207 | EXPECT_WRITE(stdout, { // NOLINT
208 | a_++;
209 | std::printf("test");
210 | }, (b_++, "test"));
211 | EXPECT_EQ(1, a_);
212 | EXPECT_EQ(1, b_);
213 |
214 | // failed EXPECT_WRITE
215 | EXPECT_NONFATAL_FAILURE(EXPECT_WRITE(stdout, { // NOLINT
216 | a_++;
217 | std::printf("test");
218 | }, (b_++, "other")), "Actual: test");
219 | EXPECT_EQ(2, a_);
220 | EXPECT_EQ(2, b_);
221 | }
222 |
223 | // Tests that the compiler will not complain about unreachable code in the
224 | // EXPECT_THROW_MSG macro.
225 | TEST(ExpectThrowTest, DoesNotGenerateUnreachableCodeWarning) {
226 | int n = 0;
227 | using std::runtime_error;
228 | EXPECT_THROW_MSG(throw runtime_error(""), runtime_error, "");
229 | EXPECT_NONFATAL_FAILURE(EXPECT_THROW_MSG(n++, runtime_error, ""), "");
230 | EXPECT_NONFATAL_FAILURE(EXPECT_THROW_MSG(throw 1, runtime_error, ""), "");
231 | EXPECT_NONFATAL_FAILURE(EXPECT_THROW_MSG(
232 | throw runtime_error("a"), runtime_error, "b"), "");
233 | }
234 |
235 | // Tests that the compiler will not complain about unreachable code in the
236 | // EXPECT_SYSTEM_ERROR macro.
237 | TEST(ExpectSystemErrorTest, DoesNotGenerateUnreachableCodeWarning) {
238 | int n = 0;
239 | EXPECT_SYSTEM_ERROR(throw fmt::SystemError(EDOM, "test"), EDOM, "test");
240 | EXPECT_NONFATAL_FAILURE(EXPECT_SYSTEM_ERROR(n++, EDOM, ""), "");
241 | EXPECT_NONFATAL_FAILURE(EXPECT_SYSTEM_ERROR(throw 1, EDOM, ""), "");
242 | EXPECT_NONFATAL_FAILURE(EXPECT_SYSTEM_ERROR(
243 | throw fmt::SystemError(EDOM, "aaa"), EDOM, "bbb"), "");
244 | }
245 |
246 | TEST(AssertionSyntaxTest, ExceptionAssertionBehavesLikeSingleStatement) {
247 | if (::testing::internal::AlwaysFalse())
248 | EXPECT_THROW_MSG(do_nothing(), std::exception, "");
249 |
250 | if (::testing::internal::AlwaysTrue())
251 | EXPECT_THROW_MSG(throw_exception(), std::exception, "test");
252 | else
253 | do_nothing();
254 | }
255 |
256 | TEST(AssertionSyntaxTest, SystemErrorAssertionBehavesLikeSingleStatement) {
257 | if (::testing::internal::AlwaysFalse())
258 | EXPECT_SYSTEM_ERROR(do_nothing(), EDOM, "");
259 |
260 | if (::testing::internal::AlwaysTrue())
261 | EXPECT_SYSTEM_ERROR(throw_system_error(), EDOM, "test");
262 | else
263 | do_nothing();
264 | }
265 |
266 | TEST(AssertionSyntaxTest, WriteAssertionBehavesLikeSingleStatement) {
267 | if (::testing::internal::AlwaysFalse())
268 | EXPECT_WRITE(stdout, std::printf("x"), "x");
269 |
270 | if (::testing::internal::AlwaysTrue())
271 | EXPECT_WRITE(stdout, std::printf("x"), "x");
272 | else
273 | do_nothing();
274 | }
275 |
276 | // Tests EXPECT_THROW_MSG.
277 | TEST(ExpectTest, EXPECT_THROW_MSG) {
278 | EXPECT_THROW_MSG(throw_exception(), std::exception, "test");
279 | EXPECT_NONFATAL_FAILURE(
280 | EXPECT_THROW_MSG(throw_exception(), std::logic_error, "test"),
281 | "Expected: throw_exception() throws an exception of "
282 | "type std::logic_error.\n Actual: it throws a different type.");
283 | EXPECT_NONFATAL_FAILURE(
284 | EXPECT_THROW_MSG(do_nothing(), std::exception, "test"),
285 | "Expected: do_nothing() throws an exception of type std::exception.\n"
286 | " Actual: it throws nothing.");
287 | EXPECT_NONFATAL_FAILURE(
288 | EXPECT_THROW_MSG(throw_exception(), std::exception, "other"),
289 | "throw_exception() throws an exception with a different message.\n"
290 | "Expected: other\n"
291 | " Actual: test");
292 | }
293 |
294 | // Tests EXPECT_SYSTEM_ERROR.
295 | TEST(ExpectTest, EXPECT_SYSTEM_ERROR) {
296 | EXPECT_SYSTEM_ERROR(throw_system_error(), EDOM, "test");
297 | EXPECT_NONFATAL_FAILURE(
298 | EXPECT_SYSTEM_ERROR(throw_exception(), EDOM, "test"),
299 | "Expected: throw_exception() throws an exception of "
300 | "type fmt::SystemError.\n Actual: it throws a different type.");
301 | EXPECT_NONFATAL_FAILURE(
302 | EXPECT_SYSTEM_ERROR(do_nothing(), EDOM, "test"),
303 | "Expected: do_nothing() throws an exception of type fmt::SystemError.\n"
304 | " Actual: it throws nothing.");
305 | EXPECT_NONFATAL_FAILURE(
306 | EXPECT_SYSTEM_ERROR(throw_system_error(), EDOM, "other"),
307 | fmt::format(
308 | "throw_system_error() throws an exception with a different message.\n"
309 | "Expected: {}\n"
310 | " Actual: {}",
311 | format_system_error(EDOM, "other"),
312 | format_system_error(EDOM, "test")));
313 | }
314 |
315 | // Tests EXPECT_WRITE.
316 | TEST(ExpectTest, EXPECT_WRITE) {
317 | EXPECT_WRITE(stdout, do_nothing(), "");
318 | EXPECT_WRITE(stdout, std::printf("test"), "test");
319 | EXPECT_WRITE(stderr, std::fprintf(stderr, "test"), "test");
320 | EXPECT_NONFATAL_FAILURE(
321 | EXPECT_WRITE(stdout, std::printf("that"), "this"),
322 | "Expected: this\n"
323 | " Actual: that");
324 | }
325 |
326 | TEST(StreamingAssertionsTest, EXPECT_THROW_MSG) {
327 | EXPECT_THROW_MSG(throw_exception(), std::exception, "test")
328 | << "unexpected failure";
329 | EXPECT_NONFATAL_FAILURE(
330 | EXPECT_THROW_MSG(throw_exception(), std::exception, "other")
331 | << "expected failure", "expected failure");
332 | }
333 |
334 | TEST(StreamingAssertionsTest, EXPECT_SYSTEM_ERROR) {
335 | EXPECT_SYSTEM_ERROR(throw_system_error(), EDOM, "test")
336 | << "unexpected failure";
337 | EXPECT_NONFATAL_FAILURE(
338 | EXPECT_SYSTEM_ERROR(throw_system_error(), EDOM, "other")
339 | << "expected failure", "expected failure");
340 | }
341 |
342 | TEST(StreamingAssertionsTest, EXPECT_WRITE) {
343 | EXPECT_WRITE(stdout, std::printf("test"), "test")
344 | << "unexpected failure";
345 | EXPECT_NONFATAL_FAILURE(
346 | EXPECT_WRITE(stdout, std::printf("test"), "other")
347 | << "expected failure", "expected failure");
348 | }
349 |
350 | TEST(UtilTest, FormatSystemError) {
351 | fmt::MemoryWriter out;
352 | fmt::internal::format_system_error(out, EDOM, "test message");
353 | EXPECT_EQ(out.str(), format_system_error(EDOM, "test message"));
354 | }
355 |
356 | #if FMT_USE_FILE_DESCRIPTORS
357 |
358 | using fmt::BufferedFile;
359 | using fmt::ErrorCode;
360 | using fmt::File;
361 |
362 | // Checks if the file is open by reading one character from it.
363 | bool isopen(int fd) {
364 | char buffer;
365 | return FMT_POSIX(read(fd, &buffer, 1)) == 1;
366 | }
367 |
368 | bool isclosed(int fd) {
369 | char buffer;
370 | std::streamsize result = 0;
371 | SUPPRESS_ASSERT(result = FMT_POSIX(read(fd, &buffer, 1)));
372 | return result == -1 && errno == EBADF;
373 | }
374 |
375 | // Attempts to read count characters from a file.
376 | std::string read(File &f, std::size_t count) {
377 | std::string buffer(count, '\0');
378 | std::streamsize n = 0;
379 | std::size_t offset = 0;
380 | do {
381 | n = f.read(&buffer[offset], count - offset);
382 | // We can't read more than size_t bytes since count has type size_t.
383 | offset += static_cast(n);
384 | } while (offset < count && n != 0);
385 | buffer.resize(offset);
386 | return buffer;
387 | }
388 |
389 | // Attempts to write a string to a file.
390 | void write(File &f, fmt::StringRef s) {
391 | std::size_t num_chars_left = s.size();
392 | const char *ptr = s.c_str();
393 | do {
394 | std::streamsize count = f.write(ptr, num_chars_left);
395 | ptr += count;
396 | // We can't write more than size_t bytes since num_chars_left
397 | // has type size_t.
398 | num_chars_left -= static_cast(count);
399 | } while (num_chars_left != 0);
400 | }
401 |
402 | #define EXPECT_READ(file, expected_content) \
403 | EXPECT_EQ(expected_content, read(file, std::strlen(expected_content)))
404 |
405 | TEST(ErrorCodeTest, Ctor) {
406 | EXPECT_EQ(0, ErrorCode().get());
407 | EXPECT_EQ(42, ErrorCode(42).get());
408 | }
409 |
410 | const char FILE_CONTENT[] = "Don't panic!";
411 |
412 | // Opens a file for reading.
413 | File open_file() {
414 | File read_end, write_end;
415 | File::pipe(read_end, write_end);
416 | write_end.write(FILE_CONTENT, sizeof(FILE_CONTENT) - 1);
417 | write_end.close();
418 | return read_end;
419 | }
420 |
421 | // Opens a buffered file for reading.
422 | BufferedFile open_buffered_file(FILE **fp = 0) {
423 | File read_end, write_end;
424 | File::pipe(read_end, write_end);
425 | write_end.write(FILE_CONTENT, sizeof(FILE_CONTENT) - 1);
426 | write_end.close();
427 | BufferedFile f = read_end.fdopen("r");
428 | if (fp)
429 | *fp = f.get();
430 | return f;
431 | }
432 |
433 | TEST(BufferedFileTest, DefaultCtor) {
434 | BufferedFile f;
435 | EXPECT_TRUE(f.get() == 0);
436 | }
437 |
438 | TEST(BufferedFileTest, MoveCtor) {
439 | BufferedFile bf = open_buffered_file();
440 | FILE *fp = bf.get();
441 | EXPECT_TRUE(fp != 0);
442 | BufferedFile bf2(std::move(bf));
443 | EXPECT_EQ(fp, bf2.get());
444 | EXPECT_TRUE(bf.get() == 0);
445 | }
446 |
447 | TEST(BufferedFileTest, MoveAssignment) {
448 | BufferedFile bf = open_buffered_file();
449 | FILE *fp = bf.get();
450 | EXPECT_TRUE(fp != 0);
451 | BufferedFile bf2;
452 | bf2 = std::move(bf);
453 | EXPECT_EQ(fp, bf2.get());
454 | EXPECT_TRUE(bf.get() == 0);
455 | }
456 |
457 | TEST(BufferedFileTest, MoveAssignmentClosesFile) {
458 | BufferedFile bf = open_buffered_file();
459 | BufferedFile bf2 = open_buffered_file();
460 | int old_fd = bf2.fileno();
461 | bf2 = std::move(bf);
462 | EXPECT_TRUE(isclosed(old_fd));
463 | }
464 |
465 | TEST(BufferedFileTest, MoveFromTemporaryInCtor) {
466 | FILE *fp = 0;
467 | BufferedFile f(open_buffered_file(&fp));
468 | EXPECT_EQ(fp, f.get());
469 | }
470 |
471 | TEST(BufferedFileTest, MoveFromTemporaryInAssignment) {
472 | FILE *fp = 0;
473 | BufferedFile f;
474 | f = open_buffered_file(&fp);
475 | EXPECT_EQ(fp, f.get());
476 | }
477 |
478 | TEST(BufferedFileTest, MoveFromTemporaryInAssignmentClosesFile) {
479 | BufferedFile f = open_buffered_file();
480 | int old_fd = f.fileno();
481 | f = open_buffered_file();
482 | EXPECT_TRUE(isclosed(old_fd));
483 | }
484 |
485 | TEST(BufferedFileTest, CloseFileInDtor) {
486 | int fd = 0;
487 | {
488 | BufferedFile f = open_buffered_file();
489 | fd = f.fileno();
490 | }
491 | EXPECT_TRUE(isclosed(fd));
492 | }
493 |
494 | TEST(BufferedFileTest, CloseErrorInDtor) {
495 | BufferedFile *f = new BufferedFile(open_buffered_file());
496 | EXPECT_WRITE(stderr, {
497 | // The close function must be called inside EXPECT_WRITE, otherwise
498 | // the system may recycle closed file descriptor when redirecting the
499 | // output in EXPECT_STDERR and the second close will break output
500 | // redirection.
501 | FMT_POSIX(close(f->fileno()));
502 | SUPPRESS_ASSERT(delete f);
503 | }, format_system_error(EBADF, "cannot close file") + "\n");
504 | }
505 |
506 | TEST(BufferedFileTest, Close) {
507 | BufferedFile f = open_buffered_file();
508 | int fd = f.fileno();
509 | f.close();
510 | EXPECT_TRUE(f.get() == 0);
511 | EXPECT_TRUE(isclosed(fd));
512 | }
513 |
514 | TEST(BufferedFileTest, CloseError) {
515 | BufferedFile f = open_buffered_file();
516 | FMT_POSIX(close(f.fileno()));
517 | EXPECT_SYSTEM_ERROR_NOASSERT(f.close(), EBADF, "cannot close file");
518 | EXPECT_TRUE(f.get() == 0);
519 | }
520 |
521 | TEST(BufferedFileTest, Fileno) {
522 | BufferedFile f;
523 | // fileno on a null FILE pointer either crashes or returns an error.
524 | EXPECT_DEATH({
525 | try {
526 | f.fileno();
527 | } catch (fmt::SystemError) {
528 | std::exit(1);
529 | }
530 | }, "");
531 | f = open_buffered_file();
532 | EXPECT_TRUE(f.fileno() != -1);
533 | File copy = File::dup(f.fileno());
534 | EXPECT_READ(copy, FILE_CONTENT);
535 | }
536 |
537 | TEST(FileTest, DefaultCtor) {
538 | File f;
539 | EXPECT_EQ(-1, f.descriptor());
540 | }
541 |
542 | TEST(FileTest, OpenBufferedFileInCtor) {
543 | FILE *fp = fopen("test-file", "w");
544 | std::fputs(FILE_CONTENT, fp);
545 | std::fclose(fp);
546 | File f("test-file", File::RDONLY);
547 | ASSERT_TRUE(isopen(f.descriptor()));
548 | }
549 |
550 | TEST(FileTest, OpenBufferedFileError) {
551 | EXPECT_SYSTEM_ERROR(File("nonexistent", File::RDONLY),
552 | ENOENT, "cannot open file nonexistent");
553 | }
554 |
555 | TEST(FileTest, MoveCtor) {
556 | File f = open_file();
557 | int fd = f.descriptor();
558 | EXPECT_NE(-1, fd);
559 | File f2(std::move(f));
560 | EXPECT_EQ(fd, f2.descriptor());
561 | EXPECT_EQ(-1, f.descriptor());
562 | }
563 |
564 | TEST(FileTest, MoveAssignment) {
565 | File f = open_file();
566 | int fd = f.descriptor();
567 | EXPECT_NE(-1, fd);
568 | File f2;
569 | f2 = std::move(f);
570 | EXPECT_EQ(fd, f2.descriptor());
571 | EXPECT_EQ(-1, f.descriptor());
572 | }
573 |
574 | TEST(FileTest, MoveAssignmentClosesFile) {
575 | File f = open_file();
576 | File f2 = open_file();
577 | int old_fd = f2.descriptor();
578 | f2 = std::move(f);
579 | EXPECT_TRUE(isclosed(old_fd));
580 | }
581 |
582 | File OpenBufferedFile(int &fd) {
583 | File f = open_file();
584 | fd = f.descriptor();
585 | return std::move(f);
586 | }
587 |
588 | TEST(FileTest, MoveFromTemporaryInCtor) {
589 | int fd = 0xdeadbeef;
590 | File f(OpenBufferedFile(fd));
591 | EXPECT_EQ(fd, f.descriptor());
592 | }
593 |
594 | TEST(FileTest, MoveFromTemporaryInAssignment) {
595 | int fd = 0xdeadbeef;
596 | File f;
597 | f = OpenBufferedFile(fd);
598 | EXPECT_EQ(fd, f.descriptor());
599 | }
600 |
601 | TEST(FileTest, MoveFromTemporaryInAssignmentClosesFile) {
602 | int fd = 0xdeadbeef;
603 | File f = open_file();
604 | int old_fd = f.descriptor();
605 | f = OpenBufferedFile(fd);
606 | EXPECT_TRUE(isclosed(old_fd));
607 | }
608 |
609 | TEST(FileTest, CloseFileInDtor) {
610 | int fd = 0;
611 | {
612 | File f = open_file();
613 | fd = f.descriptor();
614 | }
615 | EXPECT_TRUE(isclosed(fd));
616 | }
617 |
618 | TEST(FileTest, CloseErrorInDtor) {
619 | File *f = new File(open_file());
620 | EXPECT_WRITE(stderr, {
621 | // The close function must be called inside EXPECT_WRITE, otherwise
622 | // the system may recycle closed file descriptor when redirecting the
623 | // output in EXPECT_STDERR and the second close will break output
624 | // redirection.
625 | FMT_POSIX(close(f->descriptor()));
626 | SUPPRESS_ASSERT(delete f);
627 | }, format_system_error(EBADF, "cannot close file") + "\n");
628 | }
629 |
630 | TEST(FileTest, Close) {
631 | File f = open_file();
632 | int fd = f.descriptor();
633 | f.close();
634 | EXPECT_EQ(-1, f.descriptor());
635 | EXPECT_TRUE(isclosed(fd));
636 | }
637 |
638 | TEST(FileTest, CloseError) {
639 | File f = open_file();
640 | FMT_POSIX(close(f.descriptor()));
641 | EXPECT_SYSTEM_ERROR_NOASSERT(f.close(), EBADF, "cannot close file");
642 | EXPECT_EQ(-1, f.descriptor());
643 | }
644 |
645 | TEST(FileTest, Read) {
646 | File f = open_file();
647 | EXPECT_READ(f, FILE_CONTENT);
648 | }
649 |
650 | TEST(FileTest, ReadError) {
651 | File read_end, write_end;
652 | File::pipe(read_end, write_end);
653 | char buf;
654 | // We intentionally read from write_end to cause error.
655 | EXPECT_SYSTEM_ERROR(write_end.read(&buf, 1), EBADF, "cannot read from file");
656 | }
657 |
658 | TEST(FileTest, Write) {
659 | File read_end, write_end;
660 | File::pipe(read_end, write_end);
661 | write(write_end, "test");
662 | write_end.close();
663 | EXPECT_READ(read_end, "test");
664 | }
665 |
666 | TEST(FileTest, WriteError) {
667 | File read_end, write_end;
668 | File::pipe(read_end, write_end);
669 | // We intentionally write to read_end to cause error.
670 | EXPECT_SYSTEM_ERROR(read_end.write(" ", 1), EBADF, "cannot write to file");
671 | }
672 |
673 | TEST(FileTest, Dup) {
674 | File f = open_file();
675 | File copy = File::dup(f.descriptor());
676 | EXPECT_NE(f.descriptor(), copy.descriptor());
677 | EXPECT_EQ(FILE_CONTENT, read(copy, sizeof(FILE_CONTENT) - 1));
678 | }
679 |
680 | TEST(FileTest, DupError) {
681 | EXPECT_SYSTEM_ERROR_NOASSERT(File::dup(-1),
682 | EBADF, "cannot duplicate file descriptor -1");
683 | }
684 |
685 | TEST(FileTest, Dup2) {
686 | File f = open_file();
687 | File copy = open_file();
688 | f.dup2(copy.descriptor());
689 | EXPECT_NE(f.descriptor(), copy.descriptor());
690 | EXPECT_READ(copy, FILE_CONTENT);
691 | }
692 |
693 | TEST(FileTest, Dup2Error) {
694 | File f = open_file();
695 | EXPECT_SYSTEM_ERROR_NOASSERT(f.dup2(-1), EBADF,
696 | fmt::format("cannot duplicate file descriptor {} to -1", f.descriptor()));
697 | }
698 |
699 | TEST(FileTest, Dup2NoExcept) {
700 | File f = open_file();
701 | File copy = open_file();
702 | ErrorCode ec;
703 | f.dup2(copy.descriptor(), ec);
704 | EXPECT_EQ(0, ec.get());
705 | EXPECT_NE(f.descriptor(), copy.descriptor());
706 | EXPECT_READ(copy, FILE_CONTENT);
707 | }
708 |
709 | TEST(FileTest, Dup2NoExceptError) {
710 | File f = open_file();
711 | ErrorCode ec;
712 | SUPPRESS_ASSERT(f.dup2(-1, ec));
713 | EXPECT_EQ(EBADF, ec.get());
714 | }
715 |
716 | TEST(FileTest, Pipe) {
717 | File read_end, write_end;
718 | File::pipe(read_end, write_end);
719 | EXPECT_NE(-1, read_end.descriptor());
720 | EXPECT_NE(-1, write_end.descriptor());
721 | write(write_end, "test");
722 | EXPECT_READ(read_end, "test");
723 | }
724 |
725 | TEST(FileTest, Fdopen) {
726 | File read_end, write_end;
727 | File::pipe(read_end, write_end);
728 | int read_fd = read_end.descriptor();
729 | EXPECT_EQ(read_fd, FMT_POSIX(fileno(read_end.fdopen("r").get())));
730 | }
731 |
732 | TEST(FileTest, FdopenError) {
733 | File f;
734 | EXPECT_SYSTEM_ERROR_NOASSERT(
735 | f.fdopen("r"), EBADF, "cannot associate stream with file descriptor");
736 | }
737 |
738 | TEST(OutputRedirectTest, ScopedRedirect) {
739 | File read_end, write_end;
740 | File::pipe(read_end, write_end);
741 | {
742 | BufferedFile file(write_end.fdopen("w"));
743 | std::fprintf(file.get(), "[[[");
744 | {
745 | OutputRedirect redir(file.get());
746 | std::fprintf(file.get(), "censored");
747 | }
748 | std::fprintf(file.get(), "]]]");
749 | }
750 | EXPECT_READ(read_end, "[[[]]]");
751 | }
752 |
753 | // Test that OutputRedirect handles errors in flush correctly.
754 | TEST(OutputRedirectTest, FlushErrorInCtor) {
755 | File read_end, write_end;
756 | File::pipe(read_end, write_end);
757 | int write_fd = write_end.descriptor();
758 | File write_copy = write_end.dup(write_fd);
759 | BufferedFile f = write_end.fdopen("w");
760 | // Put a character in a file buffer.
761 | EXPECT_EQ('x', fputc('x', f.get()));
762 | FMT_POSIX(close(write_fd));
763 | OutputRedirect *redir = 0;
764 | EXPECT_SYSTEM_ERROR_NOASSERT(redir = new OutputRedirect(f.get()),
765 | EBADF, "cannot flush stream");
766 | delete redir;
767 | write_copy.dup2(write_fd); // "undo" close or dtor will fail
768 | }
769 |
770 | TEST(OutputRedirectTest, DupErrorInCtor) {
771 | BufferedFile f = open_buffered_file();
772 | int fd = f.fileno();
773 | File copy = File::dup(fd);
774 | FMT_POSIX(close(fd));
775 | OutputRedirect *redir = 0;
776 | EXPECT_SYSTEM_ERROR_NOASSERT(redir = new OutputRedirect(f.get()),
777 | EBADF, fmt::format("cannot duplicate file descriptor {}", fd));
778 | copy.dup2(fd); // "undo" close or dtor will fail
779 | delete redir;
780 | }
781 |
782 | TEST(OutputRedirectTest, RestoreAndRead) {
783 | File read_end, write_end;
784 | File::pipe(read_end, write_end);
785 | BufferedFile file(write_end.fdopen("w"));
786 | std::fprintf(file.get(), "[[[");
787 | OutputRedirect redir(file.get());
788 | std::fprintf(file.get(), "censored");
789 | EXPECT_EQ("censored", redir.restore_and_read());
790 | EXPECT_EQ("", redir.restore_and_read());
791 | std::fprintf(file.get(), "]]]");
792 | file = BufferedFile();
793 | EXPECT_READ(read_end, "[[[]]]");
794 | }
795 |
796 | // Test that OutputRedirect handles errors in flush correctly.
797 | TEST(OutputRedirectTest, FlushErrorInRestoreAndRead) {
798 | File read_end, write_end;
799 | File::pipe(read_end, write_end);
800 | int write_fd = write_end.descriptor();
801 | File write_copy = write_end.dup(write_fd);
802 | BufferedFile f = write_end.fdopen("w");
803 | OutputRedirect redir(f.get());
804 | // Put a character in a file buffer.
805 | EXPECT_EQ('x', fputc('x', f.get()));
806 | FMT_POSIX(close(write_fd));
807 | EXPECT_SYSTEM_ERROR_NOASSERT(redir.restore_and_read(),
808 | EBADF, "cannot flush stream");
809 | write_copy.dup2(write_fd); // "undo" close or dtor will fail
810 | }
811 |
812 | TEST(OutputRedirectTest, ErrorInDtor) {
813 | File read_end, write_end;
814 | File::pipe(read_end, write_end);
815 | int write_fd = write_end.descriptor();
816 | File write_copy = write_end.dup(write_fd);
817 | BufferedFile f = write_end.fdopen("w");
818 | OutputRedirect *redir = new OutputRedirect(f.get());
819 | // Put a character in a file buffer.
820 | EXPECT_EQ('x', fputc('x', f.get()));
821 | EXPECT_WRITE(stderr, {
822 | // The close function must be called inside EXPECT_WRITE, otherwise
823 | // the system may recycle closed file descriptor when redirecting the
824 | // output in EXPECT_STDERR and the second close will break output
825 | // redirection.
826 | FMT_POSIX(close(write_fd));
827 | SUPPRESS_ASSERT(delete redir);
828 | }, format_system_error(EBADF, "cannot flush stream"));
829 | write_copy.dup2(write_fd); // "undo" close or dtor of BufferedFile will fail
830 | }
831 |
832 | #endif // FMT_USE_FILE_DESCRIPTORS
833 |
834 | } // namespace
835 |
--------------------------------------------------------------------------------