├── 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 | --------------------------------------------------------------------------------