[protozero] 01/07: New upstream version 1.6.0
Bas Couwenberg
sebastic at debian.org
Tue Oct 24 18:14:36 UTC 2017
This is an automated email from the git hooks/post-receive script.
sebastic pushed a commit to branch master
in repository protozero.
commit 3d1e65294664451aab8f9efdc84a3b4c926ef99d
Author: Bas Couwenberg <sebastic at xs4all.nl>
Date: Tue Oct 24 19:33:35 2017 +0200
New upstream version 1.6.0
---
.clang-tidy | 50 ++
.gitignore | 18 -
.npmignore | 33 -
.travis.yml | 99 +--
CHANGELOG.md | 41 +-
CMakeLists.txt | 144 +++++
CONTRIBUTING.md | 9 +-
FUZZING.md | 22 +
Makefile | 148 -----
README.md | 72 ++-
UPGRADING.md | 14 +
appveyor.yml | 60 +-
build-appveyor.bat | 82 +--
build-msys2.bat | 18 +
cmake/FindProtozero.cmake | 63 ++
doc/.gitignore | 2 -
doc/CMakeLists.txt | 37 ++
doc/{Doxyfile => Doxyfile.in} | 13 +-
doc/tutorial.md | 12 +
gyp/common.gypi | 109 ----
gyp/protozero.gyp | 39 --
include/protozero/{types.hpp => data_view.hpp} | 119 ++--
include/protozero/exception.hpp | 21 +
include/protozero/iterators.hpp | 44 +-
include/protozero/pbf_reader.hpp | 30 +-
include/protozero/pbf_writer.hpp | 1 +
include/protozero/types.hpp | 140 -----
include/protozero/varint.hpp | 3 +-
include/protozero/version.hpp | 6 +-
include_dirs.js | 2 -
package.json | 10 -
test/.gitignore | 6 -
test/CMakeLists.txt | 120 ++++
test/README.md | 22 +-
test/include/packed_access.hpp | 14 +-
test/include/scalar_access.hpp | 3 -
test/include/test.hpp | 4 -
test/include/testcase.hpp | 2 +-
test/{tests.cpp => reader_tests.cpp} | 10 +-
test/t/.gitignore | 6 -
.../{test_cases.cpp => reader_test_cases.cpp} | 7 -
test/t/basic/reader_test_cases.cpp | 101 +++
test/t/basic/test_cases.cpp | 39 --
test/t/bool/data-also-true.pbf | 2 +-
test/t/bool/data-still-true.pbf | 2 +-
test/t/bool/reader_test_cases.cpp | 141 +++++
test/t/bool/test_cases.cpp | 155 -----
test/t/bool/testcase.cpp | 2 +-
test/t/bool/testcase.proto | 5 +-
test/t/bool/writer_test_cases.cpp | 2 +-
.../{test_cases.cpp => reader_test_cases.cpp} | 93 ++-
test/t/bytes/writer_test_cases.cpp | 4 +-
test/t/complex/reader_test_cases.cpp | 686 ++++++++++++++++++++
test/t/complex/test_cases.cpp | 700 ---------------------
.../{test_cases.cpp => reader_test_cases.cpp} | 85 ++-
.../{test_cases.cpp => reader_test_cases.cpp} | 7 -
test/t/double/writer_test_cases.cpp | 2 +-
.../{test_cases.cpp => reader_test_cases.cpp} | 24 +-
test/t/enum/reader_test_cases.cpp | 83 +++
test/t/enum/test_cases.cpp | 89 ---
test/t/enum/testcase.proto | 2 +-
test/t/enum/writer_test_cases.cpp | 4 +-
.../{test_cases.cpp => reader_test_cases.cpp} | 10 +
.../{test_cases.cpp => reader_test_cases.cpp} | 0
test/t/fixed32/writer_test_cases.cpp | 2 +-
.../{test_cases.cpp => reader_test_cases.cpp} | 0
.../{test_cases.cpp => reader_test_cases.cpp} | 8 +-
.../{test_cases.cpp => reader_test_cases.cpp} | 0
test/t/int32/writer_test_cases.cpp | 2 +-
.../{test_cases.cpp => reader_test_cases.cpp} | 0
test/t/message/reader_test_cases.cpp | 129 ++++
test/t/message/test_cases.cpp | 141 -----
test/t/message/writer_test_cases.cpp | 2 +-
.../{test_cases.cpp => reader_test_cases.cpp} | 26 +-
test/t/nested/writer_test_cases.cpp | 2 +-
test/t/repeated/reader_test_cases.cpp | 74 +++
test/t/repeated/test_cases.cpp | 80 ---
test/t/repeated/writer_test_cases.cpp | 4 +-
.../{test_cases.cpp => reader_test_cases.cpp} | 83 ++-
.../{test_cases.cpp => reader_test_cases.cpp} | 26 +-
test/t/repeated_packed_enum/reader_test_cases.cpp | 78 +++
test/t/repeated_packed_enum/test_cases.cpp | 84 ---
.../{test_cases.cpp => reader_test_cases.cpp} | 0
.../repeated_packed_fixed32/writer_test_cases.cpp | 11 +-
.../{test_cases.cpp => reader_test_cases.cpp} | 0
.../{test_cases.cpp => reader_test_cases.cpp} | 16 +-
.../{test_cases.cpp => reader_test_cases.cpp} | 0
.../{test_cases.cpp => reader_test_cases.cpp} | 0
.../repeated_packed_sfixed32/reader_test_cases.cpp | 30 +
test/t/repeated_packed_sfixed32/test_cases.cpp | 9 -
.../{test_cases.cpp => reader_test_cases.cpp} | 0
.../{test_cases.cpp => reader_test_cases.cpp} | 0
.../{test_cases.cpp => reader_test_cases.cpp} | 0
.../{test_cases.cpp => reader_test_cases.cpp} | 0
.../{test_cases.cpp => reader_test_cases.cpp} | 0
.../{test_cases.cpp => reader_test_cases.cpp} | 8 +-
.../{test_cases.cpp => reader_test_cases.cpp} | 0
.../{test_cases.cpp => reader_test_cases.cpp} | 0
.../{test_cases.cpp => reader_test_cases.cpp} | 0
.../{test_cases.cpp => reader_test_cases.cpp} | 0
.../skip/{test_cases.cpp => reader_test_cases.cpp} | 4 -
test/t/string/reader_test_cases.cpp | 106 ++++
test/t/string/test_cases.cpp | 116 ----
test/t/string/writer_test_cases.cpp | 6 +-
.../{test_cases.cpp => reader_test_cases.cpp} | 0
.../tags/{test_cases.cpp => reader_test_cases.cpp} | 32 +-
.../{test_cases.cpp => reader_test_cases.cpp} | 0
.../{test_cases.cpp => reader_test_cases.cpp} | 0
.../{test_cases.cpp => reader_test_cases.cpp} | 48 +-
.../{test_cases.cpp => reader_test_cases.cpp} | 1 -
.../{test_cases.cpp => reader_test_cases.cpp} | 0
.../{test_cases.cpp => reader_test_cases.cpp} | 0
tools/CMakeLists.txt | 51 ++
tools/pbf-decoder.cpp | 264 ++++++++
114 files changed, 2905 insertions(+), 2431 deletions(-)
diff --git a/.clang-tidy b/.clang-tidy
new file mode 100644
index 0000000..35ed1a7
--- /dev/null
+++ b/.clang-tidy
@@ -0,0 +1,50 @@
+---
+Checks: '*,-cert-dcl21-cpp,-cert-err60-cpp,-cppcoreguidelines-pro-bounds-pointer-arithmetic,-cppcoreguidelines-pro-bounds-array-to-pointer-decay,-cppcoreguidelines-pro-type-reinterpret-cast,-google-runtime-references'
+#
+# Disabled checks:
+#
+# cert-dcl21-cpp
+# It is unclear whether this is still a good recommendation in modern C++.
+#
+# cert-err60-cpp
+# Reports std::runtime_error as broken which we can't do anything about.
+#
+# cppcoreguidelines-pro-bounds-pointer-arithmetic
+# This is a low-level library, it needs to do pointer arithmetic.
+#
+# cppcoreguidelines-pro-bounds-array-to-pointer-decay
+# Limited use and many false positives including all for all asserts
+#
+# cppcoreguidelines-pro-type-reinterpret-cast
+# This is a low-level library, it needs to do reinterpret-casts.
+#
+# google-runtime-references
+# This is just a matter of preference, and we can't change the interfaces
+# now anyways.
+#
+WarningsAsErrors: '*'
+HeaderFilterRegex: '\/include\/'
+AnalyzeTemporaryDtors: false
+CheckOptions:
+ - key: google-readability-braces-around-statements.ShortStatementLines
+ value: '1'
+ - key: google-readability-function-size.StatementThreshold
+ value: '800'
+ - key: google-readability-namespace-comments.ShortNamespaceLines
+ value: '10'
+ - key: google-readability-namespace-comments.SpacesBeforeComments
+ value: '2'
+ - key: modernize-loop-convert.MaxCopySize
+ value: '16'
+ - key: modernize-loop-convert.MinConfidence
+ value: reasonable
+ - key: modernize-loop-convert.NamingStyle
+ value: CamelCase
+ - key: modernize-pass-by-value.IncludeStyle
+ value: llvm
+ - key: modernize-replace-auto-ptr.IncludeStyle
+ value: llvm
+ - key: modernize-use-nullptr.NullMacros
+ value: 'NULL'
+...
+
diff --git a/.gitignore b/.gitignore
deleted file mode 100644
index ba94541..0000000
--- a/.gitignore
+++ /dev/null
@@ -1,18 +0,0 @@
-coverage
-*.gcov
-out
-protozero.Makefile
-tests.target.mk
-*.o
-*.gcno
-*.gcno
-#Visual Studio files and folders
-Release
-Debug
-deps
-*.sdf
-*.sln
-*.suo
-*.vcxproj*
-*.7z
-compile_commands.json
diff --git a/.npmignore b/.npmignore
deleted file mode 100644
index ef6dd71..0000000
--- a/.npmignore
+++ /dev/null
@@ -1,33 +0,0 @@
-coverage
-*.gcov
-out
-protozero.Makefile
-tests.target.mk
-*.o
-*.gcno
-*.gcno
-#Visual Studio files and folders
-Release
-Debug
-deps
-*.sdf
-*.sln
-*.suo
-*.vcxproj*
-*.7z
-test
-build-local.bat
-build-appveyor.bat
-bench
-notes.md
-coverity.sh
-protozero.gyp
-common.gypi
-tutorial.md
-CHANGELOG.md
-doc
-.travis.yml
-appveyor.yml
-Makefile
-.gitattributes
-.npmignore
diff --git a/.travis.yml b/.travis.yml
index a55b84c..c6be450 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -26,14 +26,14 @@ addons_shortcuts:
apt:
sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-3.9' ]
packages: [ 'libprotobuf-dev','protobuf-compiler', 'clang-3.9' ]
- addons_clang39: &clang40
+ addons_clang40: &clang40
apt:
sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-4.0' ]
packages: [ 'libprotobuf-dev','protobuf-compiler', 'clang-4.0' ]
- addons_clang39: &clang50
+ addons_clang50: &clang50
apt:
sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-5.0' ]
- packages: [ 'libprotobuf-dev','protobuf-compiler', 'clang-5.0' ]
+ packages: [ 'libprotobuf-dev','protobuf-compiler', 'clang-5.0', 'clang-tidy-5.0' ]
addons_gcc47: &gcc47
apt:
sources: [ 'ubuntu-toolchain-r-test' ]
@@ -53,7 +53,7 @@ addons_shortcuts:
addons_gcc6: &gcc6
apt:
sources: [ 'ubuntu-toolchain-r-test' ]
- packages: [ 'libprotobuf-dev','protobuf-compiler', 'g++-6', 'gcc-6', 'doxygen', 'graphviz' ]
+ packages: [ 'libprotobuf-dev','protobuf-compiler', 'g++-6', 'gcc-6' ]
#-----------------------------------------------------------------------------
@@ -61,91 +61,116 @@ matrix:
include:
- os: linux
compiler: "clang-3.5"
- env: CXX=clang++-3.5
+ env: BUILD='Debug' CC=clang-3.5 CXX=clang++-3.5
addons: *clang35
- os: linux
compiler: "clang-3.8"
- env: CXX=clang++-3.8
+ env: BUILD='Debug' CC=clang-3.8 CXX=clang++-3.8
addons: *clang38
- os: linux
compiler: "clang-3.9"
- env: CXX=clang++-3.9
+ env: BUILD='Debug' CC=clang-3.9 CXX=clang++-3.9
addons: *clang39
- os: linux
compiler: "clang-4.0"
- env: CXX=clang++-4.0
+ env: BUILD='Debug' CC=clang-4.0 CXX=clang++-4.0
addons: *clang40
- os: linux
- compiler: "clang-4.0"
- env: CXX=clang++-5.0
+ compiler: "clang-5.0"
+ env: BUILD='Debug' CC=clang-5.0 CXX=clang++-5.0
+ CLANG_TIDY=clang-tidy-5.0
+ addons: *clang50
+ - os: linux
+ compiler: "clang-5.0"
+ env: BUILD='Release' CC=clang-5.0 CXX=clang++-5.0
addons: *clang50
- os: linux
compiler: "clang-5.0"
- env: CXX=clang++-5.0 CXX_STD=c++14
+ env: BUILD='Debug' CC=clang-5.0 CXX=clang++-5.0
+ CXXFLAGS="-fsanitize=address,undefined,integer -fno-sanitize-recover=all -fno-omit-frame-pointer"
+ LDFLAGS="-fsanitize=address,undefined,integer"
addons: *clang50
- os: linux
compiler: "gcc-4.7"
- env: CXX=g++-4.7
+ env: BUILD='Debug' CC=gcc-4.7 CXX=g++-4.7
addons: *gcc47
- os: linux
compiler: "gcc-4.8"
- env: CXX=g++-4.8
+ env: BUILD='Debug' CC=gcc-4.8 CXX=g++-4.8
addons: *gcc48
- os: linux
compiler: "gcc-4.9"
- env: CXX=g++-4.9 COVERAGE=gcov-4.9
- addons: *gcc49
- - os: linux
- compiler: "gcc-4.9"
- env: CXX=g++-4.9 CXX_STD=c++14
+ env: BUILD='Debug' CC=gcc-4.9 CXX=g++-4.9
+ COVERAGE=gcov-4.9
+ CXXFLAGS="--coverage" LDFLAGS="--coverage"
addons: *gcc49
- os: linux
compiler: "gcc-5"
- env: CXX=g++-5 CXXFLAGS="-D_GLIBCXX_USE_CXX11_ABI=0"
+ env: BUILD='Debug' CC=gcc-5 CXX=g++-5
+ CXXFLAGS="-D_GLIBCXX_USE_CXX11_ABI=0"
addons: *gcc5
- os: linux
compiler: "gcc-5"
- env: CXX=g++-5 CXXFLAGS="-D_GLIBCXX_USE_CXX11_ABI=1"
+ env: BUILD='Debug' CC=gcc-5 CXX=g++-5
+ CXXFLAGS="-D_GLIBCXX_USE_CXX11_ABI=1"
addons: *gcc5
- os: linux
compiler: "gcc-6"
- env: CXX=g++-6 BUILD_DOC=1
+ env: BUILD='Debug' CC=gcc-6 CXX=g++-6
addons: *gcc6
- os: linux
compiler: "gcc-6"
- env: CXX=g++-6 PROTOZERO_DATA_VIEW=std::experimental::string_view
+ env: BUILD='Debug' CC=gcc-6 CXX=g++-6
+ PROTOZERO_DATA_VIEW=std::experimental::string_view
addons: *gcc6
+ - os: linux
+ compiler: "gcc-6"
+ env: BUILD='Release' CC=gcc-6 CXX=g++-6
+ addons: *gcc6
+ - os: osx
+ osx_image: xcode6.4
+ compiler: clang
+ env: BUILD='Debug'
+ - os: osx
+ osx_image: xcode7.3
+ compiler: clang
+ env: BUILD='Debug'
- os: osx
- osx_image: xcode6
+ osx_image: xcode8.3
compiler: clang
+ env: BUILD='Debug'
- os: osx
- osx_image: xcode7
+ osx_image: xcode9.1
compiler: clang
+ env: BUILD='Debug'
- os: osx
- osx_image: xcode8
+ osx_image: xcode9.1
compiler: clang
+ env: BUILD='Release'
#-----------------------------------------------------------------------------
-before_install:
- - echo ${CXX}
- - if [[ $(uname -s) == 'Darwin' ]]; then
- brew install protobuf;
- fi
-
install:
- - make test
- - if [ -n "${BUILD_DOC}" ]; then make doc; fi
+ - if [[ $(uname -s) == 'Darwin' ]]; then
+ brew update;
+ brew install protobuf;
+ fi
script:
+ - mkdir build
+ - cd build
+ - cmake .. -LA -DCMAKE_BUILD_TYPE=${BUILD} -DPROTOZERO_DATA_VIEW=$PROTOZERO_DATA_VIEW -DCLANG_TIDY=$(which ${CLANG_TIDY})
+ - make VERBOSE=1
+ - ctest --output-on-failure
+ - if [ -n "${CLANG_TIDY}" ]; then make clang-tidy; fi
- |
if [ -n "${COVERAGE}" ]; then
- make clean
- CXXFLAGS="--coverage ${CXXFLAGS}" LDFLAGS="--coverage ${LDFLAGS}" make test
which ${COVERAGE}
curl -S -f https://codecov.io/bash -o codecov
chmod +x codecov
- ${COVERAGE} -p $(find test/ -name '*.o')
- ./codecov -Z -f '*protozero*' -X search
+ ${COVERAGE} -p $(find test/ tools/ -name '*.o')
+ ./codecov -Z -f '*protozero*' -f '*tools*' -f '!*catch*' -X search
fi
+
+#-----------------------------------------------------------------------------
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3fbcd08..e1aaf68 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,17 +1,49 @@
-# Change Log
+# Changelog
All notable changes to this project will be documented in this file.
+The format is based on [Keep a Changelog](http://keepachangelog.com/)
This project adheres to [Semantic Versioning](http://semver.org/).
-## [unreleased] -
+## [1.6.0] - 2017-10-24
### Added
+- Comparison functions (<, <=, >, >=) for `data_view`. Allows use in `std::map`
+ for instance.
+- Tool `pbf-decoder` for decoding raw messages. This has limited use for
+ normal users, but it can be used for fuzzing.
+
### Changed
+- Protozero now uses CMake to build the tests etc. This does not affect
+ simple users of the library, but if you are using CMake yourself you might
+ want to use the `cmake/FindProtozero.cmake` module provided. The README
+ contains more information about build options.
+- Moved `data_view` class from `types.hpp` into its own header file
+ `data_view.hpp`.
+- Implementation of the `const_fixed_iterator` to use only a single pointer
+ instead of two.
+- Made `operator==` and `operator!=` on `data_view` constexpr.
+- The `pbf_reader` constructor taking a `std::pair` is deprecated. Use one
+ of the other constructors instead.
+
### Fixed
+- Varints where the last byte was larger than what would fit in 64bit were
+ triggering undefined behaviour. This can only happen when the message
+ being decoded was corrupt in some way.
+- Do not assert when reading too long varints for bools any more. A valid
+ encoder should never generate varints with more than one byte for bools,
+ but if they are longer that's not really a problem, so just handle it.
+- Throw exception if the length of a packed repeated field of a fixed-length
+ type is invalid. The length must always be a multiple of the size of the
+ underlying type. This can only happen if the data is corrupted in some way,
+ a valid encoder would never generate data like this.
+- Throw an exception when reading invalid tags. This can only happen if the
+ data is corrupted in some way, a valid encoder would never generate invalid
+ tags.
+
## [1.5.3] - 2017-09-22
@@ -223,8 +255,9 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- Make pbf reader and writer code endianess-aware.
-[unreleased]: https://github.com/osmcode/libosmium/compare/v1.5.3...HEAD
-[1.5.3]: https://github.com/osmcode/libosmium/compare/v1.5.3...v1.5.3
+[unreleased]: https://github.com/osmcode/libosmium/compare/v1.6.0...HEAD
+[1.6.0]: https://github.com/osmcode/libosmium/compare/v1.5.3...v1.6.0
+[1.5.3]: https://github.com/osmcode/libosmium/compare/v1.5.2...v1.5.3
[1.5.2]: https://github.com/osmcode/libosmium/compare/v1.5.1...v1.5.2
[1.5.1]: https://github.com/osmcode/libosmium/compare/v1.5.0...v1.5.1
[1.5.0]: https://github.com/osmcode/libosmium/compare/v1.4.5...v1.5.0
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..e2f35bd
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,144 @@
+#-----------------------------------------------------------------------------
+#
+# CMake config
+#
+# protozero
+#
+#-----------------------------------------------------------------------------
+
+cmake_minimum_required(VERSION 2.8 FATAL_ERROR)
+
+#-----------------------------------------------------------------------------
+
+project(protozero)
+
+set(PROTOZERO_VERSION_MAJOR 1)
+set(PROTOZERO_VERSION_MINOR 6)
+set(PROTOZERO_VERSION_PATCH 0)
+
+set(PROTOZERO_VERSION
+ "${PROTOZERO_VERSION_MAJOR}.${PROTOZERO_VERSION_MINOR}.${PROTOZERO_VERSION_PATCH}")
+
+set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
+
+#-----------------------------------------------------------------------------
+
+option(WERROR "Add -Werror flag to build (turns warnings into errors)" ON)
+
+if(MSVC)
+ add_definitions(-std=c++11 /W3)
+ add_definitions(-D_CRT_SECURE_NO_WARNINGS -D_SCL_SECURE_NO_WARNINGS)
+else()
+ add_definitions(-std=c++11 -Wall -Wextra -pedantic -Wsign-compare -Wunused-parameter -Wno-float-equal -Wno-covered-switch-default)
+ if(WERROR)
+ add_definitions(-Werror)
+ endif()
+endif()
+
+include_directories("${CMAKE_SOURCE_DIR}/include")
+
+set(PROTOZERO_DATA_VIEW "" CACHE STRING "Type used for protozero::data_view")
+if(NOT PROTOZERO_DATA_VIEW STREQUAL "")
+ add_definitions(-DPROTOZERO_DATA_VIEW=${PROTOZERO_DATA_VIEW})
+endif()
+
+
+#-----------------------------------------------------------------------------
+#
+# Find dependencies
+#
+#-----------------------------------------------------------------------------
+
+find_package(Protobuf)
+
+
+#-----------------------------------------------------------------------------
+#
+# Optional "clang-tidy" target
+#
+#-----------------------------------------------------------------------------
+message(STATUS "Looking for clang-tidy")
+find_program(CLANG_TIDY NAMES clang-tidy clang-tidy-5.0)
+
+if(CLANG_TIDY)
+ message(STATUS "Looking for clang-tidy - found ${CLANG_TIDY}")
+ add_custom_target(clang-tidy
+ ${CLANG_TIDY}
+ -p ${CMAKE_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}/test/*.cpp
+ ${CMAKE_SOURCE_DIR}/test/t/*/reader_test_cases.cpp
+ ${CMAKE_SOURCE_DIR}/test/t/*/writer_test_cases.cpp
+ ${CMAKE_SOURCE_DIR}/tools/*.cpp
+ )
+ add_dependencies(clang-tidy writer_tests)
+else()
+ message(STATUS "Looking for clang-tidy - not found")
+ message(STATUS " Build target 'clang-tidy' will not be available.")
+endif()
+
+
+#-----------------------------------------------------------------------------
+#
+# Optional "cppcheck" target
+#
+#-----------------------------------------------------------------------------
+message(STATUS "Looking for cppcheck")
+find_program(CPPCHECK NAMES cppcheck)
+
+if(CPPCHECK)
+ message(STATUS "Looking for cppcheck - found")
+ add_custom_target(cppcheck
+ ${CPPCHECK}
+ -Uassert --std=c++11 --enable=all
+ ${CMAKE_SOURCE_DIR}/include/protozero/*.hpp
+ ${CMAKE_SOURCE_DIR}/test/*.cpp
+ ${CMAKE_SOURCE_DIR}/test/include/*.hpp
+ ${CMAKE_SOURCE_DIR}/test/t/*/*.cpp
+ ${CMAKE_SOURCE_DIR}/tools/*.cpp
+ )
+else()
+ message(STATUS "Looking for cppcheck - not found")
+ message(STATUS " Build target 'cppcheck' will not be available.")
+endif()
+
+
+#-----------------------------------------------------------------------------
+#
+# Include what you use
+#
+#-----------------------------------------------------------------------------
+message(STATUS "Looking for iwyu")
+find_program(IWYU_TOOL NAMES iwyu_tool)
+
+if(IWYU_TOOL)
+ message(STATUS "Looking for iwyu - found")
+ add_custom_target(iwyu
+ ${IWYU_TOOL} -p ${CMAKE_BINARY_DIR}
+ )
+else()
+ message(STATUS "Looking for iwyu - not found")
+ message(STATUS " Build target 'iwyu' will not be available.")
+endif()
+
+
+#-----------------------------------------------------------------------------
+#
+# Installation
+#
+#-----------------------------------------------------------------------------
+
+install(DIRECTORY include/protozero DESTINATION include)
+
+
+#-----------------------------------------------------------------------------
+
+enable_testing()
+
+add_subdirectory(doc)
+
+add_subdirectory(tools)
+
+add_subdirectory(test)
+
+
+#-----------------------------------------------------------------------------
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index fae897b..c116f60 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -8,19 +8,14 @@ To release a new protozero version:
- Make sure "make doc" builds
- Update version number in
- include/protozero/version.hpp (two places)
- - package.json
+ - CMakeLists.txt (one place)
- Update CHANGELOG.md
(don't forget links at the bottom of the file)
- Update UPGRADING.md if necessary
- - `git commit -m "Release X.Y.Z" include/protozero/version.hpp package.json CHANGELOG.md UPGRADING.md`
+ - `git commit -m "Release X.Y.Z" include/protozero/version.hpp CMakeLists.txt CHANGELOG.md UPGRADING.md`
- `git tag vX.Y.Z`
- `git push`
- `git push --tags`
- Go to https://github.com/mapbox/protozero/releases
and edit the new release. Put "Version x.y.z" in title and
cut-and-paste entry from CHANGELOG.md.
- - Publish to npm:
- - First run `make testpack` to see what files will be published
- - If you see any unwanted files, then add them to `.npmignore`
- - Then run: `npm publish`
-
diff --git a/FUZZING.md b/FUZZING.md
new file mode 100644
index 0000000..44ae0ef
--- /dev/null
+++ b/FUZZING.md
@@ -0,0 +1,22 @@
+
+To do fuzz testing using [AFL](http://lcamtuf.coredump.cx/afl/) compile with
+the AFL compiler wrappers:
+
+ mkdir build
+ cd build
+ CC=afl-clang CXX=afl-clang++ cmake ..
+ mkdir testcase_dir
+
+You need some data to start the fuzzing. In this case I am using all the test
+messages from the unit tests:
+
+ find ../test/t/ -name data-\*.pbf -a -not -empty -exec cp {} testcase_dir/ \;
+
+Then do the actual fuzzing:
+
+ afl-fuzz -i testcase_dir -o findings_dir -- tools/pbf-decoder -
+
+See the AFL documentation for more information.
+
+This only checkes the reading side of Protozero!
+
diff --git a/Makefile b/Makefile
deleted file mode 100644
index b896d13..0000000
--- a/Makefile
+++ /dev/null
@@ -1,148 +0,0 @@
-
-# Installation directory
-DESTDIR ?= /usr
-
-WARNING_FLAGS := -Wall -Wextra -pedantic -Wsign-compare -Wsign-conversion -Wunused-parameter -Wno-float-equal -Wno-covered-switch-default -Wshadow
-
-ifneq ($(findstring clang,$(CXX)),)
- WARNING_FLAGS += -Wno-reserved-id-macro -Weverything -Wno-weak-vtables -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-exit-time-destructors -Wno-switch-enum -Wno-padded -Wno-documentation-unknown-command
-endif
-
-ifeq ($(PROTOZERO_DATA_VIEW),std::experimental::string_view)
- PROTOZERO_FLAGS := -include experimental/string_view -DPROTOZERO_USE_VIEW=std::experimental::string_view
- CXX_STD ?= c++14
-endif
-
-CXX_STD ?= c++11
-
-COMMON_FLAGS := -fvisibility-inlines-hidden -std=$(CXX_STD) $(WARNING_FLAGS) $(PROTOZERO_FLAGS)
-
-RELEASE_FLAGS := -O3 -DNDEBUG -march=native
-DEBUG_FLAGS := -O0 -g -fno-inline-functions
-PTHREAD_FLAGS =
-
-CLANG_TIDY := clang-tidy-5.0
-
-OS:=$(shell uname -s)
-
-ifeq ($(OS),Linux)
- PTHREAD_FLAGS = -pthread
-endif
-
-ifeq ($(OS),Darwin)
- CXXFLAGS += -stdlib=libc++
- LDFLAGS += -stdlib=libc++
-endif
-
-TEST_CASES := $(wildcard test/t/*/test_cases.cpp)
-TEST_CASES_O := $(subst .cpp,.o,$(TEST_CASES))
-
-WRITER_TEST_CASES := $(wildcard test/t/*/writer_test_cases.cpp)
-WRITER_TEST_CASES_O := $(subst .cpp,.o,$(WRITER_TEST_CASES))
-
-PROTO_FILES := $(subst writer_test_cases.cpp,testcase.proto,$(WRITER_TEST_CASES))
-PROTO_FILES_CC := $(subst .proto,.pb.cc,$(PROTO_FILES))
-PROTO_FILES_H := $(subst .proto,.pb.h,$(PROTO_FILES))
-PROTO_FILES_O := $(subst .proto,.pb.o,$(PROTO_FILES))
-
-HPP_FILES := include/protozero/byteswap.hpp \
- include/protozero/config.hpp \
- include/protozero/exception.hpp \
- include/protozero/iterators.hpp \
- include/protozero/pbf_builder.hpp \
- include/protozero/pbf_message.hpp \
- include/protozero/pbf_reader.hpp \
- include/protozero/pbf_writer.hpp \
- include/protozero/types.hpp \
- include/protozero/varint.hpp \
- include/protozero/version.hpp
-
-DOC_FILES = doc/advanced.md doc/cheatsheet.md doc/tutorial.md
-
-CFLAGS_PROTOBUF := $(subst -I,-isystem ,$(shell pkg-config protobuf --cflags))
-LDFLAGS_PROTOBUF := $(shell pkg-config protobuf --libs-only-L)
-
-all: ./test/tests test/writer_tests
-
-TEST_INCLUDES := -Iinclude -Itest/include -isystem test/catch
-
-./test/t/%/test_cases.o: test/t/%/test_cases.cpp test/include/test.hpp test/include/scalar_access.hpp test/include/packed_access.hpp $(HPP_FILES)
- $(CXX) -c $(TEST_INCLUDES) $(CXXFLAGS) $(COMMON_FLAGS) $(DEBUG_FLAGS) $< -o $@
-
-./test/tests.o: test/tests.cpp $(HPP_FILES)
- $(CXX) -c $(TEST_INCLUDES) $(CXXFLAGS) $(COMMON_FLAGS) $(DEBUG_FLAGS) $< -o $@
-
-./test/tests: test/tests.o $(TEST_CASES_O)
- $(CXX) $(LDFLAGS) $^ -o $@
-
-./test/t/%/testcase.pb.cc: ./test/t/%/testcase.proto
- protoc --cpp_out=. $^
-
-./test/t/%/testcase.pb.o: ./test/t/%/testcase.pb.cc
- $(CXX) -c -I. $(TEST_INCLUDES) $(CXXFLAGS) $(CFLAGS_PROTOBUF) -std=c++11 $(DEBUG_FLAGS) $< -o $@
-
-./test/t/%/writer_test_cases.o: ./test/t/%/writer_test_cases.cpp $(HPP_FILES)
- $(CXX) -c -I. $(TEST_INCLUDES) $(CXXFLAGS) $(CFLAGS_PROTOBUF) $(COMMON_FLAGS) $(DEBUG_FLAGS) $< -o $@
-
-./test/writer_tests.o: test/writer_tests.cpp $(HPP_FILES) $(PROTO_FILES_CC)
- $(CXX) -c -I. $(TEST_INCLUDES) $(CXXFLAGS) $(COMMON_FLAGS) $(DEBUG_FLAGS) $< -o $@
-
-./test/writer_tests: test/writer_tests.o $(PROTO_FILES_O) $(WRITER_TEST_CASES_O)
- $(CXX) $(LDFLAGS) $(LDFLAGS_PROTOBUF) $^ -lprotobuf-lite $(PTHREAD_FLAGS) -o $@
-
-test: all
- ./test/tests
- ./test/writer_tests
-
-iwyu: $(HPP_FILES) test/tests.cpp test/writer_tests.cpp
- iwyu -Xiwyu -- -std=c++11 -Iinclude include/protozero/exception.hpp || true
- iwyu -Xiwyu -- -std=c++11 -Iinclude include/protozero/types.hpp || true
- iwyu -Xiwyu -- -std=c++11 -Iinclude include/protozero/varint.hpp || true
- iwyu -Xiwyu -- -std=c++11 -Iinclude include/protozero/pbf_reader.hpp || true
- iwyu -Xiwyu -- -std=c++11 -Iinclude include/protozero/pbf_writer.hpp || true
- iwyu -Xiwyu -- -std=c++11 $(TEST_INCLUDES) test/tests.cpp || true
- iwyu -Xiwyu -- -std=c++11 $(TEST_INCLUDES) test/writer_tests.cpp || true
-
-check: $(HPP_FILES) test/tests.cpp test/include/test.hpp test/include/testcase.hpp test/t/*/testcase.cpp $(TEST_CASES)
- cppcheck -Uassert --std=c++11 --enable=all --suppress=incorrectStringBooleanError $^
-
-doc: doc/Doxyfile README.md UPGRADING.md $(DOC_FILES) $(HPP_FILES)
- doxygen doc/Doxyfile
-
-clean:
- rm -f ./test/tests
- rm -f ./test/tests.o
- rm -f ./test/tests.gc*
- rm -f ./test/writer_tests
- rm -f ./test/writer_tests.o
- rm -f ./test/writer_tests.gc*
- rm -f ./test/t/*/testcase.pb.cc
- rm -f ./test/t/*/testcase.pb.h
- rm -f ./test/t/*/testcase.pb.o
- rm -f ./test/t/*/testcase.pb.gc*
- rm -f ./test/t/*/testcase.o
- rm -f ./test/t/*/testcase
- rm -f ./test/t/*/test_cases.o
- rm -f ./test/t/*/test_cases.gc*
- rm -f ./test/t/*/writer_test_cases.o
- rm -f ./test/t/*/writer_test_cases.gc*
- rm -f ./*.gcov
- rm -fr doc/doxygen_sqlite3.db doc/html coverage
-
-testpack:
- rm -f ./*tgz
- npm pack
- tar -ztvf *tgz
- rm -f ./*tgz
-
-install:
- install -m 0755 -o root -g root -d $(DESTDIR)/include/protozero
- install -m 0644 -o root -g root include/protozero/* $(DESTDIR)/include/protozero
-
-clang-tidy: clean
- bear make -j4 # create compile_commands.json compilation database
- # some checks disabled because they are too strict for our use case
- $(CLANG_TIDY) -header-filter='.*' -checks='*,-cppcoreguidelines-pro-bounds-pointer-arithmetic,-cppcoreguidelines-pro-type-reinterpret-cast,-google-runtime-references' $(TEST_CASES)
-
-.PHONY: all test iwyu check doc
-
diff --git a/README.md b/README.md
index 4aa57f2..42902b3 100644
--- a/README.md
+++ b/README.md
@@ -12,14 +12,15 @@ this approach offers no value: just use the C++ API that can be generated with
the Google Protobufs `protoc` program.
[](https://travis-ci.org/mapbox/protozero)
-[](https://ci.appveyor.com/project/Mapbox/protozero)
+[](https://ci.appveyor.com/project/Mapbox/protozero)
[](https://codecov.io/gh/mapbox/protozero)
## Depends
* C++11 compiler
-* Tests depend on the Google Protobuf library, but use of Protozero doesn't
- need it
+* CMake
+* Some tests depend on the Google Protobuf library, but use of Protozero
+ doesn't need it
## How it works
@@ -54,15 +55,9 @@ You have to have a working knowledge of how
* Read the [upgrading instructions](UPGRADING.md) if you are upgrading from
an older version of Protozero.
-Call `make doc` to build the Doxygen-based reference documentation. (You'll
-need [Doxygen](http://www.stack.nl/~dimitri/doxygen/) installed.) Then open
-`doc/html/index.html` in your browser to read it.
-
-
-## Installation
-
-Call `make install` to install include files in `/usr/include/protozero`. Call
-`make install DESTDIR=/usr/local` or similar to change install directory.
+The build process will also build the Doxygen-based reference documentation
+if you have [Doxygen](http://www.stack.nl/~dimitri/doxygen/) installed. Then
+open `doc/html/index.html` in your browser to read it.
## Endianness
@@ -73,63 +68,74 @@ case, please [open an issue](https://github.com/mapbox/protozero/issues) and
tell us about your system.
-## Tests
+## Building tests
-Extensive tests are included. Call
+Extensive tests are included. Build them using CMake:
- make test
-
-to build all tests and run them.
-
-See `test/README.md` for more details about the test.
+ mkdir build
+ cd build
+ cmake ..
+ make
-You can also use `gyp` to build the reader tests:
+Call `ctest` to run the tests.
- gyp gyp/protozero.gyp --depth=. --build=Release
- ./out/Release/tests
+The reader tests are always build, the writer tests are only build if the
+Google Protobuf library is found when running CMake.
-This will clobber the `Makefile` from the repository! Instead of `Release` you
-can use `Debug` for a debug build.
+See `test/README.md` for more details about the test.
## Coverage report
-To get a coverage report compile and link with `--coverage`:
+To get a coverage report set `CXXFLAGS` and `LDFLAGS` before calling CMake:
+
+ CXXFLAGS="--coverage" LDFLAGS="--coverage" cmake ..
- CXXFLAGS="--coverage" LDFLAGS="--coverage" make test
+Then call `make` as usual and run the tests using `ctest`.
If you are using `g++` use `gcov` to generate a report (results are in `*.gcov`
files):
- gcov -lp test/*tests.o test/t/*/*test_cases.o
+ gcov -lp $(find test/ -name '*.o')
If you are using `clang++` use `llvm-cov` instead:
- llvm-cov gcov -lp test/*tests.o test/t/*/*test_cases.o
+ llvm-cov gcov -lp $(find test/ -name '*.o')
If you are using `g++` you can use `gcovr` to generate nice HTML output:
mkdir -p coverage
- gcovr -r . --html --html-details -o coverage/index.html
+ gcovr . -r SRCDIR --html --html-details -o coverage/index.html
Open `coverage/index.html` in your browser to see the report.
## Clang-tidy
-Run
+After the CMake step, run
make clang-tidy
to check the code with [clang-tidy](https://clang.llvm.org/extra/clang-tidy/).
-You might have to change the `CLANG_TIDY` variable in the Makefile first.
+You might have to set `CLANG_TIDY` in CMake config.
## Cppcheck
-For extra checks with [Cppcheck](http://cppcheck.sourceforge.net/) you can call
+For extra checks with [Cppcheck](http://cppcheck.sourceforge.net/) you can,
+after the CMake step, call
+
+ make cppcheck
+
+
+## Installation
+
+After the CMake step, call `make install` to install the include files in
+`/usr/local/include/protozero`.
- make check
+If you are using CMake to build your own software, you can copy the file
+`cmake/FindProtozero.cmake` and use it in your build. See the file for
+details.
## Who is using Protozero?
diff --git a/UPGRADING.md b/UPGRADING.md
index 7b34d8e..9a5db8e 100644
--- a/UPGRADING.md
+++ b/UPGRADING.md
@@ -13,6 +13,20 @@ macro `PROTOZERO_STRICT_API` in which case Protozero will compile without the
code used for backwards compatibilty. You will then get compile errors for
older API usages.
+## Upgrading from *v1.5* to *v1.6.0*
+
+* The `data_view` class moved from `types.hpp` into its own header file
+ `data_view.hpp`. Most people should not include those headers directly,
+ but if you do, you might have to change your includes.
+* There are two new exceptions `invalid_tag_exception` and
+ `invalid_length_exception` which cover cases that were only checked by
+ `assert` before this version. If you catch specific exceptions in your code
+ you might have to amend it. But just catching `protozero::exception` is
+ usually fine for most code (if you catch exceptions at all).
+* The `pbf_reader` constructor taking a `std::pair` is now deprecated. If you
+ are compiling with `PROTOZERO_STRICT_API` it is not available any more. Use
+ one of the other constructors instead.
+
## Upgrading from *v1.4.5* to *v1.5.0*
* New functions for checking tag and type at the same time to make your
diff --git a/appveyor.yml b/appveyor.yml
index 80988cd..2770011 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -1,17 +1,53 @@
-os: Visual Studio 2015
+#-----------------------------------------------------------------------------
+#
+# Configuration for continuous integration service at appveyor.com
+#
+#-----------------------------------------------------------------------------
-platform:
- - x64
- - x86
+platform: x64
-configuration:
- - Debug
- - Release
+image: Visual Studio 2017
+
+clone_depth: 1
+
+#-----------------------------------------------------------------------------
+
+environment:
+ matrix:
+ - config: MSYS2
+ autocrlf: true
+ - config: Debug
+ autocrlf: true
+ - config: RelWithDebInfo
+ autocrlf: true
+ - config: Debug
+ autocrlf: false
+ - config: RelWithDebInfo
+ autocrlf: false
+
+#-----------------------------------------------------------------------------
+
+init:
+ - git config --global core.autocrlf %autocrlf%
+ - git config --get core.autocrlf
install:
- - CALL build-appveyor.bat
+ - if [%config%]==[MSYS2] (
+ C:\msys64\usr\bin\pacman --noconfirm --sync --refresh --refresh --sysupgrade --sysupgrade
+ && C:\msys64\usr\bin\pacman -Rc --noconfirm mingw-w64-x86_64-gcc-libs
+ )
+
+build_script:
+ - if [%config%]==[MSYS2] (
+ build-msys2.bat
+ ) else (
+ build-appveyor.bat
+ )
+
+# remove garbage VS messages
+# http://help.appveyor.com/discussions/problems/4569-the-target-_convertpdbfiles-listed-in-a-beforetargets-attribute-at-c-does-not-exist-in-the-project-and-will-be-ignored
+before_build:
+ - del "C:\Program Files (x86)\MSBuild\14.0\Microsoft.Common.targets\ImportAfter\Xamarin.Common.targets"
+
-build: off
-test: off
-deploy: off
-#test
+#-----------------------------------------------------------------------------
diff --git a/build-appveyor.bat b/build-appveyor.bat
index d21177c..76e848c 100644
--- a/build-appveyor.bat
+++ b/build-appveyor.bat
@@ -2,35 +2,14 @@
SETLOCAL
SET EL=0
-ECHO =========== %~f0 ===========
+ECHO ~~~~~~ %~f0 ~~~~~~
-ECHO platform^: %platform%
-ECHO configuration^: %configuration%
+::show all available env vars
+SET
+ECHO cmake on AppVeyor
+cmake -version
-SET MSBUILD_VERBOSITY=normal
-IF NOT "%1"=="" SET MSBUILD_VERBOSITY=%1
-ECHO MSBUILD_VERBOSITY^: %MSBUILD_VERBOSITY%
-
-SET PATH=C:\Program Files\7-Zip;%PATH%
-SET PATH=c:\python27;%PATH%
-SET PATH="C:\Program Files (x86)\MSBuild\14.0\bin";%PATH%
-SET PATH=%~dp0deps\protobuf;%PATH%
-
-REM add unix style "find" to front of PATH
-REM used to glob files in gyp
-IF DEFINED APPVEYOR SET PATH=C:\Program Files\Git\usr\bin;%PATH%
-IF NOT DEFINED APPVEYOR SET PATH=%GIT_INSTALL_ROOT%\bin;%PATH%
-WHERE find
-
-IF EXIST %configuration% ECHO deleting %configuration% && RD /Q /S %configuration%
-IF %ERRORLEVEL% NEQ 0 GOTO ERROR
-
-IF EXIST protozero.sln DEL protozero.sln
-IF EXIST protozero.sdf DEL protozero.sdf
-DEL *.vcxproj
-DEL *.vcxproj.filters
-
-IF exist deps\gyp (ECHO gyp already cloned) ELSE (git clone --quiet --depth 1 https://chromium.googlesource.com/external/gyp.git deps/gyp)
+ECHO activating VS cmd prompt && CALL "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" amd64
IF %ERRORLEVEL% NEQ 0 GOTO ERROR
SET protobuf_sdk=protozero-dep-protobuf-2.6.1.7z
@@ -38,42 +17,49 @@ IF EXIST %protobuf_sdk% (ECHO protobuf already downloaded) ELSE (ECHO downloadin
IF %ERRORLEVEL% NEQ 0 GOTO ERROR
IF EXIST deps\protobuf (ECHO protobuf already extracted) ELSE (CALL 7z x -y %protobuf_sdk% | %windir%\system32\FIND "ing archive")
IF %ERRORLEVEL% NEQ 0 GOTO ERROR
+SET PATH=%~dp0deps\protobuf;%PATH%
-FOR /F %%x in ('find test/ -name "testcase.proto"') DO "deps\protobuf\%platform%\%configuration%\protoc" --cpp_out=. %%x
+IF EXIST build ECHO deleting build dir... && RD /Q /S build
IF %ERRORLEVEL% NEQ 0 GOTO ERROR
-REM note windows requires --generator-output to be absolute
-python deps/gyp/gyp_main.py gyp/protozero.gyp --depth=. -f msvs -G msvs_version=2015
+MKDIR build
IF %ERRORLEVEL% NEQ 0 GOTO ERROR
-SET MSBUILD_PLATFORM=%platform%
-IF /I "%MSBUILD_PLATFORM%" == "x86" set MSBUILD_PLATFORM=Win32
+CD build
+ECHO config^: %config%
+
+::This will produce lots of LNK4099 warnings which can be ignored.
+::Unfortunately they can't be disabled, see
+::http://stackoverflow.com/questions/661606/visual-c-how-to-disable-specific-linker-warnings
+SET CMAKE_CMD=cmake .. ^
+-LA -G "Visual Studio 14 Win64"
-msbuild gyp/protozero.sln ^
-/nologo ^
-/maxcpucount:%NUMBER_OF_PROCESSORS% ^
-/p:BuildInParellel=true ^
-/p:Configuration=%configuration%;Platform=%MSBUILD_PLATFORM% ^
-/verbosity:%MSBUILD_VERBOSITY% ^
-/consoleloggerparameters:Summary
+ECHO calling^: %CMAKE_CMD%
+%CMAKE_CMD%
IF %ERRORLEVEL% NEQ 0 GOTO ERROR
-ECHO running gyp\%configuration%\%platform%\tests.exe ...
-gyp\%configuration%\%platform%\tests.exe
-:: IF %ERRORLEVEL% NEQ 0 GOTO ERROR
+SET avlogger=
+IF /I "%APPVEYOR%"=="True" SET avlogger=/logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll"
+
+msbuild protozero.sln ^
+/p:Configuration=%config% ^
+/toolsversion:14.0 ^
+/p:Platform=x64 ^
+/p:PlatformToolset=v140 %avlogger%
+IF %ERRORLEVEL% NEQ 0 GOTO ERROR
-ECHO running gyp\%configuration%\%platform%\writer_tests.exe ...
-gyp\%configuration%\%platform%\writer_tests.exe
+ctest --output-on-failure ^
+-C %config% ^
IF %ERRORLEVEL% NEQ 0 GOTO ERROR
GOTO DONE
:ERROR
-ECHO ~~~~~~~~~ ERROR %~f0 ~~~~~~~~~~~
+ECHO ~~~~~~ ERROR %~f0 ~~~~~~
SET EL=%ERRORLEVEL%
-ECHO ERRORLEVEL^: %EL%
:DONE
+IF %EL% NEQ 0 ECHO. && ECHO !!! ERRORLEVEL^: %EL% !!! && ECHO.
+ECHO ~~~~~~ DONE %~f0 ~~~~~~
-ECHO DONE %~f0 %platform% %configuration%
-EXIT /B %EL%
+EXIT /b %EL%
diff --git a/build-msys2.bat b/build-msys2.bat
new file mode 100644
index 0000000..85a4e03
--- /dev/null
+++ b/build-msys2.bat
@@ -0,0 +1,18 @@
+echo "Adding MSYS2 to path..."
+SET "PATH=C:\msys64\mingw64\bin;C:\msys64\usr\bin;%PATH%"
+echo %PATH%
+
+echo "Installing MSYS2 packages..."
+bash -lc "pacman -S --needed --noconfirm mingw-w64-x86_64-gcc mingw-w64-x86_64-cmake mingw-w64-x86_64-doxygen mingw-w64-x86_64-protobuf"
+
+echo "Generating makefiles"
+mkdir build
+cd build
+cmake .. -G "MSYS Makefiles"
+
+echo "Building"
+make
+
+echo "Testing"
+ctest
+
diff --git a/cmake/FindProtozero.cmake b/cmake/FindProtozero.cmake
new file mode 100644
index 0000000..175dd23
--- /dev/null
+++ b/cmake/FindProtozero.cmake
@@ -0,0 +1,63 @@
+#----------------------------------------------------------------------
+#
+# FindProtozero.cmake
+#
+# Find the protozero headers.
+#
+#----------------------------------------------------------------------
+#
+# Usage:
+#
+# Copy this file somewhere into your project directory, where cmake can
+# find it. Usually this will be a directory called "cmake" which you can
+# add to the CMake module search path with the following line in your
+# CMakeLists.txt:
+#
+# list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
+#
+# Then add the following in your CMakeLists.txt:
+#
+# find_package(Protozero [version] [REQUIRED])
+# include_directories(SYSTEM ${PROTOZERO_INCLUDE_DIR})
+#
+# The version number is optional. If it is not set, any version of
+# protozero will do.
+#
+# if(NOT PROTOZERO_FOUND)
+# message(WARNING "Protozero not found!\n")
+# endif()
+#
+#----------------------------------------------------------------------
+#
+# Variables:
+#
+# PROTOZERO_FOUND - True if Protozero was found.
+# PROTOZERO_INCLUDE_DIR - Where to find include files.
+#
+#----------------------------------------------------------------------
+
+# find include path
+find_path(PROTOZERO_INCLUDE_DIR protozero/version.hpp
+ PATH_SUFFIXES include
+ PATHS ../protozero
+)
+
+# Check version number
+if(Protozero_FIND_VERSION)
+ file(STRINGS "${PROTOZERO_INCLUDE_DIR}/protozero/version.hpp" _version_define REGEX "#define PROTOZERO_VERSION_STRING")
+ if("${_version_define}" MATCHES "#define PROTOZERO_VERSION_STRING \"([0-9.]+)\"")
+ set(_version "${CMAKE_MATCH_1}")
+ else()
+ set(_version "unknown")
+ endif()
+endif()
+
+#set(PROTOZERO_INCLUDE_DIRS "${PROTOZERO_INCLUDE_DIR}")
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(Protozero
+ REQUIRED_VARS PROTOZERO_INCLUDE_DIR
+ VERSION_VAR _version)
+
+
+#----------------------------------------------------------------------
diff --git a/doc/.gitignore b/doc/.gitignore
deleted file mode 100644
index 03c8987..0000000
--- a/doc/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-doxygen_sqlite3.db
-html
diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt
new file mode 100644
index 0000000..77c5420
--- /dev/null
+++ b/doc/CMakeLists.txt
@@ -0,0 +1,37 @@
+#-----------------------------------------------------------------------------
+#
+# CMake Config
+#
+# protozero documentation
+#
+#-----------------------------------------------------------------------------
+
+message(STATUS "Configuring documentation")
+
+message(STATUS "Looking for doxygen")
+find_package(Doxygen)
+
+if(DOXYGEN_FOUND)
+ message(STATUS "Looking for doxygen - found")
+ configure_file(Doxyfile.in ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile @ONLY)
+
+ file(GLOB HEADER_FILES "${CMAKE_SOURCE_DIR}/include/protozero/*.hpp")
+ add_custom_command(OUTPUT html/index.html
+ COMMAND ${DOXYGEN_EXECUTABLE}
+ ARGS ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile
+ DEPENDS Doxyfile.in advanced.md cheatsheet.md tutorial.md
+ ${HEADER_FILES}
+ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
+ COMMENT "Generating API documentation with Doxygen" VERBATIM)
+ add_custom_target(doc ALL
+ DEPENDS html/index.html)
+else()
+ message(STATUS "Looking for doxygen - not found")
+ message(STATUS " Disabled making of documentation.")
+endif()
+
+#-----------------------------------------------------------------------------
+message(STATUS "Configuring documentation - done")
+
+
+#-----------------------------------------------------------------------------
diff --git a/doc/Doxyfile b/doc/Doxyfile.in
similarity index 99%
rename from doc/Doxyfile
rename to doc/Doxyfile.in
index d0a076c..1481905 100644
--- a/doc/Doxyfile
+++ b/doc/Doxyfile.in
@@ -38,7 +38,7 @@ PROJECT_NAME = "protozero"
# could be handy for archiving the generated documentation or if some version
# control system is used.
-PROJECT_NUMBER =
+PROJECT_NUMBER = @PROTOZERO_VERSION@
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
@@ -58,7 +58,7 @@ PROJECT_LOGO =
# entered, it will be relative to the location where doxygen was started. If
# left blank the current directory will be used.
-OUTPUT_DIRECTORY = doc
+OUTPUT_DIRECTORY = "@PROJECT_BINARY_DIR@/doc"
# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub-
# directories (in 2 levels) under the output directory of each output format and
@@ -152,7 +152,7 @@ FULL_PATH_NAMES = YES
# will be relative from the directory where doxygen is started.
# This tag requires that the tag FULL_PATH_NAMES is set to YES.
-STRIP_FROM_PATH =
+STRIP_FROM_PATH = @PROJECT_SOURCE_DIR@
# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
# path mentioned in the documentation of a class, which tells the reader which
@@ -753,7 +753,10 @@ WARN_LOGFILE =
# spaces.
# Note: If this tag is empty the current directory is searched.
-INPUT = README.md UPGRADING.md doc include/protozero
+INPUT = @PROJECT_SOURCE_DIR@/README.md \
+ @PROJECT_SOURCE_DIR@/UPGRADING.md \
+ @PROJECT_SOURCE_DIR@/doc \
+ @PROJECT_SOURCE_DIR@/include/protozero
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
@@ -889,7 +892,7 @@ FILTER_SOURCE_PATTERNS =
# (index.html). This can be useful if you have a project on for instance GitHub
# and want to reuse the introduction page also for the doxygen output.
-USE_MDFILE_AS_MAINPAGE = README.md
+USE_MDFILE_AS_MAINPAGE = @PROJECT_SOURCE_DIR@/README.md
#---------------------------------------------------------------------------
# Configuration options related to source browsing
diff --git a/doc/tutorial.md b/doc/tutorial.md
index 9525343..cccb69a 100644
--- a/doc/tutorial.md
+++ b/doc/tutorial.md
@@ -277,6 +277,18 @@ Protocol Buffers implementation.
This exception indicates an illegal encoding of a varint. It means your input
data is corrupted in some way.
+#### `invalid_tag_exception`
+
+This exception is thrown when a tag has an invalid value. Tags must be
+unsigned integers between 1 and 2^29-1. Tags between 19000 and 19999 are not
+allowed. See
+https://developers.google.com/protocol-buffers/docs/proto#assigning-tags
+
+#### `invalid_length_exception`
+
+This exception is thrown when a length field of a packed repeated field is
+invalid. For fixed size types the length must be a multiple of the size of
+the type.
### The `pbf_reader` class
diff --git a/gyp/common.gypi b/gyp/common.gypi
deleted file mode 100644
index 2e329aa..0000000
--- a/gyp/common.gypi
+++ /dev/null
@@ -1,109 +0,0 @@
-{
- "conditions": [
- ["OS=='win'", {
- "target_defaults": {
- "default_configuration": "Release_x64",
- "msvs_configuration_attributes": {
- "OutputDirectory": "$(SolutionDir)$(Configuration)\\$(PlatformTarget)\\",
- },
- "msvs_settings": {
- "VCCLCompilerTool": {
- "ExceptionHandling": 1, # /EHsc
- "RuntimeTypeInfo": "true", # /GR
- "ObjectFile": "$(SolutionDir)$(Configuration)\\$(PlatformTarget)\\%(RelativeDir)",
- }
- },
- "configurations": {
- "Debug_Win32": {
- "msvs_configuration_platform": "Win32",
- "defines": [ "DEBUG","_DEBUG"],
- "msvs_settings": {
- "VCCLCompilerTool": {
- "RuntimeLibrary": "3", #0:static release /MT, 1:static debug /MTd, 2:shared /MD, 3:shared debug /MDd
- "Optimization": 0, # /Od, no optimization
- "MinimalRebuild": "false",
- "OmitFramePointers": "false",
- "BasicRuntimeChecks": 3 # /RTC1
- }
- }
- },
- "Debug_x64": {
- 'inherit_from': ['Debug_Win32'],
- "msvs_configuration_platform": "x64",
- },
- "Release_Win32": {
- "msvs_configuration_platform": "Win32",
- "defines": [ "NDEBUG"],
- "msvs_settings": {
- "VCCLCompilerTool": {
- "RuntimeLibrary": "2", #0:static release /MT, 1:static debug /MTd, 2:shared /MD, 3:shared debug /MDd
- "Optimization": 3, # /Ox, full optimization
- "FavorSizeOrSpeed": 1, # /Ot, favour speed over size
- "InlineFunctionExpansion": 2, # /Ob2, inline anything eligible
- "WholeProgramOptimization": "true", # /GL, whole program optimization, needed for LTCG
- "OmitFramePointers": "true",
- "EnableFunctionLevelLinking": "true",
- "EnableIntrinsicFunctions": "true",
- #"AdditionalOptions": [
- # "/MP", # compile across multiple CPUs
- #],
- "DebugInformationFormat": "0"
- },
- "VCLibrarianTool": {
- "AdditionalOptions": [
- "/LTCG" # link time code generation
- ],
- },
- "VCLinkerTool": {
- "LinkTimeCodeGeneration": 1, # link-time code generation
- "OptimizeReferences": 2, # /OPT:REF
- "EnableCOMDATFolding": 2, # /OPT:ICF
- "LinkIncremental": 1, # disable incremental linking
- "GenerateDebugInformation": "false"
- }
- }
- },
- "Release_x64": {
- 'inherit_from': ['Release_Win32'],
- "msvs_configuration_platform": "x64",
- }
- }
- }
- }, {
- "target_defaults": {
- "default_configuration": "Release",
- "xcode_settings": {
- "CLANG_CXX_LIBRARY": "libc++",
- "CLANG_CXX_LANGUAGE_STANDARD":"c++11",
- "GCC_VERSION": "com.apple.compilers.llvm.clang.1_0",
- },
- "cflags_cc": ["-std=c++11"],
- "configurations": {
- "Debug": {
- "defines": [
- "DEBUG"
- ],
- "xcode_settings": {
- "GCC_OPTIMIZATION_LEVEL": "0",
- "GCC_GENERATE_DEBUGGING_SYMBOLS": "YES",
- "OTHER_CPLUSPLUSFLAGS": [ "-Wall", "-Wextra", "-pedantic", "-g", "-O0" ]
- }
- },
- "Release": {
- "defines": [
- "NDEBUG"
- ],
- "xcode_settings": {
- "GCC_OPTIMIZATION_LEVEL": "3",
- "GCC_GENERATE_DEBUGGING_SYMBOLS": "NO",
- "DEAD_CODE_STRIPPING": "YES",
- "GCC_INLINES_ARE_PRIVATE_EXTERN": "YES",
- "OTHER_CPLUSPLUSFLAGS": [ "-Wall", "-Wextra", "-pedantic", "-O3" ]
- }
- }
- }
- }
- }]
- ]
-}
-
diff --git a/gyp/protozero.gyp b/gyp/protozero.gyp
deleted file mode 100644
index 0802f21..0000000
--- a/gyp/protozero.gyp
+++ /dev/null
@@ -1,39 +0,0 @@
-{
- "includes": [
- "common.gypi"
- ],
- "targets": [
- {
- "target_name": "tests",
- "type": "executable",
- "sources": [
- "<!@(find ../test/ -name '*.cpp' ! -name 'writer_tests.cpp' ! -name 'writer_test_cases.cpp' ! -name 'testcase.cpp')"
- ],
- "include_dirs": [
- "../include/",
- "../test/include/",
- "../test/catch/"
- ]
- },
- {
- "target_name": "writer_tests",
- "type": "executable",
- "sources": [
- "../test/writer_tests.cpp",
- "<!@(find ../test/ -name 'writer_test_cases.cpp')",
- "<!@(find ../include/protozero/ -name '*.hpp' ! -name 'config.hpp' ! -name 'pbf_builder.hpp' ! -name 'pbf_message.hpp' ! -name 'version.hpp')",
- "<!@(find ../test/ -name '*.pb.cc')",
- ],
- "include_dirs": [
- "../",
- "../include/",
- "../test/include/",
- "../test/catch/",
- "../deps/protobuf/include"
- ],
- "libraries" : [
- "../deps/protobuf/$(PlatformTarget)/$(Configuration)/libprotobuf-lite.lib"
- ]
- }
- ]
-}
diff --git a/include/protozero/types.hpp b/include/protozero/data_view.hpp
similarity index 62%
copy from include/protozero/types.hpp
copy to include/protozero/data_view.hpp
index 576c2e2..144025d 100644
--- a/include/protozero/types.hpp
+++ b/include/protozero/data_view.hpp
@@ -1,5 +1,5 @@
-#ifndef PROTOZERO_TYPES_HPP
-#define PROTOZERO_TYPES_HPP
+#ifndef PROTOZERO_DATA_VIEW_HPP
+#define PROTOZERO_DATA_VIEW_HPP
/*****************************************************************************
@@ -11,14 +11,13 @@ documentation.
*****************************************************************************/
/**
- * @file types.hpp
+ * @file data_view.hpp
*
- * @brief Contains the declaration of low-level types used in the pbf format.
+ * @brief Contains the implementation of the data_view class.
*/
#include <algorithm>
#include <cstddef>
-#include <cstdint>
#include <cstring>
#include <string>
#include <utility>
@@ -27,41 +26,6 @@ documentation.
namespace protozero {
-/**
- * The type used for field tags (field numbers).
- */
-using pbf_tag_type = uint32_t;
-
-/**
- * The type used to encode type information.
- * See the table on
- * https://developers.google.com/protocol-buffers/docs/encoding
- */
-enum class pbf_wire_type : uint32_t {
- varint = 0, // int32/64, uint32/64, sint32/64, bool, enum
- fixed64 = 1, // fixed64, sfixed64, double
- length_delimited = 2, // string, bytes, embedded messages,
- // packed repeated fields
- fixed32 = 5, // fixed32, sfixed32, float
- unknown = 99 // used for default setting in this library
-};
-
-/**
- * Get the tag and wire type of the current field in one integer suitable
- * for comparison with a switch statement.
- *
- * See pbf_reader.tag_and_type() for an example how to use this.
- */
-template <typename T>
-constexpr inline uint32_t tag_and_type(T tag, pbf_wire_type wire_type) noexcept {
- return (static_cast<uint32_t>(static_cast<pbf_tag_type>(tag)) << 3) | static_cast<uint32_t>(wire_type);
-}
-
-/**
- * The type used for length values, such as the length of a field.
- */
-using pbf_length_type = uint32_t;
-
#ifdef PROTOZERO_USE_VIEW
using data_view = PROTOZERO_USE_VIEW;
#else
@@ -141,6 +105,7 @@ public:
return m_size == 0;
}
+#ifndef PROTOZERO_STRICT_API
/**
* Convert data view to string.
*
@@ -154,6 +119,7 @@ public:
protozero_assert(m_data);
return {m_data, m_size};
}
+#endif
/**
* Convert data view to string.
@@ -165,6 +131,29 @@ public:
return {m_data, m_size};
}
+ /**
+ * Compares the contents of this object with the given other object.
+ *
+ * @returns 0 if they are the same, <0 if this object is smaller than
+ * the other or >0 if it is larger. If both objects have the
+ * same size returns <0 if this object is lexicographically
+ * before the other, >0 otherwise.
+ *
+ * @pre Must not be default constructed data_view.
+ */
+ int compare(data_view other) const {
+ protozero_assert(m_data && other.m_data);
+ const int cmp = std::memcmp(data(), other.data(),
+ std::min(size(), other.size()));
+ if (cmp == 0) {
+ if (size() == other.size()) {
+ return 0;
+ }
+ return size() < other.size() ? -1 : 1;
+ }
+ return cmp;
+ }
+
}; // class data_view
/**
@@ -184,8 +173,9 @@ inline void swap(data_view& lhs, data_view& rhs) noexcept {
* @param lhs First object.
* @param rhs Second object.
*/
-inline bool operator==(const data_view& lhs, const data_view& rhs) noexcept {
- return lhs.size() == rhs.size() && std::equal(lhs.data(), lhs.data() + lhs.size(), rhs.data());
+inline constexpr bool operator==(const data_view lhs, const data_view rhs) noexcept {
+ return lhs.size() == rhs.size() &&
+ std::equal(lhs.data(), lhs.data() + lhs.size(), rhs.data());
}
/**
@@ -195,13 +185,52 @@ inline bool operator==(const data_view& lhs, const data_view& rhs) noexcept {
* @param lhs First object.
* @param rhs Second object.
*/
-inline bool operator!=(const data_view& lhs, const data_view& rhs) noexcept {
+inline constexpr bool operator!=(const data_view lhs, const data_view rhs) noexcept {
return !(lhs == rhs);
}
-#endif
+/**
+ * Returns true if lhs.compare(rhs) < 0.
+ *
+ * @param lhs First object.
+ * @param rhs Second object.
+ */
+inline bool operator<(const data_view lhs, const data_view rhs) noexcept {
+ return lhs.compare(rhs) < 0;
+}
+/**
+ * Returns true if lhs.compare(rhs) <= 0.
+ *
+ * @param lhs First object.
+ * @param rhs Second object.
+ */
+inline bool operator<=(const data_view lhs, const data_view rhs) noexcept {
+ return lhs.compare(rhs) <= 0;
+}
+
+/**
+ * Returns true if lhs.compare(rhs) > 0.
+ *
+ * @param lhs First object.
+ * @param rhs Second object.
+ */
+inline bool operator>(const data_view lhs, const data_view rhs) noexcept {
+ return lhs.compare(rhs) > 0;
+}
+
+/**
+ * Returns true if lhs.compare(rhs) >= 0.
+ *
+ * @param lhs First object.
+ * @param rhs Second object.
+ */
+inline bool operator>=(const data_view lhs, const data_view rhs) noexcept {
+ return lhs.compare(rhs) >= 0;
+}
+
+#endif
} // end namespace protozero
-#endif // PROTOZERO_TYPES_HPP
+#endif // PROTOZERO_DATA_VIEW_HPP
diff --git a/include/protozero/exception.hpp b/include/protozero/exception.hpp
index ca4340e..8a20c94 100644
--- a/include/protozero/exception.hpp
+++ b/include/protozero/exception.hpp
@@ -63,6 +63,27 @@ struct end_of_buffer_exception : exception {
const char* what() const noexcept override { return "end of buffer exception"; }
};
+/**
+ * This exception is thrown when a tag has an invalid value. Tags must be
+ * unsigned integers between 1 and 2^29-1. Tags between 19000 and 19999 are
+ * not allowed. See
+ * https://developers.google.com/protocol-buffers/docs/proto#assigning-tags
+ */
+struct invalid_tag_exception : exception {
+ /// Returns the explanatory string.
+ const char* what() const noexcept override { return "invalid tag exception"; }
+};
+
+/**
+ * This exception is thrown when a length field of a packed repeated field is
+ * invalid. For fixed size types the length must be a multiple of the size of
+ * the type.
+ */
+struct invalid_length_exception : exception {
+ /// Returns the explanatory string.
+ const char* what() const noexcept override { return "invalid length exception"; }
+};
+
} // end namespace protozero
#endif // PROTOZERO_EXCEPTION_HPP
diff --git a/include/protozero/iterators.hpp b/include/protozero/iterators.hpp
index f8247a4..30bd7d6 100644
--- a/include/protozero/iterators.hpp
+++ b/include/protozero/iterators.hpp
@@ -105,7 +105,7 @@ public:
* Complexity: Constant or linear depending on the underlaying iterator.
*/
std::size_t size() const noexcept {
- return begin().size();
+ return T::range_size(begin(), end());
}
/**
@@ -162,9 +162,6 @@ class const_fixed_iterator {
/// Pointer to current iterator position
const char* m_data = nullptr;
- /// Pointer to end iterator position
- const char* m_end = nullptr;
-
public:
using iterator_category = std::forward_iterator_tag;
@@ -173,11 +170,14 @@ public:
using pointer = value_type*;
using reference = value_type&;
+ static std::size_t range_size(const const_fixed_iterator& begin, const const_fixed_iterator& end) noexcept {
+ return static_cast<std::size_t>(end.m_data - begin.m_data) / sizeof(T);
+ }
+
const_fixed_iterator() noexcept = default;
- const_fixed_iterator(const char* data, const char* end) noexcept :
- m_data(data),
- m_end(end) {
+ explicit const_fixed_iterator(const char* data) noexcept :
+ m_data(data) {
}
const_fixed_iterator(const const_fixed_iterator&) noexcept = default;
@@ -203,17 +203,13 @@ public:
}
const_fixed_iterator operator++(int) {
- const const_fixed_iterator tmp(*this);
+ const const_fixed_iterator tmp{*this};
++(*this);
return tmp;
}
- std::size_t size() const noexcept {
- return static_cast<std::size_t>(m_end - m_data) / sizeof(T);
- }
-
bool operator==(const const_fixed_iterator& rhs) const noexcept {
- return m_data == rhs.m_data && m_end == rhs.m_end;
+ return m_data == rhs.m_data;
}
bool operator!=(const const_fixed_iterator& rhs) const noexcept {
@@ -245,6 +241,15 @@ public:
using pointer = value_type*;
using reference = value_type&;
+ static std::size_t range_size(const const_varint_iterator& begin, const const_varint_iterator& end) noexcept {
+ // We know that each varint contains exactly one byte with the most
+ // significant bit not set. We can use this to quickly figure out
+ // how many varints there are without actually decoding the varints.
+ return static_cast<std::size_t>(std::count_if(begin.m_data, end.m_data, [](char c) {
+ return (static_cast<unsigned char>(c) & 0x80) == 0;
+ }));
+ }
+
const_varint_iterator() noexcept = default;
const_varint_iterator(const char* data, const char* end) noexcept :
@@ -271,20 +276,11 @@ public:
}
const_varint_iterator operator++(int) {
- const const_varint_iterator tmp(*this);
+ const const_varint_iterator tmp{*this};
++(*this);
return tmp;
}
- std::size_t size() const noexcept {
- // We know that each varint contains exactly one byte with the most
- // significant bit not set. We can use this to quickly figure out
- // how many varints there are without actually decoding the varints.
- return static_cast<std::size_t>(std::count_if(m_data, m_end, [](char c) {
- return (static_cast<unsigned char>(c) & 0x80) == 0;
- }));
- }
-
bool operator==(const const_varint_iterator& rhs) const noexcept {
return m_data == rhs.m_data && m_end == rhs.m_end;
}
@@ -337,7 +333,7 @@ public:
}
const_svarint_iterator operator++(int) {
- const const_svarint_iterator tmp(*this);
+ const const_svarint_iterator tmp{*this};
++(*this);
return tmp;
}
diff --git a/include/protozero/pbf_reader.hpp b/include/protozero/pbf_reader.hpp
index 5efdebb..aea7015 100644
--- a/include/protozero/pbf_reader.hpp
+++ b/include/protozero/pbf_reader.hpp
@@ -23,6 +23,7 @@ documentation.
#include <utility>
#include <protozero/config.hpp>
+#include <protozero/data_view.hpp>
#include <protozero/exception.hpp>
#include <protozero/iterators.hpp>
#include <protozero/types.hpp>
@@ -75,8 +76,9 @@ class pbf_reader {
template <typename T>
T get_fixed() {
T result;
+ const char* data = m_data;
skip_bytes(sizeof(T));
- std::memcpy(&result, m_data - sizeof(T), sizeof(T));
+ std::memcpy(&result, data, sizeof(T));
#if PROTOZERO_BYTE_ORDER != PROTOZERO_LITTLE_ENDIAN
detail::byteswap_inplace(&result);
#endif
@@ -87,9 +89,11 @@ class pbf_reader {
iterator_range<const_fixed_iterator<T>> packed_fixed() {
protozero_assert(tag() != 0 && "call next() before accessing field value");
const auto len = get_len_and_skip();
- protozero_assert(len % sizeof(T) == 0);
- return {const_fixed_iterator<T>(m_data - len, m_data),
- const_fixed_iterator<T>(m_data, m_data)};
+ if (len % sizeof(T) != 0) {
+ throw invalid_length_exception{};
+ }
+ return {const_fixed_iterator<T>(m_data - len),
+ const_fixed_iterator<T>(m_data)};
}
template <typename T>
@@ -166,6 +170,7 @@ public:
m_end(data + size) {
}
+#ifndef PROTOZERO_STRICT_API
/**
* Construct a pbf_reader message from a data pointer and a length. The
* pointer will be stored inside the pbf_reader object, no data is copied.
@@ -175,11 +180,13 @@ public:
* The buffer must contain a complete protobuf message.
*
* @post There is no current field.
+ * @deprecated Use one of the other constructors.
*/
explicit pbf_reader(const std::pair<const char*, std::size_t>& data) noexcept
: m_data(data.first),
m_end(data.first + data.second) {
}
+#endif
/**
* Construct a pbf_reader message from a std::string. A pointer to the
@@ -275,9 +282,10 @@ public:
m_tag = pbf_tag_type(value >> 3);
// tags 0 and 19000 to 19999 are not allowed as per
- // https://developers.google.com/protocol-buffers/docs/proto
- protozero_assert(((m_tag > 0 && m_tag < 19000) ||
- (m_tag > 19999 && m_tag <= ((1 << 29) - 1))) && "tag out of range");
+ // https://developers.google.com/protocol-buffers/docs/proto#assigning-tags
+ if (m_tag == 0 || (m_tag >= 19000 && m_tag <= 19999)) {
+ throw invalid_tag_exception{};
+ }
m_wire_type = pbf_wire_type(value & 0x07);
switch (m_wire_type) {
@@ -459,7 +467,7 @@ public:
skip_bytes(4);
break;
default:
- protozero_assert(false && "can not be here because next() should have thrown already");
+ break;
}
}
@@ -478,9 +486,9 @@ public:
bool get_bool() {
protozero_assert(tag() != 0 && "call next() before accessing field value");
protozero_assert(has_wire_type(pbf_wire_type::varint) && "not a varint");
- protozero_assert((*m_data & 0x80) == 0 && "not a 1 byte varint");
- skip_bytes(1);
- return m_data[-1] != 0; // -1 okay because we incremented m_data the line before
+ const auto data = m_data;
+ skip_varint(&m_data, m_end);
+ return data[0] != 0;
}
/**
diff --git a/include/protozero/pbf_writer.hpp b/include/protozero/pbf_writer.hpp
index c50a46d..edf5522 100644
--- a/include/protozero/pbf_writer.hpp
+++ b/include/protozero/pbf_writer.hpp
@@ -26,6 +26,7 @@ documentation.
#include <utility>
#include <protozero/config.hpp>
+#include <protozero/data_view.hpp>
#include <protozero/types.hpp>
#include <protozero/varint.hpp>
diff --git a/include/protozero/types.hpp b/include/protozero/types.hpp
index 576c2e2..0d810e9 100644
--- a/include/protozero/types.hpp
+++ b/include/protozero/types.hpp
@@ -62,146 +62,6 @@ constexpr inline uint32_t tag_and_type(T tag, pbf_wire_type wire_type) noexcept
*/
using pbf_length_type = uint32_t;
-#ifdef PROTOZERO_USE_VIEW
-using data_view = PROTOZERO_USE_VIEW;
-#else
-
-/**
- * Holds a pointer to some data and a length.
- *
- * This class is supposed to be compatible with the std::string_view
- * that will be available in C++17.
- */
-class data_view {
-
- const char* m_data = nullptr;
- std::size_t m_size = 0;
-
-public:
-
- /**
- * Default constructor. Construct an empty data_view.
- */
- constexpr data_view() noexcept = default;
-
- /**
- * Create data_view from pointer and size.
- *
- * @param ptr Pointer to the data.
- * @param length Length of the data.
- */
- constexpr data_view(const char* ptr, std::size_t length) noexcept
- : m_data(ptr),
- m_size(length) {
- }
-
- /**
- * Create data_view from string.
- *
- * @param str String with the data.
- */
- data_view(const std::string& str) noexcept // NOLINT clang-tidy: google-explicit-constructor
- : m_data(str.data()),
- m_size(str.size()) {
- }
-
- /**
- * Create data_view from zero-terminated string.
- *
- * @param ptr Pointer to the data.
- */
- data_view(const char* ptr) noexcept // NOLINT clang-tidy: google-explicit-constructor
- : m_data(ptr),
- m_size(std::strlen(ptr)) {
- }
-
- /**
- * Swap the contents of this object with the other.
- *
- * @param other Other object to swap data with.
- */
- void swap(data_view& other) noexcept {
- using std::swap;
- swap(m_data, other.m_data);
- swap(m_size, other.m_size);
- }
-
- /// Return pointer to data.
- constexpr const char* data() const noexcept {
- return m_data;
- }
-
- /// Return length of data in bytes.
- constexpr std::size_t size() const noexcept {
- return m_size;
- }
-
- /// Returns true if size is 0.
- constexpr bool empty() const noexcept {
- return m_size == 0;
- }
-
- /**
- * Convert data view to string.
- *
- * @pre Must not be default constructed data_view.
- *
- * @deprecated to_string() is not available in C++17 string_view so it
- * should not be used to make conversion to that class easier
- * in the future.
- */
- std::string to_string() const {
- protozero_assert(m_data);
- return {m_data, m_size};
- }
-
- /**
- * Convert data view to string.
- *
- * @pre Must not be default constructed data_view.
- */
- explicit operator std::string() const {
- protozero_assert(m_data);
- return {m_data, m_size};
- }
-
-}; // class data_view
-
-/**
- * Swap two data_view objects.
- *
- * @param lhs First object.
- * @param rhs Second object.
- */
-inline void swap(data_view& lhs, data_view& rhs) noexcept {
- lhs.swap(rhs);
-}
-
-/**
- * Two data_view instances are equal if they have the same size and the
- * same content.
- *
- * @param lhs First object.
- * @param rhs Second object.
- */
-inline bool operator==(const data_view& lhs, const data_view& rhs) noexcept {
- return lhs.size() == rhs.size() && std::equal(lhs.data(), lhs.data() + lhs.size(), rhs.data());
-}
-
-/**
- * Two data_view instances are not equal if they have different sizes or the
- * content differs.
- *
- * @param lhs First object.
- * @param rhs Second object.
- */
-inline bool operator!=(const data_view& lhs, const data_view& rhs) noexcept {
- return !(lhs == rhs);
-}
-
-#endif
-
-
} // end namespace protozero
#endif // PROTOZERO_TYPES_HPP
diff --git a/include/protozero/varint.hpp b/include/protozero/varint.hpp
index 6377671..21d170e 100644
--- a/include/protozero/varint.hpp
+++ b/include/protozero/varint.hpp
@@ -48,7 +48,7 @@ namespace detail {
b = *p++; val |= uint64_t((b & 0x7f) << 42); if (b >= 0) { break; }
b = *p++; val |= uint64_t((b & 0x7f) << 49); if (b >= 0) { break; }
b = *p++; val |= uint64_t((b & 0x7f) << 56); if (b >= 0) { break; }
- b = *p++; val |= uint64_t((b & 0x7f) << 63); if (b >= 0) { break; }
+ b = *p++; val |= uint64_t((b & 0x01) << 63); if (b >= 0) { break; }
throw varint_too_long_exception{};
} while (false);
} else {
@@ -138,6 +138,7 @@ inline void skip_varint(const char** data, const char* end) {
* @param data Output iterator the varint encoded value will be written to
* byte by byte.
* @param value The integer that will be encoded.
+ * @returns the number of bytes written
* @throws Any exception thrown by increment or dereference operator on data.
*/
template <typename T>
diff --git a/include/protozero/version.hpp b/include/protozero/version.hpp
index 963632f..a0ab39c 100644
--- a/include/protozero/version.hpp
+++ b/include/protozero/version.hpp
@@ -20,15 +20,15 @@ documentation.
#define PROTOZERO_VERSION_MAJOR 1
/// The minor version number
-#define PROTOZERO_VERSION_MINOR 5
+#define PROTOZERO_VERSION_MINOR 6
/// The patch number
-#define PROTOZERO_VERSION_PATCH 3
+#define PROTOZERO_VERSION_PATCH 0
/// The complete version number
#define PROTOZERO_VERSION_CODE (PROTOZERO_VERSION_MAJOR * 10000 + PROTOZERO_VERSION_MINOR * 100 + PROTOZERO_VERSION_PATCH)
/// Version number as string
-#define PROTOZERO_VERSION_STRING "1.5.3"
+#define PROTOZERO_VERSION_STRING "1.6.0"
#endif // PROTOZERO_VERSION_HPP
diff --git a/include_dirs.js b/include_dirs.js
deleted file mode 100644
index b3c2686..0000000
--- a/include_dirs.js
+++ /dev/null
@@ -1,2 +0,0 @@
-var path = require('path');
-console.log(path.join(path.relative('.', __dirname),'include'));
diff --git a/package.json b/package.json
deleted file mode 100644
index cc38a04..0000000
--- a/package.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "name": "protozero",
- "version": "1.5.3",
- "description": "Minimalist protocol buffer decoder and encoder in C++",
- "main": "include_dirs.js",
- "repository" : {
- "type" : "git",
- "url" : "git://github.com/mapbox/protozero.git"
- }
-}
diff --git a/test/.gitignore b/test/.gitignore
deleted file mode 100644
index 02a9cc0..0000000
--- a/test/.gitignore
+++ /dev/null
@@ -1,6 +0,0 @@
-tests.o
-tests
-writer_tests.o
-writer_tests
-*.gcda
-*.gcno
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
new file mode 100644
index 0000000..9121636
--- /dev/null
+++ b/test/CMakeLists.txt
@@ -0,0 +1,120 @@
+#-----------------------------------------------------------------------------
+#
+# CMake config
+#
+# protozero tests
+#
+#-----------------------------------------------------------------------------
+
+include_directories(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/catch")
+include_directories("${CMAKE_CURRENT_SOURCE_DIR}/include")
+
+set(TEST_DIRS alignment
+ basic
+ bool
+ bytes
+ complex
+ data_view
+ double
+ endian
+ enum
+ exceptions
+ fixed32
+ fixed64
+ float
+ int32
+ int64
+ message
+ nested
+ repeated
+ repeated_packed_bool
+ repeated_packed_double
+ repeated_packed_enum
+ repeated_packed_fixed32
+ repeated_packed_fixed64
+ repeated_packed_float
+ repeated_packed_int32
+ repeated_packed_int64
+ repeated_packed_sfixed32
+ repeated_packed_sfixed64
+ repeated_packed_sint32
+ repeated_packed_sint64
+ repeated_packed_uint32
+ repeated_packed_uint64
+ rollback
+ sfixed32
+ sfixed64
+ sint32
+ sint64
+ skip
+ string
+ tag_and_type
+ tags
+ uint32
+ uint64
+ varint
+ vector_tile
+ wrong_type_access
+ zigzag)
+
+string(REGEX REPLACE "([^;]+)" "t/\\1/reader_test_cases.cpp" _test_sources "${TEST_DIRS}")
+
+add_executable(reader_tests reader_tests.cpp ${_test_sources})
+
+add_test(NAME reader_tests COMMAND reader_tests)
+
+set_tests_properties(reader_tests PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
+
+if(PROTOBUF_FOUND)
+ message(STATUS "Found protobuf libraries: Adding writer tests...")
+
+ include_directories(SYSTEM ${PROTOBUF_INCLUDE_DIRS} ${CMAKE_CURRENT_BINARY_DIR})
+
+ set(PROTOBUF_GENERATE_CPP_APPEND_PATH false)
+
+ foreach(_dir IN LISTS TEST_DIRS)
+ set(_full_src_dir "${CMAKE_CURRENT_SOURCE_DIR}/t/${_dir}")
+ if(EXISTS "${_full_src_dir}/writer_test_cases.cpp")
+ message(STATUS " Adding ${_dir}")
+ set(_full_bin_dir "${CMAKE_CURRENT_BINARY_DIR}/t/${_dir}")
+ set(_proto_file "${_full_src_dir}/testcase.proto")
+ set(_src_file "${_full_bin_dir}/testcase.pb.cc")
+ set(_hdr_file "${_full_bin_dir}/testcase.pb.h")
+
+ file(MAKE_DIRECTORY ${_full_bin_dir})
+
+ list(APPEND SOURCES "${_full_src_dir}/writer_test_cases.cpp")
+ list(APPEND PROTO_FILES "${_proto_file}")
+ list(APPEND PROTO_SRCS "${_src_file}")
+ list(APPEND PROTO_HDRS "${_hdr_file}")
+
+ set_source_files_properties(${_proto_file} ${_hdr_file}
+ PROPERTIES GENERATED TRUE)
+
+ add_custom_command(
+ OUTPUT ${_src_file} ${_hdr_file}
+ COMMAND ${PROTOBUF_PROTOC_EXECUTABLE}
+ ARGS --cpp_out=${_full_bin_dir} -I ${_full_src_dir} ${_proto_file}
+ DEPENDS ${_proto_file}
+ VERBATIM)
+ endif()
+ endforeach()
+
+ add_executable(writer_tests writer_tests.cpp ${SOURCES} ${PROTO_SRCS} ${PROTO_HDRS})
+
+ target_link_libraries(writer_tests ${PROTOBUF_LITE_LIBRARY})
+
+ if(NOT MSVC)
+ set_target_properties(writer_tests PROPERTIES COMPILE_FLAGS "-pthread")
+ if(NOT APPLE)
+ set_target_properties(writer_tests PROPERTIES LINK_FLAGS "-pthread")
+ endif()
+ endif()
+
+ add_test(NAME writer_tests COMMAND writer_tests)
+else()
+ message(STATUS "Protobuf libraries not found: Disabling writer tests.")
+endif()
+
+
+#-----------------------------------------------------------------------------
diff --git a/test/README.md b/test/README.md
index fa97a7f..36d5751 100644
--- a/test/README.md
+++ b/test/README.md
@@ -3,33 +3,31 @@
Tests are using the [Catch Unit Test Framework](https://github.com/philsquared/Catch).
-Call `make test` to compile and run all tests.
-
## Organization of the test cases
Each test case is in its own directory under the `t` directory. Each directory
contains (some of) the following files:
-* `test_cases.cpp`: The C++ source code that runs the tests.
-* `writer_test_cases.cpp`: The C++ source code that runs extra writer tests.
+* `reader_test_cases.cpp`: The C++ source code that runs the reader tests.
+* `writer_test_cases.cpp`: The C++ source code that runs the writer tests.
* `data-*.pbf`: PBF data files used by the tests.
* `testcase.proto`: Protobuf file describing the format of the data files.
* `testcase.cpp`: C++ file for creating the data files.
-### Read/write tests
+### Reader tests
-The `Makefile` automatically finds all the `test_cases.cpp` files and
-compiles them. Together with the `tests.cpp` file they make up the
-`tests` executable which can be called to execute all the read tests.
+The CMake config finds all the `reader_test_cases.cpp` files and compiles them.
+Together with the `reader_tests.cpp` file they make up the `reader_tests`
+executable which can be called to execute all the reader tests.
### Extra writer tests
-The `Makefile` automatically finds all the `writer_test_cases.cpp` files and
-compiles them. Together with the `writer_tests.cpp` file they make up the
-`writer_tests` executable which can be called to execute all the write tests.
+The CMake config finds all the `writer_test_cases.cpp` files and compiles them.
+Together with the `writer_tests.cpp` file they make up the `writer_tests`
+executable which can be called to execute all the writer tests.
-The extra writer tests need the Google protobuf library to work.
+The writer tests need the Google protobuf library to work.
## Creating test data from scratch
diff --git a/test/include/packed_access.hpp b/test/include/packed_access.hpp
index a99f10a..eaeaceb 100644
--- a/test/include/packed_access.hpp
+++ b/test/include/packed_access.hpp
@@ -7,7 +7,6 @@
using packed_field_type = PROTOZERO_TEST_CONCAT(protozero::packed_field_, PBF_TYPE);
TEST_CASE("read repeated packed field: " PBF_TYPE_NAME) {
-
// Run these tests twice, the second time we basically move the data
// one byte down in the buffer. It doesn't matter how the data or buffer
// is aligned before that, in at least one of these cases the ints will
@@ -15,7 +14,6 @@ TEST_CASE("read repeated packed field: " PBF_TYPE_NAME) {
// will be extracted properly.
for (std::string::size_type n = 0; n < 2; ++n) {
-
std::string abuffer;
abuffer.reserve(1000);
abuffer.append(n, '\0');
@@ -103,9 +101,8 @@ TEST_CASE("read repeated packed field: " PBF_TYPE_NAME) {
}
TEST_CASE("write repeated packed field: " PBF_TYPE_NAME) {
-
std::string buffer;
- protozero::pbf_writer pw(buffer);
+ protozero::pbf_writer pw{buffer};
SECTION("empty") {
cpp_type data[] = { 17 };
@@ -142,9 +139,8 @@ TEST_CASE("write repeated packed field: " PBF_TYPE_NAME) {
}
TEST_CASE("write repeated packed field using packed field: " PBF_TYPE_NAME) {
-
std::string buffer;
- protozero::pbf_writer pw(buffer);
+ protozero::pbf_writer pw{buffer};
SECTION("empty - should do rollback") {
{
@@ -185,11 +181,9 @@ TEST_CASE("write repeated packed field using packed field: " PBF_TYPE_NAME) {
REQUIRE(buffer == load_data("repeated_packed_" PBF_TYPE_NAME "/data-many"));
}
-
}
TEST_CASE("move repeated packed field: " PBF_TYPE_NAME) {
-
std::string buffer;
protozero::pbf_writer pw{buffer};
@@ -247,9 +241,8 @@ TEST_CASE("move repeated packed field: " PBF_TYPE_NAME) {
}
TEST_CASE("write from different types of iterators: " PBF_TYPE_NAME) {
-
std::string buffer;
- protozero::pbf_writer pw(buffer);
+ protozero::pbf_writer pw{buffer};
SECTION("from uint16_t") {
#if PBF_TYPE_IS_SIGNED
@@ -297,6 +290,5 @@ TEST_CASE("write from different types of iterators: " PBF_TYPE_NAME) {
REQUIRE_THROWS_AS(it_range.front(), const assert_error&);
REQUIRE_THROWS_AS(it_range.drop_front(), const assert_error&);
-
}
diff --git a/test/include/scalar_access.hpp b/test/include/scalar_access.hpp
index 79cb3f7..6f1e9df 100644
--- a/test/include/scalar_access.hpp
+++ b/test/include/scalar_access.hpp
@@ -91,11 +91,9 @@ TEST_CASE("read field: " PBF_TYPE_NAME) {
REQUIRE_THROWS_AS(item.GET_TYPE(), const protozero::end_of_buffer_exception&);
}
}
-
}
TEST_CASE("write field: " PBF_TYPE_NAME) {
-
std::string buffer;
protozero::pbf_writer pw(buffer);
@@ -127,6 +125,5 @@ TEST_CASE("write field: " PBF_TYPE_NAME) {
}
}
#endif
-
}
diff --git a/test/include/test.hpp b/test/include/test.hpp
index 89d1e15..7542579 100644
--- a/test/include/test.hpp
+++ b/test/include/test.hpp
@@ -1,10 +1,6 @@
#ifndef TEST_HPP
#define TEST_HPP
-#ifdef _MSC_VER
-# define _SCL_SECURE_NO_WARNINGS
-#endif
-
#include <catch.hpp>
#include <stdexcept>
diff --git a/test/include/testcase.hpp b/test/include/testcase.hpp
index a4e33ec..c59afca 100644
--- a/test/include/testcase.hpp
+++ b/test/include/testcase.hpp
@@ -2,9 +2,9 @@
#define TESTCASE_HPP
#include <cassert>
-#include <string>
#include <fstream>
#include <limits>
+#include <string>
template <class T>
std::string write_to_file(const T& msg, const char* filename) {
diff --git a/test/tests.cpp b/test/reader_tests.cpp
similarity index 66%
rename from test/tests.cpp
rename to test/reader_tests.cpp
index 35ecd98..ed0f139 100644
--- a/test/tests.cpp
+++ b/test/reader_tests.cpp
@@ -7,11 +7,17 @@
#include <test.hpp> // IWYU pragma: keep
std::string load_data(const std::string& filename) {
- std::string fullname{"test/t/"};
+ const char* tests_dir = std::getenv("TESTS_DIR");
+ if (tests_dir == nullptr) {
+ tests_dir = "test";
+ }
+
+ std::string fullname{tests_dir};
+ fullname += "/t/";
fullname += filename;
fullname += ".pbf";
- std::ifstream stream{fullname, std::ios_base::in|std::ios_base::binary};
+ std::ifstream stream{fullname, std::ios_base::in | std::ios_base::binary};
if (!stream.is_open()) {
throw std::runtime_error{"could not open: '" + filename + "'"};
}
diff --git a/test/t/.gitignore b/test/t/.gitignore
deleted file mode 100644
index 1799818..0000000
--- a/test/t/.gitignore
+++ /dev/null
@@ -1,6 +0,0 @@
-testcase
-testcase.pb.cc
-testcase.pb.h
-testcase.pb.o
-test_cases.o
-writer_test_cases.o
diff --git a/test/t/alignment/test_cases.cpp b/test/t/alignment/reader_test_cases.cpp
similarity index 99%
rename from test/t/alignment/test_cases.cpp
rename to test/t/alignment/reader_test_cases.cpp
index aa1c870..d7f995f 100644
--- a/test/t/alignment/test_cases.cpp
+++ b/test/t/alignment/reader_test_cases.cpp
@@ -8,7 +8,6 @@
// will be extracted properly.
TEST_CASE("check alignment issues for fixed32 field") {
-
for (std::string::size_type n = 0; n < 2; ++n) {
std::string abuffer;
@@ -73,15 +72,11 @@ TEST_CASE("check alignment issues for fixed32 field") {
REQUIRE_THROWS(item.skip());
REQUIRE_FALSE(item.next());
}
-
}
-
}
TEST_CASE("check alignment issues for fixed64 field") {
-
for (std::string::size_type n = 0; n < 2; ++n) {
-
std::string abuffer;
abuffer.reserve(1000);
abuffer.append(n, '\0');
@@ -122,8 +117,6 @@ TEST_CASE("check alignment issues for fixed64 field") {
REQUIRE_THROWS_AS(item.get_fixed64(), const protozero::end_of_buffer_exception&);
}
}
-
}
-
}
diff --git a/test/t/basic/reader_test_cases.cpp b/test/t/basic/reader_test_cases.cpp
new file mode 100644
index 0000000..6d0dd55
--- /dev/null
+++ b/test/t/basic/reader_test_cases.cpp
@@ -0,0 +1,101 @@
+
+#include <test.hpp>
+
+TEST_CASE("default constructed pbf_reader is okay") {
+ protozero::pbf_reader item;
+
+ REQUIRE(item.length() == 0);
+ REQUIRE_FALSE(item); // test operator bool()
+ REQUIRE_FALSE(item.next());
+}
+
+TEST_CASE("empty buffer in pbf_reader is okay") {
+ const std::string buffer;
+ protozero::pbf_reader item{buffer};
+
+ REQUIRE(item.length() == 0);
+ REQUIRE_FALSE(item); // test operator bool()
+ REQUIRE_FALSE(item.next());
+}
+
+TEST_CASE("check every possible value for single byte in buffer") {
+ char buffer;
+ for (int i = 0; i <= 255; ++i) {
+ buffer = static_cast<char>(i);
+ protozero::pbf_reader item{&buffer, 1};
+
+ REQUIRE(item.length() == 1);
+ REQUIRE_FALSE(!item); // test operator bool()
+ REQUIRE_THROWS((item.next(), item.skip()));
+ }
+}
+
+TEST_CASE("next() should throw when illegal wire type is encountered") {
+ const char buffer = 1 << 3 | 7;
+
+ protozero::pbf_reader item{&buffer, 1};
+ REQUIRE_THROWS_AS(item.next(), const protozero::unknown_pbf_wire_type_exception&);
+}
+
+TEST_CASE("next() should throw when illegal tag is encountered") {
+ std::string data;
+
+ SECTION("tag 0") {
+ protozero::write_varint(std::back_inserter(data), 0 << 3 | 1);
+ }
+
+ SECTION("tag 19000") {
+ protozero::write_varint(std::back_inserter(data), 19000 << 3 | 1);
+ }
+
+ SECTION("tag 19001") {
+ protozero::write_varint(std::back_inserter(data), 19001 << 3 | 1);
+ }
+
+ SECTION("tag 19999") {
+ protozero::write_varint(std::back_inserter(data), 19999 << 3 | 1);
+ }
+
+ protozero::pbf_reader item{data};
+ REQUIRE_THROWS_AS(item.next(), const protozero::invalid_tag_exception&);
+}
+
+TEST_CASE("next() works when a legal tag is encountered") {
+ std::string data;
+
+ SECTION("tag 1") {
+ protozero::write_varint(std::back_inserter(data), 1u << 3 | 1);
+ }
+
+ SECTION("tag 18999") {
+ protozero::write_varint(std::back_inserter(data), 18999u << 3 | 1);
+ }
+
+ SECTION("tag 20000") {
+ protozero::write_varint(std::back_inserter(data), 20000u << 3 | 1);
+ }
+
+ SECTION("tag 1^29 - 1") {
+ protozero::write_varint(std::back_inserter(data), ((1u << 29) - 1) << 3 | 1);
+ }
+
+ protozero::pbf_reader item{data};
+ REQUIRE(item.next());
+}
+
+TEST_CASE("pbf_writer asserts on invalid tags") {
+ std::string data;
+ protozero::pbf_writer writer{data};
+
+ REQUIRE_THROWS_AS(writer.add_int32(0, 123), const assert_error&);
+ writer.add_int32(1, 123);
+ writer.add_int32(2, 123);
+ writer.add_int32(18999, 123);
+ REQUIRE_THROWS_AS(writer.add_int32(19000, 123), const assert_error&);
+ REQUIRE_THROWS_AS(writer.add_int32(19001, 123), const assert_error&);
+ REQUIRE_THROWS_AS(writer.add_int32(19999, 123), const assert_error&);
+ writer.add_int32(20000, 123);
+ writer.add_int32((1 << 29) - 1, 123);
+ REQUIRE_THROWS_AS(writer.add_int32(1 << 29, 123), const assert_error&);
+}
+
diff --git a/test/t/basic/test_cases.cpp b/test/t/basic/test_cases.cpp
deleted file mode 100644
index c992698..0000000
--- a/test/t/basic/test_cases.cpp
+++ /dev/null
@@ -1,39 +0,0 @@
-
-#include <test.hpp>
-
-TEST_CASE("default constructed pbf_reader is okay") {
- protozero::pbf_reader item;
-
- REQUIRE(item.length() == 0);
- REQUIRE_FALSE(item); // test operator bool()
- REQUIRE_FALSE(item.next());
-}
-
-TEST_CASE("empty buffer in pbf_reader is okay") {
- const std::string buffer;
- protozero::pbf_reader item{buffer};
-
- REQUIRE(item.length() == 0);
- REQUIRE_FALSE(item); // test operator bool()
- REQUIRE_FALSE(item.next());
-}
-
-TEST_CASE("check every possible value for single byte in buffer") {
- char buffer;
- for (int i = 0; i <= 255; ++i) {
- buffer = static_cast<char>(i);
- protozero::pbf_reader item{&buffer, 1};
-
- REQUIRE(item.length() == 1);
- REQUIRE_FALSE(!item); // test operator bool()
- REQUIRE_THROWS((item.next(), item.skip()));
- }
-}
-
-TEST_CASE("next() should throw when illegal wire type is encountered") {
- char buffer = 1 << 3 | 7;
-
- protozero::pbf_reader item{&buffer, 1};
- REQUIRE_THROWS_AS(item.next(), const protozero::unknown_pbf_wire_type_exception&);
-}
-
diff --git a/test/t/bool/data-also-true.pbf b/test/t/bool/data-also-true.pbf
index e19a122..009a24f 100644
--- a/test/t/bool/data-also-true.pbf
+++ b/test/t/bool/data-also-true.pbf
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/test/t/bool/data-still-true.pbf b/test/t/bool/data-still-true.pbf
index e19a122..27e77d6 100644
--- a/test/t/bool/data-still-true.pbf
+++ b/test/t/bool/data-still-true.pbf
@@ -1 +1 @@
-
\ No newline at end of file
+�
\ No newline at end of file
diff --git a/test/t/bool/reader_test_cases.cpp b/test/t/bool/reader_test_cases.cpp
new file mode 100644
index 0000000..9bf518a
--- /dev/null
+++ b/test/t/bool/reader_test_cases.cpp
@@ -0,0 +1,141 @@
+
+#include <test.hpp>
+
+namespace TestBoolean {
+
+enum class Test : protozero::pbf_tag_type {
+ required_bool_b = 1
+};
+
+} // end namespace TestBoolean
+
+TEST_CASE("read bool field using pbf_reader: false") {
+ const std::string buffer = load_data("bool/data-false");
+
+ protozero::pbf_reader item{buffer};
+
+ REQUIRE(item.next());
+ REQUIRE_FALSE(item.get_bool());
+ REQUIRE_FALSE(item.next());
+}
+
+TEST_CASE("read bool field using pbf_reader: true") {
+ const std::string buffer = load_data("bool/data-true");
+
+ protozero::pbf_reader item{buffer};
+
+ REQUIRE(item.next());
+ REQUIRE(item.get_bool());
+ REQUIRE_FALSE(item.next());
+}
+
+TEST_CASE("read bool field using pbf_reader: also true") {
+ const std::string buffer = load_data("bool/data-also-true");
+
+ protozero::pbf_reader item{buffer};
+
+ REQUIRE(item.next(1));
+ REQUIRE(item.get_bool());
+ REQUIRE_FALSE(item.next());
+}
+
+TEST_CASE("read bool field using pbf_reader: still true") {
+ const std::string buffer = load_data("bool/data-still-true");
+
+ protozero::pbf_reader item{buffer};
+
+ REQUIRE(item.next(1));
+ REQUIRE(item.get_bool());
+ REQUIRE_FALSE(item.next());
+}
+
+TEST_CASE("read bool field using pbf_message: false") {
+ const std::string buffer = load_data("bool/data-false");
+
+ protozero::pbf_message<TestBoolean::Test> item{buffer};
+
+ REQUIRE(item.next());
+ REQUIRE_FALSE(item.get_bool());
+ REQUIRE_FALSE(item.next());
+}
+
+TEST_CASE("read bool field using pbf_message: true") {
+ const std::string buffer = load_data("bool/data-true");
+
+ protozero::pbf_message<TestBoolean::Test> item{buffer};
+
+ REQUIRE(item.next());
+ REQUIRE(item.get_bool());
+ REQUIRE_FALSE(item.next());
+}
+
+TEST_CASE("read bool field using pbf_message: also true") {
+ const std::string buffer = load_data("bool/data-also-true");
+
+ protozero::pbf_message<TestBoolean::Test> item{buffer};
+
+ REQUIRE(item.next(TestBoolean::Test::required_bool_b));
+ REQUIRE(item.get_bool());
+ REQUIRE_FALSE(item.next());
+}
+
+TEST_CASE("read bool field using pbf_message: still true") {
+ const std::string buffer = load_data("bool/data-still-true");
+
+ protozero::pbf_message<TestBoolean::Test> item{buffer};
+
+ REQUIRE(item.next(TestBoolean::Test::required_bool_b));
+ REQUIRE(item.get_bool());
+ REQUIRE_FALSE(item.next());
+}
+
+TEST_CASE("write bool field using pbf_writer") {
+ std::string buffer;
+ protozero::pbf_writer pw{buffer};
+
+ SECTION("false") {
+ pw.add_bool(1, false);
+ REQUIRE(buffer == load_data("bool/data-false"));
+ }
+
+ SECTION("true") {
+ pw.add_bool(1, true);
+ REQUIRE(buffer == load_data("bool/data-true"));
+ }
+}
+
+TEST_CASE("write bool field using pbf_builder") {
+ std::string buffer;
+ protozero::pbf_builder<TestBoolean::Test> pw{buffer};
+
+ SECTION("false") {
+ pw.add_bool(TestBoolean::Test::required_bool_b, false);
+ REQUIRE(buffer == load_data("bool/data-false"));
+ }
+
+ SECTION("true") {
+ pw.add_bool(TestBoolean::Test::required_bool_b, true);
+ REQUIRE(buffer == load_data("bool/data-true"));
+ }
+}
+
+TEST_CASE("write bool field using moved pbf_builder") {
+ std::string buffer;
+ protozero::pbf_builder<TestBoolean::Test> pw2{buffer};
+ REQUIRE(pw2.valid());
+
+ protozero::pbf_builder<TestBoolean::Test> pw{std::move(pw2)};
+ REQUIRE(pw.valid());
+ REQUIRE_FALSE(pw2.valid()); // NOLINT clang-tidy: hicpp-invalid-access-moved
+
+ SECTION("false") {
+ pw.add_bool(TestBoolean::Test::required_bool_b, false);
+ REQUIRE(buffer == load_data("bool/data-false"));
+ }
+
+ SECTION("true") {
+ pw.add_bool(TestBoolean::Test::required_bool_b, true);
+ REQUIRE(buffer == load_data("bool/data-true"));
+ }
+}
+
diff --git a/test/t/bool/test_cases.cpp b/test/t/bool/test_cases.cpp
deleted file mode 100644
index e87b0f6..0000000
--- a/test/t/bool/test_cases.cpp
+++ /dev/null
@@ -1,155 +0,0 @@
-
-#include <test.hpp>
-
-namespace TestBoolean {
-
-enum class Test : protozero::pbf_tag_type {
- required_bool_b = 1
-};
-
-} // end namespace TestBoolean
-
-TEST_CASE("read bool field using pbf_reader") {
-
- SECTION("false") {
- const std::string buffer = load_data("bool/data-false");
-
- protozero::pbf_reader item{buffer};
-
- REQUIRE(item.next());
- REQUIRE_FALSE(item.get_bool());
- REQUIRE_FALSE(item.next());
- }
-
- SECTION("true") {
- const std::string buffer = load_data("bool/data-true");
-
- protozero::pbf_reader item{buffer};
-
- REQUIRE(item.next());
- REQUIRE(item.get_bool());
- REQUIRE_FALSE(item.next());
- }
-
- SECTION("also true") {
- const std::string buffer = load_data("bool/data-also-true");
-
- protozero::pbf_reader item{buffer};
-
- REQUIRE(item.next(1));
- REQUIRE(item.get_bool());
- REQUIRE_FALSE(item.next());
- }
-
- SECTION("still true") {
- const std::string buffer = load_data("bool/data-still-true");
-
- protozero::pbf_reader item{buffer};
-
- REQUIRE(item.next(1));
- REQUIRE(item.get_bool());
- REQUIRE_FALSE(item.next());
- }
-
-}
-
-TEST_CASE("read bool field using pbf_message") {
-
- SECTION("false") {
- const std::string buffer = load_data("bool/data-false");
-
- protozero::pbf_message<TestBoolean::Test> item{buffer};
-
- REQUIRE(item.next());
- REQUIRE_FALSE(item.get_bool());
- REQUIRE_FALSE(item.next());
- }
-
- SECTION("true") {
- const std::string buffer = load_data("bool/data-true");
-
- protozero::pbf_message<TestBoolean::Test> item{buffer};
-
- REQUIRE(item.next());
- REQUIRE(item.get_bool());
- REQUIRE_FALSE(item.next());
- }
-
- SECTION("also true") {
- const std::string buffer = load_data("bool/data-also-true");
-
- protozero::pbf_message<TestBoolean::Test> item{buffer};
-
- REQUIRE(item.next(TestBoolean::Test::required_bool_b));
- REQUIRE(item.get_bool());
- REQUIRE_FALSE(item.next());
- }
-
- SECTION("still true") {
- const std::string buffer = load_data("bool/data-still-true");
-
- protozero::pbf_message<TestBoolean::Test> item{buffer};
-
- REQUIRE(item.next(TestBoolean::Test::required_bool_b));
- REQUIRE(item.get_bool());
- REQUIRE_FALSE(item.next());
- }
-
-}
-
-TEST_CASE("write bool field using pbf_writer") {
-
- std::string buffer;
- protozero::pbf_writer pw{buffer};
-
- SECTION("false") {
- pw.add_bool(1, false);
- REQUIRE(buffer == load_data("bool/data-false"));
- }
-
- SECTION("true") {
- pw.add_bool(1, true);
- REQUIRE(buffer == load_data("bool/data-true"));
- }
-
-}
-
-TEST_CASE("write bool field using pbf_builder") {
-
- std::string buffer;
- protozero::pbf_builder<TestBoolean::Test> pw{buffer};
-
- SECTION("false") {
- pw.add_bool(TestBoolean::Test::required_bool_b, false);
- REQUIRE(buffer == load_data("bool/data-false"));
- }
-
- SECTION("true") {
- pw.add_bool(TestBoolean::Test::required_bool_b, true);
- REQUIRE(buffer == load_data("bool/data-true"));
- }
-
-}
-
-TEST_CASE("write bool field using moved pbf_builder") {
-
- std::string buffer;
- protozero::pbf_builder<TestBoolean::Test> pw2{buffer};
- REQUIRE(pw2.valid());
-
- protozero::pbf_builder<TestBoolean::Test> pw{std::move(pw2)};
- REQUIRE(pw.valid());
- REQUIRE_FALSE(pw2.valid()); // NOLINT clang-tidy: hicpp-invalid-access-moved
-
- SECTION("false") {
- pw.add_bool(TestBoolean::Test::required_bool_b, false);
- REQUIRE(buffer == load_data("bool/data-false"));
- }
-
- SECTION("true") {
- pw.add_bool(TestBoolean::Test::required_bool_b, true);
- REQUIRE(buffer == load_data("bool/data-true"));
- }
-
-}
-
diff --git a/test/t/bool/testcase.cpp b/test/t/bool/testcase.cpp
index 3ad5083..b2a8f76 100644
--- a/test/t/bool/testcase.cpp
+++ b/test/t/bool/testcase.cpp
@@ -14,7 +14,7 @@ int main(int c, char *argv[]) {
msg.set_b(2);
write_to_file(msg, "data-also-true.pbf");
- msg.set_b(127);
+ msg.set_b(2000);
write_to_file(msg, "data-still-true.pbf");
}
diff --git a/test/t/bool/testcase.proto b/test/t/bool/testcase.proto
index 3c9fefa..a341f38 100644
--- a/test/t/bool/testcase.proto
+++ b/test/t/bool/testcase.proto
@@ -5,7 +5,10 @@ package TestBoolean;
message Test {
- required bool b = 1;
+ // this should be bool, but we are using uint32
+ // to be able to encode values other than 0 (false)
+ // and 1 (true)
+ required uint32 b = 1;
}
diff --git a/test/t/bool/writer_test_cases.cpp b/test/t/bool/writer_test_cases.cpp
index 9b26f62..457af6a 100644
--- a/test/t/bool/writer_test_cases.cpp
+++ b/test/t/bool/writer_test_cases.cpp
@@ -3,7 +3,7 @@
#include <test.hpp> // IWYU pragma: keep
-#include "test/t/bool/testcase.pb.h"
+#include "t/bool/testcase.pb.h"
TEST_CASE("write bool field and check with libprotobuf") {
diff --git a/test/t/bytes/test_cases.cpp b/test/t/bytes/reader_test_cases.cpp
similarity index 52%
rename from test/t/bytes/test_cases.cpp
rename to test/t/bytes/reader_test_cases.cpp
index d497f8c..a7a721b 100644
--- a/test/t/bytes/test_cases.cpp
+++ b/test/t/bytes/reader_test_cases.cpp
@@ -1,68 +1,63 @@
#include <test.hpp>
-TEST_CASE("read bytes field") {
+TEST_CASE("read bytes field: empty") {
+ const std::string buffer = load_data("bytes/data-empty");
- SECTION("empty") {
- const std::string buffer = load_data("bytes/data-empty");
-
- protozero::pbf_reader item{buffer};
+ protozero::pbf_reader item{buffer};
- REQUIRE(item.next());
- REQUIRE(item.get_bytes().empty());
- REQUIRE_FALSE(item.next());
- }
+ REQUIRE(item.next());
+ REQUIRE(item.get_bytes().empty());
+ REQUIRE_FALSE(item.next());
+}
- SECTION("one") {
- const std::string buffer = load_data("bytes/data-one");
+TEST_CASE("read bytes field: one") {
+ const std::string buffer = load_data("bytes/data-one");
- protozero::pbf_reader item{buffer};
+ protozero::pbf_reader item{buffer};
- REQUIRE(item.next());
- REQUIRE(item.get_bytes() == "x");
- REQUIRE_FALSE(item.next());
- }
+ REQUIRE(item.next());
+ REQUIRE(item.get_bytes() == "x");
+ REQUIRE_FALSE(item.next());
+}
- SECTION("string") {
- const std::string buffer = load_data("bytes/data-string");
+TEST_CASE("read bytes field: string") {
+ const std::string buffer = load_data("bytes/data-string");
- protozero::pbf_reader item{buffer};
+ protozero::pbf_reader item{buffer};
- REQUIRE(item.next());
- REQUIRE(item.get_bytes() == "foobar");
- REQUIRE_FALSE(item.next());
- }
+ REQUIRE(item.next());
+ REQUIRE(item.get_bytes() == "foobar");
+ REQUIRE_FALSE(item.next());
+}
- SECTION("binary") {
- const std::string buffer = load_data("bytes/data-binary");
+TEST_CASE("read bytes field: binary") {
+ const std::string buffer = load_data("bytes/data-binary");
- protozero::pbf_reader item{buffer};
+ protozero::pbf_reader item{buffer};
- REQUIRE(item.next());
- const std::string data = item.get_bytes();
- REQUIRE(data.size() == 3);
- REQUIRE(data[0] == char(1));
- REQUIRE(data[1] == char(2));
- REQUIRE(data[2] == char(3));
- REQUIRE_FALSE(item.next());
- }
+ REQUIRE(item.next());
+ const std::string data = item.get_bytes();
+ REQUIRE(data.size() == 3);
+ REQUIRE(data[0] == char(1));
+ REQUIRE(data[1] == char(2));
+ REQUIRE(data[2] == char(3));
+ REQUIRE_FALSE(item.next());
+}
- SECTION("end_of_buffer") {
- const std::string buffer = load_data("bytes/data-binary");
+TEST_CASE("read bytes field: end of buffer") {
+ const std::string buffer = load_data("bytes/data-binary");
- for (std::string::size_type i = 1; i < buffer.size(); ++i) {
- protozero::pbf_reader item{buffer.data(), i};
- REQUIRE(item.next());
- REQUIRE_THROWS_AS(item.get_bytes(), const protozero::end_of_buffer_exception&);
- }
+ for (std::string::size_type i = 1; i < buffer.size(); ++i) {
+ protozero::pbf_reader item{buffer.data(), i};
+ REQUIRE(item.next());
+ REQUIRE_THROWS_AS(item.get_bytes(), const protozero::end_of_buffer_exception&);
}
-
}
TEST_CASE("write bytes field") {
-
std::string buffer;
- protozero::pbf_writer pw(buffer);
+ protozero::pbf_writer pw{buffer};
SECTION("empty") {
pw.add_string(1, "");
@@ -89,13 +84,11 @@ TEST_CASE("write bytes field") {
REQUIRE(buffer == load_data("bytes/data-binary"));
}
-
}
TEST_CASE("write bytes field using vectored approach") {
-
std::string buffer;
- protozero::pbf_writer pw(buffer);
+ protozero::pbf_writer pw{buffer};
SECTION("using two strings") {
std::string d1{"foo"};
@@ -134,10 +127,10 @@ TEST_CASE("write bytes field using vectored approach") {
TEST_CASE("write bytes field using vectored approach with builder") {
enum class foo : protozero::pbf_tag_type { bar = 1 };
std::string buffer;
- protozero::pbf_builder<foo> pw(buffer);
+ protozero::pbf_builder<foo> pw{buffer};
- std::string d1{"foo"};
- std::string d2{"bar"};
+ const std::string d1{"foo"};
+ const std::string d2{"bar"};
pw.add_bytes_vectored(foo::bar, d1, d2);
diff --git a/test/t/bytes/writer_test_cases.cpp b/test/t/bytes/writer_test_cases.cpp
index 04bf1ee..29d3449 100644
--- a/test/t/bytes/writer_test_cases.cpp
+++ b/test/t/bytes/writer_test_cases.cpp
@@ -1,7 +1,7 @@
#include <test.hpp>
-#include "test/t/bytes/testcase.pb.h"
+#include "t/bytes/testcase.pb.h"
TEST_CASE("write bytes field and check with libprotobuf") {
@@ -15,7 +15,7 @@ TEST_CASE("write bytes field and check with libprotobuf") {
msg.ParseFromString(buffer);
- REQUIRE(msg.s() == "");
+ REQUIRE(msg.s().empty());
}
SECTION("one") {
diff --git a/test/t/complex/reader_test_cases.cpp b/test/t/complex/reader_test_cases.cpp
new file mode 100644
index 0000000..5b722d8
--- /dev/null
+++ b/test/t/complex/reader_test_cases.cpp
@@ -0,0 +1,686 @@
+
+#include <test.hpp>
+
+namespace TestComplex {
+
+enum class Test : protozero::pbf_tag_type {
+ required_fixed32_f = 1,
+ optional_int64_i = 2,
+ optional_int64_j = 3,
+ required_Sub_submessage = 5,
+ optional_string_s = 8,
+ repeated_uint32_u = 4,
+ packed_sint32_d = 7
+};
+
+enum class Sub : protozero::pbf_tag_type {
+ required_string_s = 1
+};
+
+} // namespace TestComplex
+
+TEST_CASE("read complex data using pbf_reader: minimal") {
+ const std::string buffer = load_data("complex/data-minimal");
+
+ protozero::pbf_reader item{buffer};
+
+ while (item.next()) {
+ switch (item.tag()) {
+ case 1: {
+ REQUIRE(item.get_fixed32() == 12345678L);
+ break;
+ }
+ case 5: {
+ protozero::pbf_reader subitem = item.get_message();
+ REQUIRE(subitem.next());
+ REQUIRE(subitem.get_string() == "foobar");
+ REQUIRE_FALSE(subitem.next());
+ break;
+ }
+ default: {
+ REQUIRE(false); // should not be here
+ break;
+ }
+ }
+ }
+}
+
+TEST_CASE("read complex data using pbf_reader: some") {
+ const std::string buffer = load_data("complex/data-some");
+
+ protozero::pbf_reader item2{buffer};
+ protozero::pbf_reader item;
+ using std::swap;
+ swap(item, item2);
+
+ uint32_t sum_of_u = 0;
+ while (item.next()) {
+ switch (item.tag()) {
+ case 1: {
+ REQUIRE(item.get_fixed32() == 12345678L);
+ break;
+ }
+ case 2: {
+ REQUIRE(true);
+ item.skip();
+ break;
+ }
+ case 4: {
+ sum_of_u += item.get_uint32();
+ break;
+ }
+ case 5: {
+ protozero::pbf_reader subitem = item.get_message();
+ REQUIRE(subitem.next());
+ REQUIRE(subitem.get_string() == "foobar");
+ REQUIRE_FALSE(subitem.next());
+ break;
+ }
+ default: {
+ REQUIRE(false); // should not be here
+ break;
+ }
+ }
+ }
+ REQUIRE(sum_of_u == 66);
+}
+
+TEST_CASE("read complex data using pbf_reader: all") {
+ const std::string buffer = load_data("complex/data-all");
+
+ protozero::pbf_reader item{buffer};
+
+ int number_of_u = 0;
+ while (item.next()) {
+ switch (item.tag()) {
+ case 1: {
+ REQUIRE(item.get_fixed32() == 12345678L);
+ break;
+ }
+ case 2: {
+ REQUIRE(true);
+ item.skip();
+ break;
+ }
+ case 3: {
+ REQUIRE(item.get_int64() == 555555555LL);
+ break;
+ }
+ case 4: {
+ item.skip();
+ ++number_of_u;
+ break;
+ }
+ case 5: {
+ protozero::pbf_reader subitem = item.get_message();
+ REQUIRE(subitem.next());
+ REQUIRE(subitem.get_string() == "foobar");
+ REQUIRE_FALSE(subitem.next());
+ break;
+ }
+ case 7: {
+ const auto pi = item.get_packed_sint32();
+ int32_t sum = 0;
+ for (auto val : pi) {
+ sum += val;
+ }
+ REQUIRE(sum == 5);
+ break;
+ }
+ case 8: {
+ REQUIRE(item.get_string() == "optionalstring");
+ break;
+ }
+ default: {
+ REQUIRE(false); // should not be here
+ break;
+ }
+ }
+ }
+ REQUIRE(number_of_u == 5);
+}
+
+TEST_CASE("read complex data using pbf_reader: skip everything") {
+ const std::string buffer = load_data("complex/data-all");
+
+ protozero::pbf_reader item{buffer};
+
+ while (item.next()) {
+ switch (item.tag()) {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 7:
+ case 8:
+ item.skip();
+ break;
+ default: {
+ REQUIRE(false); // should not be here
+ break;
+ }
+ }
+ }
+}
+
+TEST_CASE("read complex data using pbf_message: minimal") {
+ const std::string buffer = load_data("complex/data-minimal");
+
+ protozero::pbf_message<TestComplex::Test> item{buffer};
+
+ while (item.next()) {
+ switch (item.tag()) {
+ case TestComplex::Test::required_fixed32_f: {
+ REQUIRE(item.get_fixed32() == 12345678L);
+ break;
+ }
+ case TestComplex::Test::required_Sub_submessage: {
+ protozero::pbf_message<TestComplex::Sub> subitem{item.get_message()};
+ REQUIRE(subitem.next());
+ REQUIRE(subitem.get_string() == "foobar");
+ REQUIRE_FALSE(subitem.next());
+ break;
+ }
+ default: {
+ REQUIRE(false); // should not be here
+ break;
+ }
+ }
+ }
+}
+
+TEST_CASE("read complex data using pbf_message: some") {
+ const std::string buffer = load_data("complex/data-some");
+
+ protozero::pbf_message<TestComplex::Test> item2{buffer};
+ protozero::pbf_message<TestComplex::Test> item;
+ using std::swap;
+ swap(item, item2);
+
+ uint32_t sum_of_u = 0;
+ while (item.next()) {
+ switch (item.tag()) {
+ case TestComplex::Test::required_fixed32_f: {
+ REQUIRE(item.get_fixed32() == 12345678L);
+ break;
+ }
+ case TestComplex::Test::optional_int64_i: {
+ REQUIRE(true);
+ item.skip();
+ break;
+ }
+ case TestComplex::Test::repeated_uint32_u: {
+ sum_of_u += item.get_uint32();
+ break;
+ }
+ case TestComplex::Test::required_Sub_submessage: {
+ protozero::pbf_message<TestComplex::Sub> subitem = item.get_message();
+ REQUIRE(subitem.next());
+ REQUIRE(subitem.get_string() == "foobar");
+ REQUIRE_FALSE(subitem.next());
+ break;
+ }
+ default: {
+ REQUIRE(false); // should not be here
+ break;
+ }
+ }
+ }
+ REQUIRE(sum_of_u == 66);
+}
+
+TEST_CASE("read complex data using pbf_message: all") {
+ const std::string buffer = load_data("complex/data-all");
+
+ protozero::pbf_message<TestComplex::Test> item{buffer};
+
+ int number_of_u = 0;
+ while (item.next()) {
+ switch (item.tag()) {
+ case TestComplex::Test::required_fixed32_f: {
+ REQUIRE(item.get_fixed32() == 12345678L);
+ break;
+ }
+ case TestComplex::Test::optional_int64_i: {
+ REQUIRE(true);
+ item.skip();
+ break;
+ }
+ case TestComplex::Test::optional_int64_j: {
+ REQUIRE(item.get_int64() == 555555555LL);
+ break;
+ }
+ case TestComplex::Test::repeated_uint32_u: {
+ item.skip();
+ ++number_of_u;
+ break;
+ }
+ case TestComplex::Test::required_Sub_submessage: {
+ protozero::pbf_message<TestComplex::Sub> subitem = item.get_message();
+ REQUIRE(subitem.next());
+ REQUIRE(subitem.get_string() == "foobar");
+ REQUIRE_FALSE(subitem.next());
+ break;
+ }
+ case TestComplex::Test::packed_sint32_d: {
+ const auto pi = item.get_packed_sint32();
+ int32_t sum = 0;
+ for (auto val : pi) {
+ sum += val;
+ }
+ REQUIRE(sum == 5);
+ break;
+ }
+ case TestComplex::Test::optional_string_s: {
+ REQUIRE(item.get_string() == "optionalstring");
+ break;
+ }
+ default: {
+ REQUIRE(false); // should not be here
+ break;
+ }
+ }
+ }
+ REQUIRE(number_of_u == 5);
+}
+
+TEST_CASE("read complex data using pbf_message: skip everything") {
+ const std::string buffer = load_data("complex/data-all");
+
+ protozero::pbf_message<TestComplex::Test> item{buffer};
+
+ while (item.next()) {
+ switch (item.tag()) {
+ case TestComplex::Test::required_fixed32_f:
+ case TestComplex::Test::optional_int64_i:
+ case TestComplex::Test::optional_int64_j:
+ case TestComplex::Test::repeated_uint32_u:
+ case TestComplex::Test::required_Sub_submessage:
+ case TestComplex::Test::packed_sint32_d:
+ case TestComplex::Test::optional_string_s:
+ item.skip();
+ break;
+ default: {
+ REQUIRE(false); // should not be here
+ break;
+ }
+ }
+ }
+}
+
+TEST_CASE("write complex data using pbf_writer: minimal") {
+ std::string buffer;
+ protozero::pbf_writer pw{buffer};
+ pw.add_fixed32(1, 12345678);
+
+ std::string submessage;
+ protozero::pbf_writer pws{submessage};
+ pws.add_string(1, "foobar");
+
+ pw.add_message(5, submessage);
+
+ protozero::pbf_reader item{buffer};
+
+ while (item.next()) {
+ switch (item.tag()) {
+ case 1: {
+ REQUIRE(item.get_fixed32() == 12345678L);
+ break;
+ }
+ case 5: {
+ protozero::pbf_reader subitem = item.get_message();
+ REQUIRE(subitem.next());
+ REQUIRE(subitem.get_string() == "foobar");
+ REQUIRE_FALSE(subitem.next());
+ break;
+ }
+ default: {
+ REQUIRE(false); // should not be here
+ break;
+ }
+ }
+ }
+}
+
+TEST_CASE("write complex data using pbf_writer: some") {
+ std::string buffer;
+ protozero::pbf_writer pw2{buffer};
+ pw2.add_fixed32(1, 12345678);
+
+ protozero::pbf_writer pw;
+ using std::swap;
+ swap(pw, pw2);
+
+ REQUIRE(pw.valid());
+ REQUIRE_FALSE(pw2.valid());
+
+ std::string submessage;
+ protozero::pbf_writer pws{submessage};
+ pws.add_string(1, "foobar");
+
+ pw.add_uint32(4, 22);
+ pw.add_uint32(4, 44);
+ pw.add_int64(2, -9876543);
+ pw.add_message(5, submessage);
+
+ protozero::pbf_reader item{buffer};
+
+ uint32_t sum_of_u = 0;
+ while (item.next()) {
+ switch (item.tag()) {
+ case 1: {
+ REQUIRE(item.get_fixed32() == 12345678L);
+ break;
+ }
+ case 2: {
+ REQUIRE(true);
+ item.skip();
+ break;
+ }
+ case 4: {
+ sum_of_u += item.get_uint32();
+ break;
+ }
+ case 5: {
+ const auto view = item.get_view();
+ protozero::pbf_reader subitem{view};
+ REQUIRE(subitem.next());
+ REQUIRE(std::string(subitem.get_view()) == "foobar");
+ REQUIRE_FALSE(subitem.next());
+ break;
+ }
+ default: {
+ REQUIRE(false); // should not be here
+ break;
+ }
+ }
+ }
+ REQUIRE(sum_of_u == 66);
+}
+
+TEST_CASE("write complex data using pbf_writer: all") {
+ std::string buffer;
+ protozero::pbf_writer pw{buffer};
+ pw.add_fixed32(1, 12345678);
+
+ std::string submessage;
+ protozero::pbf_writer pws{submessage};
+ pws.add_string(1, "foobar");
+ pw.add_message(5, submessage);
+
+ pw.add_uint32(4, 22);
+ pw.add_uint32(4, 44);
+ pw.add_int64(2, -9876543);
+ pw.add_uint32(4, 44);
+ pw.add_uint32(4, 66);
+ pw.add_uint32(4, 66);
+
+ const int32_t d[] = { -17, 22 };
+ pw.add_packed_sint32(7, std::begin(d), std::end(d));
+
+ pw.add_int64(3, 555555555);
+
+ protozero::pbf_reader item{buffer};
+
+ int number_of_u = 0;
+ while (item.next()) {
+ switch (item.tag()) {
+ case 1: {
+ REQUIRE(item.get_fixed32() == 12345678L);
+ break;
+ }
+ case 2: {
+ REQUIRE(true);
+ item.skip();
+ break;
+ }
+ case 3: {
+ REQUIRE(item.get_int64() == 555555555LL);
+ break;
+ }
+ case 4: {
+ item.skip();
+ ++number_of_u;
+ break;
+ }
+ case 5: {
+ protozero::pbf_reader subitem = item.get_message();
+ REQUIRE(subitem.next());
+ REQUIRE(subitem.get_string() == "foobar");
+ REQUIRE_FALSE(subitem.next());
+ break;
+ }
+ case 7: {
+ const auto pi = item.get_packed_sint32();
+ int32_t sum = 0;
+ for (auto val : pi) {
+ sum += val;
+ }
+ REQUIRE(sum == 5);
+ break;
+ }
+ case 8: {
+ REQUIRE(item.get_string() == "optionalstring");
+ break;
+ }
+ default: {
+ REQUIRE(false); // should not be here
+ break;
+ }
+ }
+ }
+ REQUIRE(number_of_u == 5);
+}
+
+TEST_CASE("write complex data using pbf_builder: minimal") {
+ std::string buffer;
+ protozero::pbf_builder<TestComplex::Test> pw{buffer};
+ pw.add_fixed32(TestComplex::Test::required_fixed32_f, 12345678);
+
+ std::string submessage;
+ protozero::pbf_builder<TestComplex::Sub> pws{submessage};
+ pws.add_string(TestComplex::Sub::required_string_s, "foobar");
+
+ pw.add_message(TestComplex::Test::required_Sub_submessage, submessage);
+
+ protozero::pbf_reader item{buffer};
+
+ while (item.next()) {
+ switch (item.tag()) {
+ case 1: {
+ REQUIRE(item.get_fixed32() == 12345678L);
+ break;
+ }
+ case 5: {
+ protozero::pbf_reader subitem = item.get_message();
+ REQUIRE(subitem.next());
+ REQUIRE(subitem.get_string() == "foobar");
+ REQUIRE_FALSE(subitem.next());
+ break;
+ }
+ default: {
+ REQUIRE(false); // should not be here
+ break;
+ }
+ }
+ }
+}
+
+TEST_CASE("write complex data using pbf_builder: some") {
+ std::string buffer;
+ protozero::pbf_builder<TestComplex::Test> pw2{buffer};
+ pw2.add_fixed32(TestComplex::Test::required_fixed32_f, 12345678);
+
+ std::string dummy_buffer;
+ protozero::pbf_builder<TestComplex::Test> pw{dummy_buffer};
+ using std::swap;
+ swap(pw, pw2);
+
+ std::string submessage;
+ protozero::pbf_builder<TestComplex::Sub> pws{submessage};
+ pws.add_string(TestComplex::Sub::required_string_s, "foobar");
+
+ pw.add_uint32(TestComplex::Test::repeated_uint32_u, 22);
+ pw.add_uint32(TestComplex::Test::repeated_uint32_u, 44);
+ pw.add_int64(TestComplex::Test::optional_int64_i, -9876543);
+ pw.add_message(TestComplex::Test::required_Sub_submessage, submessage);
+
+ protozero::pbf_reader item{buffer};
+
+ uint32_t sum_of_u = 0;
+ while (item.next()) {
+ switch (item.tag()) {
+ case 1: {
+ REQUIRE(item.get_fixed32() == 12345678L);
+ break;
+ }
+ case 2: {
+ REQUIRE(true);
+ item.skip();
+ break;
+ }
+ case 4: {
+ sum_of_u += item.get_uint32();
+ break;
+ }
+ case 5: {
+ protozero::pbf_reader subitem = item.get_message();
+ REQUIRE(subitem.next());
+ REQUIRE(subitem.get_string() == "foobar");
+ REQUIRE_FALSE(subitem.next());
+ break;
+ }
+ default: {
+ REQUIRE(false); // should not be here
+ break;
+ }
+ }
+ }
+ REQUIRE(sum_of_u == 66);
+}
+
+TEST_CASE("write complex data using pbf_builder: all") {
+ std::string buffer;
+ protozero::pbf_builder<TestComplex::Test> pw{buffer};
+ pw.add_fixed32(TestComplex::Test::required_fixed32_f, 12345678);
+
+ std::string submessage;
+ protozero::pbf_builder<TestComplex::Sub> pws{submessage};
+ pws.add_string(TestComplex::Sub::required_string_s, "foobar");
+ pw.add_message(TestComplex::Test::required_Sub_submessage, submessage);
+
+ pw.add_uint32(TestComplex::Test::repeated_uint32_u, 22);
+ pw.add_uint32(TestComplex::Test::repeated_uint32_u, 44);
+ pw.add_int64(TestComplex::Test::optional_int64_i, -9876543);
+ pw.add_uint32(TestComplex::Test::repeated_uint32_u, 44);
+ pw.add_uint32(TestComplex::Test::repeated_uint32_u, 66);
+ pw.add_uint32(TestComplex::Test::repeated_uint32_u, 66);
+
+ const int32_t d[] = { -17, 22 };
+ pw.add_packed_sint32(TestComplex::Test::packed_sint32_d, std::begin(d), std::end(d));
+
+ pw.add_int64(TestComplex::Test::optional_int64_j, 555555555);
+
+ protozero::pbf_reader item{buffer};
+
+ int number_of_u = 0;
+ while (item.next()) {
+ switch (item.tag()) {
+ case 1: {
+ REQUIRE(item.get_fixed32() == 12345678L);
+ break;
+ }
+ case 2: {
+ REQUIRE(true);
+ item.skip();
+ break;
+ }
+ case 3: {
+ REQUIRE(item.get_int64() == 555555555LL);
+ break;
+ }
+ case 4: {
+ item.skip();
+ ++number_of_u;
+ break;
+ }
+ case 5: {
+ protozero::pbf_reader subitem = item.get_message();
+ REQUIRE(subitem.next());
+ REQUIRE(subitem.get_string() == "foobar");
+ REQUIRE_FALSE(subitem.next());
+ break;
+ }
+ case 7: {
+ const auto pi = item.get_packed_sint32();
+ int32_t sum = 0;
+ for (auto val : pi) {
+ sum += val;
+ }
+ REQUIRE(sum == 5);
+ break;
+ }
+ case 8: {
+ REQUIRE(item.get_string() == "optionalstring");
+ break;
+ }
+ default: {
+ REQUIRE(false); // should not be here
+ break;
+ }
+ }
+ }
+ REQUIRE(number_of_u == 5);
+}
+
+static void check_message(const std::string& buffer) {
+ protozero::pbf_reader item{buffer};
+
+ while (item.next()) {
+ switch (item.tag()) {
+ case 1: {
+ REQUIRE(item.get_fixed32() == 42L);
+ break;
+ }
+ case 5: {
+ protozero::pbf_reader subitem = item.get_message();
+ REQUIRE(subitem.next());
+ REQUIRE(subitem.get_string() == "foobar");
+ REQUIRE_FALSE(subitem.next());
+ break;
+ }
+ default: {
+ REQUIRE(false); // should not be here
+ break;
+ }
+ }
+ }
+}
+
+TEST_CASE("write complex with subwriter using pbf_writer") {
+ std::string buffer_test;
+ protozero::pbf_writer pbf_test{buffer_test};
+ pbf_test.add_fixed32(1, 42L);
+
+ SECTION("message in message") {
+ protozero::pbf_writer pbf_submessage{pbf_test, 5};
+ pbf_submessage.add_string(1, "foobar");
+ }
+
+ check_message(buffer_test);
+}
+
+TEST_CASE("write complex with subwriter using pbf_builder") {
+ std::string buffer_test;
+ protozero::pbf_builder<TestComplex::Test> pbf_test{buffer_test};
+ pbf_test.add_fixed32(TestComplex::Test::required_fixed32_f, 42L);
+
+ SECTION("message in message") {
+ protozero::pbf_builder<TestComplex::Sub> pbf_submessage{pbf_test, TestComplex::Test::required_Sub_submessage};
+ pbf_submessage.add_string(TestComplex::Sub::required_string_s, "foobar");
+ }
+
+ check_message(buffer_test);
+}
+
diff --git a/test/t/complex/test_cases.cpp b/test/t/complex/test_cases.cpp
deleted file mode 100644
index dfa1c54..0000000
--- a/test/t/complex/test_cases.cpp
+++ /dev/null
@@ -1,700 +0,0 @@
-
-#include <test.hpp>
-
-namespace TestComplex {
-
-enum class Test : protozero::pbf_tag_type {
- required_fixed32_f = 1,
- optional_int64_i = 2,
- optional_int64_j = 3,
- required_Sub_submessage = 5,
- optional_string_s = 8,
- repeated_uint32_u = 4,
- packed_sint32_d = 7
-};
-
-enum class Sub : protozero::pbf_tag_type {
- required_string_s = 1
-};
-
-} // end namespace TestComplex
-
-TEST_CASE("read complex data using pbf_reader") {
-
- SECTION("minimal") {
- const std::string buffer = load_data("complex/data-minimal");
-
- protozero::pbf_reader item{buffer};
-
- while (item.next()) {
- switch (item.tag()) {
- case 1: {
- REQUIRE(item.get_fixed32() == 12345678L);
- break;
- }
- case 5: {
- protozero::pbf_reader subitem = item.get_message();
- REQUIRE(subitem.next());
- REQUIRE(subitem.get_string() == "foobar");
- REQUIRE_FALSE(subitem.next());
- break;
- }
- default: {
- REQUIRE(false); // should not be here
- break;
- }
- }
- }
- }
-
- SECTION("some") {
- const std::string buffer = load_data("complex/data-some");
-
- protozero::pbf_reader item2{buffer};
- protozero::pbf_reader item;
- using std::swap;
- swap(item, item2);
-
- uint32_t sum_of_u = 0;
- while (item.next()) {
- switch (item.tag()) {
- case 1: {
- REQUIRE(item.get_fixed32() == 12345678L);
- break;
- }
- case 2: {
- REQUIRE(true);
- item.skip();
- break;
- }
- case 4: {
- sum_of_u += item.get_uint32();
- break;
- }
- case 5: {
- protozero::pbf_reader subitem = item.get_message();
- REQUIRE(subitem.next());
- REQUIRE(subitem.get_string() == "foobar");
- REQUIRE_FALSE(subitem.next());
- break;
- }
- default: {
- REQUIRE(false); // should not be here
- break;
- }
- }
- }
- REQUIRE(sum_of_u == 66);
- }
-
- SECTION("all") {
- const std::string buffer = load_data("complex/data-all");
-
- protozero::pbf_reader item{buffer};
-
- int number_of_u = 0;
- while (item.next()) {
- switch (item.tag()) {
- case 1: {
- REQUIRE(item.get_fixed32() == 12345678L);
- break;
- }
- case 2: {
- REQUIRE(true);
- item.skip();
- break;
- }
- case 3: {
- REQUIRE(item.get_int64() == 555555555LL);
- break;
- }
- case 4: {
- item.skip();
- ++number_of_u;
- break;
- }
- case 5: {
- protozero::pbf_reader subitem = item.get_message();
- REQUIRE(subitem.next());
- REQUIRE(subitem.get_string() == "foobar");
- REQUIRE_FALSE(subitem.next());
- break;
- }
- case 7: {
- const auto pi = item.get_packed_sint32();
- int32_t sum = 0;
- for (auto val : pi) {
- sum += val;
- }
- REQUIRE(sum == 5);
- break;
- }
- case 8: {
- REQUIRE(item.get_string() == "optionalstring");
- break;
- }
- default: {
- REQUIRE(false); // should not be here
- break;
- }
- }
- }
- REQUIRE(number_of_u == 5);
- }
-
- SECTION("skip everything") {
- const std::string buffer = load_data("complex/data-all");
-
- protozero::pbf_reader item{buffer};
-
- while (item.next()) {
- switch (item.tag()) {
- case 1:
- case 2:
- case 3:
- case 4:
- case 5:
- case 7:
- case 8:
- item.skip();
- break;
- default: {
- REQUIRE(false); // should not be here
- break;
- }
- }
- }
- }
-
-}
-
-TEST_CASE("read complex data using pbf_message") {
-
- SECTION("minimal") {
- const std::string buffer = load_data("complex/data-minimal");
-
- protozero::pbf_message<TestComplex::Test> item{buffer};
-
- while (item.next()) {
- switch (item.tag()) {
- case TestComplex::Test::required_fixed32_f: {
- REQUIRE(item.get_fixed32() == 12345678L);
- break;
- }
- case TestComplex::Test::required_Sub_submessage: {
- protozero::pbf_message<TestComplex::Sub> subitem{item.get_message()};
- REQUIRE(subitem.next());
- REQUIRE(subitem.get_string() == "foobar");
- REQUIRE_FALSE(subitem.next());
- break;
- }
- default: {
- REQUIRE(false); // should not be here
- break;
- }
- }
- }
- }
-
- SECTION("some") {
- const std::string buffer = load_data("complex/data-some");
-
- protozero::pbf_message<TestComplex::Test> item2{buffer};
- protozero::pbf_message<TestComplex::Test> item;
- using std::swap;
- swap(item, item2);
-
- uint32_t sum_of_u = 0;
- while (item.next()) {
- switch (item.tag()) {
- case TestComplex::Test::required_fixed32_f: {
- REQUIRE(item.get_fixed32() == 12345678L);
- break;
- }
- case TestComplex::Test::optional_int64_i: {
- REQUIRE(true);
- item.skip();
- break;
- }
- case TestComplex::Test::repeated_uint32_u: {
- sum_of_u += item.get_uint32();
- break;
- }
- case TestComplex::Test::required_Sub_submessage: {
- protozero::pbf_message<TestComplex::Sub> subitem = item.get_message();
- REQUIRE(subitem.next());
- REQUIRE(subitem.get_string() == "foobar");
- REQUIRE_FALSE(subitem.next());
- break;
- }
- default: {
- REQUIRE(false); // should not be here
- break;
- }
- }
- }
- REQUIRE(sum_of_u == 66);
- }
-
- SECTION("all") {
- const std::string buffer = load_data("complex/data-all");
-
- protozero::pbf_message<TestComplex::Test> item{buffer};
-
- int number_of_u = 0;
- while (item.next()) {
- switch (item.tag()) {
- case TestComplex::Test::required_fixed32_f: {
- REQUIRE(item.get_fixed32() == 12345678L);
- break;
- }
- case TestComplex::Test::optional_int64_i: {
- REQUIRE(true);
- item.skip();
- break;
- }
- case TestComplex::Test::optional_int64_j: {
- REQUIRE(item.get_int64() == 555555555LL);
- break;
- }
- case TestComplex::Test::repeated_uint32_u: {
- item.skip();
- ++number_of_u;
- break;
- }
- case TestComplex::Test::required_Sub_submessage: {
- protozero::pbf_message<TestComplex::Sub> subitem = item.get_message();
- REQUIRE(subitem.next());
- REQUIRE(subitem.get_string() == "foobar");
- REQUIRE_FALSE(subitem.next());
- break;
- }
- case TestComplex::Test::packed_sint32_d: {
- const auto pi = item.get_packed_sint32();
- int32_t sum = 0;
- for (auto val : pi) {
- sum += val;
- }
- REQUIRE(sum == 5);
- break;
- }
- case TestComplex::Test::optional_string_s: {
- REQUIRE(item.get_string() == "optionalstring");
- break;
- }
- default: {
- REQUIRE(false); // should not be here
- break;
- }
- }
- }
- REQUIRE(number_of_u == 5);
- }
-
- SECTION("skip everything") {
- const std::string buffer = load_data("complex/data-all");
-
- protozero::pbf_message<TestComplex::Test> item{buffer};
-
- while (item.next()) {
- switch (item.tag()) {
- case TestComplex::Test::required_fixed32_f:
- case TestComplex::Test::optional_int64_i:
- case TestComplex::Test::optional_int64_j:
- case TestComplex::Test::repeated_uint32_u:
- case TestComplex::Test::required_Sub_submessage:
- case TestComplex::Test::packed_sint32_d:
- case TestComplex::Test::optional_string_s:
- item.skip();
- break;
- default: {
- REQUIRE(false); // should not be here
- break;
- }
- }
- }
- }
-
-}
-
-TEST_CASE("write complex data using pbf_writer") {
-
- SECTION("minimal") {
- std::string buffer;
- protozero::pbf_writer pw{buffer};
- pw.add_fixed32(1, 12345678);
-
- std::string submessage;
- protozero::pbf_writer pws{submessage};
- pws.add_string(1, "foobar");
-
- pw.add_message(5, submessage);
-
- protozero::pbf_reader item{buffer};
-
- while (item.next()) {
- switch (item.tag()) {
- case 1: {
- REQUIRE(item.get_fixed32() == 12345678L);
- break;
- }
- case 5: {
- protozero::pbf_reader subitem = item.get_message();
- REQUIRE(subitem.next());
- REQUIRE(subitem.get_string() == "foobar");
- REQUIRE_FALSE(subitem.next());
- break;
- }
- default: {
- REQUIRE(false); // should not be here
- break;
- }
- }
- }
- }
-
- SECTION("some") {
- std::string buffer;
- protozero::pbf_writer pw2{buffer};
- pw2.add_fixed32(1, 12345678);
-
- protozero::pbf_writer pw;
- using std::swap;
- swap(pw, pw2);
-
- REQUIRE(pw.valid());
- REQUIRE_FALSE(pw2.valid());
-
- std::string submessage;
- protozero::pbf_writer pws{submessage};
- pws.add_string(1, "foobar");
-
- pw.add_uint32(4, 22);
- pw.add_uint32(4, 44);
- pw.add_int64(2, -9876543);
- pw.add_message(5, submessage);
-
- protozero::pbf_reader item{buffer};
-
- uint32_t sum_of_u = 0;
- while (item.next()) {
- switch (item.tag()) {
- case 1: {
- REQUIRE(item.get_fixed32() == 12345678L);
- break;
- }
- case 2: {
- REQUIRE(true);
- item.skip();
- break;
- }
- case 4: {
- sum_of_u += item.get_uint32();
- break;
- }
- case 5: {
- const auto view = item.get_view();
- protozero::pbf_reader subitem{view};
- REQUIRE(subitem.next());
- REQUIRE(std::string(subitem.get_view()) == "foobar");
- REQUIRE_FALSE(subitem.next());
- break;
- }
- default: {
- REQUIRE(false); // should not be here
- break;
- }
- }
- }
- REQUIRE(sum_of_u == 66);
- }
-
- SECTION("all") {
- std::string buffer;
- protozero::pbf_writer pw{buffer};
- pw.add_fixed32(1, 12345678);
-
- std::string submessage;
- protozero::pbf_writer pws{submessage};
- pws.add_string(1, "foobar");
- pw.add_message(5, submessage);
-
- pw.add_uint32(4, 22);
- pw.add_uint32(4, 44);
- pw.add_int64(2, -9876543);
- pw.add_uint32(4, 44);
- pw.add_uint32(4, 66);
- pw.add_uint32(4, 66);
-
- const int32_t d[] = { -17, 22 };
- pw.add_packed_sint32(7, std::begin(d), std::end(d));
-
- pw.add_int64(3, 555555555);
-
- protozero::pbf_reader item{buffer};
-
- int number_of_u = 0;
- while (item.next()) {
- switch (item.tag()) {
- case 1: {
- REQUIRE(item.get_fixed32() == 12345678L);
- break;
- }
- case 2: {
- REQUIRE(true);
- item.skip();
- break;
- }
- case 3: {
- REQUIRE(item.get_int64() == 555555555LL);
- break;
- }
- case 4: {
- item.skip();
- ++number_of_u;
- break;
- }
- case 5: {
- protozero::pbf_reader subitem = item.get_message();
- REQUIRE(subitem.next());
- REQUIRE(subitem.get_string() == "foobar");
- REQUIRE_FALSE(subitem.next());
- break;
- }
- case 7: {
- const auto pi = item.get_packed_sint32();
- int32_t sum = 0;
- for (auto val : pi) {
- sum += val;
- }
- REQUIRE(sum == 5);
- break;
- }
- case 8: {
- REQUIRE(item.get_string() == "optionalstring");
- break;
- }
- default: {
- REQUIRE(false); // should not be here
- break;
- }
- }
- }
- REQUIRE(number_of_u == 5);
- }
-}
-
-TEST_CASE("write complex data using pbf_builder") {
-
- SECTION("minimal") {
- std::string buffer;
- protozero::pbf_builder<TestComplex::Test> pw{buffer};
- pw.add_fixed32(TestComplex::Test::required_fixed32_f, 12345678);
-
- std::string submessage;
- protozero::pbf_builder<TestComplex::Sub> pws{submessage};
- pws.add_string(TestComplex::Sub::required_string_s, "foobar");
-
- pw.add_message(TestComplex::Test::required_Sub_submessage, submessage);
-
- protozero::pbf_reader item{buffer};
-
- while (item.next()) {
- switch (item.tag()) {
- case 1: {
- REQUIRE(item.get_fixed32() == 12345678L);
- break;
- }
- case 5: {
- protozero::pbf_reader subitem = item.get_message();
- REQUIRE(subitem.next());
- REQUIRE(subitem.get_string() == "foobar");
- REQUIRE_FALSE(subitem.next());
- break;
- }
- default: {
- REQUIRE(false); // should not be here
- break;
- }
- }
- }
- }
-
- SECTION("some") {
- std::string buffer;
- protozero::pbf_builder<TestComplex::Test> pw2{buffer};
- pw2.add_fixed32(TestComplex::Test::required_fixed32_f, 12345678);
-
- std::string dummy_buffer;
- protozero::pbf_builder<TestComplex::Test> pw{dummy_buffer};
- using std::swap;
- swap(pw, pw2);
-
- std::string submessage;
- protozero::pbf_builder<TestComplex::Sub> pws{submessage};
- pws.add_string(TestComplex::Sub::required_string_s, "foobar");
-
- pw.add_uint32(TestComplex::Test::repeated_uint32_u, 22);
- pw.add_uint32(TestComplex::Test::repeated_uint32_u, 44);
- pw.add_int64(TestComplex::Test::optional_int64_i, -9876543);
- pw.add_message(TestComplex::Test::required_Sub_submessage, submessage);
-
- protozero::pbf_reader item{buffer};
-
- uint32_t sum_of_u = 0;
- while (item.next()) {
- switch (item.tag()) {
- case 1: {
- REQUIRE(item.get_fixed32() == 12345678L);
- break;
- }
- case 2: {
- REQUIRE(true);
- item.skip();
- break;
- }
- case 4: {
- sum_of_u += item.get_uint32();
- break;
- }
- case 5: {
- protozero::pbf_reader subitem = item.get_message();
- REQUIRE(subitem.next());
- REQUIRE(subitem.get_string() == "foobar");
- REQUIRE_FALSE(subitem.next());
- break;
- }
- default: {
- REQUIRE(false); // should not be here
- break;
- }
- }
- }
- REQUIRE(sum_of_u == 66);
- }
-
- SECTION("all") {
- std::string buffer;
- protozero::pbf_builder<TestComplex::Test> pw{buffer};
- pw.add_fixed32(TestComplex::Test::required_fixed32_f, 12345678);
-
- std::string submessage;
- protozero::pbf_builder<TestComplex::Sub> pws{submessage};
- pws.add_string(TestComplex::Sub::required_string_s, "foobar");
- pw.add_message(TestComplex::Test::required_Sub_submessage, submessage);
-
- pw.add_uint32(TestComplex::Test::repeated_uint32_u, 22);
- pw.add_uint32(TestComplex::Test::repeated_uint32_u, 44);
- pw.add_int64(TestComplex::Test::optional_int64_i, -9876543);
- pw.add_uint32(TestComplex::Test::repeated_uint32_u, 44);
- pw.add_uint32(TestComplex::Test::repeated_uint32_u, 66);
- pw.add_uint32(TestComplex::Test::repeated_uint32_u, 66);
-
- const int32_t d[] = { -17, 22 };
- pw.add_packed_sint32(TestComplex::Test::packed_sint32_d, std::begin(d), std::end(d));
-
- pw.add_int64(TestComplex::Test::optional_int64_j, 555555555);
-
- protozero::pbf_reader item{buffer};
-
- int number_of_u = 0;
- while (item.next()) {
- switch (item.tag()) {
- case 1: {
- REQUIRE(item.get_fixed32() == 12345678L);
- break;
- }
- case 2: {
- REQUIRE(true);
- item.skip();
- break;
- }
- case 3: {
- REQUIRE(item.get_int64() == 555555555LL);
- break;
- }
- case 4: {
- item.skip();
- ++number_of_u;
- break;
- }
- case 5: {
- protozero::pbf_reader subitem = item.get_message();
- REQUIRE(subitem.next());
- REQUIRE(subitem.get_string() == "foobar");
- REQUIRE_FALSE(subitem.next());
- break;
- }
- case 7: {
- const auto pi = item.get_packed_sint32();
- int32_t sum = 0;
- for (auto val : pi) {
- sum += val;
- }
- REQUIRE(sum == 5);
- break;
- }
- case 8: {
- REQUIRE(item.get_string() == "optionalstring");
- break;
- }
- default: {
- REQUIRE(false); // should not be here
- break;
- }
- }
- }
- REQUIRE(number_of_u == 5);
- }
-}
-
-static void check_message(const std::string& buffer) {
- protozero::pbf_reader item{buffer};
-
- while (item.next()) {
- switch (item.tag()) {
- case 1: {
- REQUIRE(item.get_fixed32() == 42L);
- break;
- }
- case 5: {
- protozero::pbf_reader subitem = item.get_message();
- REQUIRE(subitem.next());
- REQUIRE(subitem.get_string() == "foobar");
- REQUIRE_FALSE(subitem.next());
- break;
- }
- default: {
- REQUIRE(false); // should not be here
- break;
- }
- }
- }
-}
-
-TEST_CASE("write complex with subwriter using pbf_writer") {
- std::string buffer_test;
- protozero::pbf_writer pbf_test{buffer_test};
- pbf_test.add_fixed32(1, 42L);
-
- SECTION("message in message") {
- protozero::pbf_writer pbf_submessage{pbf_test, 5};
- pbf_submessage.add_string(1, "foobar");
- }
-
- check_message(buffer_test);
-}
-
-TEST_CASE("write complex with subwriter using pbf_builder") {
- std::string buffer_test;
- protozero::pbf_builder<TestComplex::Test> pbf_test{buffer_test};
- pbf_test.add_fixed32(TestComplex::Test::required_fixed32_f, 42L);
-
- SECTION("message in message") {
- protozero::pbf_builder<TestComplex::Sub> pbf_submessage{pbf_test, TestComplex::Test::required_Sub_submessage};
- pbf_submessage.add_string(TestComplex::Sub::required_string_s, "foobar");
- }
-
- check_message(buffer_test);
-}
-
diff --git a/test/t/data_view/test_cases.cpp b/test/t/data_view/reader_test_cases.cpp
similarity index 51%
rename from test/t/data_view/test_cases.cpp
rename to test/t/data_view/reader_test_cases.cpp
index a9c51c0..b4db378 100644
--- a/test/t/data_view/test_cases.cpp
+++ b/test/t/data_view/reader_test_cases.cpp
@@ -6,51 +6,51 @@
#include <protozero/types.hpp>
TEST_CASE("default constructed data_view") {
- protozero::data_view view;
+ const protozero::data_view view{};
REQUIRE(view.data() == nullptr);
REQUIRE(view.size() == 0); // NOLINT clang-tidy: readability-container-size-empty
REQUIRE(view.empty());
}
TEST_CASE("data_view from C string") {
- protozero::data_view view{"foobar"};
+ const protozero::data_view view{"foobar"};
REQUIRE(view.data());
REQUIRE(view.size() == 6);
REQUIRE_FALSE(view.empty());
}
TEST_CASE("data_view from std::string") {
- std::string str{"foobar"};
- protozero::data_view view{str};
+ const std::string str{"foobar"};
+ const protozero::data_view view{str};
REQUIRE(view.data());
REQUIRE(view.size() == 6);
}
TEST_CASE("data_view from ptr, size") {
- std::string str{"foobar"};
- protozero::data_view view{str.data(), str.size()};
+ const std::string str{"foobar"};
+ const protozero::data_view view{str.data(), str.size()};
REQUIRE(view.data());
REQUIRE(view.size() == 6);
}
TEST_CASE("data_view from C array") {
const char* str = "foobar";
- protozero::data_view view{str};
+ const protozero::data_view view{str};
REQUIRE(view.data());
REQUIRE(view.size() == 6);
}
TEST_CASE("data_view from std::array") {
- std::array<char, 7> str{"foobar"};
- protozero::data_view view{str.data(), 6};
+ const std::array<char, 7> str{"foobar"};
+ const protozero::data_view view{str.data(), 6};
REQUIRE(view.data());
REQUIRE(view.size() == 6);
}
TEST_CASE("convert data_view to std::string") {
- protozero::data_view view{"foobar"};
+ const protozero::data_view view{"foobar"};
- std::string s = std::string(view);
+ const std::string s = std::string(view);
REQUIRE(s == "foobar");
REQUIRE(std::string(view) == "foobar");
REQUIRE(view.to_string() == "foobar");
@@ -60,7 +60,7 @@ TEST_CASE("convert data_view to std::string") {
// This test only works with our own data_view implementation, because only
// that one contains the protozero_assert() which generates the exception.
TEST_CASE("converting default constructed data_view to string fails") {
- protozero::data_view view;
+ const protozero::data_view view{};
REQUIRE_THROWS_AS(view.to_string(), const assert_error&);
}
#endif
@@ -80,13 +80,13 @@ TEST_CASE("swapping data_view") {
}
TEST_CASE("comparing data_views") {
- protozero::data_view v1{"foo"};
- protozero::data_view v2{"bar"};
- protozero::data_view v3{"foox"};
- protozero::data_view v4{"foo"};
- protozero::data_view v5{"fooooooo", 3};
- protozero::data_view v6{"f\0o", 3};
- protozero::data_view v7{"f\0obar", 3};
+ const protozero::data_view v1{"foo"};
+ const protozero::data_view v2{"bar"};
+ const protozero::data_view v3{"foox"};
+ const protozero::data_view v4{"foo"};
+ const protozero::data_view v5{"fooooooo", 3};
+ const protozero::data_view v6{"f\0o", 3};
+ const protozero::data_view v7{"f\0obar", 3};
REQUIRE_FALSE(v1 == v2);
REQUIRE_FALSE(v1 == v3);
@@ -113,3 +113,50 @@ TEST_CASE("comparing data_views") {
REQUIRE_FALSE(v6 != v7);
}
+TEST_CASE("ordering of data_views") {
+ const protozero::data_view v1{"foo"};
+ const protozero::data_view v2{"foo"};
+ const protozero::data_view v3{"bar"};
+ const protozero::data_view v4{"foox"};
+ const protozero::data_view v5{"zzz"};
+
+ REQUIRE(v1.compare(v1) == 0);
+ REQUIRE(v1.compare(v2) == 0);
+ REQUIRE(v1.compare(v3) > 0);
+ REQUIRE(v1.compare(v4) < 0);
+ REQUIRE(v1.compare(v5) < 0);
+
+ REQUIRE(v2.compare(v1) == 0);
+ REQUIRE(v2.compare(v2) == 0);
+ REQUIRE(v2.compare(v3) > 0);
+ REQUIRE(v2.compare(v4) < 0);
+ REQUIRE(v2.compare(v5) < 0);
+
+ REQUIRE(v3.compare(v1) < 0);
+ REQUIRE(v3.compare(v2) < 0);
+ REQUIRE(v3.compare(v3) == 0);
+ REQUIRE(v3.compare(v4) < 0);
+ REQUIRE(v3.compare(v5) < 0);
+
+ REQUIRE(v4.compare(v1) > 0);
+ REQUIRE(v4.compare(v2) > 0);
+ REQUIRE(v4.compare(v3) > 0);
+ REQUIRE(v4.compare(v4) == 0);
+ REQUIRE(v4.compare(v5) < 0);
+
+ REQUIRE(v5.compare(v1) > 0);
+ REQUIRE(v5.compare(v2) > 0);
+ REQUIRE(v5.compare(v3) > 0);
+ REQUIRE(v5.compare(v4) > 0);
+ REQUIRE(v5.compare(v5) == 0);
+
+ REQUIRE(v1 == v2);
+ REQUIRE(v1 <= v2);
+ REQUIRE(v1 >= v2);
+ REQUIRE(v1 < v4);
+ REQUIRE(v3 < v1);
+ REQUIRE(v3 <= v1);
+ REQUIRE(v5 > v1);
+ REQUIRE(v5 >= v1);
+}
+
diff --git a/test/t/double/test_cases.cpp b/test/t/double/reader_test_cases.cpp
similarity index 99%
rename from test/t/double/test_cases.cpp
rename to test/t/double/reader_test_cases.cpp
index e4165f5..4c22fcd 100644
--- a/test/t/double/test_cases.cpp
+++ b/test/t/double/reader_test_cases.cpp
@@ -2,15 +2,12 @@
#include <test.hpp>
TEST_CASE("read double field") {
-
// Run these tests twice, the second time we basically move the data
// one byte down in the buffer. It doesn't matter how the data or buffer
// is aligned before that, in at least one of these cases the double will
// not be aligned properly. So we test that even in that case the double
// will be extracted properly.
-
for (std::string::size_type n = 0; n < 2; ++n) {
-
std::string abuffer;
abuffer.reserve(1000);
abuffer.append(n, '\0');
@@ -51,13 +48,10 @@ TEST_CASE("read double field") {
REQUIRE_THROWS_AS(item.get_double(), const protozero::end_of_buffer_exception&);
}
}
-
}
-
}
TEST_CASE("write double field") {
-
std::string buffer;
protozero::pbf_writer pw{buffer};
@@ -75,6 +69,5 @@ TEST_CASE("write double field") {
pw.add_double(1, -9232.33);
REQUIRE(buffer == load_data("double/data-neg"));
}
-
}
diff --git a/test/t/double/writer_test_cases.cpp b/test/t/double/writer_test_cases.cpp
index c4a85dd..5ec5e1c 100644
--- a/test/t/double/writer_test_cases.cpp
+++ b/test/t/double/writer_test_cases.cpp
@@ -1,7 +1,7 @@
#include <test.hpp>
-#include "test/t/double/testcase.pb.h"
+#include "t/double/testcase.pb.h"
TEST_CASE("write double field and check with libprotobuf") {
diff --git a/test/t/endian/test_cases.cpp b/test/t/endian/reader_test_cases.cpp
similarity index 72%
rename from test/t/endian/test_cases.cpp
rename to test/t/endian/reader_test_cases.cpp
index 8968e09..95aafe0 100644
--- a/test/t/endian/test_cases.cpp
+++ b/test/t/endian/reader_test_cases.cpp
@@ -30,14 +30,30 @@ TEST_CASE("byte swapping") {
REQUIRE(0 == check_swap_8(0));
REQUIRE(1 == check_swap_8(1));
REQUIRE(-1 == check_swap_8(-1));
- REQUIRE(395503 == check_swap_8(395503));
- REQUIRE(-804022 == check_swap_8(-804022));
- REQUIRE(3280329805 == check_swap_8(3280329805));
- REQUIRE(-2489204041 == check_swap_8(-2489204041));
+ REQUIRE(395503ll == check_swap_8(395503ll));
+ REQUIRE(-804022ll == check_swap_8(-804022ll));
+ REQUIRE(3280329805ll == check_swap_8(3280329805ll));
+ REQUIRE(-2489204041ll == check_swap_8(-2489204041ll));
REQUIRE(std::numeric_limits<int64_t>::max() == check_swap_8(std::numeric_limits<int64_t>::max()));
REQUIRE(std::numeric_limits<int64_t>::min() == check_swap_8(std::numeric_limits<int64_t>::min()));
}
+TEST_CASE("byte swap uint32_t") {
+ uint32_t a = 17;
+ protozero::detail::byteswap_inplace(&a);
+ protozero::detail::byteswap_inplace(&a);
+
+ REQUIRE(17 == a);
+}
+
+TEST_CASE("byte swap uint64_t") {
+ uint64_t a = 347529808;
+ protozero::detail::byteswap_inplace(&a);
+ protozero::detail::byteswap_inplace(&a);
+
+ REQUIRE(347529808 == a);
+}
+
TEST_CASE("byte swap double") {
double a = 1.1;
protozero::detail::byteswap_inplace(&a);
diff --git a/test/t/enum/reader_test_cases.cpp b/test/t/enum/reader_test_cases.cpp
new file mode 100644
index 0000000..026d1ed
--- /dev/null
+++ b/test/t/enum/reader_test_cases.cpp
@@ -0,0 +1,83 @@
+
+#include <test.hpp>
+
+TEST_CASE("read enum field: zero") {
+ const std::string buffer = load_data("enum/data-black");
+
+ protozero::pbf_reader item{buffer};
+
+ REQUIRE(item.next());
+ REQUIRE(item.get_enum() == 0L);
+ REQUIRE_FALSE(item.next());
+}
+
+TEST_CASE("read enum field: positive") {
+ const std::string buffer = load_data("enum/data-blue");
+
+ protozero::pbf_reader item{buffer};
+
+ REQUIRE(item.next());
+ REQUIRE(item.get_enum() == 3L);
+ REQUIRE_FALSE(item.next());
+}
+
+TEST_CASE("read enum field: negative") {
+ const std::string buffer = load_data("enum/data-neg");
+
+ protozero::pbf_reader item{buffer};
+
+ REQUIRE(item.next());
+ REQUIRE(item.get_enum() == -1L);
+ REQUIRE_FALSE(item.next());
+}
+
+TEST_CASE("read enum field: max") {
+ const std::string buffer = load_data("enum/data-max");
+
+ protozero::pbf_reader item{buffer};
+
+ REQUIRE(item.next());
+ REQUIRE(item.get_enum() == std::numeric_limits<int32_t>::max());
+ REQUIRE_FALSE(item.next());
+}
+
+TEST_CASE("read enum field: min") {
+ const std::string buffer = load_data("enum/data-min");
+
+ protozero::pbf_reader item{buffer};
+
+ REQUIRE(item.next());
+ REQUIRE(item.get_enum() == (std::numeric_limits<int32_t>::min() + 1));
+ REQUIRE_FALSE(item.next());
+}
+
+TEST_CASE("write enum field") {
+ std::string buffer;
+ protozero::pbf_writer pw{buffer};
+
+ SECTION("zero") {
+ pw.add_enum(1, 0L);
+ REQUIRE(buffer == load_data("enum/data-black"));
+ }
+
+ SECTION("positive") {
+ pw.add_enum(1, 3L);
+ REQUIRE(buffer == load_data("enum/data-blue"));
+ }
+
+ SECTION("negative") {
+ pw.add_enum(1, -1L);
+ REQUIRE(buffer == load_data("enum/data-neg"));
+ }
+
+ SECTION("max") {
+ pw.add_enum(1, std::numeric_limits<int32_t>::max());
+ REQUIRE(buffer == load_data("enum/data-max"));
+ }
+
+ SECTION("min") {
+ pw.add_enum(1, std::numeric_limits<int32_t>::min() + 1);
+ REQUIRE(buffer == load_data("enum/data-min"));
+ }
+}
+
diff --git a/test/t/enum/test_cases.cpp b/test/t/enum/test_cases.cpp
deleted file mode 100644
index 484d873..0000000
--- a/test/t/enum/test_cases.cpp
+++ /dev/null
@@ -1,89 +0,0 @@
-
-#include <test.hpp>
-
-TEST_CASE("read enum field") {
-
- SECTION("zero") {
- const std::string buffer = load_data("enum/data-black");
-
- protozero::pbf_reader item{buffer};
-
- REQUIRE(item.next());
- REQUIRE(item.get_enum() == 0L);
- REQUIRE_FALSE(item.next());
- }
-
- SECTION("positive") {
- const std::string buffer = load_data("enum/data-blue");
-
- protozero::pbf_reader item{buffer};
-
- REQUIRE(item.next());
- REQUIRE(item.get_enum() == 3L);
- REQUIRE_FALSE(item.next());
- }
-
- SECTION("negative") {
- const std::string buffer = load_data("enum/data-neg");
-
- protozero::pbf_reader item{buffer};
-
- REQUIRE(item.next());
- REQUIRE(item.get_enum() == -1L);
- REQUIRE_FALSE(item.next());
- }
-
- SECTION("max") {
- const std::string buffer = load_data("enum/data-max");
-
- protozero::pbf_reader item{buffer};
-
- REQUIRE(item.next());
- REQUIRE(item.get_enum() == std::numeric_limits<int32_t>::max());
- REQUIRE_FALSE(item.next());
- }
-
- SECTION("min") {
- const std::string buffer = load_data("enum/data-min");
-
- protozero::pbf_reader item{buffer};
-
- REQUIRE(item.next());
- REQUIRE(item.get_enum() == (std::numeric_limits<int32_t>::min() + 1));
- REQUIRE_FALSE(item.next());
- }
-
-}
-
-TEST_CASE("write enum field") {
-
- std::string buffer;
- protozero::pbf_writer pw{buffer};
-
- SECTION("zero") {
- pw.add_enum(1, 0L);
- REQUIRE(buffer == load_data("enum/data-black"));
- }
-
- SECTION("positive") {
- pw.add_enum(1, 3L);
- REQUIRE(buffer == load_data("enum/data-blue"));
- }
-
- SECTION("negative") {
- pw.add_enum(1, -1L);
- REQUIRE(buffer == load_data("enum/data-neg"));
- }
-
- SECTION("max") {
- pw.add_enum(1, std::numeric_limits<int32_t>::max());
- REQUIRE(buffer == load_data("enum/data-max"));
- }
-
- SECTION("min") {
- pw.add_enum(1, std::numeric_limits<int32_t>::min() + 1);
- REQUIRE(buffer == load_data("enum/data-min"));
- }
-
-}
-
diff --git a/test/t/enum/testcase.proto b/test/t/enum/testcase.proto
index 12eef42..d99d7ee 100644
--- a/test/t/enum/testcase.proto
+++ b/test/t/enum/testcase.proto
@@ -8,7 +8,7 @@ enum Color {
RED = 1;
GREEN = 2;
BLUE = 3;
- MAX = 2147483647;
+ MAX = 2147483646;
NEG = -1;
// Older versions (before 2.6.0) of the google protobuf compiler have a
diff --git a/test/t/enum/writer_test_cases.cpp b/test/t/enum/writer_test_cases.cpp
index 1f3a4c3..2d20c89 100644
--- a/test/t/enum/writer_test_cases.cpp
+++ b/test/t/enum/writer_test_cases.cpp
@@ -1,7 +1,7 @@
#include <test.hpp>
-#include "test/t/enum/testcase.pb.h"
+#include "t/enum/testcase.pb.h"
TEST_CASE("write enum field and check with libprotobuf") {
@@ -35,7 +35,7 @@ TEST_CASE("write enum field and check with libprotobuf") {
}
SECTION("max") {
- pw.add_enum(1, std::numeric_limits<int32_t>::max());
+ pw.add_enum(1, std::numeric_limits<int32_t>::max() - 1);
msg.ParseFromString(buffer);
diff --git a/test/t/exceptions/test_cases.cpp b/test/t/exceptions/reader_test_cases.cpp
similarity index 67%
rename from test/t/exceptions/test_cases.cpp
rename to test/t/exceptions/reader_test_cases.cpp
index b1063f1..1c4170c 100644
--- a/test/t/exceptions/test_cases.cpp
+++ b/test/t/exceptions/reader_test_cases.cpp
@@ -21,3 +21,13 @@ TEST_CASE("exceptions messages for end of buffer") {
REQUIRE(std::string{e.what()} == std::string{"end of buffer exception"});
}
+TEST_CASE("exceptions messages for invalid tag") {
+ protozero::invalid_tag_exception e;
+ REQUIRE(std::string{e.what()} == std::string{"invalid tag exception"});
+}
+
+TEST_CASE("exceptions messages for invalid length") {
+ protozero::invalid_length_exception e;
+ REQUIRE(std::string{e.what()} == std::string{"invalid length exception"});
+}
+
diff --git a/test/t/fixed32/test_cases.cpp b/test/t/fixed32/reader_test_cases.cpp
similarity index 100%
rename from test/t/fixed32/test_cases.cpp
rename to test/t/fixed32/reader_test_cases.cpp
diff --git a/test/t/fixed32/writer_test_cases.cpp b/test/t/fixed32/writer_test_cases.cpp
index f09742c..6fbf023 100644
--- a/test/t/fixed32/writer_test_cases.cpp
+++ b/test/t/fixed32/writer_test_cases.cpp
@@ -1,7 +1,7 @@
#include <test.hpp>
-#include "test/t/fixed32/testcase.pb.h"
+#include "t/fixed32/testcase.pb.h"
TEST_CASE("write fixed32 field and check with libprotobuf") {
diff --git a/test/t/fixed64/test_cases.cpp b/test/t/fixed64/reader_test_cases.cpp
similarity index 100%
rename from test/t/fixed64/test_cases.cpp
rename to test/t/fixed64/reader_test_cases.cpp
diff --git a/test/t/float/test_cases.cpp b/test/t/float/reader_test_cases.cpp
similarity index 98%
rename from test/t/float/test_cases.cpp
rename to test/t/float/reader_test_cases.cpp
index 9e92740..f1891b0 100644
--- a/test/t/float/test_cases.cpp
+++ b/test/t/float/reader_test_cases.cpp
@@ -2,7 +2,6 @@
#include <test.hpp>
TEST_CASE("read float field") {
-
// Run these tests twice, the second time we basically move the data
// one byte down in the buffer. It doesn't matter how the data or buffer
// is aligned before that, in at least one of these cases the float will
@@ -10,7 +9,6 @@ TEST_CASE("read float field") {
// will be extracted properly.
for (std::string::size_type n = 0; n < 2; ++n) {
-
std::string abuffer;
abuffer.reserve(1000);
abuffer.append(n, '\0');
@@ -51,15 +49,12 @@ TEST_CASE("read float field") {
REQUIRE_THROWS_AS(item.get_float(), const protozero::end_of_buffer_exception&);
}
}
-
}
-
}
TEST_CASE("write float field") {
-
std::string buffer;
- protozero::pbf_writer pw(buffer);
+ protozero::pbf_writer pw{buffer};
SECTION("zero") {
pw.add_float(1, 0.0f);
@@ -75,6 +70,5 @@ TEST_CASE("write float field") {
pw.add_float(1, -1.71f);
REQUIRE(buffer == load_data("float/data-neg"));
}
-
}
diff --git a/test/t/int32/test_cases.cpp b/test/t/int32/reader_test_cases.cpp
similarity index 100%
rename from test/t/int32/test_cases.cpp
rename to test/t/int32/reader_test_cases.cpp
diff --git a/test/t/int32/writer_test_cases.cpp b/test/t/int32/writer_test_cases.cpp
index 9bdf634..e17813c 100644
--- a/test/t/int32/writer_test_cases.cpp
+++ b/test/t/int32/writer_test_cases.cpp
@@ -1,7 +1,7 @@
#include <test.hpp>
-#include "test/t/int32/testcase.pb.h"
+#include "t/int32/testcase.pb.h"
TEST_CASE("write int32 field and check with libprotobuf") {
diff --git a/test/t/int64/test_cases.cpp b/test/t/int64/reader_test_cases.cpp
similarity index 100%
rename from test/t/int64/test_cases.cpp
rename to test/t/int64/reader_test_cases.cpp
diff --git a/test/t/message/reader_test_cases.cpp b/test/t/message/reader_test_cases.cpp
new file mode 100644
index 0000000..04e4e7d
--- /dev/null
+++ b/test/t/message/reader_test_cases.cpp
@@ -0,0 +1,129 @@
+
+#include <test.hpp>
+
+TEST_CASE("read message field: string") {
+ const std::string buffer = load_data("message/data-message");
+
+ protozero::pbf_reader item{buffer};
+
+ REQUIRE(item.next());
+ protozero::pbf_reader subitem{item.get_message()};
+ REQUIRE_FALSE(item.next());
+
+ REQUIRE(subitem.next());
+ REQUIRE(subitem.get_string() == "foobar");
+ REQUIRE_FALSE(subitem.next());
+}
+
+TEST_CASE("read message field: end of buffer") {
+ const std::string buffer = load_data("message/data-message");
+
+ for (std::string::size_type i = 1; i < buffer.size(); ++i) {
+ protozero::pbf_reader item{buffer.data(), i};
+ REQUIRE(item.next());
+ REQUIRE_THROWS_AS(item.get_string(), const protozero::end_of_buffer_exception&);
+ }
+}
+
+TEST_CASE("read message field: optional contents of message - empty") {
+ const std::string buffer = load_data("message/data-opt-empty");
+
+ protozero::pbf_reader item{buffer};
+
+ REQUIRE_FALSE(item.next());
+}
+
+TEST_CASE("read message field: string opt") {
+ const std::string buffer = load_data("message/data-opt-element");
+
+ protozero::pbf_reader item{buffer};
+
+ REQUIRE(item.next());
+ REQUIRE(item.get_string() == "optional");
+ REQUIRE_FALSE(item.next());
+}
+
+TEST_CASE("write message field") {
+ std::string buffer;
+ protozero::pbf_writer pbf_test{buffer};
+
+ SECTION("string") {
+ std::string buffer_submessage;
+ protozero::pbf_writer pbf_submessage{buffer_submessage};
+ pbf_submessage.add_string(1, "foobar");
+
+ pbf_test.add_message(1, buffer_submessage);
+ }
+
+ SECTION("string with subwriter") {
+ protozero::pbf_writer pbf_submessage{pbf_test, 1};
+ pbf_submessage.add_string(1, "foobar");
+ }
+
+ SECTION("string with subwriter with reserved size") {
+ std::string str{"foobar"};
+ const auto size = 1 /* tag */ + 1 /* length field */ + str.size();
+ protozero::pbf_writer pbf_submessage{pbf_test, 1, size};
+ pbf_submessage.add_string(1, "foobar");
+ }
+
+ REQUIRE(buffer == load_data("message/data-message"));
+}
+
+TEST_CASE("write message field into non-empty buffer") {
+ std::string buffer{"some data already in here"};
+ protozero::pbf_writer pbf_test{buffer};
+
+ SECTION("string") {
+ std::string buffer_submessage;
+ protozero::pbf_writer pbf_submessage{buffer_submessage};
+ pbf_submessage.add_string(1, "foobar");
+
+ pbf_test.add_message(1, buffer_submessage);
+ }
+
+ SECTION("string with subwriter") {
+ protozero::pbf_writer pbf_submessage{pbf_test, 1};
+ pbf_submessage.add_string(1, "foobar");
+ }
+
+ REQUIRE(buffer == std::string{"some data already in here"} + load_data("message/data-message"));
+}
+
+TEST_CASE("write message field reserving memory beforehand") {
+ std::string buffer;
+ protozero::pbf_writer pbf_test{buffer};
+ pbf_test.reserve(100);
+ REQUIRE(buffer.capacity() >= 100);
+
+ SECTION("string") {
+ std::string buffer_submessage;
+ protozero::pbf_writer pbf_submessage{buffer_submessage};
+ pbf_submessage.add_string(1, "foobar");
+
+ pbf_test.add_message(1, buffer_submessage);
+ }
+
+ SECTION("string with subwriter") {
+ protozero::pbf_writer pbf_submessage{pbf_test, 1};
+ pbf_submessage.add_string(1, "foobar");
+ }
+
+ REQUIRE(buffer == load_data("message/data-message"));
+}
+
+TEST_CASE("write optional message field") {
+ std::string buffer;
+ protozero::pbf_writer pbf_opt{buffer};
+
+ SECTION("add nothing") {
+ REQUIRE(buffer == load_data("message/data-opt-empty"));
+ }
+
+ SECTION("add string") {
+ pbf_opt.add_string(1, "optional");
+
+ REQUIRE(buffer == load_data("message/data-opt-element"));
+ }
+}
+
diff --git a/test/t/message/test_cases.cpp b/test/t/message/test_cases.cpp
deleted file mode 100644
index af4b11f..0000000
--- a/test/t/message/test_cases.cpp
+++ /dev/null
@@ -1,141 +0,0 @@
-
-#include <test.hpp>
-
-TEST_CASE("read message field") {
-
- SECTION("string") {
- const std::string buffer = load_data("message/data-message");
-
- protozero::pbf_reader item{buffer};
-
- REQUIRE(item.next());
- protozero::pbf_reader subitem{item.get_message()};
- REQUIRE_FALSE(item.next());
-
- REQUIRE(subitem.next());
- REQUIRE(subitem.get_string() == "foobar");
- REQUIRE_FALSE(subitem.next());
- }
-
- SECTION("end_of_buffer") {
- const std::string buffer = load_data("message/data-message");
-
- for (std::string::size_type i = 1; i < buffer.size(); ++i) {
- protozero::pbf_reader item{buffer.data(), i};
- REQUIRE(item.next());
- REQUIRE_THROWS_AS(item.get_string(), const protozero::end_of_buffer_exception&);
- }
- }
-
- SECTION("optional contents of message - empty") {
- const std::string buffer = load_data("message/data-opt-empty");
-
- protozero::pbf_reader item{buffer};
-
- REQUIRE_FALSE(item.next());
- }
-
- SECTION("string") {
- const std::string buffer = load_data("message/data-opt-element");
-
- protozero::pbf_reader item{buffer};
-
- REQUIRE(item.next());
- REQUIRE(item.get_string() == "optional");
- REQUIRE_FALSE(item.next());
- }
-
-}
-
-TEST_CASE("write message field") {
-
- std::string buffer_test;
- protozero::pbf_writer pbf_test{buffer_test};
-
- SECTION("string") {
- std::string buffer_submessage;
- protozero::pbf_writer pbf_submessage{buffer_submessage};
- pbf_submessage.add_string(1, "foobar");
-
- pbf_test.add_message(1, buffer_submessage);
- }
-
- SECTION("string with subwriter") {
- protozero::pbf_writer pbf_submessage{pbf_test, 1};
- pbf_submessage.add_string(1, "foobar");
- }
-
- SECTION("string with subwriter with reserved size") {
- std::string str{"foobar"};
- auto size = 1 /* tag */ + 1 /* length field */ + str.size();
- protozero::pbf_writer pbf_submessage{pbf_test, 1, size};
- pbf_submessage.add_string(1, "foobar");
- }
-
- REQUIRE(buffer_test == load_data("message/data-message"));
-
-}
-
-TEST_CASE("write message field into non-empty buffer") {
-
- std::string buffer_test{"some data already in here"};
- protozero::pbf_writer pbf_test{buffer_test};
-
- SECTION("string") {
- std::string buffer_submessage;
- protozero::pbf_writer pbf_submessage{buffer_submessage};
- pbf_submessage.add_string(1, "foobar");
-
- pbf_test.add_message(1, buffer_submessage);
- }
-
- SECTION("string with subwriter") {
- protozero::pbf_writer pbf_submessage{pbf_test, 1};
- pbf_submessage.add_string(1, "foobar");
- }
-
- REQUIRE(buffer_test == std::string{"some data already in here"} + load_data("message/data-message"));
-
-}
-
-TEST_CASE("write message field reserving memory beforehand") {
-
- std::string buffer_test;
- protozero::pbf_writer pbf_test{buffer_test};
- pbf_test.reserve(100);
- REQUIRE(buffer_test.capacity() >= 100);
-
- SECTION("string") {
- std::string buffer_submessage;
- protozero::pbf_writer pbf_submessage{buffer_submessage};
- pbf_submessage.add_string(1, "foobar");
-
- pbf_test.add_message(1, buffer_submessage);
- }
-
- SECTION("string with subwriter") {
- protozero::pbf_writer pbf_submessage{pbf_test, 1};
- pbf_submessage.add_string(1, "foobar");
- }
-
- REQUIRE(buffer_test == load_data("message/data-message"));
-
-}
-
-TEST_CASE("write optional message field") {
-
- std::string buffer_opt;
- protozero::pbf_writer pbf_opt{buffer_opt};
-
- SECTION("add nothing") {
- REQUIRE(buffer_opt == load_data("message/data-opt-empty"));
- }
-
- SECTION("add string") {
- pbf_opt.add_string(1, "optional");
-
- REQUIRE(buffer_opt == load_data("message/data-opt-element"));
- }
-
-}
-
diff --git a/test/t/message/writer_test_cases.cpp b/test/t/message/writer_test_cases.cpp
index e13d661..9cd2dfb 100644
--- a/test/t/message/writer_test_cases.cpp
+++ b/test/t/message/writer_test_cases.cpp
@@ -1,7 +1,7 @@
#include <test.hpp>
-#include "test/t/message/testcase.pb.h"
+#include "t/message/testcase.pb.h"
TEST_CASE("write message field and check with libprotobuf") {
diff --git a/test/t/nested/test_cases.cpp b/test/t/nested/reader_test_cases.cpp
similarity index 88%
rename from test/t/nested/test_cases.cpp
rename to test/t/nested/reader_test_cases.cpp
index 879e031..0c35d53 100644
--- a/test/t/nested/test_cases.cpp
+++ b/test/t/nested/reader_test_cases.cpp
@@ -77,26 +77,21 @@ inline void check_empty(protozero::pbf_reader message) {
}
}
-TEST_CASE("read nested message fields") {
+TEST_CASE("read nested message fields: string") {
+ const std::string buffer = load_data("nested/data-message");
- SECTION("string") {
- const std::string buffer = load_data("nested/data-message");
-
- protozero::pbf_reader message{buffer};
- check(message);
- }
+ protozero::pbf_reader message{buffer};
+ check(message);
+}
- SECTION("no submessage") {
- const std::string buffer = load_data("nested/data-no-message");
-
- protozero::pbf_reader message{buffer};
- check_empty(message);
- }
+TEST_CASE("read nested message fields: no submessage") {
+ const std::string buffer = load_data("nested/data-no-message");
+ protozero::pbf_reader message{buffer};
+ check_empty(message);
}
TEST_CASE("write nested message fields") {
-
std::string buffer_test;
protozero::pbf_writer pbf_test{buffer_test};
@@ -131,7 +126,6 @@ TEST_CASE("write nested message fields") {
}
TEST_CASE("write nested message fields - no message") {
-
std::string buffer_test;
protozero::pbf_writer pbf_test{buffer_test};
@@ -152,7 +146,7 @@ TEST_CASE("write nested message fields - no message") {
}
SECTION("string with subwriter") {
- protozero::pbf_writer pbf_sub(pbf_test, 1);
+ protozero::pbf_writer pbf_sub{pbf_test, 1};
}
pbf_test.add_int32(2, 77);
diff --git a/test/t/nested/writer_test_cases.cpp b/test/t/nested/writer_test_cases.cpp
index b6272b4..925fb7c 100644
--- a/test/t/nested/writer_test_cases.cpp
+++ b/test/t/nested/writer_test_cases.cpp
@@ -1,7 +1,7 @@
#include <test.hpp>
-#include "test/t/nested/testcase.pb.h"
+#include "t/nested/testcase.pb.h"
TEST_CASE("write nested message fields and check with libprotobuf") {
diff --git a/test/t/repeated/reader_test_cases.cpp b/test/t/repeated/reader_test_cases.cpp
new file mode 100644
index 0000000..8fb17c4
--- /dev/null
+++ b/test/t/repeated/reader_test_cases.cpp
@@ -0,0 +1,74 @@
+
+#include <test.hpp>
+
+TEST_CASE("read repeated fields: empty") {
+ const std::string buffer = load_data("repeated/data-empty");
+
+ protozero::pbf_reader item{buffer};
+
+ REQUIRE_FALSE(item.next());
+}
+
+TEST_CASE("read repeated fields: one") {
+ const std::string buffer = load_data("repeated/data-one");
+
+ protozero::pbf_reader item{buffer};
+
+ REQUIRE(item.next());
+ REQUIRE(item.get_int32() == 0L);
+ REQUIRE_FALSE(item.next());
+}
+
+TEST_CASE("read repeated fields: many") {
+ const std::string buffer = load_data("repeated/data-many");
+
+ protozero::pbf_reader item{buffer};
+
+ REQUIRE(item.next());
+ REQUIRE(item.get_int32() == 0L);
+
+ REQUIRE(item.next());
+ REQUIRE(item.get_int32() == 1L);
+
+ REQUIRE(item.next());
+ REQUIRE(item.get_int32() == -1L);
+
+ REQUIRE(item.next());
+ REQUIRE(item.get_int32() == std::numeric_limits<int32_t>::max());
+
+ REQUIRE(item.next());
+ REQUIRE(item.get_int32() == std::numeric_limits<int32_t>::min());
+
+ REQUIRE_FALSE(item.next());
+}
+
+TEST_CASE("read repeated fields: end of buffer") {
+ const std::string buffer = load_data("repeated/data-one");
+
+ for (std::string::size_type i = 1; i < buffer.size(); ++i) {
+ protozero::pbf_reader item{buffer.data(), i};
+ REQUIRE(item.next());
+ REQUIRE_THROWS_AS(item.get_int32(), const protozero::end_of_buffer_exception&);
+ }
+}
+
+TEST_CASE("write repeated fields") {
+ std::string buffer;
+ protozero::pbf_writer pw{buffer};
+
+ SECTION("one") {
+ pw.add_int32(1, 0L);
+ REQUIRE(buffer == load_data("repeated/data-one"));
+ }
+
+ SECTION("many") {
+ pw.add_int32(1, 0L);
+ pw.add_int32(1, 1L);
+ pw.add_int32(1, -1L);
+ pw.add_int32(1, std::numeric_limits<int32_t>::max());
+ pw.add_int32(1, std::numeric_limits<int32_t>::min());
+
+ REQUIRE(buffer == load_data("repeated/data-many"));
+ }
+}
+
diff --git a/test/t/repeated/test_cases.cpp b/test/t/repeated/test_cases.cpp
deleted file mode 100644
index 6a08b18..0000000
--- a/test/t/repeated/test_cases.cpp
+++ /dev/null
@@ -1,80 +0,0 @@
-
-#include <test.hpp>
-
-TEST_CASE("read repeated fields") {
-
- SECTION("empty") {
- const std::string buffer = load_data("repeated/data-empty");
-
- protozero::pbf_reader item(buffer);
-
- REQUIRE_FALSE(item.next());
- }
-
- SECTION("one") {
- const std::string buffer = load_data("repeated/data-one");
-
- protozero::pbf_reader item(buffer);
-
- REQUIRE(item.next());
- REQUIRE(item.get_int32() == 0L);
- REQUIRE_FALSE(item.next());
- }
-
- SECTION("many") {
- const std::string buffer = load_data("repeated/data-many");
-
- protozero::pbf_reader item(buffer);
-
- REQUIRE(item.next());
- REQUIRE(item.get_int32() == 0L);
-
- REQUIRE(item.next());
- REQUIRE(item.get_int32() == 1L);
-
- REQUIRE(item.next());
- REQUIRE(item.get_int32() == -1L);
-
- REQUIRE(item.next());
- REQUIRE(item.get_int32() == std::numeric_limits<int32_t>::max());
-
- REQUIRE(item.next());
- REQUIRE(item.get_int32() == std::numeric_limits<int32_t>::min());
-
- REQUIRE_FALSE(item.next());
- }
-
- SECTION("end_of_buffer") {
- const std::string buffer = load_data("repeated/data-one");
-
- for (std::string::size_type i = 1; i < buffer.size(); ++i) {
- protozero::pbf_reader item(buffer.data(), i);
- REQUIRE(item.next());
- REQUIRE_THROWS_AS(item.get_int32(), const protozero::end_of_buffer_exception&);
- }
- }
-
-}
-
-TEST_CASE("write repeated fields") {
-
- std::string buffer;
- protozero::pbf_writer pw(buffer);
-
- SECTION("one") {
- pw.add_int32(1, 0L);
- REQUIRE(buffer == load_data("repeated/data-one"));
- }
-
- SECTION("many") {
- pw.add_int32(1, 0L);
- pw.add_int32(1, 1L);
- pw.add_int32(1, -1L);
- pw.add_int32(1, std::numeric_limits<int32_t>::max());
- pw.add_int32(1, std::numeric_limits<int32_t>::min());
-
- REQUIRE(buffer == load_data("repeated/data-many"));
- }
-
-}
-
diff --git a/test/t/repeated/writer_test_cases.cpp b/test/t/repeated/writer_test_cases.cpp
index 90194b0..ebe1b06 100644
--- a/test/t/repeated/writer_test_cases.cpp
+++ b/test/t/repeated/writer_test_cases.cpp
@@ -1,12 +1,12 @@
#include <test.hpp>
-#include "test/t/repeated/testcase.pb.h"
+#include "t/repeated/testcase.pb.h"
TEST_CASE("write repeated fields and check with libprotobuf") {
std::string buffer;
- protozero::pbf_writer pw(buffer);
+ protozero::pbf_writer pw{buffer};
TestRepeated::Test msg;
diff --git a/test/t/repeated_packed_bool/test_cases.cpp b/test/t/repeated_packed_bool/reader_test_cases.cpp
similarity index 62%
rename from test/t/repeated_packed_bool/test_cases.cpp
rename to test/t/repeated_packed_bool/reader_test_cases.cpp
index 002f819..aea44a4 100644
--- a/test/t/repeated_packed_bool/test_cases.cpp
+++ b/test/t/repeated_packed_bool/reader_test_cases.cpp
@@ -1,64 +1,59 @@
#include <test.hpp>
-TEST_CASE("read repeated packed bool field") {
+TEST_CASE("read repeated packed bool field: empty") {
+ const std::string buffer = load_data("repeated_packed_bool/data-empty");
- SECTION("empty") {
- const std::string buffer = load_data("repeated_packed_bool/data-empty");
+ protozero::pbf_reader item{buffer};
- protozero::pbf_reader item{buffer};
+ REQUIRE_FALSE(item.next());
+}
- REQUIRE_FALSE(item.next());
- }
+TEST_CASE("read repeated packed bool field: one") {
+ const std::string buffer = load_data("repeated_packed_bool/data-one");
- SECTION("one") {
- const std::string buffer = load_data("repeated_packed_bool/data-one");
+ protozero::pbf_reader item{buffer};
- protozero::pbf_reader item{buffer};
+ REQUIRE(item.next());
+ const auto it_range = item.get_packed_bool();
+ REQUIRE(it_range.size() == 1);
+ REQUIRE_FALSE(item.next());
- REQUIRE(item.next());
- const auto it_range = item.get_packed_bool();
- REQUIRE(it_range.size() == 1);
- REQUIRE_FALSE(item.next());
+ REQUIRE(it_range.begin() != it_range.end());
+ REQUIRE(*it_range.begin());
+ REQUIRE(std::next(it_range.begin()) == it_range.end());
+}
- REQUIRE(it_range.begin() != it_range.end());
- REQUIRE(*it_range.begin());
- REQUIRE(std::next(it_range.begin()) == it_range.end());
- }
+TEST_CASE("read repeated packed bool field: many") {
+ const std::string buffer = load_data("repeated_packed_bool/data-many");
- SECTION("many") {
- const std::string buffer = load_data("repeated_packed_bool/data-many");
+ protozero::pbf_reader item{buffer};
- protozero::pbf_reader item{buffer};
+ REQUIRE(item.next());
+ const auto it_range = item.get_packed_bool();
+ REQUIRE(it_range.size() == 4);
+ REQUIRE_FALSE(item.next());
- REQUIRE(item.next());
- const auto it_range = item.get_packed_bool();
- REQUIRE(it_range.size() == 4);
- REQUIRE_FALSE(item.next());
-
- auto it = it_range.begin();
- REQUIRE(it != it_range.end());
- REQUIRE(*it++);
- REQUIRE(*it++);
- REQUIRE_FALSE(*it++);
- REQUIRE(*it++);
- REQUIRE(it == it_range.end());
- }
+ auto it = it_range.begin();
+ REQUIRE(it != it_range.end());
+ REQUIRE(*it++);
+ REQUIRE(*it++);
+ REQUIRE_FALSE(*it++);
+ REQUIRE(*it++);
+ REQUIRE(it == it_range.end());
+}
- SECTION("end_of_buffer") {
- const std::string buffer = load_data("repeated_packed_bool/data-many");
+TEST_CASE("read repeated packed bool field: end of buffer") {
+ const std::string buffer = load_data("repeated_packed_bool/data-many");
- for (std::string::size_type i = 1; i < buffer.size(); ++i) {
- protozero::pbf_reader item{buffer.data(), i};
- REQUIRE(item.next());
- REQUIRE_THROWS_AS(item.get_packed_bool(), const protozero::end_of_buffer_exception&);
- }
+ for (std::string::size_type i = 1; i < buffer.size(); ++i) {
+ protozero::pbf_reader item{buffer.data(), i};
+ REQUIRE(item.next());
+ REQUIRE_THROWS_AS(item.get_packed_bool(), const protozero::end_of_buffer_exception&);
}
-
}
TEST_CASE("write repeated packed bool field") {
-
std::string buffer;
protozero::pbf_writer pw{buffer};
@@ -86,7 +81,6 @@ TEST_CASE("write repeated packed bool field") {
}
TEST_CASE("write repeated packed bool field using packed_field_bool") {
-
std::string buffer;
protozero::pbf_writer pw{buffer};
@@ -118,11 +112,9 @@ TEST_CASE("write repeated packed bool field using packed_field_bool") {
REQUIRE(buffer == load_data("repeated_packed_bool/data-many"));
}
-
}
TEST_CASE("write repeated packed bool field using packed_field_bool with pbf_builder") {
-
enum class msg : protozero::pbf_tag_type {
f = 1
};
@@ -158,6 +150,5 @@ TEST_CASE("write repeated packed bool field using packed_field_bool with pbf_bui
REQUIRE(buffer == load_data("repeated_packed_bool/data-many"));
}
-
}
diff --git a/test/t/repeated_packed_double/test_cases.cpp b/test/t/repeated_packed_double/reader_test_cases.cpp
similarity index 78%
rename from test/t/repeated_packed_double/test_cases.cpp
rename to test/t/repeated_packed_double/reader_test_cases.cpp
index 238c77d..4d2a789 100644
--- a/test/t/repeated_packed_double/test_cases.cpp
+++ b/test/t/repeated_packed_double/reader_test_cases.cpp
@@ -2,7 +2,6 @@
#include <test.hpp>
TEST_CASE("read repeated packed double field") {
-
// Run these tests twice, the second time we basically move the data
// one byte down in the buffer. It doesn't matter how the data or buffer
// is aligned before that, in at least one of these cases the doubles will
@@ -10,24 +9,23 @@ TEST_CASE("read repeated packed double field") {
// will be extracted properly.
for (std::string::size_type n = 0; n < 2; ++n) {
-
std::string abuffer;
abuffer.reserve(1000);
abuffer.append(n, '\0');
SECTION("empty") {
abuffer.append(load_data("repeated_packed_double/data-empty"));
- protozero::pbf_reader item(abuffer.data() + n, abuffer.size() - n);
+ protozero::pbf_reader item{abuffer.data() + n, abuffer.size() - n};
REQUIRE_FALSE(item.next());
}
SECTION("one") {
abuffer.append(load_data("repeated_packed_double/data-one"));
- protozero::pbf_reader item(abuffer.data() + n, abuffer.size() - n);
+ protozero::pbf_reader item{abuffer.data() + n, abuffer.size() - n};
REQUIRE(item.next());
- auto it_range = item.get_packed_double();
+ const auto it_range = item.get_packed_double();
REQUIRE_FALSE(item.next());
REQUIRE(*it_range.begin() == 17.34);
@@ -36,10 +34,10 @@ TEST_CASE("read repeated packed double field") {
SECTION("many") {
abuffer.append(load_data("repeated_packed_double/data-many"));
- protozero::pbf_reader item(abuffer.data() + n, abuffer.size() - n);
+ protozero::pbf_reader item{abuffer.data() + n, abuffer.size() - n};
REQUIRE(item.next());
- auto it_range = item.get_packed_double();
+ const auto it_range = item.get_packed_double();
REQUIRE_FALSE(item.next());
auto it = it_range.begin();
@@ -55,41 +53,37 @@ TEST_CASE("read repeated packed double field") {
abuffer.append(load_data("repeated_packed_double/data-many"));
for (std::string::size_type i = 1; i < abuffer.size() - n; ++i) {
- protozero::pbf_reader item(abuffer.data() + n, i);
+ protozero::pbf_reader item{abuffer.data() + n, i};
REQUIRE(item.next());
REQUIRE_THROWS_AS(item.get_packed_double(), const protozero::end_of_buffer_exception&);
}
}
-
}
-
}
TEST_CASE("write repeated packed double field") {
-
std::string buffer;
- protozero::pbf_writer pw(buffer);
+ protozero::pbf_writer pw{buffer};
SECTION("empty") {
- double data[] = { 17.34 };
+ const double data[] = { 17.34 };
pw.add_packed_double(1, std::begin(data), std::begin(data) /* !!!! */);
REQUIRE(buffer == load_data("repeated_packed_double/data-empty"));
}
SECTION("one") {
- double data[] = { 17.34 };
+ const double data[] = { 17.34 };
pw.add_packed_double(1, std::begin(data), std::end(data));
REQUIRE(buffer == load_data("repeated_packed_double/data-one"));
}
SECTION("many") {
- double data[] = { 17.34, 0.0, 1.0, std::numeric_limits<double>::min(), std::numeric_limits<double>::max() };
+ const double data[] = { 17.34, 0.0, 1.0, std::numeric_limits<double>::min(), std::numeric_limits<double>::max() };
pw.add_packed_double(1, std::begin(data), std::end(data));
REQUIRE(buffer == load_data("repeated_packed_double/data-many"));
}
-
}
diff --git a/test/t/repeated_packed_enum/reader_test_cases.cpp b/test/t/repeated_packed_enum/reader_test_cases.cpp
new file mode 100644
index 0000000..248474c
--- /dev/null
+++ b/test/t/repeated_packed_enum/reader_test_cases.cpp
@@ -0,0 +1,78 @@
+
+#include <test.hpp>
+
+TEST_CASE("read repeated packed enum field: empty") {
+ const std::string buffer = load_data("repeated_packed_enum/data-empty");
+
+ protozero::pbf_reader item{buffer};
+
+ REQUIRE_FALSE(item.next());
+}
+
+TEST_CASE("read repeated packed enum field: one") {
+ const std::string buffer = load_data("repeated_packed_enum/data-one");
+
+ protozero::pbf_reader item{buffer};
+
+ REQUIRE(item.next());
+ const auto it_range = item.get_packed_enum();
+ REQUIRE_FALSE(item.next());
+
+ REQUIRE(it_range.begin() != it_range.end());
+ REQUIRE(*it_range.begin() == 0 /* BLACK */);
+ REQUIRE(std::next(it_range.begin()) == it_range.end());
+}
+
+TEST_CASE("read repeated packed enum field: many") {
+ const std::string buffer = load_data("repeated_packed_enum/data-many");
+
+ protozero::pbf_reader item{buffer};
+
+ REQUIRE(item.next());
+ const auto it_range = item.get_packed_enum();
+ REQUIRE_FALSE(item.next());
+
+ auto it = it_range.begin();
+ REQUIRE(it != it_range.end());
+ REQUIRE(*it++ == 0 /* BLACK */);
+ REQUIRE(*it++ == 3 /* BLUE */);
+ REQUIRE(*it++ == 2 /* GREEN */);
+ REQUIRE(it == it_range.end());
+}
+
+TEST_CASE("read repeated packed enum field: end of buffer") {
+ const std::string buffer = load_data("repeated_packed_enum/data-many");
+
+ for (std::string::size_type i = 1; i < buffer.size(); ++i) {
+ protozero::pbf_reader item{buffer.data(), i};
+ REQUIRE(item.next());
+ REQUIRE_THROWS_AS(item.get_packed_enum(), const protozero::end_of_buffer_exception&);
+ }
+}
+
+TEST_CASE("write repeated packed enum field") {
+ std::string buffer;
+ protozero::pbf_writer pw{buffer};
+
+ SECTION("empty") {
+ const int32_t data[] = { 0 /* BLACK */ };
+ pw.add_packed_enum(1, std::begin(data), std::begin(data) /* !!!! */);
+
+ REQUIRE(buffer == load_data("repeated_packed_enum/data-empty"));
+ }
+
+ SECTION("one") {
+ const int32_t data[] = { 0 /* BLACK */ };
+ pw.add_packed_enum(1, std::begin(data), std::end(data));
+
+ REQUIRE(buffer == load_data("repeated_packed_enum/data-one"));
+ }
+
+ SECTION("many") {
+ const int32_t data[] = { 0 /* BLACK */, 3 /* BLUE */, 2 /* GREEN */ };
+ pw.add_packed_enum(1, std::begin(data), std::end(data));
+
+ REQUIRE(buffer == load_data("repeated_packed_enum/data-many"));
+ }
+}
+
diff --git a/test/t/repeated_packed_enum/test_cases.cpp b/test/t/repeated_packed_enum/test_cases.cpp
deleted file mode 100644
index d3b7794..0000000
--- a/test/t/repeated_packed_enum/test_cases.cpp
+++ /dev/null
@@ -1,84 +0,0 @@
-
-#include <test.hpp>
-
-TEST_CASE("read repeated packed enum field") {
-
- SECTION("empty") {
- const std::string buffer = load_data("repeated_packed_enum/data-empty");
-
- protozero::pbf_reader item(buffer);
-
- REQUIRE_FALSE(item.next());
- }
-
- SECTION("one") {
- const std::string buffer = load_data("repeated_packed_enum/data-one");
-
- protozero::pbf_reader item(buffer);
-
- REQUIRE(item.next());
- auto it_range = item.get_packed_enum();
- REQUIRE_FALSE(item.next());
-
- REQUIRE(it_range.begin() != it_range.end());
- REQUIRE(*it_range.begin() == 0 /* BLACK */);
- REQUIRE(std::next(it_range.begin()) == it_range.end());
- }
-
- SECTION("many") {
- const std::string buffer = load_data("repeated_packed_enum/data-many");
-
- protozero::pbf_reader item(buffer);
-
- REQUIRE(item.next());
- auto it_range = item.get_packed_enum();
- REQUIRE_FALSE(item.next());
-
- auto it = it_range.begin();
- REQUIRE(it != it_range.end());
- REQUIRE(*it++ == 0 /* BLACK */);
- REQUIRE(*it++ == 3 /* BLUE */);
- REQUIRE(*it++ == 2 /* GREEN */);
- REQUIRE(it == it_range.end());
- }
-
- SECTION("end_of_buffer") {
- const std::string buffer = load_data("repeated_packed_enum/data-many");
-
- for (std::string::size_type i = 1; i < buffer.size(); ++i) {
- protozero::pbf_reader item(buffer.data(), i);
- REQUIRE(item.next());
- REQUIRE_THROWS_AS(item.get_packed_enum(), const protozero::end_of_buffer_exception&);
- }
- }
-
-}
-
-TEST_CASE("write repeated packed enum field") {
-
- std::string buffer;
- protozero::pbf_writer pw(buffer);
-
- SECTION("empty") {
- int32_t data[] = { 0 /* BLACK */ };
- pw.add_packed_enum(1, std::begin(data), std::begin(data) /* !!!! */);
-
- REQUIRE(buffer == load_data("repeated_packed_enum/data-empty"));
- }
-
- SECTION("one") {
- int32_t data[] = { 0 /* BLACK */ };
- pw.add_packed_enum(1, std::begin(data), std::end(data));
-
- REQUIRE(buffer == load_data("repeated_packed_enum/data-one"));
- }
-
- SECTION("many") {
- int32_t data[] = { 0 /* BLACK */, 3 /* BLUE */, 2 /* GREEN */ };
- pw.add_packed_enum(1, std::begin(data), std::end(data));
-
- REQUIRE(buffer == load_data("repeated_packed_enum/data-many"));
- }
-
-}
-
diff --git a/test/t/repeated_packed_fixed32/test_cases.cpp b/test/t/repeated_packed_fixed32/reader_test_cases.cpp
similarity index 100%
rename from test/t/repeated_packed_fixed32/test_cases.cpp
rename to test/t/repeated_packed_fixed32/reader_test_cases.cpp
diff --git a/test/t/repeated_packed_fixed32/writer_test_cases.cpp b/test/t/repeated_packed_fixed32/writer_test_cases.cpp
index 2d49c0f..416b174 100644
--- a/test/t/repeated_packed_fixed32/writer_test_cases.cpp
+++ b/test/t/repeated_packed_fixed32/writer_test_cases.cpp
@@ -1,22 +1,18 @@
#include <test.hpp>
-#include "test/t/repeated_packed_fixed32/testcase.pb.h"
+#include "t/repeated_packed_fixed32/testcase.pb.h"
TEST_CASE("write repeated packed fixed32 field and check with libprotobuf") {
std::string buffer;
- protozero::pbf_writer pw(buffer);
+ protozero::pbf_writer pw{buffer};
TestRepeatedPackedFixed32::Test msg;
SECTION("empty") {
uint32_t data[] = { 17UL };
pw.add_packed_fixed32(1, std::begin(data), std::begin(data) /* !!!! */);
-
- msg.ParseFromString(buffer);
-
- REQUIRE(msg.i().size() == 0);
}
SECTION("one") {
@@ -41,13 +37,12 @@ TEST_CASE("write repeated packed fixed32 field and check with libprotobuf") {
REQUIRE(msg.i(2) == 1UL);
REQUIRE(msg.i(3) == std::numeric_limits<uint32_t>::max());
}
-
}
TEST_CASE("write from different types of iterators and check with libprotobuf") {
std::string buffer;
- protozero::pbf_writer pw(buffer);
+ protozero::pbf_writer pw{buffer};
TestRepeatedPackedFixed32::Test msg;
diff --git a/test/t/repeated_packed_fixed64/test_cases.cpp b/test/t/repeated_packed_fixed64/reader_test_cases.cpp
similarity index 100%
rename from test/t/repeated_packed_fixed64/test_cases.cpp
rename to test/t/repeated_packed_fixed64/reader_test_cases.cpp
diff --git a/test/t/repeated_packed_float/test_cases.cpp b/test/t/repeated_packed_float/reader_test_cases.cpp
similarity index 88%
rename from test/t/repeated_packed_float/test_cases.cpp
rename to test/t/repeated_packed_float/reader_test_cases.cpp
index c0d9d46..e600933 100644
--- a/test/t/repeated_packed_float/test_cases.cpp
+++ b/test/t/repeated_packed_float/reader_test_cases.cpp
@@ -2,7 +2,6 @@
#include <test.hpp>
TEST_CASE("read repeated packed float field") {
-
// Run these tests twice, the second time we basically move the data
// one byte down in the buffer. It doesn't matter how the data or buffer
// is aligned before that, in at least one of these cases the floats will
@@ -10,21 +9,20 @@ TEST_CASE("read repeated packed float field") {
// will be extracted properly.
for (std::string::size_type n = 0; n < 2; ++n) {
-
std::string abuffer;
abuffer.reserve(1000);
abuffer.append(n, '\0');
SECTION("empty") {
abuffer.append(load_data("repeated_packed_float/data-empty"));
- protozero::pbf_reader item(abuffer.data() + n, abuffer.size() - n);
+ protozero::pbf_reader item{abuffer.data() + n, abuffer.size() - n};
REQUIRE_FALSE(item.next());
}
SECTION("one") {
abuffer.append(load_data("repeated_packed_float/data-one"));
- protozero::pbf_reader item(abuffer.data() + n, abuffer.size() - n);
+ protozero::pbf_reader item{abuffer.data() + n, abuffer.size() - n};
REQUIRE(item.next());
auto it_range = item.get_packed_float();
@@ -36,7 +34,7 @@ TEST_CASE("read repeated packed float field") {
SECTION("many") {
abuffer.append(load_data("repeated_packed_float/data-many"));
- protozero::pbf_reader item(abuffer.data() + n, abuffer.size() - n);
+ protozero::pbf_reader item{abuffer.data() + n, abuffer.size() - n};
REQUIRE(item.next());
auto it_range = item.get_packed_float();
@@ -55,20 +53,17 @@ TEST_CASE("read repeated packed float field") {
abuffer.append(load_data("repeated_packed_float/data-many"));
for (std::string::size_type i = 1; i < abuffer.size() - n; ++i) {
- protozero::pbf_reader item(abuffer.data() + n, i);
+ protozero::pbf_reader item{abuffer.data() + n, i};
REQUIRE(item.next());
REQUIRE_THROWS_AS(item.get_packed_float(), const protozero::end_of_buffer_exception&);
}
}
-
}
-
}
TEST_CASE("write repeated packed float field") {
-
std::string buffer;
- protozero::pbf_writer pw(buffer);
+ protozero::pbf_writer pw{buffer};
SECTION("empty") {
float data[] = { 17.34f };
@@ -90,6 +85,5 @@ TEST_CASE("write repeated packed float field") {
REQUIRE(buffer == load_data("repeated_packed_float/data-many"));
}
-
}
diff --git a/test/t/repeated_packed_int32/test_cases.cpp b/test/t/repeated_packed_int32/reader_test_cases.cpp
similarity index 100%
rename from test/t/repeated_packed_int32/test_cases.cpp
rename to test/t/repeated_packed_int32/reader_test_cases.cpp
diff --git a/test/t/repeated_packed_int64/test_cases.cpp b/test/t/repeated_packed_int64/reader_test_cases.cpp
similarity index 100%
rename from test/t/repeated_packed_int64/test_cases.cpp
rename to test/t/repeated_packed_int64/reader_test_cases.cpp
diff --git a/test/t/repeated_packed_sfixed32/reader_test_cases.cpp b/test/t/repeated_packed_sfixed32/reader_test_cases.cpp
new file mode 100644
index 0000000..eb308f7
--- /dev/null
+++ b/test/t/repeated_packed_sfixed32/reader_test_cases.cpp
@@ -0,0 +1,30 @@
+
+#include <test.hpp>
+
+#define PBF_TYPE sfixed32
+#define PBF_TYPE_IS_SIGNED 1
+using cpp_type = int32_t;
+
+#include <packed_access.hpp>
+
+TEST_CASE("length value must be dividable by sizeof(T)") {
+ std::string data{load_data("repeated_packed_sfixed32/data-many")};
+
+ SECTION("1") {
+ data[1] = 1;
+ }
+
+ SECTION("2") {
+ data[1] = 2;
+ }
+
+ SECTION("3") {
+ data[1] = 3;
+ }
+
+ protozero::pbf_reader item{data};
+
+ REQUIRE(item.next());
+ REQUIRE_THROWS_AS(item.get_packed_sfixed32(), const protozero::invalid_length_exception&);
+}
+
diff --git a/test/t/repeated_packed_sfixed32/test_cases.cpp b/test/t/repeated_packed_sfixed32/test_cases.cpp
deleted file mode 100644
index c8eb8dd..0000000
--- a/test/t/repeated_packed_sfixed32/test_cases.cpp
+++ /dev/null
@@ -1,9 +0,0 @@
-
-#include <test.hpp>
-
-#define PBF_TYPE sfixed32
-#define PBF_TYPE_IS_SIGNED 1
-using cpp_type = int32_t;
-
-#include <packed_access.hpp>
-
diff --git a/test/t/repeated_packed_sfixed64/test_cases.cpp b/test/t/repeated_packed_sfixed64/reader_test_cases.cpp
similarity index 100%
rename from test/t/repeated_packed_sfixed64/test_cases.cpp
rename to test/t/repeated_packed_sfixed64/reader_test_cases.cpp
diff --git a/test/t/repeated_packed_sint32/test_cases.cpp b/test/t/repeated_packed_sint32/reader_test_cases.cpp
similarity index 100%
rename from test/t/repeated_packed_sint32/test_cases.cpp
rename to test/t/repeated_packed_sint32/reader_test_cases.cpp
diff --git a/test/t/repeated_packed_sint64/test_cases.cpp b/test/t/repeated_packed_sint64/reader_test_cases.cpp
similarity index 100%
rename from test/t/repeated_packed_sint64/test_cases.cpp
rename to test/t/repeated_packed_sint64/reader_test_cases.cpp
diff --git a/test/t/repeated_packed_uint32/test_cases.cpp b/test/t/repeated_packed_uint32/reader_test_cases.cpp
similarity index 100%
rename from test/t/repeated_packed_uint32/test_cases.cpp
rename to test/t/repeated_packed_uint32/reader_test_cases.cpp
diff --git a/test/t/repeated_packed_uint64/test_cases.cpp b/test/t/repeated_packed_uint64/reader_test_cases.cpp
similarity index 100%
rename from test/t/repeated_packed_uint64/test_cases.cpp
rename to test/t/repeated_packed_uint64/reader_test_cases.cpp
diff --git a/test/t/rollback/test_cases.cpp b/test/t/rollback/reader_test_cases.cpp
similarity index 97%
rename from test/t/rollback/test_cases.cpp
rename to test/t/rollback/reader_test_cases.cpp
index 51bf5f3..fa4c77f 100644
--- a/test/t/rollback/test_cases.cpp
+++ b/test/t/rollback/reader_test_cases.cpp
@@ -2,7 +2,6 @@
#include <test.hpp>
TEST_CASE("rollback when using packed_field functions") {
-
std::string buffer;
protozero::pbf_writer pw{buffer};
@@ -51,7 +50,7 @@ TEST_CASE("rollback when using packed_field functions") {
msg.next();
REQUIRE(msg.tag() == 1);
- auto it_range = msg.get_packed_sint64();
+ const auto it_range = msg.get_packed_sint64();
auto it = it_range.begin();
REQUIRE(*it++ == 17L);
REQUIRE(it == it_range.end());
@@ -86,7 +85,7 @@ TEST_CASE("rollback when using packed_field functions") {
msg.next();
REQUIRE(msg.tag() == 1);
- auto it_range = msg.get_packed_sint64();
+ const auto it_range = msg.get_packed_sint64();
auto it = it_range.begin();
REQUIRE(*it++ == 17L);
REQUIRE(*it++ == 0L);
@@ -138,7 +137,6 @@ TEST_CASE("rollback when using packed_field functions") {
}
TEST_CASE("rollback when using submessages") {
-
std::string buffer;
protozero::pbf_writer pw{buffer};
@@ -191,7 +189,7 @@ TEST_CASE("rollback on parent message is not allowed even if there is a submessa
TEST_CASE("rollback on message is not allowed if there is a nested submessage") {
std::string buffer;
- protozero::pbf_writer pw(buffer);
+ protozero::pbf_writer pw{buffer};
pw.add_fixed64(2, 111);
pw.add_string(3, "foo");
diff --git a/test/t/sfixed32/test_cases.cpp b/test/t/sfixed32/reader_test_cases.cpp
similarity index 100%
rename from test/t/sfixed32/test_cases.cpp
rename to test/t/sfixed32/reader_test_cases.cpp
diff --git a/test/t/sfixed64/test_cases.cpp b/test/t/sfixed64/reader_test_cases.cpp
similarity index 100%
rename from test/t/sfixed64/test_cases.cpp
rename to test/t/sfixed64/reader_test_cases.cpp
diff --git a/test/t/sint32/test_cases.cpp b/test/t/sint32/reader_test_cases.cpp
similarity index 100%
rename from test/t/sint32/test_cases.cpp
rename to test/t/sint32/reader_test_cases.cpp
diff --git a/test/t/sint64/test_cases.cpp b/test/t/sint64/reader_test_cases.cpp
similarity index 100%
rename from test/t/sint64/test_cases.cpp
rename to test/t/sint64/reader_test_cases.cpp
diff --git a/test/t/skip/test_cases.cpp b/test/t/skip/reader_test_cases.cpp
similarity index 99%
rename from test/t/skip/test_cases.cpp
rename to test/t/skip/reader_test_cases.cpp
index ed1a3b5..b6de3e8 100644
--- a/test/t/skip/test_cases.cpp
+++ b/test/t/skip/reader_test_cases.cpp
@@ -2,7 +2,6 @@
#include <test.hpp>
TEST_CASE("skip() skips the right amount of bytes") {
-
// These are all the data files which contain exactly one field.
//
// Create this list with:
@@ -107,9 +106,7 @@ TEST_CASE("skip() skips the right amount of bytes") {
}
}
-
TEST_CASE("exceptional cases") {
-
std::string buffer;
protozero::pbf_writer pw{buffer};
pw.add_fixed32(1, 123);
@@ -129,6 +126,5 @@ TEST_CASE("exceptional cases") {
REQUIRE(item.next());
REQUIRE_THROWS_AS(item.skip(), const protozero::end_of_buffer_exception&);
}
-
}
diff --git a/test/t/string/reader_test_cases.cpp b/test/t/string/reader_test_cases.cpp
new file mode 100644
index 0000000..f80c4c0
--- /dev/null
+++ b/test/t/string/reader_test_cases.cpp
@@ -0,0 +1,106 @@
+
+#include <test.hpp>
+
+TEST_CASE("read string field using get_string: empty") {
+ const std::string buffer = load_data("string/data-empty");
+
+ protozero::pbf_reader item{buffer};
+
+ REQUIRE(item.next());
+ REQUIRE(item.get_string().empty());
+ REQUIRE_FALSE(item.next());
+}
+
+TEST_CASE("read string field using get_string: one") {
+ const std::string buffer = load_data("string/data-one");
+
+ protozero::pbf_reader item{buffer};
+
+ REQUIRE(item.next());
+ REQUIRE(item.get_string() == "x");
+ REQUIRE_FALSE(item.next());
+}
+
+TEST_CASE("read string field using get_string: string") {
+ const std::string buffer = load_data("string/data-string");
+
+ protozero::pbf_reader item{buffer};
+
+ REQUIRE(item.next());
+ REQUIRE(item.get_string() == "foobar");
+ REQUIRE_FALSE(item.next());
+}
+
+TEST_CASE("read string field using get_string: end of buffer") {
+ const std::string buffer = load_data("string/data-string");
+
+ for (std::string::size_type i = 1; i < buffer.size(); ++i) {
+ protozero::pbf_reader item{buffer.data(), i};
+ REQUIRE(item.next());
+ REQUIRE_THROWS_AS(item.get_string(), const protozero::end_of_buffer_exception&);
+ }
+}
+
+TEST_CASE("read string field using get_view: empty") {
+ const std::string buffer = load_data("string/data-empty");
+
+ protozero::pbf_reader item{buffer};
+
+ REQUIRE(item.next());
+ const auto v = item.get_view();
+ REQUIRE(v.empty());
+ REQUIRE_FALSE(item.next());
+}
+
+TEST_CASE("read string field using get_view: one") {
+ const std::string buffer = load_data("string/data-one");
+
+ protozero::pbf_reader item{buffer};
+
+ REQUIRE(item.next());
+ const auto v = item.get_view();
+ REQUIRE(*v.data() == 'x');
+ REQUIRE(v.size() == 1);
+ REQUIRE_FALSE(item.next());
+}
+
+TEST_CASE("read string field using get_view: string") {
+ const std::string buffer = load_data("string/data-string");
+
+ protozero::pbf_reader item{buffer};
+
+ REQUIRE(item.next());
+ REQUIRE(std::string(item.get_view()) == "foobar");
+ REQUIRE_FALSE(item.next());
+}
+
+TEST_CASE("read string field using get_view: end of buffer") {
+ const std::string buffer = load_data("string/data-string");
+
+ for (std::string::size_type i = 1; i < buffer.size(); ++i) {
+ protozero::pbf_reader item{buffer.data(), i};
+ REQUIRE(item.next());
+ REQUIRE_THROWS_AS(item.get_view(), const protozero::end_of_buffer_exception&);
+ }
+}
+
+TEST_CASE("write string field") {
+ std::string buffer_test;
+ protozero::pbf_writer pbf_test{buffer_test};
+
+ SECTION("empty") {
+ pbf_test.add_string(1, "");
+ REQUIRE(buffer_test == load_data("string/data-empty"));
+ }
+
+ SECTION("one") {
+ pbf_test.add_string(1, "x");
+ REQUIRE(buffer_test == load_data("string/data-one"));
+ }
+
+ SECTION("string") {
+ pbf_test.add_string(1, "foobar");
+ REQUIRE(buffer_test == load_data("string/data-string"));
+ }
+}
+
diff --git a/test/t/string/test_cases.cpp b/test/t/string/test_cases.cpp
deleted file mode 100644
index 393c3bb..0000000
--- a/test/t/string/test_cases.cpp
+++ /dev/null
@@ -1,116 +0,0 @@
-
-#include <test.hpp>
-
-TEST_CASE("read string field using get_string") {
-
- SECTION("empty") {
- const std::string buffer = load_data("string/data-empty");
-
- protozero::pbf_reader item(buffer);
-
- REQUIRE(item.next());
- REQUIRE(item.get_string().empty());
- REQUIRE_FALSE(item.next());
- }
-
- SECTION("one") {
- const std::string buffer = load_data("string/data-one");
-
- protozero::pbf_reader item(buffer);
-
- REQUIRE(item.next());
- REQUIRE(item.get_string() == "x");
- REQUIRE_FALSE(item.next());
- }
-
- SECTION("string") {
- const std::string buffer = load_data("string/data-string");
-
- protozero::pbf_reader item(buffer);
-
- REQUIRE(item.next());
- REQUIRE(item.get_string() == "foobar");
- REQUIRE_FALSE(item.next());
- }
-
- SECTION("end_of_buffer") {
- const std::string buffer = load_data("string/data-string");
-
- for (std::string::size_type i = 1; i < buffer.size(); ++i) {
- protozero::pbf_reader item(buffer.data(), i);
- REQUIRE(item.next());
- REQUIRE_THROWS_AS(item.get_string(), const protozero::end_of_buffer_exception&);
- }
- }
-
-}
-
-TEST_CASE("read string field using get_view") {
-
- SECTION("empty") {
- const std::string buffer = load_data("string/data-empty");
-
- protozero::pbf_reader item(buffer);
-
- REQUIRE(item.next());
- auto v = item.get_view();
- REQUIRE(v.empty());
- REQUIRE_FALSE(item.next());
- }
-
- SECTION("one") {
- const std::string buffer = load_data("string/data-one");
-
- protozero::pbf_reader item(buffer);
-
- REQUIRE(item.next());
- auto v = item.get_view();
- REQUIRE(*v.data() == 'x');
- REQUIRE(v.size() == 1);
- REQUIRE_FALSE(item.next());
- }
-
- SECTION("string") {
- const std::string buffer = load_data("string/data-string");
-
- protozero::pbf_reader item(buffer);
-
- REQUIRE(item.next());
- REQUIRE(std::string(item.get_view()) == "foobar");
- REQUIRE_FALSE(item.next());
- }
-
- SECTION("end_of_buffer") {
- const std::string buffer = load_data("string/data-string");
-
- for (std::string::size_type i = 1; i < buffer.size(); ++i) {
- protozero::pbf_reader item(buffer.data(), i);
- REQUIRE(item.next());
- REQUIRE_THROWS_AS(item.get_view(), const protozero::end_of_buffer_exception&);
- }
- }
-
-}
-
-TEST_CASE("write string field") {
-
- std::string buffer_test;
- protozero::pbf_writer pbf_test(buffer_test);
-
- SECTION("empty") {
- pbf_test.add_string(1, "");
- REQUIRE(buffer_test == load_data("string/data-empty"));
- }
-
- SECTION("one") {
- pbf_test.add_string(1, "x");
- REQUIRE(buffer_test == load_data("string/data-one"));
- }
-
- SECTION("string") {
- pbf_test.add_string(1, "foobar");
- REQUIRE(buffer_test == load_data("string/data-string"));
- }
-
-}
-
diff --git a/test/t/string/writer_test_cases.cpp b/test/t/string/writer_test_cases.cpp
index 145fd78..6645dab 100644
--- a/test/t/string/writer_test_cases.cpp
+++ b/test/t/string/writer_test_cases.cpp
@@ -1,12 +1,12 @@
#include <test.hpp>
-#include "test/t/string/testcase.pb.h"
+#include "t/string/testcase.pb.h"
TEST_CASE("write string field and check with libprotobuf") {
std::string buffer;
- protozero::pbf_writer pw(buffer);
+ protozero::pbf_writer pw{buffer};
TestString::Test msg;
@@ -15,7 +15,7 @@ TEST_CASE("write string field and check with libprotobuf") {
msg.ParseFromString(buffer);
- REQUIRE(msg.s() == "");
+ REQUIRE(msg.s().empty());
}
SECTION("one") {
diff --git a/test/t/tag_and_type/test_cases.cpp b/test/t/tag_and_type/reader_test_cases.cpp
similarity index 100%
rename from test/t/tag_and_type/test_cases.cpp
rename to test/t/tag_and_type/reader_test_cases.cpp
diff --git a/test/t/tags/test_cases.cpp b/test/t/tags/reader_test_cases.cpp
similarity index 63%
rename from test/t/tags/test_cases.cpp
rename to test/t/tags/reader_test_cases.cpp
index 22169ec..f2626ed 100644
--- a/test/t/tags/test_cases.cpp
+++ b/test/t/tags/reader_test_cases.cpp
@@ -2,7 +2,7 @@
#include <test.hpp>
inline void check_tag(const std::string& buffer, protozero::pbf_tag_type tag) {
- protozero::pbf_reader item(buffer);
+ protozero::pbf_reader item{buffer};
REQUIRE(item.next());
REQUIRE(item.tag() == tag);
@@ -10,30 +10,25 @@ inline void check_tag(const std::string& buffer, protozero::pbf_tag_type tag) {
REQUIRE_FALSE(item.next());
}
-TEST_CASE("read tags") {
-
- SECTION("tag 1") {
- check_tag(load_data("tags/data-tag-1"), 1L);
- }
-
- SECTION("tag 200") {
- check_tag(load_data("tags/data-tag-200"), 200L);
- }
+TEST_CASE("read tag: 1") {
+ check_tag(load_data("tags/data-tag-1"), 1L);
+}
- SECTION("tag 200000") {
- check_tag(load_data("tags/data-tag-200000"), 200000L);
- }
+TEST_CASE("read tag: 200") {
+ check_tag(load_data("tags/data-tag-200"), 200L);
+}
- SECTION("tag max") {
- check_tag(load_data("tags/data-tag-max"), (1L << 29) - 1);
- }
+TEST_CASE("read tag: 200000") {
+ check_tag(load_data("tags/data-tag-200000"), 200000L);
+}
+TEST_CASE("read tag: max") {
+ check_tag(load_data("tags/data-tag-max"), (1L << 29) - 1);
}
TEST_CASE("write tags") {
-
std::string buffer;
- protozero::pbf_writer pw(buffer);
+ protozero::pbf_writer pw{buffer};
SECTION("tag 1") {
pw.add_int32(1L, 333L);
@@ -54,6 +49,5 @@ TEST_CASE("write tags") {
pw.add_int32((1L << 29) - 1, 333L);
REQUIRE(buffer == load_data("tags/data-tag-max"));
}
-
}
diff --git a/test/t/uint32/test_cases.cpp b/test/t/uint32/reader_test_cases.cpp
similarity index 100%
rename from test/t/uint32/test_cases.cpp
rename to test/t/uint32/reader_test_cases.cpp
diff --git a/test/t/uint64/test_cases.cpp b/test/t/uint64/reader_test_cases.cpp
similarity index 100%
rename from test/t/uint64/test_cases.cpp
rename to test/t/uint64/reader_test_cases.cpp
diff --git a/test/t/varint/test_cases.cpp b/test/t/varint/reader_test_cases.cpp
similarity index 72%
rename from test/t/varint/test_cases.cpp
rename to test/t/varint/reader_test_cases.cpp
index a88c1af..68111be 100644
--- a/test/t/varint/test_cases.cpp
+++ b/test/t/varint/reader_test_cases.cpp
@@ -6,7 +6,6 @@ TEST_CASE("max varint length") {
}
TEST_CASE("varint") {
-
std::string buffer;
protozero::pbf_writer pw{buffer};
@@ -102,11 +101,24 @@ TEST_CASE("varint") {
REQUIRE_THROWS_AS(item.skip(), const protozero::varint_too_long_exception&);
}
}
+}
+TEST_CASE("10-byte varint") {
+ std::string buffer;
+ protozero::pbf_writer pw{buffer};
+ pw.add_uint64(1, 1);
+ buffer.back() = static_cast<char>(0xff);
+ for (int i = 0; i < 9; ++i) {
+ buffer.push_back(static_cast<char>(0xff));
+ }
+ buffer.push_back(0x02);
+
+ protozero::pbf_reader item{buffer};
+ REQUIRE(item.next());
+ REQUIRE_THROWS_AS(item.get_uint64(), const protozero::varint_too_long_exception&);
}
TEST_CASE("lots of varints back and forth") {
-
std::string buffer;
for (uint32_t n = 0; n < 70000; ++n) {
@@ -139,5 +151,37 @@ TEST_CASE("lots of varints back and forth") {
buffer.clear();
}
+ for (int i = 0; i < 63; ++i) {
+ int64_t n = 1ll << i;
+ protozero::pbf_writer pw{buffer};
+ pw.add_int64(1, n);
+ protozero::pbf_reader item{buffer};
+ REQUIRE(item.next());
+ REQUIRE(n == item.get_int64());
+ REQUIRE_FALSE(item.next());
+ buffer.clear();
+ }
+
+ for (int i = 0; i < 63; ++i) {
+ int64_t n = - (1ll << i);
+ protozero::pbf_writer pw{buffer};
+ pw.add_int64(1, n);
+ protozero::pbf_reader item{buffer};
+ REQUIRE(item.next());
+ REQUIRE(n == item.get_int64());
+ REQUIRE_FALSE(item.next());
+ buffer.clear();
+ }
+
+ for (int i = 0; i < 64; ++i) {
+ uint64_t n = 1ull << i;
+ protozero::pbf_writer pw{buffer};
+ pw.add_int64(1, n);
+ protozero::pbf_reader item{buffer};
+ REQUIRE(item.next());
+ REQUIRE(n == item.get_int64());
+ REQUIRE_FALSE(item.next());
+ buffer.clear();
+ }
}
diff --git a/test/t/vector_tile/test_cases.cpp b/test/t/vector_tile/reader_test_cases.cpp
similarity index 99%
rename from test/t/vector_tile/test_cases.cpp
rename to test/t/vector_tile/reader_test_cases.cpp
index f28f634..4d0c729 100644
--- a/test/t/vector_tile/test_cases.cpp
+++ b/test/t/vector_tile/reader_test_cases.cpp
@@ -149,6 +149,5 @@ TEST_CASE("reading vector tiles") {
REQUIRE(n_id == 502);
REQUIRE(n_geomtype == 502);
}
-
}
diff --git a/test/t/wrong_type_access/test_cases.cpp b/test/t/wrong_type_access/reader_test_cases.cpp
similarity index 100%
rename from test/t/wrong_type_access/test_cases.cpp
rename to test/t/wrong_type_access/reader_test_cases.cpp
diff --git a/test/t/zigzag/test_cases.cpp b/test/t/zigzag/reader_test_cases.cpp
similarity index 100%
rename from test/t/zigzag/test_cases.cpp
rename to test/t/zigzag/reader_test_cases.cpp
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt
new file mode 100644
index 0000000..721a19f
--- /dev/null
+++ b/tools/CMakeLists.txt
@@ -0,0 +1,51 @@
+#-----------------------------------------------------------------------------
+#
+# CMake config
+#
+# protozero tools
+#
+#-----------------------------------------------------------------------------
+
+# Needs getopt, which is not available on Windows
+if(NOT MSVC)
+ add_executable(pbf-decoder pbf-decoder.cpp)
+
+ add_test(NAME pbf-decoder-no-args
+ COMMAND pbf-decoder)
+ set_tests_properties(pbf-decoder-no-args PROPERTIES
+ PASS_REGULAR_EXPRESSION "^Usage:")
+
+ add_test(NAME pbf-decoder-help
+ COMMAND pbf-decoder --help)
+ set_tests_properties(pbf-decoder-help PROPERTIES
+ PASS_REGULAR_EXPRESSION "^Usage:")
+
+ add_test(NAME pbf-decoder-empty
+ COMMAND pbf-decoder "${CMAKE_SOURCE_DIR}/test/t/message/data-opt-empty.pbf")
+ set_tests_properties(pbf-decoder-empty PROPERTIES
+ PASS_REGULAR_EXPRESSION "^$")
+
+ add_test(NAME pbf-decoder-data
+ COMMAND pbf-decoder "${CMAKE_SOURCE_DIR}/test/t/message/data-message.pbf")
+ set_tests_properties(pbf-decoder-data PROPERTIES
+ PASS_REGULAR_EXPRESSION "^1:")
+
+ add_test(NAME pbf-decoder-vt
+ COMMAND pbf-decoder -l 999999 -o 0 "${CMAKE_SOURCE_DIR}/test/t/vector_tile/data.vector.pbf")
+ set_tests_properties(pbf-decoder-vt PROPERTIES
+ PASS_REGULAR_EXPRESSION "^3:")
+
+ add_test(NAME pbf-decoder-fail
+ COMMAND pbf-decoder -l 1 "${CMAKE_SOURCE_DIR}/test/t/vector_tile/data.vector.pbf")
+ set_tests_properties(pbf-decoder-fail PROPERTIES
+ WILL_FAIL true)
+
+ add_test(NAME pbf-decoder-fail-msg
+ COMMAND pbf-decoder -l 1 "${CMAKE_SOURCE_DIR}/test/t/vector_tile/data.vector.pbf")
+ set_tests_properties(pbf-decoder-fail-msg PROPERTIES
+ PASS_REGULAR_EXPRESSION "^end of buffer exception")
+
+endif()
+
+
+#-----------------------------------------------------------------------------
diff --git a/tools/pbf-decoder.cpp b/tools/pbf-decoder.cpp
new file mode 100644
index 0000000..3f6700e
--- /dev/null
+++ b/tools/pbf-decoder.cpp
@@ -0,0 +1,264 @@
+/*****************************************************************************
+
+Protobuf decoder tool
+
+Tool to decode unknown protocol buffer encoded messages. The protocol buffer
+format doesn't contain enough information about the contents of a file to make
+it decodable without the format description usually found in a `.proto` file,
+so this tool does some informed guessing.
+
+Usage:
+
+ pbf-decoder [OPTIONS] [FILENAME]
+
+Use "-" as a file name to read from STDIN.
+
+The output always goes to STDOUT.
+
+Call with --help/-h to see more options.
+
+*****************************************************************************/
+
+#include <protozero/pbf_reader.hpp>
+
+#include <algorithm>
+#include <cctype>
+#include <cstddef>
+#include <exception>
+#include <fstream>
+#include <getopt.h>
+#include <iostream>
+#include <limits>
+#include <sstream>
+#include <string>
+
+std::string decode(const char* data, std::size_t len, const std::string& indent);
+
+// Try decoding as a nested message
+bool decode_message(std::stringstream& out, const std::string& indent, const protozero::data_view view) {
+ try {
+ const auto nested = decode(view.data(), view.size(), indent + " ");
+ out << '\n' << nested;
+ return true;
+ } catch (const protozero::exception&) {
+ }
+ return false;
+}
+
+// Try decoding as a string (only printable characters allowed).
+bool decode_printable_string(std::stringstream& out, const protozero::data_view view) {
+ static constexpr const std::size_t max_string_length = 60;
+
+ const std::string str{view.data(), view.size()};
+ if (str.find_first_not_of("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_:-") != std::string::npos) {
+ return false;
+ }
+
+ if (str.size() > max_string_length) {
+ out << '"' << str.substr(0, max_string_length) << "\"...\n";
+ } else {
+ out << '"' << str << '"' << '\n';
+ }
+ return true;
+}
+
+// Try decoding as a string.
+bool decode_string(std::stringstream& out, const protozero::data_view view) {
+ static constexpr const std::size_t max_string_length = 60;
+
+ std::string str{view.data(), std::min(view.size(), max_string_length)};
+ out << '"';
+
+ for (const auto c : str) {
+ if (std::isprint(c) != 0) {
+ out << c;
+ } else {
+ out << '.';
+ }
+ }
+
+ out << '"' << '\n';
+
+ return true;
+}
+
+// Print a list of numbers from a range
+template <typename TRange>
+void print_number_range(std::stringstream& out, const TRange& range) {
+ bool first = true;
+ for (auto val : range) {
+ if (first) {
+ first = false;
+ } else {
+ out << ',';
+ }
+ out << val;
+ }
+ out << '\n';
+}
+
+// Try decoding as packed repeated double
+bool decode_packed_double(std::stringstream& out, std::size_t size, protozero::pbf_reader& message) {
+ if (size % 8 != 0) {
+ return false;
+ }
+ try {
+ print_number_range(out, message.get_packed_double());
+ return true;
+ } catch (const protozero::exception&) {
+ }
+
+ return false;
+}
+
+// Try decoding as packed repeated float
+bool decode_packed_float(std::stringstream& out, std::size_t size, protozero::pbf_reader& message) {
+ if (size % 4 != 0) {
+ return false;
+ }
+ try {
+ print_number_range(out, message.get_packed_float());
+ return true;
+ } catch (const protozero::exception&) {
+ }
+
+ return false;
+}
+
+// Try decoding as packed repeated varint
+bool decode_packed_varint(std::stringstream& out, protozero::pbf_reader& message) {
+ try {
+ print_number_range(out, message.get_packed_int64());
+ return true;
+ } catch (const protozero::exception&) {
+ }
+
+ return false;
+}
+
+std::string decode(const char* data, std::size_t len, const std::string& indent) {
+ std::stringstream stream;
+ protozero::pbf_reader message{data, len};
+ while (message.next()) {
+ stream << indent << message.tag() << ": ";
+ switch (message.wire_type()) {
+ case protozero::pbf_wire_type::varint: {
+ // This is int32, int64, uint32, uint64, sint32, sint64, bool, or enum.
+ // Try decoding as int64.
+ stream << message.get_int64() << '\n';
+ break;
+ }
+ case protozero::pbf_wire_type::fixed64:
+ // This is fixed64, sfixed64, or double.
+ // Try decoding as a double, because int64_t or uint64_t
+ // would probably be encoded as varint.
+ stream << message.get_double() << '\n';
+ break;
+ case protozero::pbf_wire_type::length_delimited: {
+ // This is string, bytes, embedded messages, or packed repeated fields.
+ protozero::pbf_reader message_copy{message};
+ const auto view = message.get_view();
+
+ decode_message(stream, indent, view) ||
+ decode_printable_string(stream, view) ||
+ decode_packed_double(stream, view.size(), message_copy) ||
+ decode_packed_float(stream, view.size(), message_copy) ||
+ decode_packed_varint(stream, message_copy) ||
+ decode_string(stream, view);
+ break;
+ }
+ case protozero::pbf_wire_type::fixed32:
+ // This is fixed32, sfixed32, or float.
+ // Try decoding as a float, because int32_t or uint32_t
+ // would probably be encoded as varint.
+ stream << message.get_float() << '\n';
+ break;
+ default:
+ throw protozero::unknown_pbf_wire_type_exception{};
+ }
+ }
+
+ return stream.str();
+}
+
+void print_help() {
+ std::cout << "Usage: pbf-decoder [OPTIONS] [INPUT_FILE]\n\n"
+ << "Dump raw contents of protobuf encoded file.\n"
+ << "To read from STDIN use '-' as INPUT_FILE.\n"
+ << "\nOptions:\n"
+ << " -h, --help This help message\n"
+ << " -l, --length=LENGTH Read only LENGTH bytes\n"
+ << " -o, --offset=OFFSET Start reading from OFFSET bytes\n";
+}
+
+std::string read_from_file(const char* filename) {
+ std::ifstream file{filename, std::ios::binary};
+ return std::string{std::istreambuf_iterator<char>(file.rdbuf()),
+ std::istreambuf_iterator<char>()};
+}
+
+std::string read_from_stdin() {
+ return std::string{std::istreambuf_iterator<char>(std::cin.rdbuf()),
+ std::istreambuf_iterator<char>()};
+}
+
+int main(int argc, char* argv[]) {
+ static struct option long_options[] = {
+ {"help", no_argument, nullptr, 'h'},
+ {"length", required_argument, nullptr, 'l'},
+ {"offset", required_argument, nullptr, 'o'},
+ {nullptr, 0, nullptr, 0}
+ };
+
+ std::size_t offset = 0;
+ std::size_t length = std::numeric_limits<std::size_t>::max();
+
+ while (true) {
+ const int c = getopt_long(argc, argv, "hl:o:", long_options, nullptr);
+ if (c == -1) {
+ break;
+ }
+
+ switch (c) {
+ case 'h':
+ print_help();
+ return 0;
+ case 'l':
+ length = std::atoll(optarg); // NOLINT clang-tidy: cert-err34-c
+ // good enough for a limited-use tool
+ break;
+ case 'o':
+ offset = std::atoll(optarg); // NOLINT clang-tidy: cert-err34-c
+ // good enough for a limited-use tool
+ break;
+ default:
+ return 1;
+ }
+ }
+
+ const int remaining_args = argc - optind;
+ if (remaining_args != 1) {
+ std::cerr << "Usage: " << argv[0] << " [OPTIONS] [INPUT_FILE]\n\n"
+ << "Call with --help/-h to see options.\n";
+ return 1;
+ }
+
+ const std::string filename{argv[optind]};
+
+ try {
+ const std::string buffer{filename == "-" ? read_from_stdin() :
+ read_from_file(argv[optind])};
+
+ if (length > buffer.size() - offset) {
+ length = buffer.size() - offset;
+ }
+
+ std::cout << decode(buffer.data() + offset, length, "");
+ } catch (const std::exception& ex) {
+ std::cerr << ex.what() << '\n';
+ return 1;
+ }
+
+ return 0;
+}
+
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-grass/protozero.git
More information about the Pkg-grass-devel
mailing list