[protozero] 01/06: New upstream version 1.5.3

Bas Couwenberg sebastic at debian.org
Fri Sep 22 15:05:42 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 beecb56054dfada7917df2bfd3e2b596a296af51
Author: Bas Couwenberg <sebastic at xs4all.nl>
Date:   Fri Sep 22 16:48:12 2017 +0200

    New upstream version 1.5.3
---
 .gitignore                                   |   1 +
 .travis.yml                                  |  93 +++--
 CHANGELOG.md                                 |  35 +-
 Makefile                                     |  36 +-
 README.md                                    |  10 +
 doc/advanced.md                              |  31 +-
 doc/cheatsheet.md                            |   4 +-
 doc/tutorial.md                              |  84 +++--
 gyp/protozero.gyp                            |   4 +-
 include/protozero/iterators.hpp              |  53 ++-
 include/protozero/pbf_builder.hpp            | 105 ++++++
 include/protozero/pbf_message.hpp            |  94 ++++-
 include/protozero/pbf_reader.hpp             |  57 ++-
 include/protozero/pbf_writer.hpp             | 129 +++++--
 include/protozero/types.hpp                  |  21 +-
 include/protozero/varint.hpp                 |  38 +-
 include/protozero/version.hpp                |   4 +-
 package.json                                 |   2 +-
 test/{include => catch}/catch.hpp            | 507 +++++++++++++++------------
 test/include/packed_access.hpp               | 100 +++++-
 test/include/scalar_access.hpp               |  33 +-
 test/include/test.hpp                        |  10 +-
 test/include/testcase.hpp                    |   2 +-
 test/t/alignment/test_cases.cpp              |  44 +--
 test/t/basic/test_cases.cpp                  |  14 +-
 test/t/bool/test_cases.cpp                   |  62 ++--
 test/t/bool/writer_test_cases.cpp            |   4 +-
 test/t/bytes/test_cases.cpp                  |  24 +-
 test/t/bytes/writer_test_cases.cpp           |   2 +-
 test/t/complex/test_cases.cpp                | 101 +++---
 test/t/data_view/test_cases.cpp              |  10 +-
 test/t/double/test_cases.cpp                 |  18 +-
 test/t/double/writer_test_cases.cpp          |   2 +-
 test/t/endian/test_cases.cpp                 |  22 +-
 test/t/enum/test_cases.cpp                   |  22 +-
 test/t/enum/writer_test_cases.cpp            |   2 +-
 test/t/fixed32/writer_test_cases.cpp         |   2 +-
 test/t/float/test_cases.cpp                  |  16 +-
 test/t/int32/writer_test_cases.cpp           |   2 +-
 test/t/message/test_cases.cpp                |  42 +--
 test/t/message/writer_test_cases.cpp         |   6 +-
 test/t/nested/test_cases.cpp                 |  24 +-
 test/t/nested/writer_test_cases.cpp          |   8 +-
 test/t/repeated/test_cases.cpp               |   8 +-
 test/t/repeated_packed_bool/test_cases.cpp   |  36 +-
 test/t/repeated_packed_double/test_cases.cpp |   8 +-
 test/t/repeated_packed_enum/test_cases.cpp   |   8 +-
 test/t/repeated_packed_float/test_cases.cpp  |   8 +-
 test/t/rollback/test_cases.cpp               |  34 +-
 test/t/skip/test_cases.cpp                   |   6 +-
 test/t/string/test_cases.cpp                 |  20 +-
 test/t/tag_and_type/test_cases.cpp           |   2 +-
 test/t/tags/test_cases.cpp                   |   2 +-
 test/t/varint/test_cases.cpp                 |  18 +-
 test/t/vector_tile/test_cases.cpp            |  21 +-
 test/t/wrong_type_access/test_cases.cpp      |  24 +-
 test/tests.cpp                               |  12 +-
 57 files changed, 1325 insertions(+), 762 deletions(-)

diff --git a/.gitignore b/.gitignore
index 68e1aeb..ba94541 100644
--- a/.gitignore
+++ b/.gitignore
@@ -15,3 +15,4 @@ deps
 *.suo
 *.vcxproj*
 *.7z
+compile_commands.json
diff --git a/.travis.yml b/.travis.yml
index 19d4de2..a55b84c 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,53 +1,64 @@
-language: c
+#-----------------------------------------------------------------------------
+#
+#  Configuration for continuous integration service at travis-ci.org
+#
+#-----------------------------------------------------------------------------
+
+language: generic
 
 sudo: false
 
+dist: trusty
+
+#-----------------------------------------------------------------------------
+
 # Save common build configurations as shortcuts, so we can reference them later.
 addons_shortcuts:
   addons_clang35: &clang35
     apt:
-      sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.5' ]
-      packages: [ 'clang-3.5', 'libprotobuf-dev','protobuf-compiler' ]
+      sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-3.5' ]
+      packages: [ 'libprotobuf-dev','protobuf-compiler', 'clang-3.5' ]
   addons_clang38: &clang38
     apt:
-      sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.8' ]
-      packages: [ 'clang-3.8', 'libprotobuf-dev','protobuf-compiler' ]
-#  addons_clang39: &clang39
-#    apt:
-#      sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.9' ]
-#      packages: [ 'clang-3.9', 'libprotobuf-dev','protobuf-compiler' ]
+      sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-3.8' ]
+      packages: [ 'libprotobuf-dev','protobuf-compiler', 'clang-3.8' ]
+  addons_clang39: &clang39
+    apt:
+      sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-3.9' ]
+      packages: [ 'libprotobuf-dev','protobuf-compiler', 'clang-3.9' ]
+  addons_clang39: &clang40
+    apt:
+      sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-4.0' ]
+      packages: [ 'libprotobuf-dev','protobuf-compiler', 'clang-4.0' ]
+  addons_clang39: &clang50
+    apt:
+      sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-5.0' ]
+      packages: [ 'libprotobuf-dev','protobuf-compiler', 'clang-5.0' ]
   addons_gcc47: &gcc47
     apt:
       sources: [ 'ubuntu-toolchain-r-test' ]
-      packages: [ 'g++-4.7', 'gcc-4.7', 'libprotobuf-dev','protobuf-compiler' ]
+      packages: [ 'libprotobuf-dev','protobuf-compiler', 'g++-4.7', 'gcc-4.7' ]
   addons_gcc48: &gcc48
     apt:
       sources: [ 'ubuntu-toolchain-r-test' ]
-      packages: [ 'g++-4.8', 'gcc-4.8', 'libprotobuf-dev','protobuf-compiler' ]
+      packages: [ 'libprotobuf-dev','protobuf-compiler', 'g++-4.8', 'gcc-4.8' ]
   addons_gcc49: &gcc49
     apt:
       sources: [ 'ubuntu-toolchain-r-test' ]
-      packages: [ 'g++-4.9', 'gcc-4.9', 'libprotobuf-dev','protobuf-compiler' ]
+      packages: [ 'libprotobuf-dev','protobuf-compiler', 'g++-4.9', 'gcc-4.9' ]
   addons_gcc5: &gcc5
     apt:
       sources: [ 'ubuntu-toolchain-r-test' ]
-      packages: [ 'g++-5', 'gcc-5', 'libprotobuf-dev','protobuf-compiler' ]
+      packages: [ 'libprotobuf-dev','protobuf-compiler', 'g++-5', 'gcc-5' ]
   addons_gcc6: &gcc6
     apt:
       sources: [ 'ubuntu-toolchain-r-test' ]
-      packages: [ 'g++-6', 'gcc-6', 'libprotobuf-dev','protobuf-compiler', 'doxygen', 'graphviz' ]
+      packages: [ 'libprotobuf-dev','protobuf-compiler', 'g++-6', 'gcc-6', 'doxygen', 'graphviz' ]
+
+#-----------------------------------------------------------------------------
 
 matrix:
   include:
-    - os: osx
-      osx_image: xcode6
-      compiler: clang
-    - os: osx
-      osx_image: xcode7
-      compiler: clang
-    - os: osx
-      osx_image: xcode8
-      compiler: clang
     - os: linux
       compiler: "clang-3.5"
       env: CXX=clang++-3.5
@@ -57,9 +68,21 @@ matrix:
       env: CXX=clang++-3.8
       addons: *clang38
     - os: linux
-      compiler: "clang-3.8"
-      env: CXX=clang++-3.8 CXX_STD=c++14
-      addons: *clang38
+      compiler: "clang-3.9"
+      env: CXX=clang++-3.9
+      addons: *clang39
+    - os: linux
+      compiler: "clang-4.0"
+      env: CXX=clang++-4.0
+      addons: *clang40
+    - os: linux
+      compiler: "clang-4.0"
+      env: CXX=clang++-5.0
+      addons: *clang50
+    - os: linux
+      compiler: "clang-5.0"
+      env: CXX=clang++-5.0 CXX_STD=c++14
+      addons: *clang50
     - os: linux
       compiler: "gcc-4.7"
       env: CXX=g++-4.7
@@ -88,6 +111,21 @@ matrix:
       compiler: "gcc-6"
       env: CXX=g++-6 BUILD_DOC=1
       addons: *gcc6
+    - os: linux
+      compiler: "gcc-6"
+      env: CXX=g++-6 PROTOZERO_DATA_VIEW=std::experimental::string_view
+      addons: *gcc6
+    - os: osx
+      osx_image: xcode6
+      compiler: clang
+    - os: osx
+      osx_image: xcode7
+      compiler: clang
+    - os: osx
+      osx_image: xcode8
+      compiler: clang
+
+#-----------------------------------------------------------------------------
 
 before_install:
  - echo ${CXX}
@@ -109,4 +147,5 @@ script:
       chmod +x codecov
       ${COVERAGE} -p $(find test/ -name '*.o')
       ./codecov -Z -f '*protozero*' -X search
-    fi
\ No newline at end of file
+    fi
+
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 10a5684..3fbcd08 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -13,6 +13,38 @@ This project adheres to [Semantic Versioning](http://semver.org/).
 ### Fixed
 
 
+## [1.5.3] - 2017-09-22
+
+### Added
+
+- More documentation.
+- New `size()` method on iterator range used for packed repeated fields to
+  find out how many elements there are in the range. This is much faster
+  compared to the `std::difference()` call you had to do before, because the
+  varints don't have to be fully decoded. See [Advanced
+  Topics](doc/advanced.md) for details.
+
+### Changed
+
+- Updated clang-tidy settings in Makefiles and fixed a lot of minor issues
+  reported by clang-tidy.
+- Update included catch.hpp to version 1.10.0.
+- Miscellaneous code cleanups.
+- Support for invalid state in `pbf_writer` and `packed_repeated_fields`.
+  This fixes move construction and move assignement in `pbf_writer` and
+  disables the copy construction and copy assignement which don't have
+  clear semantics. It introduces an invalid or empty state in the
+  `pbf_writer`, `pbf_builder`, and `packed_repeated_fields` classes used for
+  default-constructed, moved from, or committed objects. There is a new
+  `commit()` function for `pbf_writer` and the `packed_repeated_fields` which
+  basically does the same as the destructor but can be called explicitly.
+
+### Fixed
+
+- The `empty()` method of the iterator range now returns a `bool` instead of
+  a `size_t`.
+
+
 ## [1.5.2] - 2017-06-30
 
 ### Added
@@ -191,7 +223,8 @@ 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.2...HEAD
+[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
 [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/Makefile b/Makefile
index 5b6cf38..b896d13 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,3 @@
-# first inherit from env
-CXX := $(CXX)
-CXXFLAGS := $(CXXFLAGS)
-LDFLAGS := $(LDFLAGS)
 
 # Installation directory
 DESTDIR ?= /usr
@@ -12,12 +8,21 @@ 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
 
-COMMON_FLAGS := -fvisibility-inlines-hidden -std=c++11 $(WARNING_FLAGS)
+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)
@@ -59,11 +64,13 @@ 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 -Iinclude -Itest/include $(CXXFLAGS) $(COMMON_FLAGS) $(DEBUG_FLAGS) $< -o $@
+	$(CXX) -c $(TEST_INCLUDES) $(CXXFLAGS) $(COMMON_FLAGS) $(DEBUG_FLAGS) $< -o $@
 
 ./test/tests.o: test/tests.cpp $(HPP_FILES)
-	$(CXX) -c -Iinclude -Itest/include $(CXXFLAGS) $(COMMON_FLAGS) $(DEBUG_FLAGS) $< -o $@
+	$(CXX) -c $(TEST_INCLUDES) $(CXXFLAGS) $(COMMON_FLAGS) $(DEBUG_FLAGS) $< -o $@
 
 ./test/tests: test/tests.o $(TEST_CASES_O)
 	$(CXX) $(LDFLAGS) $^ -o $@
@@ -72,13 +79,13 @@ all: ./test/tests test/writer_tests
 	protoc --cpp_out=. $^
 
 ./test/t/%/testcase.pb.o: ./test/t/%/testcase.pb.cc
-	$(CXX) -c -I. -Iinclude -Itest/include $(CXXFLAGS) $(CFLAGS_PROTOBUF) -std=c++11 $(DEBUG_FLAGS) $< -o $@
+	$(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. -Iinclude -Itest/include $(CXXFLAGS) $(CFLAGS_PROTOBUF) $(COMMON_FLAGS) $(DEBUG_FLAGS) $< -o $@
+	$(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. -Iinclude -Itest/include $(CXXFLAGS) $(COMMON_FLAGS) $(DEBUG_FLAGS) $< -o $@
+	$(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 $@
@@ -93,8 +100,8 @@ iwyu: $(HPP_FILES) test/tests.cpp test/writer_tests.cpp
 	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 -Iinclude -Itest/include test/tests.cpp || true
-	iwyu -Xiwyu -- -std=c++11 -Iinclude -Itest/include test/writer_tests.cpp || 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 $^
@@ -132,5 +139,10 @@ 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 473f4e8..4aa57f2 100644
--- a/README.md
+++ b/README.md
@@ -115,6 +115,16 @@ If you are using `g++` you can use `gcovr` to generate nice HTML output:
 Open `coverage/index.html` in your browser to see the report.
 
 
+## Clang-tidy
+
+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.
+
+
 ## Cppcheck
 
 For extra checks with [Cppcheck](http://cppcheck.sourceforge.net/) you can call
diff --git a/doc/advanced.md b/doc/advanced.md
index fd98aca..ee00611 100644
--- a/doc/advanced.md
+++ b/doc/advanced.md
@@ -142,13 +142,13 @@ a rough estimate. Still, you should probably only use this facility if you have
 benchmarks proving that it actually makes your program faster.
 
 
-## Using the Low-Level Varint and Zigzag Encoding and Decoding Functions
+## Using the low-level varint and zigzag encoding and decoding functions
 
 Protozero gives you access to the low-level functions for encoding and
 decoding varint and zigzag integer encodings, because these functions can
 sometimes be useful outside the Protocol Buffer context.
 
-### Using Low-Level Functions
+### Using low-level functions
 
 To use the low-level functions, add this include to your C++ program:
 
@@ -223,3 +223,30 @@ fields.
 
 The function is also available in the `pbf_builder` class.
 
+
+## How many items are there in a repeated packed field?
+
+Sometimes it is useful to know how many values there are in a repeated packed
+field. For instance when you want to reserve space in a `std::vector`.
+
+```cpp
+protozero::pbf_reader message{...};
+message.next(...);
+const auto range = message.get_packed_sint32();
+
+std::vector<int> myvalues;
+myvalues.reserve(range.size());
+
+for (auto value : range) {
+    myvalues.push_back(value);
+}
+```
+
+It depends on the type of range how expensive the `size()` call is. For ranges
+derived from packed repeated fixed sized values the effort will be constant,
+for ranges derived from packed repeated varints, the effort will be linear, but
+still considerably cheaper than decoding the varints (for instance by calling
+`std::distance(range.begin(), range.end());`). You have to benchmark your use
+case to see whether the `reserve()` (or whatever you are using the `size()`
+for) is worth it.
+
diff --git a/doc/cheatsheet.md b/doc/cheatsheet.md
index ef17f24..128ec67 100644
--- a/doc/cheatsheet.md
+++ b/doc/cheatsheet.md
@@ -5,7 +5,7 @@ See also this
 [handy table](https://developers.google.com/protocol-buffers/docs/proto#scalar)
 from the Google Protocol Buffers documentation.
 
-## Scalar Types
+## Scalar types
 
 | PBF Type | Underlying Storage | C++ Type      | Getter           | Notes |
 | -------- | ------------------ | ------------- | ---------------- | ----- |
@@ -44,7 +44,7 @@ from the Google Protocol Buffers documentation.
   overloads are available.
 
 
-## Packed Repeated Fields
+## Packed repeated fields
 
 | PBF Type | Getter                  |
 | -------- | ----------------------- |
diff --git a/doc/tutorial.md b/doc/tutorial.md
index 79b1e35..9525343 100644
--- a/doc/tutorial.md
+++ b/doc/tutorial.md
@@ -1,7 +1,7 @@
 
 # Protozero Tutorial
 
-## Getting to Know Protocol Buffers
+## Getting to know Protocol Buffers
 
 Protozero is a very low level library. You really have to know some of the
 insides of Protocol Buffers to work with it!
@@ -44,7 +44,7 @@ The `pbf_reader` class contains asserts that will detect some programming
 errors. We encourage you to compile with asserts enabled in your debug builds.
 
 
-### An Introductory Example
+### An introductory example
 
 Lets say you have a protocol description in a `.proto` file like this:
 
@@ -66,7 +66,7 @@ looks somewhat like this:
 std::string input = get_input_data();
 
 // initialize pbf message with this data
-protozero::pbf_reader message(input);
+protozero::pbf_reader message{input};
 
 // iterate over fields in the message
 while (message.next()) {
@@ -110,7 +110,7 @@ fields, too, unless you want your program to break if somebody adds a new
 field.
 
 
-### If You Only Need a Single Field
+### If you only need a single field
 
 If, out of a protocol buffer message, you only need the value of a single
 field, you can use the version of the `next()` function with a parameter:
@@ -125,7 +125,7 @@ while (message.next(17)) {
 }
 ```
 
-### Handling Scalar Fields
+### Handling scalar fields
 
 As you saw in the example, handling scalar field types is reasonably easy. You
 just check the `.proto` file for the type of a field and call the corresponding
@@ -139,10 +139,10 @@ returns a `data_view` containing a pointer into the data (access with `data()`)
 and the length of the data (access with `size()`).
 
 
-### Handling Repeated Packed Fields
+### Handling repeated packed fields
 
 Fields that are marked as `[packed=true]` in the `.proto` file are handled
-somewhat differently. `get_packed_...()` functions returning an iterator pair
+somewhat differently. `get_packed_...()` functions returning an iterator range
 are used to access the data.
 
 So, for example, if you have a protocol description in a `.proto` file like
@@ -157,28 +157,36 @@ message Example2 {
 You can get to the data like this:
 
 ```cpp
-protozero::pbf_reader message(input.data(), input.size());
+protozero::pbf_reader message{input.data(), input.size()};
 
 // set current field
-item.next(1);
+message.next(1);
 
-// get an iterator pair
-auto pi = item.get_packed_sint32();
+// get an iterator range
+auto pi = message.get_packed_sint32();
 
 // iterate to get to all values
-for (auto it = pi.first; it != pi.second; ++it) {
-    std::cout << *it << "\n";
+for (auto it = pi.begin(); it != pi.end(); ++it) {
+    std::cout << *it << '\n';
 }
 ```
 
-So you are getting a pair of normal forward iterators that can be used with any
-STL algorithms etc.
+Or, with a range-based for-loop:
+
+```cpp
+for (auto value : pi) {
+    std::cout << v << '\n';
+}
+```
+
+So you are getting a pair of normal forward iterators wrapped in an iterator
+range object. The iterators can be used with any STL algorithms etc.
 
 Note that the previous only applies to repeated **packed** fields, normal
 repeated fields are handled in the usual way for scalar fields.
 
 
-### Handling Embedded Messages
+### Handling embedded messages
 
 Protocol Buffers can embed any message inside another message. To access an
 embedded message use the `get_message()` function. So for this description:
@@ -197,7 +205,7 @@ message Example3 {
 you can parse with this code:
 
 ```cpp
-protozero::pbf_reader message(input);
+protozero::pbf_reader message{input};
 
 while (message.next(10)) {
     protozero::pbf_reader point = message.get_message();
@@ -218,7 +226,7 @@ while (message.next(10)) {
 }
 ```
 
-### Handling Enums
+### Handling enums
 
 Enums are stored as varints and they can't be differentiated from them. Use
 the `get_enum()` function to get the value of the enum, you have to translate
@@ -270,7 +278,7 @@ This exception indicates an illegal encoding of a varint. It means your input
 data is corrupted in some way.
 
 
-### The `pbf_reader` Class
+### The `pbf_reader` class
 
 The `pbf_reader` class behaves like a value type. Objects are reasonably small
 (two pointers and two `uint32_t`, so 24 bytes on a 64bit system) and they can
@@ -282,7 +290,7 @@ In all cases objects of the `pbf_reader` class store a pointer into the input
 data that was given to the constructor. You have to make sure this pointer
 stays valid for the duration of the objects lifetime.
 
-## Parsing Protobuf-Encoded Messages Using `pbf_message`
+## Parsing protobuf-encoded messages using `pbf_message`
 
 One problem in the code above are the "magic numbers" used as tags for the
 different fields that you got from the `.proto` file. Instead of spreading
@@ -329,7 +337,7 @@ looks somewhat like this, this time using `pbf_message` instead of
 std::string input = get_input_data();
 
 // initialize pbf message with this data
-protozero::pbf_message<Example1> message(input);
+protozero::pbf_message<Example1> message{input};
 
 // iterate over fields in the message
 while (message.next()) {
@@ -373,7 +381,7 @@ for future extension of those messages (and maybe also to detect corrupted
 data). You can switch of this warning with `-Wno-covered-switch-default`).
 
 
-## Writing Protobuf-Encoded Messages
+## Writing protobuf-encoded messages
 
 ### Using `pbf_writer`
 
@@ -387,7 +395,7 @@ The `pbf_writer` class contains asserts that will detect some programming
 errors. We encourage you to compile with asserts enabled in your debug builds.
 
 
-### An Introductory Example
+### An introductory example
 
 Lets say you have a protocol description in a `.proto` file like this:
 
@@ -406,7 +414,7 @@ that looks somewhat like this:
 #include <protozero/pbf_writer.hpp>
 
 std::string data;
-protozero::pbf_writer pbf_example(data);
+protozero::pbf_writer pbf_example{data};
 
 pbf_example.add_uint32(1, 27);       // uint32_t x
 pbf_example.add_fixed64(17, 1);      // fixed64 r
@@ -422,7 +430,7 @@ The buffer doesn't have to be empty, the `pbf_writer` will simply append its
 data to whatever is there already.
 
 
-### Handling Scalar Fields
+### Handling scalar fields
 
 As you could see in the introductory example handling any kind of scalar field
 is easy. The type of field doesn't matter and it doesn't matter whether it is
@@ -439,13 +447,13 @@ For `enum` types you have to use the numeric value as the symbolic names from
 the `.proto` file are not available.
 
 
-### Handling Repeated Packed Fields
+### Handling repeated packed fields
 
 Repeated packed fields can easily be set from a pair of iterators:
 
 ```cpp
 std::string data;
-protozero::pbf_writer pw(data);
+protozero::pbf_writer pw{data};
 
 std::vector<int> v = { 1, 4, 9, 16, 25, 36 };
 pw.add_packed_int32(1, std::begin(v), std::end(v));
@@ -455,7 +463,7 @@ If you don't have an iterator you can use the alternative form:
 
 ```cpp
 std::string data;
-protozero::pbf_writer pw(data);
+protozero::pbf_writer pw{data};
 {
     protozero::packed_field_int32 field{pw, 1};
     field.add_element(1);
@@ -478,7 +486,7 @@ fixed length elements, you can tell Protozero and it can optimize this case:
 
 ```cpp
 std::string data;
-protozero::pbf_writer pw(data);
+protozero::pbf_writer pw{data};
 {
     protozero::packed_field_fixed32 field{pw, 1, 2}; // exactly two elements
     field.add_element(42);
@@ -498,7 +506,7 @@ calling `rollback()`:
 
 ```cpp
 std::string data;
-protozero::pbf_writer pw(data);
+protozero::pbf_writer pw{data};
 {
     protozero::packed_field_int32 field{pw, 1};
     field.add_element(42);
@@ -511,14 +519,14 @@ The result is the same as if the lines inside the nested brackets had never
 been called. Do not try to call `add_element()` after a rollback.
 
 
-### Handling Sub-Messages
+### Handling sub-messages
 
 Nested sub-messages can be handled by first creating the submessage and then
 adding to the parent message:
 
 ```cpp
 std::string buffer_sub;
-protozero::pbf_writer pbf_sub(buffer_sub);
+protozero::pbf_writer pbf_sub{buffer_sub};
 
 // add fields to sub-message
 pbf_sub.add_...(...);
@@ -527,7 +535,7 @@ pbf_sub.add_...(...);
 // sub-message is finished here
 
 std::string buffer_parent;
-protozero::pbf_writer pbf_parent(buffer_parent);
+protozero::pbf_writer pbf_parent{buffer_parent};
 pbf_parent.add_message(1, buffer_sub);
 ```
 
@@ -537,7 +545,7 @@ Google protobuf library if it doesn't?) there is another way:
 
 ```cpp
 std::string data;
-protozero::pbf_writer pbf_parent(data);
+protozero::pbf_writer pbf_parent{data};
 
 // optionally add fields to parent here
 pbf_parent.add_...(...);
@@ -546,7 +554,7 @@ pbf_parent.add_...(...);
 {
     // create new pbf_writer with parent and the tag (field number)
     // as parameters
-    protozero::pbf_writer pbf_sub(pbf_parent, 1);
+    protozero::pbf_writer pbf_sub{pbf_parent, 1};
 
     // add fields to sub here...
     pbf_sub.add_...(...);
@@ -571,13 +579,13 @@ calling `rollback()`:
 
 ```cpp
 std::string data;
-protozero::pbf_writer pbf_parent(data);
+protozero::pbf_writer pbf_parent{data};
 
 // open a new scope
 {
     // create new pbf_writer with parent and the tag (field number)
     // as parameters
-    protozero::pbf_writer pbf_sub(pbf_parent, 1);
+    protozero::pbf_writer pbf_sub{pbf_parent, 1};
 
     // add fields to sub here...
     pbf_sub.add_...(...);
@@ -594,7 +602,7 @@ The result is the same as if the lines inside the nested brackets had never
 been called. Do not try to call any of the `add_*` functions on the submessage
 after a rollback.
 
-## Writing Protobuf-Encoded Messages Using `pbf_builder`
+## Writing protobuf-encoded messages using `pbf_builder`
 
 Just like the `pbf_message` template class wraps the `pbf_reader` class, there
 is a `pbf_builder` template class wrapping the `pbf_writer` class. It is
diff --git a/gyp/protozero.gyp b/gyp/protozero.gyp
index 7d14efb..0802f21 100644
--- a/gyp/protozero.gyp
+++ b/gyp/protozero.gyp
@@ -11,7 +11,8 @@
       ],
       "include_dirs": [
         "../include/",
-        "../test/include/"
+        "../test/include/",
+        "../test/catch/"
       ]
     },
     {
@@ -27,6 +28,7 @@
         "../",
         "../include/",
         "../test/include/",
+        "../test/catch/",
         "../deps/protobuf/include"
       ],
       "libraries" : [
diff --git a/include/protozero/iterators.hpp b/include/protozero/iterators.hpp
index a19f202..f8247a4 100644
--- a/include/protozero/iterators.hpp
+++ b/include/protozero/iterators.hpp
@@ -16,6 +16,7 @@ documentation.
  * @brief Contains the iterators for access to packed repeated fields.
  */
 
+#include <algorithm>
 #include <cstring>
 #include <iterator>
 #include <utility>
@@ -89,12 +90,25 @@ public:
         return this->second;
     }
 
-    /// Return true if this range is empty.
-    constexpr std::size_t empty() const noexcept {
+    /**
+     * Return true if this range is empty.
+     *
+     * Complexity: Constant.
+     */
+    constexpr bool empty() const noexcept {
         return begin() == end();
     }
 
     /**
+     * Get the size of the range, ie the number of elements it contains.
+     *
+     * Complexity: Constant or linear depending on the underlaying iterator.
+     */
+    std::size_t size() const noexcept {
+        return begin().size();
+    }
+
+    /**
      * Get element at the beginning of the range.
      *
      * @pre Range must not be empty.
@@ -146,10 +160,10 @@ template <typename T>
 class const_fixed_iterator {
 
     /// Pointer to current iterator position
-    const char* m_data;
+    const char* m_data = nullptr;
 
     /// Pointer to end iterator position
-    const char* m_end;
+    const char* m_end = nullptr;
 
 public:
 
@@ -159,10 +173,7 @@ public:
     using pointer           = value_type*;
     using reference         = value_type&;
 
-    const_fixed_iterator() noexcept :
-        m_data(nullptr),
-        m_end(nullptr) {
-    }
+    const_fixed_iterator() noexcept = default;
 
     const_fixed_iterator(const char* data, const char* end) noexcept :
         m_data(data),
@@ -197,6 +208,10 @@ public:
         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;
     }
@@ -217,10 +232,10 @@ class const_varint_iterator {
 protected:
 
     /// Pointer to current iterator position
-    const char* m_data;
+    const char* m_data = nullptr;
 
     /// Pointer to end iterator position
-    const char* m_end;
+    const char* m_end = nullptr;
 
 public:
 
@@ -230,10 +245,7 @@ public:
     using pointer           = value_type*;
     using reference         = value_type&;
 
-    const_varint_iterator() noexcept :
-        m_data(nullptr),
-        m_end(nullptr) {
-    }
+    const_varint_iterator() noexcept = default;
 
     const_varint_iterator(const char* data, const char* end) noexcept :
         m_data(data),
@@ -264,6 +276,15 @@ public:
         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;
     }
@@ -298,10 +319,10 @@ public:
     }
 
     const_svarint_iterator(const const_svarint_iterator&) = default;
-    const_svarint_iterator(const_svarint_iterator&&) = default;
+    const_svarint_iterator(const_svarint_iterator&&) noexcept = default;
 
     const_svarint_iterator& operator=(const const_svarint_iterator&) = default;
-    const_svarint_iterator& operator=(const_svarint_iterator&&) = default;
+    const_svarint_iterator& operator=(const_svarint_iterator&&) noexcept = default;
 
     ~const_svarint_iterator() = default;
 
diff --git a/include/protozero/pbf_builder.hpp b/include/protozero/pbf_builder.hpp
index 8197395..aa4f545 100644
--- a/include/protozero/pbf_builder.hpp
+++ b/include/protozero/pbf_builder.hpp
@@ -44,12 +44,27 @@ class pbf_builder : public pbf_writer {
 
 public:
 
+    /// The type of messages this class will build.
     using enum_type = T;
 
+    pbf_builder() = default;
+
+    /**
+     * Create a builder using the given string as a data store. The object
+     * stores a reference to that string and adds all data to it. The string
+     * doesn't have to be empty. The pbf_message object will just append data.
+     */
     explicit pbf_builder(std::string& data) noexcept :
         pbf_writer(data) {
     }
 
+    /**
+     * Construct a pbf_builder for a submessage from the pbf_message or
+     * pbf_writer of the parent message.
+     *
+     * @param parent_writer The parent pbf_message or pbf_writer
+     * @param tag Tag of the field that will be written
+     */
     template <typename P>
     pbf_builder(pbf_writer& parent_writer, P tag) noexcept :
         pbf_writer(parent_writer, pbf_tag_type(tag)) {
@@ -79,51 +94,141 @@ public:
 #undef PROTOZERO_WRITER_WRAP_ADD_SCALAR
 /// @endcond
 
+    /**
+     * Add "bytes" field to data.
+     *
+     * @param tag Tag of the field
+     * @param value Pointer to value to be written
+     * @param size Number of bytes to be written
+     */
     void add_bytes(T tag, const char* value, std::size_t size) {
         pbf_writer::add_bytes(pbf_tag_type(tag), value, size);
     }
 
+    /**
+     * Add "bytes" field to data.
+     *
+     * @param tag Tag of the field
+     * @param value Value to be written
+     */
     void add_bytes(T tag, const data_view& value) {
         pbf_writer::add_bytes(pbf_tag_type(tag), value);
     }
 
+    /**
+     * Add "bytes" field to data.
+     *
+     * @param tag Tag of the field
+     * @param value Value to be written
+     */
     void add_bytes(T tag, const std::string& value) {
         pbf_writer::add_bytes(pbf_tag_type(tag), value);
     }
 
+    /**
+     * Add "bytes" field to data. Bytes from the value are written until
+     * a null byte is encountered. The null byte is not added.
+     *
+     * @param tag Tag of the field
+     * @param value Pointer to zero-delimited value to be written
+     */
     void add_bytes(T tag, const char* value) {
         pbf_writer::add_bytes(pbf_tag_type(tag), value);
     }
 
+    /**
+     * Add "bytes" field to data using vectored input. All the data in the
+     * 2nd and further arguments is "concatenated" with only a single copy
+     * into the final buffer.
+     *
+     * This will work with objects of any type supporting the data() and
+     * size() methods like std::string or protozero::data_view.
+     *
+     * Example:
+     * @code
+     * std::string data1 = "abc";
+     * std::string data2 = "xyz";
+     * builder.add_bytes_vectored(1, data1, data2);
+     * @endcode
+     *
+     * @tparam Ts List of types supporting data() and size() methods.
+     * @param tag Tag of the field
+     * @param values List of objects of types Ts with data to be appended.
+     */
     template <typename... Ts>
     void add_bytes_vectored(T tag, Ts&&... values) {
         pbf_writer::add_bytes_vectored(pbf_tag_type(tag), std::forward<Ts>(values)...);
     }
 
+    /**
+     * Add "string" field to data.
+     *
+     * @param tag Tag of the field
+     * @param value Pointer to value to be written
+     * @param size Number of bytes to be written
+     */
     void add_string(T tag, const char* value, std::size_t size) {
         pbf_writer::add_string(pbf_tag_type(tag), value, size);
     }
 
+    /**
+     * Add "string" field to data.
+     *
+     * @param tag Tag of the field
+     * @param value Value to be written
+     */
     void add_string(T tag, const data_view& value) {
         pbf_writer::add_string(pbf_tag_type(tag), value);
     }
 
+    /**
+     * Add "string" field to data.
+     *
+     * @param tag Tag of the field
+     * @param value Value to be written
+     */
     void add_string(T tag, const std::string& value) {
         pbf_writer::add_string(pbf_tag_type(tag), value);
     }
 
+    /**
+     * Add "string" field to data. Bytes from the value are written until
+     * a null byte is encountered. The null byte is not added.
+     *
+     * @param tag Tag of the field
+     * @param value Pointer to value to be written
+     */
     void add_string(T tag, const char* value) {
         pbf_writer::add_string(pbf_tag_type(tag), value);
     }
 
+    /**
+     * Add "message" field to data.
+     *
+     * @param tag Tag of the field
+     * @param value Pointer to message to be written
+     * @param size Length of the message
+     */
     void add_message(T tag, const char* value, std::size_t size) {
         pbf_writer::add_message(pbf_tag_type(tag), value, size);
     }
 
+    /**
+     * Add "message" field to data.
+     *
+     * @param tag Tag of the field
+     * @param value Value to be written. The value must be a complete message.
+     */
     void add_message(T tag, const data_view& value) {
         pbf_writer::add_message(pbf_tag_type(tag), value);
     }
 
+    /**
+     * Add "message" field to data.
+     *
+     * @param tag Tag of the field
+     * @param value Value to be written. The value must be a complete message.
+     */
     void add_message(T tag, const std::string& value) {
         pbf_writer::add_message(pbf_tag_type(tag), value);
     }
diff --git a/include/protozero/pbf_message.hpp b/include/protozero/pbf_message.hpp
index c599cf1..8adf207 100644
--- a/include/protozero/pbf_message.hpp
+++ b/include/protozero/pbf_message.hpp
@@ -35,7 +35,7 @@ namespace protozero {
  *
  *    std::string buffer;
  *    // fill buffer...
- *    pbf_message<Message> message(buffer.data(), buffer.size());
+ *    pbf_message<Message> message{buffer.data(), buffer.size()};
  * @endcode
  *
  * Sub-messages are created using get_message():
@@ -45,7 +45,7 @@ namespace protozero {
  *       ...
  *    };
  *
- *    pbf_message<Message> message(...);
+ *    pbf_message<Message> message{...};
  *    message.next();
  *    pbf_message<SubMessage> submessage = message.get_message();
  * @endcode
@@ -64,29 +64,115 @@ namespace protozero {
 template <typename T>
 class pbf_message : public pbf_reader {
 
-    static_assert(std::is_same<pbf_tag_type, typename std::underlying_type<T>::type>::value, "T must be enum with underlying type protozero::pbf_tag_type");
+    static_assert(std::is_same<pbf_tag_type, typename std::underlying_type<T>::type>::value,
+                  "T must be enum with underlying type protozero::pbf_tag_type");
 
 public:
 
+    /// The type of messages this class will read.
     using enum_type = T;
 
+    /**
+     * Construct a pbf_message. All arguments are forwarded to the pbf_reader
+     * parent class.
+     */
     template <typename... Args>
-    pbf_message(Args&&... args) noexcept :
+    pbf_message(Args&&... args) noexcept : // NOLINT clang-tidy: google-explicit-constructor
         pbf_reader(std::forward<Args>(args)...) {
     }
 
+    /**
+     * Set next field in the message as the current field. This is usually
+     * called in a while loop:
+     *
+     * @code
+     *    pbf_message<...> message(...);
+     *    while (message.next()) {
+     *        // handle field
+     *    }
+     * @endcode
+     *
+     * @returns `true` if there is a next field, `false` if not.
+     * @pre There must be no current field.
+     * @post If it returns `true` there is a current field now.
+     */
     bool next() {
         return pbf_reader::next();
     }
 
+    /**
+     * Set next field with given tag in the message as the current field.
+     * Fields with other tags are skipped. This is usually called in a while
+     * loop for repeated fields:
+     *
+     * @code
+     *    pbf_message<Example1> message{...};
+     *    while (message.next(Example1::repeated_fixed64_r)) {
+     *        // handle field
+     *    }
+     * @endcode
+     *
+     * or you can call it just once to get the one field with this tag:
+     *
+     * @code
+     *    pbf_message<Example1> message{...};
+     *    if (message.next(Example1::required_uint32_x)) {
+     *        // handle field
+     *    }
+     * @endcode
+     *
+     * Note that this will not check the wire type. The two-argument version
+     * of this function will also check the wire type.
+     *
+     * @returns `true` if there is a next field with this tag.
+     * @pre There must be no current field.
+     * @post If it returns `true` there is a current field now with the given tag.
+     */
     bool next(T next_tag) {
         return pbf_reader::next(pbf_tag_type(next_tag));
     }
 
+    /**
+     * Set next field with given tag and wire type in the message as the
+     * current field. Fields with other tags are skipped. This is usually
+     * called in a while loop for repeated fields:
+     *
+     * @code
+     *    pbf_message<Example1> message{...};
+     *    while (message.next(Example1::repeated_fixed64_r, pbf_wire_type::varint)) {
+     *        // handle field
+     *    }
+     * @endcode
+     *
+     * or you can call it just once to get the one field with this tag:
+     *
+     * @code
+     *    pbf_message<Example1> message{...};
+     *    if (message.next(Example1::required_uint32_x, pbf_wire_type::varint)) {
+     *        // handle field
+     *    }
+     * @endcode
+     *
+     * Note that this will also check the wire type. The one-argument version
+     * of this function will not check the wire type.
+     *
+     * @returns `true` if there is a next field with this tag.
+     * @pre There must be no current field.
+     * @post If it returns `true` there is a current field now with the given tag.
+     */
     bool next(T next_tag, pbf_wire_type type) {
         return pbf_reader::next(pbf_tag_type(next_tag), type);
     }
 
+    /**
+     * The tag of the current field. The tag is the enum value for the field
+     * number from the description in the .proto file.
+     *
+     * Call next() before calling this function to set the current field.
+     *
+     * @returns tag of the current field.
+     * @pre There must be a current field (ie. next() must have returned `true`).
+     */
     T tag() const noexcept {
         return T(pbf_reader::tag());
     }
diff --git a/include/protozero/pbf_reader.hpp b/include/protozero/pbf_reader.hpp
index 905ca0a..5efdebb 100644
--- a/include/protozero/pbf_reader.hpp
+++ b/include/protozero/pbf_reader.hpp
@@ -18,6 +18,7 @@ documentation.
 
 #include <cstddef>
 #include <cstdint>
+#include <cstring>
 #include <string>
 #include <utility>
 
@@ -41,13 +42,13 @@ namespace protozero {
  * @code
  *    std::string buffer;
  *    // fill buffer...
- *    pbf_reader message(buffer.data(), buffer.size());
+ *    pbf_reader message{buffer.data(), buffer.size()};
  * @endcode
  *
  * Sub-messages are created using get_message():
  *
  * @code
- *    pbf_reader message(...);
+ *    pbf_reader message{...};
  *    message.next();
  *    pbf_reader submessage = message.get_message();
  * @endcode
@@ -87,8 +88,8 @@ class pbf_reader {
         protozero_assert(tag() != 0 && "call next() before accessing field value");
         const auto len = get_len_and_skip();
         protozero_assert(len % sizeof(T) == 0);
-        return iterator_range<const_fixed_iterator<T>>{const_fixed_iterator<T>(m_data - len, m_data),
-                                                       const_fixed_iterator<T>(m_data, m_data)};
+        return {const_fixed_iterator<T>(m_data - len, m_data),
+                const_fixed_iterator<T>(m_data, m_data)};
     }
 
     template <typename T>
@@ -108,7 +109,7 @@ class pbf_reader {
 
     void skip_bytes(pbf_length_type len) {
         if (m_data + len > m_end) {
-            throw end_of_buffer_exception();
+            throw end_of_buffer_exception{};
         }
         m_data += len;
 
@@ -129,8 +130,8 @@ class pbf_reader {
     iterator_range<T> get_packed() {
         protozero_assert(tag() != 0 && "call next() before accessing field value");
         const auto len = get_len_and_skip();
-        return iterator_range<T>{T{m_data - len, m_data},
-                                 T{m_data, m_data}};
+        return {T{m_data - len, m_data},
+                T{m_data, m_data}};
     }
 
 public:
@@ -147,9 +148,7 @@ public:
      */
     explicit pbf_reader(const data_view& view) noexcept
         : m_data(view.data()),
-          m_end(view.data() + view.size()),
-          m_wire_type(pbf_wire_type::unknown),
-          m_tag(0) {
+          m_end(view.data() + view.size()) {
     }
 
     /**
@@ -164,9 +163,7 @@ public:
      */
     pbf_reader(const char* data, std::size_t size) noexcept
         : m_data(data),
-          m_end(data + size),
-          m_wire_type(pbf_wire_type::unknown),
-          m_tag(0) {
+          m_end(data + size) {
     }
 
     /**
@@ -181,9 +178,7 @@ public:
      */
     explicit pbf_reader(const std::pair<const char*, std::size_t>& data) noexcept
         : m_data(data.first),
-          m_end(data.first + data.second),
-          m_wire_type(pbf_wire_type::unknown),
-          m_tag(0) {
+          m_end(data.first + data.second) {
     }
 
     /**
@@ -198,9 +193,7 @@ public:
      */
     explicit pbf_reader(const std::string& data) noexcept
         : m_data(data.data()),
-          m_end(data.data() + data.size()),
-          m_wire_type(pbf_wire_type::unknown),
-          m_tag(0) {
+          m_end(data.data() + data.size()) {
     }
 
     /**
@@ -241,7 +234,7 @@ public:
      * are still fields available and to `false` if the last field has been
      * read.
      */
-    operator bool() const noexcept {
+    operator bool() const noexcept { // NOLINT clang-tidy: google-explicit-constructor
         return m_data < m_end;
     }
 
@@ -294,7 +287,7 @@ public:
             case pbf_wire_type::fixed32:
                 break;
             default:
-                throw unknown_pbf_wire_type_exception();
+                throw unknown_pbf_wire_type_exception{};
         }
 
         return true;
@@ -306,7 +299,7 @@ public:
      * loop for repeated fields:
      *
      * @code
-     *    pbf_reader message(...);
+     *    pbf_reader message{...};
      *    while (message.next(17)) {
      *        // handle field
      *    }
@@ -315,7 +308,7 @@ public:
      * or you can call it just once to get the one field with this tag:
      *
      * @code
-     *    pbf_reader message(...);
+     *    pbf_reader message{...};
      *    if (message.next(17)) {
      *        // handle field
      *    }
@@ -332,9 +325,8 @@ public:
         while (next()) {
             if (m_tag == next_tag) {
                 return true;
-            } else {
-                skip();
             }
+            skip();
         }
         return false;
     }
@@ -345,7 +337,7 @@ public:
      * called in a while loop for repeated fields:
      *
      * @code
-     *    pbf_reader message(...);
+     *    pbf_reader message{...};
      *    while (message.next(17, pbf_wire_type::varint)) {
      *        // handle field
      *    }
@@ -354,7 +346,7 @@ public:
      * or you can call it just once to get the one field with this tag:
      *
      * @code
-     *    pbf_reader message(...);
+     *    pbf_reader message{...};
      *    if (message.next(17, pbf_wire_type::varint)) {
      *        // handle field
      *    }
@@ -371,9 +363,8 @@ public:
         while (next()) {
             if (m_tag == next_tag && m_wire_type == type) {
                 return true;
-            } else {
-                skip();
             }
+            skip();
         }
         return false;
     }
@@ -417,7 +408,7 @@ public:
      * Use it like this:
      *
      * @code
-     *    pbf_reader message(...);
+     *    pbf_reader message{...};
      *    while (message.next()) {
      *        switch (message.tag_and_type()) {
      *            case tag_and_type(17, pbf_wire_type::length_delimited):
@@ -667,7 +658,7 @@ public:
         protozero_assert(tag() != 0 && "call next() before accessing field value");
         protozero_assert(has_wire_type(pbf_wire_type::length_delimited) && "not of type string, bytes or message");
         const auto len = get_len_and_skip();
-        return data_view{m_data - len, len};
+        return {m_data - len, len};
     }
 
 #ifndef PROTOZERO_STRICT_API
@@ -683,7 +674,7 @@ public:
         protozero_assert(tag() != 0 && "call next() before accessing field value");
         protozero_assert(has_wire_type(pbf_wire_type::length_delimited) && "not of type string, bytes or message");
         const auto len = get_len_and_skip();
-        return std::make_pair(m_data - len, len);
+        return {m_data - len, len};
     }
 #endif
 
@@ -717,7 +708,7 @@ public:
      * @post The current field was consumed and there is no current field now.
      */
     pbf_reader get_message() {
-        return pbf_reader(get_view());
+        return pbf_reader{get_view()};
     }
 
     ///@}
diff --git a/include/protozero/pbf_writer.hpp b/include/protozero/pbf_writer.hpp
index af626bd..c50a46d 100644
--- a/include/protozero/pbf_writer.hpp
+++ b/include/protozero/pbf_writer.hpp
@@ -19,6 +19,7 @@ documentation.
 #include <cstddef>
 #include <cstdint>
 #include <cstring>
+#include <initializer_list>
 #include <iterator>
 #include <limits>
 #include <string>
@@ -53,11 +54,11 @@ class pbf_writer {
     // A pointer to a string buffer holding the data already written to the
     // PBF message. For default constructed writers or writers that have been
     // rolled back, this is a nullptr.
-    std::string* m_data;
+    std::string* m_data = nullptr;
 
     // A pointer to a parent writer object if this is a submessage. If this
     // is a top-level writer, it is a nullptr.
-    pbf_writer* m_parent_writer;
+    pbf_writer* m_parent_writer = nullptr;
 
     // This is usually 0. If there is an open submessage, this is set in the
     // parent to the rollback position, ie. the last position before the
@@ -97,12 +98,12 @@ class pbf_writer {
     }
 
     template <typename T, typename It>
-    void add_packed_fixed(pbf_tag_type tag, It first, It last, std::input_iterator_tag) {
+    void add_packed_fixed(pbf_tag_type tag, It first, It last, std::input_iterator_tag /*unused*/) {
         if (first == last) {
             return;
         }
 
-        pbf_writer sw(*this, tag);
+        pbf_writer sw{*this, tag};
 
         while (first != last) {
             sw.add_fixed<T>(*first++);
@@ -110,7 +111,7 @@ class pbf_writer {
     }
 
     template <typename T, typename It>
-    void add_packed_fixed(pbf_tag_type tag, It first, It last, std::forward_iterator_tag) {
+    void add_packed_fixed(pbf_tag_type tag, It first, It last, std::forward_iterator_tag /*unused*/) {
         if (first == last) {
             return;
         }
@@ -130,7 +131,7 @@ class pbf_writer {
             return;
         }
 
-        pbf_writer sw(*this, tag);
+        pbf_writer sw{*this, tag};
 
         while (first != last) {
             sw.add_varint(uint64_t(*first++));
@@ -143,7 +144,7 @@ class pbf_writer {
             return;
         }
 
-        pbf_writer sw(*this, tag);
+        pbf_writer sw{*this, tag};
 
         while (first != last) {
             sw.add_varint(encode_zigzag64(*first++));
@@ -194,9 +195,9 @@ class pbf_writer {
         const auto length = pbf_length_type(m_data->size() - m_pos);
 
         protozero_assert(m_data->size() >= m_pos - reserve_bytes);
-        const auto n = write_varint(m_data->begin() + long(m_pos) - reserve_bytes, length);
+        const auto n = write_varint(m_data->begin() + int64_t(m_pos) - reserve_bytes, length);
 
-        m_data->erase(m_data->begin() + long(m_pos) - reserve_bytes + n, m_data->begin() + long(m_pos));
+        m_data->erase(m_data->begin() + int64_t(m_pos) - reserve_bytes + n, m_data->begin() + int64_t(m_pos));
         m_pos = 0;
     }
 
@@ -225,18 +226,14 @@ public:
      * doesn't have to be empty. The pbf_writer will just append data.
      */
     explicit pbf_writer(std::string& data) noexcept :
-        m_data(&data),
-        m_parent_writer(nullptr) {
+        m_data(&data) {
     }
 
     /**
      * Create a writer without a data store. In this form the writer can not
      * be used!
      */
-    pbf_writer() noexcept :
-        m_data(nullptr),
-        m_parent_writer(nullptr) {
-    }
+    pbf_writer() noexcept = default;
 
     /**
      * Construct a pbf_writer for a submessage from the pbf_writer of the
@@ -254,25 +251,59 @@ public:
         m_parent_writer->open_submessage(tag, size);
     }
 
-    /// A pbf_writer object can be copied
-    pbf_writer(const pbf_writer&) noexcept = default;
+    /// A pbf_writer object can not be copied
+    pbf_writer(const pbf_writer&) = delete;
 
-    /// A pbf_writer object can be copied
-    pbf_writer& operator=(const pbf_writer&) noexcept = default;
+    /// A pbf_writer object can not be copied
+    pbf_writer& operator=(const pbf_writer&) = delete;
 
-    /// A pbf_writer object can be moved
-    pbf_writer(pbf_writer&&) noexcept = default;
+    /**
+     * A pbf_writer object can be moved. After this the other pbf_writer will
+     * be invalid.
+     */
+    pbf_writer(pbf_writer&& other) noexcept :
+        m_data(other.m_data),
+        m_parent_writer(other.m_parent_writer),
+        m_rollback_pos(other.m_rollback_pos),
+        m_pos(other.m_pos) {
+        other.m_data = nullptr;
+        other.m_parent_writer = nullptr;
+        other.m_rollback_pos = 0;
+        other.m_pos = 0;
+    }
 
-    /// A pbf_writer object can be moved
-    pbf_writer& operator=(pbf_writer&&) noexcept = default;
+    /**
+     * A pbf_writer object can be moved. After this the other pbf_writer will
+     * be invalid.
+     */
+    pbf_writer& operator=(pbf_writer&& other) noexcept {
+        m_data = other.m_data;
+        m_parent_writer = other.m_parent_writer;
+        m_rollback_pos = other.m_rollback_pos;
+        m_pos = other.m_pos;
+        other.m_data = nullptr;
+        other.m_parent_writer = nullptr;
+        other.m_rollback_pos = 0;
+        other.m_pos = 0;
+        return *this;
+    }
 
     ~pbf_writer() {
-        if (m_parent_writer) {
+        if (m_parent_writer != nullptr) {
             m_parent_writer->close_submessage();
         }
     }
 
     /**
+     * Check if this writer is valid. A writer is invalid if it was default
+     * constructed, moved from, or if commit() has been called on it.
+     * Otherwise it is valid.
+     */
+    bool valid() const noexcept {
+        return m_data != nullptr;
+    }
+
+    /**
      * Swap the contents of this object with the other.
      *
      * @param other Other object to swap data with.
@@ -299,16 +330,34 @@ public:
     }
 
     /**
+     * Commit this submessage. This does the same as when the pbf_writer
+     * goes out of scope and is destructed.
+     *
+     * @pre Must be a pbf_writer of a submessage, ie one opened with the
+     *      pbf_writer constructor taking a parent message.
+     * @post The pbf_writer is invalid and can't be used any more.
+     */
+    void commit() {
+        protozero_assert(m_parent_writer && "you can't call commit() on a pbf_writer without a parent");
+        protozero_assert(m_pos == 0 && "you can't call commit() on a pbf_writer that has an open nested submessage");
+        m_parent_writer->close_submessage();
+        m_parent_writer = nullptr;
+        m_data = nullptr;
+    }
+
+    /**
      * Cancel writing of this submessage. The complete submessage will be
      * removed as if it was never created and no fields were added.
      *
      * @pre Must be a pbf_writer of a submessage, ie one opened with the
      *      pbf_writer constructor taking a parent message.
+     * @post The pbf_writer is invalid and can't be used any more.
      */
     void rollback() {
         protozero_assert(m_parent_writer && "you can't call rollback() on a pbf_writer without a parent");
         protozero_assert(m_pos == 0 && "you can't call rollback() on a pbf_writer that has an open nested submessage");
         m_parent_writer->rollback_submessage();
+        m_parent_writer = nullptr;
         m_data = nullptr;
     }
 
@@ -327,7 +376,7 @@ public:
         add_field(tag, pbf_wire_type::varint);
         protozero_assert(m_pos == 0 && "you can't add fields to a parent pbf_writer if there is an existing pbf_writer for a submessage");
         protozero_assert(m_data);
-        m_data->append(1, value);
+        m_data->append(1, char(value));
     }
 
     /**
@@ -849,15 +898,17 @@ namespace detail {
 
     protected:
 
-        pbf_writer m_writer;
+        pbf_writer m_writer{};
 
     public:
 
         packed_field(const packed_field&) = delete;
         packed_field& operator=(const packed_field&) = delete;
 
-        packed_field(packed_field&&) = default;
-        packed_field& operator=(packed_field&&) = default;
+        packed_field(packed_field&&) noexcept = default;
+        packed_field& operator=(packed_field&&) noexcept = default;
+
+        packed_field() = default;
 
         packed_field(pbf_writer& parent_writer, pbf_tag_type tag) :
             m_writer(parent_writer, tag) {
@@ -867,6 +918,16 @@ namespace detail {
             m_writer(parent_writer, tag, size) {
         }
 
+        ~packed_field() noexcept = default;
+
+        bool valid() const noexcept {
+            return m_writer.valid();
+        }
+
+        void commit() {
+            m_writer.commit();
+        }
+
         void rollback() {
             m_writer.rollback();
         }
@@ -878,6 +939,10 @@ namespace detail {
 
     public:
 
+        packed_field_fixed() :
+            packed_field() {
+        }
+
         template <typename P>
         packed_field_fixed(pbf_writer& parent_writer, P tag) :
             packed_field(parent_writer, static_cast<pbf_tag_type>(tag)) {
@@ -899,6 +964,10 @@ namespace detail {
 
     public:
 
+        packed_field_varint() :
+            packed_field() {
+        }
+
         template <typename P>
         packed_field_varint(pbf_writer& parent_writer, P tag) :
             packed_field(parent_writer, static_cast<pbf_tag_type>(tag)) {
@@ -915,6 +984,10 @@ namespace detail {
 
     public:
 
+        packed_field_svarint() :
+            packed_field() {
+        }
+
         template <typename P>
         packed_field_svarint(pbf_writer& parent_writer, P tag) :
             packed_field(parent_writer, static_cast<pbf_tag_type>(tag)) {
diff --git a/include/protozero/types.hpp b/include/protozero/types.hpp
index 3dbdaf1..576c2e2 100644
--- a/include/protozero/types.hpp
+++ b/include/protozero/types.hpp
@@ -74,18 +74,15 @@ using data_view = PROTOZERO_USE_VIEW;
  */
 class data_view {
 
-    const char* m_data;
-    std::size_t m_size;
+    const char* m_data = nullptr;
+    std::size_t m_size = 0;
 
 public:
 
     /**
      * Default constructor. Construct an empty data_view.
      */
-    constexpr data_view() noexcept
-        : m_data(nullptr),
-          m_size(0) {
-    }
+    constexpr data_view() noexcept = default;
 
     /**
      * Create data_view from pointer and size.
@@ -103,7 +100,7 @@ public:
      *
      * @param str String with the data.
      */
-    data_view(const std::string& str) noexcept
+    data_view(const std::string& str) noexcept // NOLINT clang-tidy: google-explicit-constructor
         : m_data(str.data()),
           m_size(str.size()) {
     }
@@ -113,7 +110,7 @@ public:
      *
      * @param ptr Pointer to the data.
      */
-    data_view(const char* ptr) noexcept
+    data_view(const char* ptr) noexcept // NOLINT clang-tidy: google-explicit-constructor
         : m_data(ptr),
           m_size(std::strlen(ptr)) {
     }
@@ -148,10 +145,14 @@ public:
      * 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 std::string{m_data, m_size};
+        return {m_data, m_size};
     }
 
     /**
@@ -161,7 +162,7 @@ public:
      */
     explicit operator std::string() const {
         protozero_assert(m_data);
-        return std::string{m_data, m_size};
+        return {m_data, m_size};
     }
 
 }; // class data_view
diff --git a/include/protozero/varint.hpp b/include/protozero/varint.hpp
index d115d5f..6377671 100644
--- a/include/protozero/varint.hpp
+++ b/include/protozero/varint.hpp
@@ -31,25 +31,25 @@ namespace detail {
 
     // from https://github.com/facebook/folly/blob/master/folly/Varint.h
     inline uint64_t decode_varint_impl(const char** data, const char* end) {
-        const int8_t* begin = reinterpret_cast<const int8_t*>(*data);
-        const int8_t* iend = reinterpret_cast<const int8_t*>(end);
+        const auto begin = reinterpret_cast<const int8_t*>(*data);
+        const auto iend = reinterpret_cast<const int8_t*>(end);
         const int8_t* p = begin;
         uint64_t val = 0;
 
         if (iend - begin >= max_varint_length) {  // fast path
             do {
                 int64_t b;
-                b = *p++; val  = uint64_t((b & 0x7f)      ); if (b >= 0) break;
-                b = *p++; val |= uint64_t((b & 0x7f) <<  7); if (b >= 0) break;
-                b = *p++; val |= uint64_t((b & 0x7f) << 14); if (b >= 0) break;
-                b = *p++; val |= uint64_t((b & 0x7f) << 21); if (b >= 0) break;
-                b = *p++; val |= uint64_t((b & 0x7f) << 28); if (b >= 0) break;
-                b = *p++; val |= uint64_t((b & 0x7f) << 35); if (b >= 0) break;
-                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;
-                throw varint_too_long_exception();
+                b = *p++; val  = uint64_t((b & 0x7f)      ); if (b >= 0) { break; }
+                b = *p++; val |= uint64_t((b & 0x7f) <<  7); if (b >= 0) { break; }
+                b = *p++; val |= uint64_t((b & 0x7f) << 14); if (b >= 0) { break; }
+                b = *p++; val |= uint64_t((b & 0x7f) << 21); if (b >= 0) { break; }
+                b = *p++; val |= uint64_t((b & 0x7f) << 28); if (b >= 0) { break; }
+                b = *p++; val |= uint64_t((b & 0x7f) << 35); if (b >= 0) { break; }
+                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; }
+                throw varint_too_long_exception{};
             } while (false);
         } else {
             int shift = 0;
@@ -58,7 +58,7 @@ namespace detail {
                 shift += 7;
             }
             if (p == iend) {
-                throw end_of_buffer_exception();
+                throw end_of_buffer_exception{};
             }
             val |= uint64_t(*p++) << shift;
         }
@@ -89,7 +89,7 @@ namespace detail {
 inline uint64_t decode_varint(const char** data, const char* end) {
     // If this is a one-byte varint, decode it here.
     if (end != *data && ((**data & 0x80) == 0)) {
-        uint64_t val = uint64_t(**data);
+        const auto val = static_cast<uint64_t>(**data);
         ++(*data);
         return val;
     }
@@ -110,8 +110,8 @@ inline uint64_t decode_varint(const char** data, const char* end) {
  *         before the end of the varint.
  */
 inline void skip_varint(const char** data, const char* end) {
-    const int8_t* begin = reinterpret_cast<const int8_t*>(*data);
-    const int8_t* iend = reinterpret_cast<const int8_t*>(end);
+    const auto begin = reinterpret_cast<const int8_t*>(*data);
+    const auto iend = reinterpret_cast<const int8_t*>(end);
     const int8_t* p = begin;
 
     while (p != iend && *p < 0) {
@@ -119,11 +119,11 @@ inline void skip_varint(const char** data, const char* end) {
     }
 
     if (p >= begin + max_varint_length) {
-        throw varint_too_long_exception();
+        throw varint_too_long_exception{};
     }
 
     if (p == iend) {
-        throw end_of_buffer_exception();
+        throw end_of_buffer_exception{};
     }
 
     ++p;
diff --git a/include/protozero/version.hpp b/include/protozero/version.hpp
index 6d82823..963632f 100644
--- a/include/protozero/version.hpp
+++ b/include/protozero/version.hpp
@@ -23,12 +23,12 @@ documentation.
 #define PROTOZERO_VERSION_MINOR 5
 
 /// The patch number
-#define PROTOZERO_VERSION_PATCH 2
+#define PROTOZERO_VERSION_PATCH 3
 
 /// 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.2"
+#define PROTOZERO_VERSION_STRING "1.5.3"
 
 #endif // PROTOZERO_VERSION_HPP
diff --git a/package.json b/package.json
index b858b59..cc38a04 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
     "name": "protozero",
-    "version": "1.5.2",
+    "version": "1.5.3",
     "description": "Minimalist protocol buffer decoder and encoder in C++",
     "main": "include_dirs.js",
     "repository"   :  {
diff --git a/test/include/catch.hpp b/test/catch/catch.hpp
similarity index 97%
rename from test/include/catch.hpp
rename to test/catch/catch.hpp
index f7681f4..4d1fc33 100644
--- a/test/include/catch.hpp
+++ b/test/catch/catch.hpp
@@ -1,6 +1,6 @@
 /*
- *  Catch v1.9.6
- *  Generated: 2017-06-27 12:19:54.557875
+ *  Catch v1.10.0
+ *  Generated: 2017-08-26 15:16:46.676990
  *  ----------------------------------------------------------
  *  This file has been merged from multiple headers. Please don't edit it directly
  *  Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved.
@@ -145,6 +145,11 @@
 
 #endif
 
+#ifdef __OS400__
+#       define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS
+#       define CATCH_CONFIG_COLOUR_NONE
+#endif
+
 ////////////////////////////////////////////////////////////////////////////////
 // Cygwin
 #ifdef __CYGWIN__
@@ -414,14 +419,14 @@ namespace Catch {
     };
 
     template<typename ContainerT>
-    inline void deleteAll( ContainerT& container ) {
+    void deleteAll( ContainerT& container ) {
         typename ContainerT::const_iterator it = container.begin();
         typename ContainerT::const_iterator itEnd = container.end();
         for(; it != itEnd; ++it )
             delete *it;
     }
     template<typename AssociativeContainerT>
-    inline void deleteAllValues( AssociativeContainerT& container ) {
+    void deleteAllValues( AssociativeContainerT& container ) {
         typename AssociativeContainerT::const_iterator it = container.begin();
         typename AssociativeContainerT::const_iterator itEnd = container.end();
         for(; it != itEnd; ++it )
@@ -501,7 +506,6 @@ namespace Catch {
     {
     public:
         NotImplementedException( SourceLineInfo const& lineInfo );
-        NotImplementedException( NotImplementedException const& ) {}
 
         virtual ~NotImplementedException() CATCH_NOEXCEPT {}
 
@@ -771,7 +775,7 @@ void registerTestCaseFunction
     #define INTERNAL_CATCH_TESTCASE2( TestName, ... ) \
         static void TestName(); \
         CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \
-        namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &TestName, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); } \
+        namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &TestName, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); } /* NOLINT */ \
         CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \
         static void TestName()
     #define INTERNAL_CATCH_TESTCASE( ... ) \
@@ -780,7 +784,7 @@ void registerTestCaseFunction
     ///////////////////////////////////////////////////////////////////////////////
     #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \
         CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \
-        namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); } \
+        namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); } /* NOLINT */ \
         CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS
 
     ///////////////////////////////////////////////////////////////////////////////
@@ -790,7 +794,7 @@ void registerTestCaseFunction
             struct TestName : ClassName{ \
                 void test(); \
             }; \
-            Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &TestName::test, #ClassName, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); \
+            Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &TestName::test, #ClassName, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); /* NOLINT */ \
         } \
         CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \
         void TestName::test()
@@ -800,7 +804,7 @@ void registerTestCaseFunction
     ///////////////////////////////////////////////////////////////////////////////
     #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \
         CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \
-        Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); \
+        Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); /* NOLINT */ \
         CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS
 
 #else
@@ -808,7 +812,7 @@ void registerTestCaseFunction
     #define INTERNAL_CATCH_TESTCASE2( TestName, Name, Desc ) \
         static void TestName(); \
         CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \
-        namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &TestName, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); }\
+        namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &TestName, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); } /* NOLINT */ \
         CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \
         static void TestName()
     #define INTERNAL_CATCH_TESTCASE( Name, Desc ) \
@@ -817,7 +821,7 @@ void registerTestCaseFunction
     ///////////////////////////////////////////////////////////////////////////////
     #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, Name, Desc ) \
         CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \
-        namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( Name, Desc ), CATCH_INTERNAL_LINEINFO ); } \
+        namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( Name, Desc ), CATCH_INTERNAL_LINEINFO ); } /* NOLINT */ \
         CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS
 
     ///////////////////////////////////////////////////////////////////////////////
@@ -827,7 +831,7 @@ void registerTestCaseFunction
             struct TestCaseName : ClassName{ \
                 void test(); \
             }; \
-            Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &TestCaseName::test, #ClassName, Catch::NameAndDesc( TestName, Desc ), CATCH_INTERNAL_LINEINFO ); \
+            Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &TestCaseName::test, #ClassName, Catch::NameAndDesc( TestName, Desc ), CATCH_INTERNAL_LINEINFO ); /* NOLINT */ \
         } \
         CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \
         void TestCaseName::test()
@@ -837,7 +841,7 @@ void registerTestCaseFunction
     ///////////////////////////////////////////////////////////////////////////////
     #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, Name, Desc ) \
         CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \
-        Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); \
+        Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); /* NOLINT */ \
         CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS
 
 #endif
@@ -933,7 +937,7 @@ namespace Catch {
 
     struct AssertionInfo
     {
-        AssertionInfo() {}
+        AssertionInfo();
         AssertionInfo(  char const * _macroName,
                         SourceLineInfo const& _lineInfo,
                         char const * _capturedExpression,
@@ -1158,23 +1162,23 @@ namespace Matchers {
     // This allows the types to be inferred
     // - deprecated: prefer ||, && and !
     template<typename T>
-    inline Impl::MatchNotOf<T> Not( Impl::MatcherBase<T> const& underlyingMatcher ) {
+    Impl::MatchNotOf<T> Not( Impl::MatcherBase<T> const& underlyingMatcher ) {
         return Impl::MatchNotOf<T>( underlyingMatcher );
     }
     template<typename T>
-    inline Impl::MatchAllOf<T> AllOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2 ) {
+    Impl::MatchAllOf<T> AllOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2 ) {
         return Impl::MatchAllOf<T>() && m1 && m2;
     }
     template<typename T>
-    inline Impl::MatchAllOf<T> AllOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2, Impl::MatcherBase<T> const& m3 ) {
+    Impl::MatchAllOf<T> AllOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2, Impl::MatcherBase<T> const& m3 ) {
         return Impl::MatchAllOf<T>() && m1 && m2 && m3;
     }
     template<typename T>
-    inline Impl::MatchAnyOf<T> AnyOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2 ) {
+    Impl::MatchAnyOf<T> AnyOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2 ) {
         return Impl::MatchAnyOf<T>() || m1 || m2;
     }
     template<typename T>
-    inline Impl::MatchAnyOf<T> AnyOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2, Impl::MatcherBase<T> const& m3 ) {
+    Impl::MatchAnyOf<T> AnyOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2, Impl::MatcherBase<T> const& m3 ) {
         return Impl::MatchAnyOf<T>() || m1 || m2 || m3;
     }
 
@@ -1219,7 +1223,7 @@ namespace Catch {
 
         template<typename T>
         ResultBuilder& operator << ( T const& value ) {
-            m_stream().oss << value;
+            stream().oss << value;
             return *this;
         }
 
@@ -1253,6 +1257,16 @@ namespace Catch {
         AssertionInfo m_assertionInfo;
         AssertionResultData m_data;
 
+        CopyableStream &stream()
+        {
+            if(!m_usedStream)
+            {
+                m_usedStream = true;
+                m_stream().oss.str("");
+            }
+            return m_stream();
+        }
+
         static CopyableStream &m_stream()
         {
             static CopyableStream s;
@@ -1262,6 +1276,7 @@ namespace Catch {
         bool m_shouldDebugBreak;
         bool m_shouldThrow;
         bool m_guardException;
+        bool m_usedStream;
     };
 
 } // namespace Catch
@@ -1276,6 +1291,7 @@ namespace Catch {
 #ifdef _MSC_VER
 #pragma warning(push)
 #pragma warning(disable:4389) // '==' : signed/unsigned mismatch
+#pragma warning(disable:4018) // more "signed/unsigned mismatch"
 #pragma warning(disable:4312) // Converting int to T* using reinterpret_cast (issue on x64 platform)
 #endif
 
@@ -1302,176 +1318,103 @@ namespace Internal {
     template<> struct OperatorTraits<IsGreaterThanOrEqualTo>{ static const char* getName(){ return ">="; } };
 
     template<typename T>
-    inline T& opCast(T const& t) { return const_cast<T&>(t); }
-
-// nullptr_t support based on pull request #154 from Konstantin Baumann
+    T& removeConst(T const &t) { return const_cast<T&>(t); }
 #ifdef CATCH_CONFIG_CPP11_NULLPTR
-    inline std::nullptr_t opCast(std::nullptr_t) { return nullptr; }
-#endif // CATCH_CONFIG_CPP11_NULLPTR
+    inline std::nullptr_t removeConst(std::nullptr_t) { return nullptr; }
+#endif
 
     // So the compare overloads can be operator agnostic we convey the operator as a template
     // enum, which is used to specialise an Evaluator for doing the comparison.
     template<typename T1, typename T2, Operator Op>
-    class Evaluator{};
+    struct Evaluator{};
 
     template<typename T1, typename T2>
     struct Evaluator<T1, T2, IsEqualTo> {
         static bool evaluate( T1 const& lhs, T2 const& rhs) {
-            return bool( opCast( lhs ) ==  opCast( rhs ) );
+            return bool(removeConst(lhs) == removeConst(rhs) );
         }
     };
     template<typename T1, typename T2>
     struct Evaluator<T1, T2, IsNotEqualTo> {
         static bool evaluate( T1 const& lhs, T2 const& rhs ) {
-            return bool( opCast( lhs ) != opCast( rhs ) );
+            return bool(removeConst(lhs) != removeConst(rhs) );
         }
     };
     template<typename T1, typename T2>
     struct Evaluator<T1, T2, IsLessThan> {
         static bool evaluate( T1 const& lhs, T2 const& rhs ) {
-            return bool( opCast( lhs ) < opCast( rhs ) );
+            return bool(removeConst(lhs) < removeConst(rhs) );
         }
     };
     template<typename T1, typename T2>
     struct Evaluator<T1, T2, IsGreaterThan> {
         static bool evaluate( T1 const& lhs, T2 const& rhs ) {
-            return bool( opCast( lhs ) > opCast( rhs ) );
+            return bool(removeConst(lhs) > removeConst(rhs) );
         }
     };
     template<typename T1, typename T2>
     struct Evaluator<T1, T2, IsGreaterThanOrEqualTo> {
         static bool evaluate( T1 const& lhs, T2 const& rhs ) {
-            return bool( opCast( lhs ) >= opCast( rhs ) );
+            return bool(removeConst(lhs) >= removeConst(rhs) );
         }
     };
     template<typename T1, typename T2>
     struct Evaluator<T1, T2, IsLessThanOrEqualTo> {
         static bool evaluate( T1 const& lhs, T2 const& rhs ) {
-            return bool( opCast( lhs ) <= opCast( rhs ) );
+            return bool(removeConst(lhs) <= removeConst(rhs) );
         }
     };
 
-    template<Operator Op, typename T1, typename T2>
-    bool applyEvaluator( T1 const& lhs, T2 const& rhs ) {
-        return Evaluator<T1, T2, Op>::evaluate( lhs, rhs );
-    }
-
-    // This level of indirection allows us to specialise for integer types
-    // to avoid signed/ unsigned warnings
-
-    // "base" overload
-    template<Operator Op, typename T1, typename T2>
-    bool compare( T1 const& lhs, T2 const& rhs ) {
-        return Evaluator<T1, T2, Op>::evaluate( lhs, rhs );
-    }
-
-    // unsigned X to int
-    template<Operator Op> bool compare( unsigned int lhs, int rhs ) {
-        return applyEvaluator<Op>( lhs, static_cast<unsigned int>( rhs ) );
-    }
-    template<Operator Op> bool compare( unsigned long lhs, int rhs ) {
-        return applyEvaluator<Op>( lhs, static_cast<unsigned int>( rhs ) );
-    }
-    template<Operator Op> bool compare( unsigned char lhs, int rhs ) {
-        return applyEvaluator<Op>( lhs, static_cast<unsigned int>( rhs ) );
-    }
-
-    // unsigned X to long
-    template<Operator Op> bool compare( unsigned int lhs, long rhs ) {
-        return applyEvaluator<Op>( lhs, static_cast<unsigned long>( rhs ) );
-    }
-    template<Operator Op> bool compare( unsigned long lhs, long rhs ) {
-        return applyEvaluator<Op>( lhs, static_cast<unsigned long>( rhs ) );
-    }
-    template<Operator Op> bool compare( unsigned char lhs, long rhs ) {
-        return applyEvaluator<Op>( lhs, static_cast<unsigned long>( rhs ) );
-    }
-
-    // int to unsigned X
-    template<Operator Op> bool compare( int lhs, unsigned int rhs ) {
-        return applyEvaluator<Op>( static_cast<unsigned int>( lhs ), rhs );
-    }
-    template<Operator Op> bool compare( int lhs, unsigned long rhs ) {
-        return applyEvaluator<Op>( static_cast<unsigned int>( lhs ), rhs );
-    }
-    template<Operator Op> bool compare( int lhs, unsigned char rhs ) {
-        return applyEvaluator<Op>( static_cast<unsigned int>( lhs ), rhs );
-    }
-
-    // long to unsigned X
-    template<Operator Op> bool compare( long lhs, unsigned int rhs ) {
-        return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
-    }
-    template<Operator Op> bool compare( long lhs, unsigned long rhs ) {
-        return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
-    }
-    template<Operator Op> bool compare( long lhs, unsigned char rhs ) {
-        return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
-    }
-
-    // pointer to long (when comparing against NULL)
-    template<Operator Op, typename T> bool compare( long lhs, T* rhs ) {
-        return Evaluator<T*, T*, Op>::evaluate( reinterpret_cast<T*>( lhs ), rhs );
-    }
-    template<Operator Op, typename T> bool compare( T* lhs, long rhs ) {
-        return Evaluator<T*, T*, Op>::evaluate( lhs, reinterpret_cast<T*>( rhs ) );
-    }
-
-    // pointer to int (when comparing against NULL)
-    template<Operator Op, typename T> bool compare( int lhs, T* rhs ) {
-        return Evaluator<T*, T*, Op>::evaluate( reinterpret_cast<T*>( lhs ), rhs );
-    }
-    template<Operator Op, typename T> bool compare( T* lhs, int rhs ) {
-        return Evaluator<T*, T*, Op>::evaluate( lhs, reinterpret_cast<T*>( rhs ) );
-    }
-
-#ifdef CATCH_CONFIG_CPP11_LONG_LONG
-    // long long to unsigned X
-    template<Operator Op> bool compare( long long lhs, unsigned int rhs ) {
-        return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
-    }
-    template<Operator Op> bool compare( long long lhs, unsigned long rhs ) {
-        return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
-    }
-    template<Operator Op> bool compare( long long lhs, unsigned long long rhs ) {
-        return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
-    }
-    template<Operator Op> bool compare( long long lhs, unsigned char rhs ) {
-        return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
-    }
-
-    // unsigned long long to X
-    template<Operator Op> bool compare( unsigned long long lhs, int rhs ) {
-        return applyEvaluator<Op>( static_cast<long>( lhs ), rhs );
-    }
-    template<Operator Op> bool compare( unsigned long long lhs, long rhs ) {
-        return applyEvaluator<Op>( static_cast<long>( lhs ), rhs );
-    }
-    template<Operator Op> bool compare( unsigned long long lhs, long long rhs ) {
-        return applyEvaluator<Op>( static_cast<long>( lhs ), rhs );
-    }
-    template<Operator Op> bool compare( unsigned long long lhs, char rhs ) {
-        return applyEvaluator<Op>( static_cast<long>( lhs ), rhs );
-    }
-
-    // pointer to long long (when comparing against NULL)
-    template<Operator Op, typename T> bool compare( long long lhs, T* rhs ) {
-        return Evaluator<T*, T*, Op>::evaluate( reinterpret_cast<T*>( lhs ), rhs );
-    }
-    template<Operator Op, typename T> bool compare( T* lhs, long long rhs ) {
-        return Evaluator<T*, T*, Op>::evaluate( lhs, reinterpret_cast<T*>( rhs ) );
-    }
-#endif // CATCH_CONFIG_CPP11_LONG_LONG
+    // Special case for comparing a pointer to an int (deduced for p==0)
+    template<typename T>
+    struct Evaluator<int const&, T* const&, IsEqualTo> {
+        static bool evaluate( int lhs, T* rhs) {
+            return reinterpret_cast<void const*>( lhs ) ==  rhs;
+        }
+    };
+    template<typename T>
+    struct Evaluator<T* const&, int const&, IsEqualTo> {
+        static bool evaluate( T* lhs, int rhs) {
+            return lhs == reinterpret_cast<void const*>( rhs );
+        }
+    };
+    template<typename T>
+    struct Evaluator<int const&, T* const&, IsNotEqualTo> {
+        static bool evaluate( int lhs, T* rhs) {
+            return reinterpret_cast<void const*>( lhs ) !=  rhs;
+        }
+    };
+    template<typename T>
+    struct Evaluator<T* const&, int const&, IsNotEqualTo> {
+        static bool evaluate( T* lhs, int rhs) {
+            return lhs != reinterpret_cast<void const*>( rhs );
+        }
+    };
 
-#ifdef CATCH_CONFIG_CPP11_NULLPTR
-    // pointer to nullptr_t (when comparing against nullptr)
-    template<Operator Op, typename T> bool compare( std::nullptr_t, T* rhs ) {
-        return Evaluator<T*, T*, Op>::evaluate( nullptr, rhs );
-    }
-    template<Operator Op, typename T> bool compare( T* lhs, std::nullptr_t ) {
-        return Evaluator<T*, T*, Op>::evaluate( lhs, nullptr );
-    }
-#endif // CATCH_CONFIG_CPP11_NULLPTR
+    template<typename T>
+    struct Evaluator<long const&, T* const&, IsEqualTo> {
+        static bool evaluate( long lhs, T* rhs) {
+            return reinterpret_cast<void const*>( lhs ) ==  rhs;
+        }
+    };
+    template<typename T>
+    struct Evaluator<T* const&, long const&, IsEqualTo> {
+        static bool evaluate( T* lhs, long rhs) {
+            return lhs == reinterpret_cast<void const*>( rhs );
+        }
+    };
+    template<typename T>
+    struct Evaluator<long const&, T* const&, IsNotEqualTo> {
+        static bool evaluate( long lhs, T* rhs) {
+            return reinterpret_cast<void const*>( lhs ) !=  rhs;
+        }
+    };
+    template<typename T>
+    struct Evaluator<T* const&, long const&, IsNotEqualTo> {
+        static bool evaluate( T* lhs, long rhs) {
+            return lhs != reinterpret_cast<void const*>( rhs );
+        }
+    };
 
 } // end of namespace Internal
 } // end of namespace Catch
@@ -1667,7 +1610,7 @@ namespace Detail {
     std::string rawMemoryToString( const void *object, std::size_t size );
 
     template<typename T>
-    inline std::string rawMemoryToString( const T& object ) {
+    std::string rawMemoryToString( const T& object ) {
       return rawMemoryToString( &object, sizeof(object) );
     }
 
@@ -1892,7 +1835,7 @@ public:
 
     void endExpression() const {
         m_rb
-            .setResultType( Internal::compare<Op>( m_lhs, m_rhs ) )
+            .setResultType(  Internal::Evaluator<LhsT, RhsT, Op>::evaluate( m_lhs, m_rhs ) )
             .endExpression( *this );
     }
 
@@ -1956,7 +1899,7 @@ private:
 namespace Catch {
 
     template<typename T>
-    inline ExpressionLhs<T const&> ResultBuilder::operator <= ( T const& operand ) {
+    ExpressionLhs<T const&> ResultBuilder::operator <= ( T const& operand ) {
         return ExpressionLhs<T const&>( *this, operand );
     }
 
@@ -1965,7 +1908,7 @@ namespace Catch {
     }
 
     template<typename ArgT, typename MatcherT>
-    inline void ResultBuilder::captureMatch( ArgT const& arg, MatcherT const& matcher,
+    void ResultBuilder::captureMatch( ArgT const& arg, MatcherT const& matcher,
                                              char const* matcherString ) {
         MatchExpression<ArgT const&, MatcherT const&> expr( arg, matcher, matcherString );
         setResultType( matcher.match( arg ) );
@@ -2064,6 +2007,10 @@ namespace Catch {
         virtual void exceptionEarlyReported() = 0;
 
         virtual void handleFatalErrorCondition( std::string const& message ) = 0;
+
+        virtual bool lastAssertionPassed() = 0;
+        virtual void assertionPassed() = 0;
+        virtual void assertionRun() = 0;
     };
 
     IResultCapture& getResultCapture();
@@ -2106,9 +2053,9 @@ namespace Catch{
     #if defined(__ppc64__) || defined(__ppc__)
         #define CATCH_TRAP() \
                 __asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n" \
-                : : : "memory","r0","r3","r4" )
+                : : : "memory","r0","r3","r4" ) /* NOLINT */
     #else
-        #define CATCH_TRAP() __asm__("int $3\n" : : )
+        #define CATCH_TRAP() __asm__("int $3\n" : : /* NOLINT */ )
     #endif
 
 #elif defined(CATCH_PLATFORM_LINUX)
@@ -2116,7 +2063,7 @@ namespace Catch{
     // directly at the location of the failing check instead of breaking inside
     // raise() called from it, i.e. one stack frame below.
     #if defined(__GNUC__) && (defined(__i386) || defined(__x86_64))
-        #define CATCH_TRAP() asm volatile ("int $3")
+        #define CATCH_TRAP() asm volatile ("int $3") /* NOLINT */
     #else // Fall back to the generic way.
         #include <signal.h>
 
@@ -2147,6 +2094,12 @@ namespace Catch {
     };
 }
 
+#if !defined(CATCH_CONFIG_DISABLE_STRINGIFICATION)
+# define CATCH_INTERNAL_STRINGIFY(expr) #expr
+#else
+# define CATCH_INTERNAL_STRINGIFY(expr) "Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION"
+#endif
+
 #if defined(CATCH_CONFIG_FAST_COMPILE)
 ///////////////////////////////////////////////////////////////////////////////
 // We can speedup compilation significantly by breaking into debugger lower in
@@ -2162,7 +2115,7 @@ namespace Catch {
 // the exception before it propagates back up to the runner.
 #define INTERNAL_CATCH_TEST_NO_TRY( macroName, resultDisposition, expr ) \
     do { \
-        Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \
+        Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr), resultDisposition ); \
         __catchResult.setExceptionGuard(); \
         CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
         ( __catchResult <= expr ).endExpression(); \
@@ -2174,9 +2127,9 @@ namespace Catch {
 
 #define INTERNAL_CHECK_THAT_NO_TRY( macroName, matcher, resultDisposition, arg ) \
     do { \
-        Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg ", " #matcher, resultDisposition ); \
+        Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(arg) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
         __catchResult.setExceptionGuard(); \
-        __catchResult.captureMatch( arg, matcher, #matcher ); \
+        __catchResult.captureMatch( arg, matcher, CATCH_INTERNAL_STRINGIFY(matcher) ); \
         __catchResult.unsetExceptionGuard(); \
         INTERNAL_CATCH_REACT( __catchResult ) \
     } while( Catch::alwaysFalse() )
@@ -2195,7 +2148,7 @@ namespace Catch {
 ///////////////////////////////////////////////////////////////////////////////
 #define INTERNAL_CATCH_TEST( macroName, resultDisposition, expr ) \
     do { \
-        Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \
+        Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr), resultDisposition ); \
         try { \
             CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
             ( __catchResult <= expr ).endExpression(); \
@@ -2211,17 +2164,17 @@ namespace Catch {
 ///////////////////////////////////////////////////////////////////////////////
 #define INTERNAL_CATCH_IF( macroName, resultDisposition, expr ) \
     INTERNAL_CATCH_TEST( macroName, resultDisposition, expr ); \
-    if( Catch::getResultCapture().getLastResult()->succeeded() )
+    if( Catch::getResultCapture().lastAssertionPassed() )
 
 ///////////////////////////////////////////////////////////////////////////////
 #define INTERNAL_CATCH_ELSE( macroName, resultDisposition, expr ) \
     INTERNAL_CATCH_TEST( macroName, resultDisposition, expr ); \
-    if( !Catch::getResultCapture().getLastResult()->succeeded() )
+    if( !Catch::getResultCapture().lastAssertionPassed() )
 
 ///////////////////////////////////////////////////////////////////////////////
 #define INTERNAL_CATCH_NO_THROW( macroName, resultDisposition, expr ) \
     do { \
-        Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \
+        Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr), resultDisposition ); \
         try { \
             static_cast<void>(expr); \
             __catchResult.captureResult( Catch::ResultWas::Ok ); \
@@ -2235,7 +2188,7 @@ namespace Catch {
 ///////////////////////////////////////////////////////////////////////////////
 #define INTERNAL_CATCH_THROWS( macroName, resultDisposition, matcher, expr ) \
     do { \
-        Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition, #matcher ); \
+        Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr), resultDisposition, CATCH_INTERNAL_STRINGIFY(matcher) ); \
         if( __catchResult.allowThrows() ) \
             try { \
                 static_cast<void>(expr); \
@@ -2252,7 +2205,7 @@ namespace Catch {
 ///////////////////////////////////////////////////////////////////////////////
 #define INTERNAL_CATCH_THROWS_AS( macroName, exceptionType, resultDisposition, expr ) \
     do { \
-        Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr ", " #exceptionType, resultDisposition ); \
+        Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr) ", " CATCH_INTERNAL_STRINGIFY(exceptionType), resultDisposition ); \
         if( __catchResult.allowThrows() ) \
             try { \
                 static_cast<void>(expr); \
@@ -2295,9 +2248,9 @@ namespace Catch {
 ///////////////////////////////////////////////////////////////////////////////
 #define INTERNAL_CHECK_THAT( macroName, matcher, resultDisposition, arg ) \
     do { \
-        Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg ", " #matcher, resultDisposition ); \
+        Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(arg) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
         try { \
-            __catchResult.captureMatch( arg, matcher, #matcher ); \
+            __catchResult.captureMatch( arg, matcher, CATCH_INTERNAL_STRINGIFY(matcher) ); \
         } catch( ... ) { \
             __catchResult.useActiveException( resultDisposition | Catch::ResultDisposition::ContinueOnFailure ); \
         } \
@@ -2776,13 +2729,6 @@ namespace Detail {
             m_value( value )
         {}
 
-        Approx( Approx const& other )
-        :   m_epsilon( other.m_epsilon ),
-            m_margin( other.m_margin ),
-            m_scale( other.m_scale ),
-            m_value( other.m_value )
-        {}
-
         static Approx custom() {
             return Approx( 0 );
         }
@@ -3706,7 +3652,7 @@ namespace Catch {
         ITagAliasRegistry const* m_tagAliases;
 
     public:
-        TestSpecParser( ITagAliasRegistry const& tagAliases ) : m_tagAliases( &tagAliases ) {}
+        TestSpecParser( ITagAliasRegistry const& tagAliases ) :m_mode(None), m_exclusion(false), m_start(0), m_pos(0), m_tagAliases( &tagAliases ) {}
 
         TestSpecParser& parse( std::string const& arg ) {
             m_mode = None;
@@ -3840,6 +3786,12 @@ namespace Catch {
         Yes,
         No
     }; };
+    struct WaitForKeypress { enum When {
+        Never,
+        BeforeStart = 1,
+        BeforeExit = 2,
+        BeforeStartAndExit = BeforeStart | BeforeExit
+    }; };
 
     class TestSpec;
 
@@ -3890,6 +3842,7 @@ namespace Catch {
 
     std::ostream& cout();
     std::ostream& cerr();
+    std::ostream& clog();
 
     struct IStream {
         virtual ~IStream() CATCH_NOEXCEPT;
@@ -3952,13 +3905,15 @@ namespace Catch {
             showHelp( false ),
             showInvisibles( false ),
             filenamesAsTags( false ),
+            libIdentify( false ),
             abortAfter( -1 ),
             rngSeed( 0 ),
             verbosity( Verbosity::Normal ),
             warnings( WarnAbout::Nothing ),
             showDurations( ShowDurations::DefaultForReporter ),
             runOrder( RunTests::InDeclarationOrder ),
-            useColour( UseColour::Auto )
+            useColour( UseColour::Auto ),
+            waitForKeypress( WaitForKeypress::Never )
         {}
 
         bool listTests;
@@ -3973,6 +3928,7 @@ namespace Catch {
         bool showHelp;
         bool showInvisibles;
         bool filenamesAsTags;
+        bool libIdentify;
 
         int abortAfter;
         unsigned int rngSeed;
@@ -3982,6 +3938,7 @@ namespace Catch {
         ShowDurations::OrNot showDurations;
         RunTests::InWhatOrder runOrder;
         UseColour::YesOrNo useColour;
+        WaitForKeypress::When waitForKeypress;
 
         std::string outputFilename;
         std::string name;
@@ -4222,7 +4179,7 @@ namespace Tbc {
             return oss.str();
         }
 
-        inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) {
+        friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) {
             for( Text::const_iterator it = _text.begin(), itEnd = _text.end();
                 it != itEnd; ++it ) {
                 if( it != _text.begin() )
@@ -5175,6 +5132,18 @@ namespace Catch {
         else
             throw std::runtime_error( "colour mode must be one of: auto, yes or no" );
     }
+    inline void setWaitForKeypress( ConfigData& config, std::string const& keypress ) {
+        std::string keypressLc = toLower( keypress );
+        if( keypressLc == "start" )
+            config.waitForKeypress = WaitForKeypress::BeforeStart;
+        else if( keypressLc == "exit" )
+            config.waitForKeypress = WaitForKeypress::BeforeExit;
+        else if( keypressLc == "both" )
+            config.waitForKeypress = WaitForKeypress::BeforeStartAndExit;
+        else
+            throw std::runtime_error( "keypress argument must be one of: start, exit or both. '" + keypress + "' not recognised" );
+    };
+
     inline void forceColour( ConfigData& config ) {
         config.useColour = UseColour::Yes;
     }
@@ -5310,6 +5279,18 @@ namespace Catch {
             .describe( "should output be colourised" )
             .bind( &setUseColour, "yes|no" );
 
+        cli["--use-colour"]
+            .describe( "should output be colourised" )
+            .bind( &setUseColour, "yes|no" );
+
+        cli["--libidentify"]
+            .describe( "report name and version according to libidentify standard" )
+            .bind( &ConfigData::libIdentify );
+
+        cli["--wait-for-keypress"]
+                .describe( "waits for a keypress before exiting" )
+                .bind( &setWaitForKeypress, "start|exit|both" );
+
         return cli;
     }
 
@@ -6574,6 +6555,29 @@ namespace Catch {
         std::string& m_targetString;
     };
 
+    // StdErr has two constituent streams in C++, std::cerr and std::clog
+    // This means that we need to redirect 2 streams into 1 to keep proper
+    // order of writes and cannot use StreamRedirect on its own
+    class StdErrRedirect {
+    public:
+        StdErrRedirect(std::string& targetString)
+        :m_cerrBuf( cerr().rdbuf() ), m_clogBuf(clog().rdbuf()),
+        m_targetString(targetString){
+            cerr().rdbuf(m_oss.rdbuf());
+            clog().rdbuf(m_oss.rdbuf());
+        }
+        ~StdErrRedirect() {
+            m_targetString += m_oss.str();
+            cerr().rdbuf(m_cerrBuf);
+            clog().rdbuf(m_clogBuf);
+        }
+    private:
+        std::streambuf* m_cerrBuf;
+        std::streambuf* m_clogBuf;
+        std::ostringstream m_oss;
+        std::string& m_targetString;
+    };
+
     ///////////////////////////////////////////////////////////////////////////
 
     class RunContext : public IResultCapture, public IRunner {
@@ -6664,7 +6668,10 @@ namespace Catch {
                 m_totals.assertions.passed++;
             }
             else if( !result.isOk() ) {
-                m_totals.assertions.failed++;
+                if( m_activeTestCase->getTestCaseInfo().okToFail() )
+                    m_totals.assertions.failedButOk++;
+                else
+                    m_totals.assertions.failed++;
             }
 
             // We have no use for the return value (whether messages should be cleared), because messages were made scoped
@@ -6676,6 +6683,23 @@ namespace Catch {
             m_lastResult = result;
         }
 
+        virtual bool lastAssertionPassed()
+        {
+            return m_totals.assertions.passed == (m_prevPassed + 1);
+        }
+
+        virtual void assertionPassed()
+        {
+            m_totals.assertions.passed++;
+            m_lastAssertionInfo.capturedExpression = "{Unknown expression after the reported line}";
+            m_lastAssertionInfo.macroName = "";
+        }
+
+        virtual void assertionRun()
+        {
+            m_prevPassed = m_totals.assertions.passed;
+        }
+
         virtual bool sectionStarted (
             SectionInfo const& sectionInfo,
             Counts& assertions
@@ -6776,6 +6800,7 @@ namespace Catch {
 
             Totals deltaTotals;
             deltaTotals.testCases.failed = 1;
+            deltaTotals.assertions.failed = 1;
             m_reporter->testCaseEnded( TestCaseStats(   testInfo,
                                                         deltaTotals,
                                                         std::string(),
@@ -6810,7 +6835,7 @@ namespace Catch {
                 timer.start();
                 if( m_reporter->getPreferences().shouldRedirectStdOut ) {
                     StreamRedirect coutRedir( Catch::cout(), redirectedCout );
-                    StreamRedirect cerrRedir( Catch::cerr(), redirectedCerr );
+                    StdErrRedirect errRedir( redirectedCerr );
                     invokeActiveTestCase();
                 }
                 else {
@@ -6835,12 +6860,6 @@ namespace Catch {
             Counts assertions = m_totals.assertions - prevAssertions;
             bool missingAssertions = testForMissingAssertions( assertions );
 
-            if( testCaseInfo.okToFail() ) {
-                std::swap( assertions.failedButOk, assertions.failed );
-                m_totals.assertions.failed -= assertions.failedButOk;
-                m_totals.assertions.failedButOk += assertions.failedButOk;
-            }
-
             SectionStats testCaseSectionStats( testCaseSection, assertions, duration, missingAssertions );
             m_reporter->sectionEnded( testCaseSectionStats );
         }
@@ -6886,6 +6905,7 @@ namespace Catch {
         std::vector<SectionEndInfo> m_unfinishedSections;
         std::vector<ITracker*> m_activeSections;
         TrackerContext m_trackerContext;
+        size_t m_prevPassed;
         bool m_shouldReportUnexpected;
     };
 
@@ -6944,10 +6964,14 @@ namespace Catch {
         return reporter;
     }
 
+#if !defined(CATCH_CONFIG_DEFAULT_REPORTER)
+#define CATCH_CONFIG_DEFAULT_REPORTER "console"
+#endif
+
     Ptr<IStreamingReporter> makeReporter( Ptr<Config> const& config ) {
         std::vector<std::string> reporters = config->getReporterNames();
         if( reporters.empty() )
-            reporters.push_back( "console" );
+            reporters.push_back( CATCH_CONFIG_DEFAULT_REPORTER );
 
         Ptr<IStreamingReporter> reporter;
         for( std::vector<std::string>::const_iterator it = reporters.begin(), itEnd = reporters.end();
@@ -7007,11 +7031,11 @@ namespace Catch {
             if( lastSlash != std::string::npos )
                 filename = filename.substr( lastSlash+1 );
 
-            std::string::size_type lastDot = filename.find_last_of( "." );
+            std::string::size_type lastDot = filename.find_last_of( '.' );
             if( lastDot != std::string::npos )
                 filename = filename.substr( 0, lastDot );
 
-            tags.insert( "#" + filename );
+            tags.insert( '#' + filename );
             setTags( test, tags );
         }
     }
@@ -7042,6 +7066,13 @@ namespace Catch {
             m_cli.usage( Catch::cout(), processName );
             Catch::cout() << "For more detail usage please see the project docs\n" << std::endl;
         }
+        void libIdentify() {
+            Catch::cout()
+                    << std::left << std::setw(16) << "description: " << "A Catch test executable\n"
+                    << std::left << std::setw(16) << "category: " << "testframework\n"
+                    << std::left << std::setw(16) << "framework: " << "Catch Test\n"
+                    << std::left << std::setw(16) << "version: " << libraryVersion() << std::endl;
+        }
 
         int applyCommandLine( int argc, char const* const* const argv, OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) {
             try {
@@ -7049,6 +7080,8 @@ namespace Catch {
                 m_unusedTokens = m_cli.parseInto( Clara::argsToVector( argc, argv ), m_configData );
                 if( m_configData.showHelp )
                     showHelp( m_configData.processName );
+                if( m_configData.libIdentify )
+                    libIdentify();
                 m_config.reset();
             }
             catch( std::exception& ex ) {
@@ -7105,7 +7138,36 @@ namespace Catch {
     #endif
 
         int run() {
-            if( m_configData.showHelp )
+            if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeStart ) != 0 ) {
+                Catch::cout() << "...waiting for enter/ return before starting" << std::endl;
+                static_cast<void>(std::getchar());
+            }
+            int exitCode = runInternal();
+            if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeExit ) != 0 ) {
+                Catch::cout() << "...waiting for enter/ return before exiting, with code: " << exitCode << std::endl;
+                static_cast<void>(std::getchar());
+            }
+            return exitCode;
+        }
+
+        Clara::CommandLine<ConfigData> const& cli() const {
+            return m_cli;
+        }
+        std::vector<Clara::Parser::Token> const& unusedTokens() const {
+            return m_unusedTokens;
+        }
+        ConfigData& configData() {
+            return m_configData;
+        }
+        Config& config() {
+            if( !m_config )
+                m_config = new Config( m_configData );
+            return *m_config;
+        }
+    private:
+
+        int runInternal() {
+            if( m_configData.showHelp || m_configData.libIdentify )
                 return 0;
 
             try
@@ -7129,21 +7191,6 @@ namespace Catch {
             }
         }
 
-        Clara::CommandLine<ConfigData> const& cli() const {
-            return m_cli;
-        }
-        std::vector<Clara::Parser::Token> const& unusedTokens() const {
-            return m_unusedTokens;
-        }
-        ConfigData& configData() {
-            return m_configData;
-        }
-        Config& config() {
-            if( !m_config )
-                m_config = new Config( m_configData );
-            return *m_config;
-        }
-    private:
         Clara::CommandLine<ConfigData> m_cli;
         std::vector<Clara::Parser::Token> m_unusedTokens;
         ConfigData m_configData;
@@ -7663,6 +7710,9 @@ namespace Catch {
     std::ostream& cerr() {
         return std::cerr;
     }
+    std::ostream& clog() {
+        return std::clog;
+    }
 #endif
 }
 
@@ -8033,6 +8083,8 @@ namespace Catch {
 
 namespace Catch {
 
+    AssertionInfo::AssertionInfo():macroName(""), capturedExpression(""), resultDisposition(ResultDisposition::Normal), secondArg(""){}
+
     AssertionInfo::AssertionInfo(   char const * _macroName,
                                     SourceLineInfo const& _lineInfo,
                                     char const * _capturedExpression,
@@ -8342,7 +8394,7 @@ namespace Catch {
     }
 
     inline Version libraryVersion() {
-        static Version version( 1, 9, 6, "", 0 );
+        static Version version( 1, 10, 0, "", 0 );
         return version;
     }
 
@@ -9050,15 +9102,14 @@ namespace Catch {
     :   m_assertionInfo( macroName, lineInfo, capturedExpression, resultDisposition, secondArg ),
         m_shouldDebugBreak( false ),
         m_shouldThrow( false ),
-        m_guardException( false )
-    {
-        m_stream().oss.str("");
-    }
+        m_guardException( false ),
+        m_usedStream( false )
+    {}
 
     ResultBuilder::~ResultBuilder() {
 #if defined(CATCH_CONFIG_FAST_COMPILE)
         if ( m_guardException ) {
-            m_stream().oss << "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE";
+            stream().oss << "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE";
             captureResult( ResultWas::ThrewException );
             getCurrentContext().getResultCapture()->exceptionEarlyReported();
         }
@@ -9075,13 +9126,25 @@ namespace Catch {
     }
 
     void ResultBuilder::endExpression( DecomposedExpression const& expr ) {
-        AssertionResult result = build( expr );
-        handleResult( result );
+        // Flip bool results if FalseTest flag is set
+        if( isFalseTest( m_assertionInfo.resultDisposition ) ) {
+            m_data.negate( expr.isBinaryExpression() );
+        }
+
+        getResultCapture().assertionRun();
+
+        if(getCurrentContext().getConfig()->includeSuccessfulResults() || m_data.resultType != ResultWas::Ok)
+        {
+            AssertionResult result = build( expr );
+            handleResult( result );
+        }
+        else
+            getResultCapture().assertionPassed();
     }
 
     void ResultBuilder::useActiveException( ResultDisposition::Flags resultDisposition ) {
         m_assertionInfo.resultDisposition = resultDisposition;
-        m_stream().oss << Catch::translateActiveException();
+        stream().oss << Catch::translateActiveException();
         captureResult( ResultWas::ThrewException );
     }
 
@@ -9163,12 +9226,8 @@ namespace Catch {
         assert( m_data.resultType != ResultWas::Unknown );
         AssertionResultData data = m_data;
 
-        // Flip bool results if FalseTest flag is set
-        if( isFalseTest( m_assertionInfo.resultDisposition ) ) {
-            data.negate( expr.isBinaryExpression() );
-        }
-
-        data.message = m_stream().oss.str();
+        if(m_usedStream)
+            data.message = m_stream().oss.str();
         data.decomposedExpression = &expr; // for lazy reconstruction
         return AssertionResult( m_assertionInfo, data );
     }
@@ -9597,7 +9656,8 @@ namespace Catch {
             BySectionInfo( SectionInfo const& other ) : m_other( other ) {}
             BySectionInfo( BySectionInfo const& other ) : m_other( other.m_other ) {}
             bool operator() ( Ptr<SectionNode> const& node ) const {
-                return node->stats.sectionInfo.lineInfo == m_other.lineInfo;
+                return ((node->stats.sectionInfo.name == m_other.name) &&
+                        (node->stats.sectionInfo.lineInfo == m_other.lineInfo));
             }
         private:
             void operator=( BySectionInfo const& );
@@ -10319,6 +10379,7 @@ namespace Catch {
         JunitReporter( ReporterConfig const& _config )
         :   CumulativeReporterBase( _config ),
             xml( _config.stream() ),
+            unexpectedExceptions( 0 ),
             m_okToFail( false )
         {
             m_reporterPrefs.shouldRedirectStdOut = true;
diff --git a/test/include/packed_access.hpp b/test/include/packed_access.hpp
index 3d8b98d..a99f10a 100644
--- a/test/include/packed_access.hpp
+++ b/test/include/packed_access.hpp
@@ -1,3 +1,4 @@
+// NOLINT clang-tidy: llvm-header-guard
 
 #define PBF_TYPE_NAME PROTOZERO_TEST_STRING(PBF_TYPE)
 #define GET_TYPE PROTOZERO_TEST_CONCAT(get_packed_, PBF_TYPE)
@@ -22,19 +23,19 @@ TEST_CASE("read repeated packed field: " PBF_TYPE_NAME) {
         SECTION("empty") {
             abuffer.append(load_data("repeated_packed_" PBF_TYPE_NAME "/data-empty"));
 
-            protozero::pbf_reader item(abuffer.data() + n, abuffer.size() - n);
+            protozero::pbf_reader item{abuffer.data() + n, abuffer.size() - n};
 
-            REQUIRE(!item.next());
+            REQUIRE_FALSE(item.next());
         }
 
         SECTION("one") {
             abuffer.append(load_data("repeated_packed_" PBF_TYPE_NAME "/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());
             const auto it_range = item.GET_TYPE();
-            REQUIRE(!item.next());
+            REQUIRE_FALSE(item.next());
 
             REQUIRE(it_range.begin() != it_range.end());
             REQUIRE(*it_range.begin() == 17);
@@ -44,11 +45,11 @@ TEST_CASE("read repeated packed field: " PBF_TYPE_NAME) {
         SECTION("many") {
             abuffer.append(load_data("repeated_packed_" PBF_TYPE_NAME "/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());
             const auto it_range = item.GET_TYPE();
-            REQUIRE(!item.next());
+            REQUIRE_FALSE(item.next());
 
             auto it = it_range.begin();
             REQUIRE(it != it_range.end());
@@ -68,11 +69,11 @@ TEST_CASE("read repeated packed field: " PBF_TYPE_NAME) {
         SECTION("swap iterator range") {
             abuffer.append(load_data("repeated_packed_" PBF_TYPE_NAME "/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_range1 = item.GET_TYPE();
-            REQUIRE(!item.next());
+            REQUIRE_FALSE(item.next());
 
             decltype(it_range1) it_range;
             using std::swap;
@@ -91,9 +92,9 @@ TEST_CASE("read repeated packed field: " PBF_TYPE_NAME) {
             abuffer.append(load_data("repeated_packed_" PBF_TYPE_NAME "/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_TYPE(), protozero::end_of_buffer_exception);
+                REQUIRE_THROWS_AS(item.GET_TYPE(), const protozero::end_of_buffer_exception&);
             }
         }
 
@@ -175,6 +176,11 @@ TEST_CASE("write repeated packed field using packed field: " PBF_TYPE_NAME) {
             field.add_element(cpp_type(  -1));
             field.add_element(std::numeric_limits<cpp_type>::min());
 #endif
+            REQUIRE(field.valid());
+            SECTION("with commit") {
+                field.commit();
+                REQUIRE_FALSE(field.valid());
+            }
         }
 
         REQUIRE(buffer == load_data("repeated_packed_" PBF_TYPE_NAME "/data-many"));
@@ -182,6 +188,64 @@ TEST_CASE("write repeated packed field using packed field: " PBF_TYPE_NAME) {
 
 }
 
+TEST_CASE("move repeated packed field: " PBF_TYPE_NAME) {
+
+    std::string buffer;
+    protozero::pbf_writer pw{buffer};
+
+    SECTION("move rvalue") {
+        packed_field_type field;
+        REQUIRE_FALSE(field.valid());
+        field = packed_field_type{pw, 1};
+        REQUIRE(field.valid());
+        field.add_element(cpp_type(17));
+    }
+
+    SECTION("explicit move") {
+        packed_field_type field2{pw, 1};
+        packed_field_type field;
+
+        REQUIRE(field2.valid());
+        REQUIRE_FALSE(field.valid());
+
+        field = std::move(field2);
+
+        REQUIRE_FALSE(field2.valid()); // NOLINT clang-tidy: hicpp-invalid-access-moved
+        REQUIRE(field.valid());
+
+        field.add_element(cpp_type(17));
+    }
+
+    SECTION("move constructor") {
+        packed_field_type field2{pw, 1};
+        REQUIRE(field2.valid());
+
+        packed_field_type field{std::move(field2)};
+        REQUIRE(field.valid());
+        REQUIRE_FALSE(field2.valid()); // NOLINT clang-tidy: hicpp-invalid-access-moved
+
+        field.add_element(cpp_type(17));
+    }
+
+    SECTION("swap") {
+        packed_field_type field;
+        packed_field_type field2{pw, 1};
+
+        REQUIRE_FALSE(field.valid());
+        REQUIRE(field2.valid());
+
+        using std::swap;
+        swap(field, field2);
+
+        REQUIRE(field.valid());
+        REQUIRE_FALSE(field2.valid());
+
+        field.add_element(cpp_type(17));
+    }
+
+    REQUIRE(buffer == load_data("repeated_packed_" PBF_TYPE_NAME "/data-one"));
+}
+
 TEST_CASE("write from different types of iterators: " PBF_TYPE_NAME) {
 
     std::string buffer;
@@ -198,8 +262,8 @@ TEST_CASE("write from different types of iterators: " PBF_TYPE_NAME) {
     }
 
     SECTION("from string") {
-        std::string data = "1 4 9 16 25";
-        std::stringstream sdata(data);
+        std::string data{"1 4 9 16 25"};
+        std::stringstream sdata{data};
 
 #if PBF_TYPE_IS_SIGNED
         using test_type =  int32_t;
@@ -213,22 +277,26 @@ TEST_CASE("write from different types of iterators: " PBF_TYPE_NAME) {
         pw.ADD_TYPE(1, it, eod);
     }
 
-    protozero::pbf_reader item(buffer);
+    protozero::pbf_reader item{buffer};
 
     REQUIRE(item.next());
     auto it_range = item.GET_TYPE();
-    REQUIRE(!item.next());
+    REQUIRE_FALSE(item.next());
+    REQUIRE_FALSE(it_range.empty());
     REQUIRE(std::distance(it_range.begin(), it_range.end()) == 5);
+    REQUIRE(it_range.size() == 5);
 
     REQUIRE(it_range.front() ==  1); it_range.drop_front();
     REQUIRE(it_range.front() ==  4); it_range.drop_front();
+    REQUIRE(it_range.size() == 3);
     REQUIRE(it_range.front() ==  9); it_range.drop_front();
     REQUIRE(it_range.front() == 16); it_range.drop_front();
     REQUIRE(it_range.front() == 25); it_range.drop_front();
     REQUIRE(it_range.empty());
+    REQUIRE(it_range.size() == 0); // NOLINT clang-tidy: readability-container-size-empty
 
-    REQUIRE_THROWS_AS(it_range.front(), assert_error);
-    REQUIRE_THROWS_AS(it_range.drop_front(), assert_error);
+    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 6137119..79cb3f7 100644
--- a/test/include/scalar_access.hpp
+++ b/test/include/scalar_access.hpp
@@ -1,3 +1,4 @@
+// NOLINT clang-tidy: llvm-header-guard
 
 #define PBF_TYPE_NAME PROTOZERO_TEST_STRING(PBF_TYPE)
 #define GET_TYPE PROTOZERO_TEST_CONCAT(get_, PBF_TYPE)
@@ -8,41 +9,41 @@ TEST_CASE("read field: " PBF_TYPE_NAME) {
     SECTION("zero") {
         const std::string buffer = load_data(PBF_TYPE_NAME "/data-zero");
 
-        protozero::pbf_reader item(buffer);
+        protozero::pbf_reader item{buffer};
 
         REQUIRE(item.next());
         REQUIRE(item.GET_TYPE() == 0);
-        REQUIRE(!item.next());
+        REQUIRE_FALSE(item.next());
     }
 
     SECTION("positive") {
         const std::string buffer = load_data(PBF_TYPE_NAME "/data-pos");
 
-        protozero::pbf_reader item(buffer);
+        protozero::pbf_reader item{buffer};
 
         REQUIRE(item.next());
         REQUIRE(item.GET_TYPE() == 1);
-        REQUIRE(!item.next());
+        REQUIRE_FALSE(item.next());
     }
 
     SECTION("pos200") {
         const std::string buffer = load_data(PBF_TYPE_NAME "/data-pos200");
 
-        protozero::pbf_reader item(buffer);
+        protozero::pbf_reader item{buffer};
 
         REQUIRE(item.next());
         REQUIRE(item.GET_TYPE() == 200);
-        REQUIRE(!item.next());
+        REQUIRE_FALSE(item.next());
     }
 
     SECTION("max") {
         const std::string buffer = load_data(PBF_TYPE_NAME "/data-max");
 
-        protozero::pbf_reader item(buffer);
+        protozero::pbf_reader item{buffer};
 
         REQUIRE(item.next());
         REQUIRE(item.GET_TYPE() == std::numeric_limits<cpp_type>::max());
-        REQUIRE(!item.next());
+        REQUIRE_FALSE(item.next());
     }
 
 #if PBF_TYPE_IS_SIGNED
@@ -50,33 +51,33 @@ TEST_CASE("read field: " PBF_TYPE_NAME) {
         if (std::is_signed<cpp_type>::value) {
             const std::string buffer = load_data(PBF_TYPE_NAME "/data-neg");
 
-            protozero::pbf_reader item(buffer);
+            protozero::pbf_reader item{buffer};
 
             REQUIRE(item.next());
             REQUIRE(item.GET_TYPE() == -1);
-            REQUIRE(!item.next());
+            REQUIRE_FALSE(item.next());
         }
     }
 
     SECTION("neg200") {
         const std::string buffer = load_data(PBF_TYPE_NAME "/data-neg200");
 
-        protozero::pbf_reader item(buffer);
+        protozero::pbf_reader item{buffer};
 
         REQUIRE(item.next());
         REQUIRE(item.GET_TYPE() == -200);
-        REQUIRE(!item.next());
+        REQUIRE_FALSE(item.next());
     }
 
     SECTION("min") {
         if (std::is_signed<cpp_type>::value) {
             const std::string buffer = load_data(PBF_TYPE_NAME "/data-min");
 
-            protozero::pbf_reader item(buffer);
+            protozero::pbf_reader item{buffer};
 
             REQUIRE(item.next());
             REQUIRE(item.GET_TYPE() == std::numeric_limits<cpp_type>::min());
-            REQUIRE(!item.next());
+            REQUIRE_FALSE(item.next());
         }
     }
 #endif
@@ -85,9 +86,9 @@ TEST_CASE("read field: " PBF_TYPE_NAME) {
         const std::string buffer = load_data(PBF_TYPE_NAME "/data-max");
 
         for (std::string::size_type i = 1; i < buffer.size(); ++i) {
-            protozero::pbf_reader item(buffer.data(), i);
+            protozero::pbf_reader item{buffer.data(), i};
             REQUIRE(item.next());
-            REQUIRE_THROWS_AS(item.GET_TYPE(), protozero::end_of_buffer_exception);
+            REQUIRE_THROWS_AS(item.GET_TYPE(), const protozero::end_of_buffer_exception&);
         }
     }
 
diff --git a/test/include/test.hpp b/test/include/test.hpp
index 0f99c11..89d1e15 100644
--- a/test/include/test.hpp
+++ b/test/include/test.hpp
@@ -1,3 +1,5 @@
+#ifndef TEST_HPP
+#define TEST_HPP
 
 #ifdef _MSC_VER
 # define _SCL_SECURE_NO_WARNINGS
@@ -12,13 +14,12 @@ struct assert_error : public std::runtime_error {
     explicit assert_error(const char* what_arg) : std::runtime_error(what_arg) {
     }
 };
-#define protozero_assert(x) if (!(x)) { throw(assert_error(#x)); }
+#define protozero_assert(x) if (!(x)) { throw assert_error{#x}; }
 
-#include <protozero/pbf_reader.hpp>
+#include <protozero/pbf_builder.hpp>
 #include <protozero/pbf_message.hpp>
-
+#include <protozero/pbf_reader.hpp>
 #include <protozero/pbf_writer.hpp>
-#include <protozero/pbf_builder.hpp>
 
 extern std::string load_data(const std::string& filename);
 
@@ -28,3 +29,4 @@ extern std::string load_data(const std::string& filename);
 #define PROTOZERO_TEST_STRING2(s) #s
 #define PROTOZERO_TEST_STRING(s) PROTOZERO_TEST_STRING2(s)
 
+#endif // TEST_HPP
diff --git a/test/include/testcase.hpp b/test/include/testcase.hpp
index 8df0584..a4e33ec 100644
--- a/test/include/testcase.hpp
+++ b/test/include/testcase.hpp
@@ -11,7 +11,7 @@ std::string write_to_file(const T& msg, const char* filename) {
     std::string out;
 
     msg.SerializeToString(&out);
-    std::ofstream d(filename, std::ios_base::out|std::ios_base::binary);
+    std::ofstream d{filename, std::ios_base::out|std::ios_base::binary};
     assert(d.is_open());
     d << out;
 
diff --git a/test/t/alignment/test_cases.cpp b/test/t/alignment/test_cases.cpp
index 2d6a212..aa1c870 100644
--- a/test/t/alignment/test_cases.cpp
+++ b/test/t/alignment/test_cases.cpp
@@ -17,61 +17,61 @@ TEST_CASE("check alignment issues for fixed32 field") {
 
         SECTION("zero") {
             abuffer.append(load_data("fixed32/data-zero"));
-            protozero::pbf_reader item(abuffer.data() + n, abuffer.size() - n);
+            protozero::pbf_reader item{abuffer.data() + n, abuffer.size() - n};
 
             REQUIRE(item.next());
             REQUIRE(item.get_fixed32() == 0UL);
-            REQUIRE(!item.next());
+            REQUIRE_FALSE(item.next());
         }
 
         SECTION("positive") {
             abuffer.append(load_data("fixed32/data-pos"));
-            protozero::pbf_reader item(abuffer.data() + n, abuffer.size() - n);
+            protozero::pbf_reader item{abuffer.data() + n, abuffer.size() - n};
 
             REQUIRE(item.next());
             REQUIRE(item.get_fixed32() == 1UL);
-            REQUIRE(!item.next());
+            REQUIRE_FALSE(item.next());
         }
 
         SECTION("max") {
             abuffer.append(load_data("fixed32/data-max"));
-            protozero::pbf_reader item(abuffer.data() + n, abuffer.size() - n);
+            protozero::pbf_reader item{abuffer.data() + n, abuffer.size() - n};
 
             REQUIRE(item.next());
             REQUIRE(item.get_fixed32() == std::numeric_limits<uint32_t>::max());
-            REQUIRE(!item.next());
+            REQUIRE_FALSE(item.next());
         }
 
         SECTION("end_of_buffer") {
             abuffer.append(load_data("fixed32/data-pos"));
 
             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_fixed32(), protozero::end_of_buffer_exception);
+                REQUIRE_THROWS_AS(item.get_fixed32(), const protozero::end_of_buffer_exception&);
             }
         }
 
         SECTION("assert detecting tag==0") {
             abuffer.append(load_data("fixed32/data-zero"));
-            protozero::pbf_reader item(abuffer.data() + n, abuffer.size() - n);
+            protozero::pbf_reader item{abuffer.data() + n, abuffer.size() - n};
 
-            REQUIRE_THROWS_AS(item.get_fixed32(), assert_error);
+            REQUIRE_THROWS_AS(item.get_fixed32(), const assert_error&);
             REQUIRE(item.next());
             REQUIRE(item.get_fixed32() == 0UL);
             REQUIRE_THROWS(item.get_fixed32());
-            REQUIRE(!item.next());
+            REQUIRE_FALSE(item.next());
         }
 
         SECTION("skip") {
             abuffer.append(load_data("fixed32/data-zero"));
-            protozero::pbf_reader item(abuffer.data() + n, abuffer.size() - n);
+            protozero::pbf_reader item{abuffer.data() + n, abuffer.size() - n};
 
-            REQUIRE_THROWS_AS(item.skip(), assert_error);
+            REQUIRE_THROWS_AS(item.skip(), const assert_error&);
             REQUIRE(item.next());
             item.skip();
             REQUIRE_THROWS(item.skip());
-            REQUIRE(!item.next());
+            REQUIRE_FALSE(item.next());
         }
 
     }
@@ -88,38 +88,38 @@ TEST_CASE("check alignment issues for fixed64 field") {
 
         SECTION("zero") {
             abuffer.append(load_data("fixed64/data-zero"));
-            protozero::pbf_reader item(abuffer.data() + n, abuffer.size() - n);
+            protozero::pbf_reader item{abuffer.data() + n, abuffer.size() - n};
 
             REQUIRE(item.next());
             REQUIRE(item.get_fixed64() == 0ULL);
-            REQUIRE(!item.next());
+            REQUIRE_FALSE(item.next());
         }
 
         SECTION("positive") {
             abuffer.append(load_data("fixed64/data-pos"));
-            protozero::pbf_reader item(abuffer.data() + n, abuffer.size() - n);
+            protozero::pbf_reader item{abuffer.data() + n, abuffer.size() - n};
 
             REQUIRE(item.next());
             REQUIRE(item.get_fixed64() == 1ULL);
-            REQUIRE(!item.next());
+            REQUIRE_FALSE(item.next());
         }
 
         SECTION("max") {
             abuffer.append(load_data("fixed64/data-max"));
-            protozero::pbf_reader item(abuffer.data() + n, abuffer.size() - n);
+            protozero::pbf_reader item{abuffer.data() + n, abuffer.size() - n};
 
             REQUIRE(item.next());
             REQUIRE(item.get_fixed64() == std::numeric_limits<uint64_t>::max());
-            REQUIRE(!item.next());
+            REQUIRE_FALSE(item.next());
         }
 
         SECTION("end_of_buffer") {
             abuffer.append(load_data("fixed64/data-pos"));
 
             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_fixed64(), protozero::end_of_buffer_exception);
+                REQUIRE_THROWS_AS(item.get_fixed64(), const protozero::end_of_buffer_exception&);
             }
         }
 
diff --git a/test/t/basic/test_cases.cpp b/test/t/basic/test_cases.cpp
index 8f66d4e..c992698 100644
--- a/test/t/basic/test_cases.cpp
+++ b/test/t/basic/test_cases.cpp
@@ -5,8 +5,8 @@ TEST_CASE("default constructed pbf_reader is okay") {
     protozero::pbf_reader item;
 
     REQUIRE(item.length() == 0);
-    REQUIRE(!item); // test operator bool()
-    REQUIRE(!item.next());
+    REQUIRE_FALSE(item); // test operator bool()
+    REQUIRE_FALSE(item.next());
 }
 
 TEST_CASE("empty buffer in pbf_reader is okay") {
@@ -14,18 +14,18 @@ TEST_CASE("empty buffer in pbf_reader is okay") {
     protozero::pbf_reader item{buffer};
 
     REQUIRE(item.length() == 0);
-    REQUIRE(!item); // test operator bool()
-    REQUIRE(!item.next());
+    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);
+        protozero::pbf_reader item{&buffer, 1};
 
         REQUIRE(item.length() == 1);
-        REQUIRE(!!item); // test operator bool()
+        REQUIRE_FALSE(!item); // test operator bool()
         REQUIRE_THROWS((item.next(), item.skip()));
     }
 }
@@ -34,6 +34,6 @@ 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(), protozero::unknown_pbf_wire_type_exception);
+    REQUIRE_THROWS_AS(item.next(), const protozero::unknown_pbf_wire_type_exception&);
 }
 
diff --git a/test/t/bool/test_cases.cpp b/test/t/bool/test_cases.cpp
index 9a4b0fe..e87b0f6 100644
--- a/test/t/bool/test_cases.cpp
+++ b/test/t/bool/test_cases.cpp
@@ -14,41 +14,41 @@ TEST_CASE("read bool field using pbf_reader") {
     SECTION("false") {
         const std::string buffer = load_data("bool/data-false");
 
-        protozero::pbf_reader item(buffer);
+        protozero::pbf_reader item{buffer};
 
         REQUIRE(item.next());
-        REQUIRE(!item.get_bool());
-        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);
+        protozero::pbf_reader item{buffer};
 
         REQUIRE(item.next());
         REQUIRE(item.get_bool());
-        REQUIRE(!item.next());
+        REQUIRE_FALSE(item.next());
     }
 
     SECTION("also true") {
         const std::string buffer = load_data("bool/data-also-true");
 
-        protozero::pbf_reader item(buffer);
+        protozero::pbf_reader item{buffer};
 
         REQUIRE(item.next(1));
         REQUIRE(item.get_bool());
-        REQUIRE(!item.next());
+        REQUIRE_FALSE(item.next());
     }
 
     SECTION("still true") {
         const std::string buffer = load_data("bool/data-still-true");
 
-        protozero::pbf_reader item(buffer);
+        protozero::pbf_reader item{buffer};
 
         REQUIRE(item.next(1));
         REQUIRE(item.get_bool());
-        REQUIRE(!item.next());
+        REQUIRE_FALSE(item.next());
     }
 
 }
@@ -58,41 +58,41 @@ 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);
+        protozero::pbf_message<TestBoolean::Test> item{buffer};
 
         REQUIRE(item.next());
-        REQUIRE(!item.get_bool());
-        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);
+        protozero::pbf_message<TestBoolean::Test> item{buffer};
 
         REQUIRE(item.next());
         REQUIRE(item.get_bool());
-        REQUIRE(!item.next());
+        REQUIRE_FALSE(item.next());
     }
 
     SECTION("also true") {
         const std::string buffer = load_data("bool/data-also-true");
 
-        protozero::pbf_message<TestBoolean::Test> item(buffer);
+        protozero::pbf_message<TestBoolean::Test> item{buffer};
 
         REQUIRE(item.next(TestBoolean::Test::required_bool_b));
         REQUIRE(item.get_bool());
-        REQUIRE(!item.next());
+        REQUIRE_FALSE(item.next());
     }
 
     SECTION("still true") {
         const std::string buffer = load_data("bool/data-still-true");
 
-        protozero::pbf_message<TestBoolean::Test> item(buffer);
+        protozero::pbf_message<TestBoolean::Test> item{buffer};
 
         REQUIRE(item.next(TestBoolean::Test::required_bool_b));
         REQUIRE(item.get_bool());
-        REQUIRE(!item.next());
+        REQUIRE_FALSE(item.next());
     }
 
 }
@@ -100,7 +100,7 @@ TEST_CASE("read bool field using pbf_message") {
 TEST_CASE("write bool field using pbf_writer") {
 
     std::string buffer;
-    protozero::pbf_writer pw(buffer);
+    protozero::pbf_writer pw{buffer};
 
     SECTION("false") {
         pw.add_bool(1, false);
@@ -117,7 +117,29 @@ TEST_CASE("write bool field using pbf_writer") {
 TEST_CASE("write bool field using pbf_builder") {
 
     std::string buffer;
-    protozero::pbf_builder<TestBoolean::Test> pw(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);
diff --git a/test/t/bool/writer_test_cases.cpp b/test/t/bool/writer_test_cases.cpp
index 8494b73..9b26f62 100644
--- a/test/t/bool/writer_test_cases.cpp
+++ b/test/t/bool/writer_test_cases.cpp
@@ -8,7 +8,7 @@
 TEST_CASE("write bool field and check with libprotobuf") {
 
     std::string buffer;
-    protozero::pbf_writer pw(buffer);
+    protozero::pbf_writer pw{buffer};
 
     TestBoolean::Test msg;
 
@@ -17,7 +17,7 @@ TEST_CASE("write bool field and check with libprotobuf") {
 
         msg.ParseFromString(buffer);
 
-        REQUIRE(!msg.b());
+        REQUIRE_FALSE(msg.b());
     }
 
     SECTION("true") {
diff --git a/test/t/bytes/test_cases.cpp b/test/t/bytes/test_cases.cpp
index b3284c0..d497f8c 100644
--- a/test/t/bytes/test_cases.cpp
+++ b/test/t/bytes/test_cases.cpp
@@ -6,37 +6,37 @@ TEST_CASE("read bytes field") {
     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() == "");
-        REQUIRE(!item.next());
+        REQUIRE(item.get_bytes().empty());
+        REQUIRE_FALSE(item.next());
     }
 
     SECTION("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(!item.next());
+        REQUIRE_FALSE(item.next());
     }
 
     SECTION("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(!item.next());
+        REQUIRE_FALSE(item.next());
     }
 
     SECTION("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();
@@ -44,16 +44,16 @@ TEST_CASE("read bytes field") {
         REQUIRE(data[0] == char(1));
         REQUIRE(data[1] == char(2));
         REQUIRE(data[2] == char(3));
-        REQUIRE(!item.next());
+        REQUIRE_FALSE(item.next());
     }
 
     SECTION("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);
+            protozero::pbf_reader item{buffer.data(), i};
             REQUIRE(item.next());
-            REQUIRE_THROWS_AS(item.get_bytes(), protozero::end_of_buffer_exception);
+            REQUIRE_THROWS_AS(item.get_bytes(), const protozero::end_of_buffer_exception&);
         }
     }
 
@@ -122,7 +122,7 @@ TEST_CASE("write bytes field using vectored approach") {
 
     SECTION("with empty string") {
         std::string d1{"foo"};
-        std::string d2{""};
+        std::string d2{};
         std::string d3{"bar"};
 
         pw.add_bytes_vectored(1, d1, d2, d3);
diff --git a/test/t/bytes/writer_test_cases.cpp b/test/t/bytes/writer_test_cases.cpp
index 140e852..04bf1ee 100644
--- a/test/t/bytes/writer_test_cases.cpp
+++ b/test/t/bytes/writer_test_cases.cpp
@@ -6,7 +6,7 @@
 TEST_CASE("write bytes field and check with libprotobuf") {
 
     std::string buffer;
-    protozero::pbf_writer pw(buffer);
+    protozero::pbf_writer pw{buffer};
 
     TestBytes::Test msg;
 
diff --git a/test/t/complex/test_cases.cpp b/test/t/complex/test_cases.cpp
index 9772da0..dfa1c54 100644
--- a/test/t/complex/test_cases.cpp
+++ b/test/t/complex/test_cases.cpp
@@ -24,7 +24,7 @@ TEST_CASE("read complex data using pbf_reader") {
     SECTION("minimal") {
         const std::string buffer = load_data("complex/data-minimal");
 
-        protozero::pbf_reader item(buffer);
+        protozero::pbf_reader item{buffer};
 
         while (item.next()) {
             switch (item.tag()) {
@@ -36,7 +36,7 @@ TEST_CASE("read complex data using pbf_reader") {
                     protozero::pbf_reader subitem = item.get_message();
                     REQUIRE(subitem.next());
                     REQUIRE(subitem.get_string() == "foobar");
-                    REQUIRE(!subitem.next());
+                    REQUIRE_FALSE(subitem.next());
                     break;
                 }
                 default: {
@@ -50,7 +50,7 @@ TEST_CASE("read complex data using pbf_reader") {
     SECTION("some") {
         const std::string buffer = load_data("complex/data-some");
 
-        protozero::pbf_reader item2(buffer);
+        protozero::pbf_reader item2{buffer};
         protozero::pbf_reader item;
         using std::swap;
         swap(item, item2);
@@ -75,7 +75,7 @@ TEST_CASE("read complex data using pbf_reader") {
                     protozero::pbf_reader subitem = item.get_message();
                     REQUIRE(subitem.next());
                     REQUIRE(subitem.get_string() == "foobar");
-                    REQUIRE(!subitem.next());
+                    REQUIRE_FALSE(subitem.next());
                     break;
                 }
                 default: {
@@ -90,7 +90,7 @@ TEST_CASE("read complex data using pbf_reader") {
     SECTION("all") {
         const std::string buffer = load_data("complex/data-all");
 
-        protozero::pbf_reader item(buffer);
+        protozero::pbf_reader item{buffer};
 
         int number_of_u = 0;
         while (item.next()) {
@@ -117,7 +117,7 @@ TEST_CASE("read complex data using pbf_reader") {
                     protozero::pbf_reader subitem = item.get_message();
                     REQUIRE(subitem.next());
                     REQUIRE(subitem.get_string() == "foobar");
-                    REQUIRE(!subitem.next());
+                    REQUIRE_FALSE(subitem.next());
                     break;
                 }
                 case 7: {
@@ -145,7 +145,7 @@ TEST_CASE("read complex data using pbf_reader") {
     SECTION("skip everything") {
         const std::string buffer = load_data("complex/data-all");
 
-        protozero::pbf_reader item(buffer);
+        protozero::pbf_reader item{buffer};
 
         while (item.next()) {
             switch (item.tag()) {
@@ -173,7 +173,7 @@ 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);
+        protozero::pbf_message<TestComplex::Test> item{buffer};
 
         while (item.next()) {
             switch (item.tag()) {
@@ -182,10 +182,10 @@ TEST_CASE("read complex data using pbf_message") {
                     break;
                 }
                 case TestComplex::Test::required_Sub_submessage: {
-                    protozero::pbf_message<TestComplex::Sub> subitem = item.get_message();
+                    protozero::pbf_message<TestComplex::Sub> subitem{item.get_message()};
                     REQUIRE(subitem.next());
                     REQUIRE(subitem.get_string() == "foobar");
-                    REQUIRE(!subitem.next());
+                    REQUIRE_FALSE(subitem.next());
                     break;
                 }
                 default: {
@@ -199,7 +199,7 @@ TEST_CASE("read complex data using pbf_message") {
     SECTION("some") {
         const std::string buffer = load_data("complex/data-some");
 
-        protozero::pbf_message<TestComplex::Test> item2(buffer);
+        protozero::pbf_message<TestComplex::Test> item2{buffer};
         protozero::pbf_message<TestComplex::Test> item;
         using std::swap;
         swap(item, item2);
@@ -224,7 +224,7 @@ TEST_CASE("read complex data using pbf_message") {
                     protozero::pbf_message<TestComplex::Sub> subitem = item.get_message();
                     REQUIRE(subitem.next());
                     REQUIRE(subitem.get_string() == "foobar");
-                    REQUIRE(!subitem.next());
+                    REQUIRE_FALSE(subitem.next());
                     break;
                 }
                 default: {
@@ -239,7 +239,7 @@ TEST_CASE("read complex data using pbf_message") {
     SECTION("all") {
         const std::string buffer = load_data("complex/data-all");
 
-        protozero::pbf_message<TestComplex::Test> item(buffer);
+        protozero::pbf_message<TestComplex::Test> item{buffer};
 
         int number_of_u = 0;
         while (item.next()) {
@@ -266,7 +266,7 @@ TEST_CASE("read complex data using pbf_message") {
                     protozero::pbf_message<TestComplex::Sub> subitem = item.get_message();
                     REQUIRE(subitem.next());
                     REQUIRE(subitem.get_string() == "foobar");
-                    REQUIRE(!subitem.next());
+                    REQUIRE_FALSE(subitem.next());
                     break;
                 }
                 case TestComplex::Test::packed_sint32_d: {
@@ -294,7 +294,7 @@ TEST_CASE("read complex data using pbf_message") {
     SECTION("skip everything") {
         const std::string buffer = load_data("complex/data-all");
 
-        protozero::pbf_message<TestComplex::Test> item(buffer);
+        protozero::pbf_message<TestComplex::Test> item{buffer};
 
         while (item.next()) {
             switch (item.tag()) {
@@ -321,16 +321,16 @@ TEST_CASE("write complex data using pbf_writer") {
 
     SECTION("minimal") {
         std::string buffer;
-        protozero::pbf_writer pw(buffer);
+        protozero::pbf_writer pw{buffer};
         pw.add_fixed32(1, 12345678);
 
         std::string submessage;
-        protozero::pbf_writer pws(submessage);
+        protozero::pbf_writer pws{submessage};
         pws.add_string(1, "foobar");
 
         pw.add_message(5, submessage);
 
-        protozero::pbf_reader item(buffer);
+        protozero::pbf_reader item{buffer};
 
         while (item.next()) {
             switch (item.tag()) {
@@ -342,7 +342,7 @@ TEST_CASE("write complex data using pbf_writer") {
                     protozero::pbf_reader subitem = item.get_message();
                     REQUIRE(subitem.next());
                     REQUIRE(subitem.get_string() == "foobar");
-                    REQUIRE(!subitem.next());
+                    REQUIRE_FALSE(subitem.next());
                     break;
                 }
                 default: {
@@ -355,15 +355,18 @@ TEST_CASE("write complex data using pbf_writer") {
 
     SECTION("some") {
         std::string buffer;
-        protozero::pbf_writer pw2(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);
+        protozero::pbf_writer pws{submessage};
         pws.add_string(1, "foobar");
 
         pw.add_uint32(4, 22);
@@ -371,7 +374,7 @@ TEST_CASE("write complex data using pbf_writer") {
         pw.add_int64(2, -9876543);
         pw.add_message(5, submessage);
 
-        protozero::pbf_reader item(buffer);
+        protozero::pbf_reader item{buffer};
 
         uint32_t sum_of_u = 0;
         while (item.next()) {
@@ -390,11 +393,11 @@ TEST_CASE("write complex data using pbf_writer") {
                     break;
                 }
                 case 5: {
-                    auto view = item.get_view();
+                    const auto view = item.get_view();
                     protozero::pbf_reader subitem{view};
                     REQUIRE(subitem.next());
                     REQUIRE(std::string(subitem.get_view()) == "foobar");
-                    REQUIRE(!subitem.next());
+                    REQUIRE_FALSE(subitem.next());
                     break;
                 }
                 default: {
@@ -408,11 +411,11 @@ TEST_CASE("write complex data using pbf_writer") {
 
     SECTION("all") {
         std::string buffer;
-        protozero::pbf_writer pw(buffer);
+        protozero::pbf_writer pw{buffer};
         pw.add_fixed32(1, 12345678);
 
         std::string submessage;
-        protozero::pbf_writer pws(submessage);
+        protozero::pbf_writer pws{submessage};
         pws.add_string(1, "foobar");
         pw.add_message(5, submessage);
 
@@ -423,12 +426,12 @@ TEST_CASE("write complex data using pbf_writer") {
         pw.add_uint32(4, 66);
         pw.add_uint32(4, 66);
 
-        int32_t d[] = { -17, 22 };
+        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);
+        protozero::pbf_reader item{buffer};
 
         int number_of_u = 0;
         while (item.next()) {
@@ -455,7 +458,7 @@ TEST_CASE("write complex data using pbf_writer") {
                     protozero::pbf_reader subitem = item.get_message();
                     REQUIRE(subitem.next());
                     REQUIRE(subitem.get_string() == "foobar");
-                    REQUIRE(!subitem.next());
+                    REQUIRE_FALSE(subitem.next());
                     break;
                 }
                 case 7: {
@@ -485,16 +488,16 @@ TEST_CASE("write complex data using pbf_builder") {
 
     SECTION("minimal") {
         std::string buffer;
-        protozero::pbf_builder<TestComplex::Test> pw(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);
+        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);
+        protozero::pbf_reader item{buffer};
 
         while (item.next()) {
             switch (item.tag()) {
@@ -506,7 +509,7 @@ TEST_CASE("write complex data using pbf_builder") {
                     protozero::pbf_reader subitem = item.get_message();
                     REQUIRE(subitem.next());
                     REQUIRE(subitem.get_string() == "foobar");
-                    REQUIRE(!subitem.next());
+                    REQUIRE_FALSE(subitem.next());
                     break;
                 }
                 default: {
@@ -519,16 +522,16 @@ TEST_CASE("write complex data using pbf_builder") {
 
     SECTION("some") {
         std::string buffer;
-        protozero::pbf_builder<TestComplex::Test> pw2(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);
+        protozero::pbf_builder<TestComplex::Test> pw{dummy_buffer};
         using std::swap;
         swap(pw, pw2);
 
         std::string submessage;
-        protozero::pbf_builder<TestComplex::Sub> pws(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);
@@ -536,7 +539,7 @@ TEST_CASE("write complex data using pbf_builder") {
         pw.add_int64(TestComplex::Test::optional_int64_i, -9876543);
         pw.add_message(TestComplex::Test::required_Sub_submessage, submessage);
 
-        protozero::pbf_reader item(buffer);
+        protozero::pbf_reader item{buffer};
 
         uint32_t sum_of_u = 0;
         while (item.next()) {
@@ -558,7 +561,7 @@ TEST_CASE("write complex data using pbf_builder") {
                     protozero::pbf_reader subitem = item.get_message();
                     REQUIRE(subitem.next());
                     REQUIRE(subitem.get_string() == "foobar");
-                    REQUIRE(!subitem.next());
+                    REQUIRE_FALSE(subitem.next());
                     break;
                 }
                 default: {
@@ -572,11 +575,11 @@ TEST_CASE("write complex data using pbf_builder") {
 
     SECTION("all") {
         std::string buffer;
-        protozero::pbf_builder<TestComplex::Test> pw(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);
+        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);
 
@@ -587,12 +590,12 @@ TEST_CASE("write complex data using pbf_builder") {
         pw.add_uint32(TestComplex::Test::repeated_uint32_u, 66);
         pw.add_uint32(TestComplex::Test::repeated_uint32_u, 66);
 
-        int32_t d[] = { -17, 22 };
+        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);
+        protozero::pbf_reader item{buffer};
 
         int number_of_u = 0;
         while (item.next()) {
@@ -619,7 +622,7 @@ TEST_CASE("write complex data using pbf_builder") {
                     protozero::pbf_reader subitem = item.get_message();
                     REQUIRE(subitem.next());
                     REQUIRE(subitem.get_string() == "foobar");
-                    REQUIRE(!subitem.next());
+                    REQUIRE_FALSE(subitem.next());
                     break;
                 }
                 case 7: {
@@ -646,7 +649,7 @@ TEST_CASE("write complex data using pbf_builder") {
 }
 
 static void check_message(const std::string& buffer) {
-    protozero::pbf_reader item(buffer);
+    protozero::pbf_reader item{buffer};
 
     while (item.next()) {
         switch (item.tag()) {
@@ -658,7 +661,7 @@ static void check_message(const std::string& buffer) {
                 protozero::pbf_reader subitem = item.get_message();
                 REQUIRE(subitem.next());
                 REQUIRE(subitem.get_string() == "foobar");
-                REQUIRE(!subitem.next());
+                REQUIRE_FALSE(subitem.next());
                 break;
             }
             default: {
@@ -671,11 +674,11 @@ static void check_message(const std::string& buffer) {
 
 TEST_CASE("write complex with subwriter using pbf_writer") {
     std::string buffer_test;
-    protozero::pbf_writer pbf_test(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);
+        protozero::pbf_writer pbf_submessage{pbf_test, 5};
         pbf_submessage.add_string(1, "foobar");
     }
 
@@ -684,11 +687,11 @@ TEST_CASE("write complex with subwriter using pbf_writer") {
 
 TEST_CASE("write complex with subwriter using pbf_builder") {
     std::string buffer_test;
-    protozero::pbf_builder<TestComplex::Test> pbf_test(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);
+        protozero::pbf_builder<TestComplex::Sub> pbf_submessage{pbf_test, TestComplex::Test::required_Sub_submessage};
         pbf_submessage.add_string(TestComplex::Sub::required_string_s, "foobar");
     }
 
diff --git a/test/t/data_view/test_cases.cpp b/test/t/data_view/test_cases.cpp
index 43c8c1c..a9c51c0 100644
--- a/test/t/data_view/test_cases.cpp
+++ b/test/t/data_view/test_cases.cpp
@@ -8,7 +8,7 @@
 TEST_CASE("default constructed data_view") {
     protozero::data_view view;
     REQUIRE(view.data() == nullptr);
-    REQUIRE(view.size() == 0);
+    REQUIRE(view.size() == 0); // NOLINT clang-tidy: readability-container-size-empty
     REQUIRE(view.empty());
 }
 
@@ -34,7 +34,7 @@ TEST_CASE("data_view from ptr, size") {
 }
 
 TEST_CASE("data_view from C array") {
-    const char str[] = "foobar";
+    const char* str = "foobar";
     protozero::data_view view{str};
     REQUIRE(view.data());
     REQUIRE(view.size() == 6);
@@ -56,10 +56,14 @@ TEST_CASE("convert data_view to std::string") {
     REQUIRE(view.to_string() == "foobar");
 }
 
+#ifndef PROTOZERO_USE_VIEW
+// 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;
-    REQUIRE_THROWS_AS(view.to_string(), assert_error);
+    REQUIRE_THROWS_AS(view.to_string(), const assert_error&);
 }
+#endif
 
 TEST_CASE("swapping data_view") {
     protozero::data_view view1{"foo"};
diff --git a/test/t/double/test_cases.cpp b/test/t/double/test_cases.cpp
index 301e34f..e4165f5 100644
--- a/test/t/double/test_cases.cpp
+++ b/test/t/double/test_cases.cpp
@@ -17,38 +17,38 @@ TEST_CASE("read double field") {
 
         SECTION("zero") {
             abuffer.append(load_data("double/data-zero"));
-            protozero::pbf_reader item(abuffer.data() + n, abuffer.size() - n);
+            protozero::pbf_reader item{abuffer.data() + n, abuffer.size() - n};
 
             REQUIRE(item.next());
             REQUIRE(item.get_double() == Approx(0.0));
-            REQUIRE(!item.next());
+            REQUIRE_FALSE(item.next());
         }
 
         SECTION("positive") {
             abuffer.append(load_data("double/data-pos"));
-            protozero::pbf_reader item(abuffer.data() + n, abuffer.size() - n);
+            protozero::pbf_reader item{abuffer.data() + n, abuffer.size() - n};
 
             REQUIRE(item.next());
             REQUIRE(item.get_double() == Approx(4.893));
-            REQUIRE(!item.next());
+            REQUIRE_FALSE(item.next());
         }
 
         SECTION("negative") {
             abuffer.append(load_data("double/data-neg"));
-            protozero::pbf_reader item(abuffer.data() + n, abuffer.size() - n);
+            protozero::pbf_reader item{abuffer.data() + n, abuffer.size() - n};
 
             REQUIRE(item.next());
             REQUIRE(item.get_double() == Approx(-9232.33));
-            REQUIRE(!item.next());
+            REQUIRE_FALSE(item.next());
         }
 
         SECTION("end_of_buffer") {
             abuffer.append(load_data("double/data-neg"));
 
             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_double(), protozero::end_of_buffer_exception);
+                REQUIRE_THROWS_AS(item.get_double(), const protozero::end_of_buffer_exception&);
             }
         }
 
@@ -59,7 +59,7 @@ TEST_CASE("read double field") {
 TEST_CASE("write double field") {
 
     std::string buffer;
-    protozero::pbf_writer pw(buffer);
+    protozero::pbf_writer pw{buffer};
 
     SECTION("zero") {
         pw.add_double(1, 0.0);
diff --git a/test/t/double/writer_test_cases.cpp b/test/t/double/writer_test_cases.cpp
index bb29f52..c4a85dd 100644
--- a/test/t/double/writer_test_cases.cpp
+++ b/test/t/double/writer_test_cases.cpp
@@ -6,7 +6,7 @@
 TEST_CASE("write double field and check with libprotobuf") {
 
     std::string buffer;
-    protozero::pbf_writer pw(buffer);
+    protozero::pbf_writer pw{buffer};
 
     TestDouble::Test msg;
 
diff --git a/test/t/endian/test_cases.cpp b/test/t/endian/test_cases.cpp
index 6e39c41..8968e09 100644
--- a/test/t/endian/test_cases.cpp
+++ b/test/t/endian/test_cases.cpp
@@ -6,20 +6,16 @@
 
 #include <protozero/byteswap.hpp>
 
-namespace {
-
-    int32_t check_swap_4(int32_t data) {
-        protozero::detail::byteswap_inplace(&data);
-        protozero::detail::byteswap_inplace(&data);
-        return data;
-    }
-
-    int64_t check_swap_8(int64_t data) {
-        protozero::detail::byteswap_inplace(&data);
-        protozero::detail::byteswap_inplace(&data);
-        return data;
-    }
+static int32_t check_swap_4(int32_t data) noexcept {
+    protozero::detail::byteswap_inplace(&data);
+    protozero::detail::byteswap_inplace(&data);
+    return data;
+}
 
+static int64_t check_swap_8(int64_t data) noexcept {
+    protozero::detail::byteswap_inplace(&data);
+    protozero::detail::byteswap_inplace(&data);
+    return data;
 }
 
 TEST_CASE("byte swapping") {
diff --git a/test/t/enum/test_cases.cpp b/test/t/enum/test_cases.cpp
index 126042b..484d873 100644
--- a/test/t/enum/test_cases.cpp
+++ b/test/t/enum/test_cases.cpp
@@ -6,51 +6,51 @@ TEST_CASE("read enum field") {
     SECTION("zero") {
         const std::string buffer = load_data("enum/data-black");
 
-        protozero::pbf_reader item(buffer);
+        protozero::pbf_reader item{buffer};
 
         REQUIRE(item.next());
         REQUIRE(item.get_enum() == 0L);
-        REQUIRE(!item.next());
+        REQUIRE_FALSE(item.next());
     }
 
     SECTION("positive") {
         const std::string buffer = load_data("enum/data-blue");
 
-        protozero::pbf_reader item(buffer);
+        protozero::pbf_reader item{buffer};
 
         REQUIRE(item.next());
         REQUIRE(item.get_enum() == 3L);
-        REQUIRE(!item.next());
+        REQUIRE_FALSE(item.next());
     }
 
     SECTION("negative") {
         const std::string buffer = load_data("enum/data-neg");
 
-        protozero::pbf_reader item(buffer);
+        protozero::pbf_reader item{buffer};
 
         REQUIRE(item.next());
         REQUIRE(item.get_enum() == -1L);
-        REQUIRE(!item.next());
+        REQUIRE_FALSE(item.next());
     }
 
     SECTION("max") {
         const std::string buffer = load_data("enum/data-max");
 
-        protozero::pbf_reader item(buffer);
+        protozero::pbf_reader item{buffer};
 
         REQUIRE(item.next());
         REQUIRE(item.get_enum() == std::numeric_limits<int32_t>::max());
-        REQUIRE(!item.next());
+        REQUIRE_FALSE(item.next());
     }
 
     SECTION("min") {
         const std::string buffer = load_data("enum/data-min");
 
-        protozero::pbf_reader item(buffer);
+        protozero::pbf_reader item{buffer};
 
         REQUIRE(item.next());
         REQUIRE(item.get_enum() == (std::numeric_limits<int32_t>::min() + 1));
-        REQUIRE(!item.next());
+        REQUIRE_FALSE(item.next());
     }
 
 }
@@ -58,7 +58,7 @@ TEST_CASE("read enum field") {
 TEST_CASE("write enum field") {
 
     std::string buffer;
-    protozero::pbf_writer pw(buffer);
+    protozero::pbf_writer pw{buffer};
 
     SECTION("zero") {
         pw.add_enum(1, 0L);
diff --git a/test/t/enum/writer_test_cases.cpp b/test/t/enum/writer_test_cases.cpp
index 450725a..1f3a4c3 100644
--- a/test/t/enum/writer_test_cases.cpp
+++ b/test/t/enum/writer_test_cases.cpp
@@ -6,7 +6,7 @@
 TEST_CASE("write enum field and check with libprotobuf") {
 
     std::string buffer;
-    protozero::pbf_writer pw(buffer);
+    protozero::pbf_writer pw{buffer};
 
     TestEnum::Test msg;
 
diff --git a/test/t/fixed32/writer_test_cases.cpp b/test/t/fixed32/writer_test_cases.cpp
index a76ca3c..f09742c 100644
--- a/test/t/fixed32/writer_test_cases.cpp
+++ b/test/t/fixed32/writer_test_cases.cpp
@@ -6,7 +6,7 @@
 TEST_CASE("write fixed32 field and check with libprotobuf") {
 
     std::string buffer;
-    protozero::pbf_writer pw(buffer);
+    protozero::pbf_writer pw{buffer};
 
     TestFixed32::Test msg;
 
diff --git a/test/t/float/test_cases.cpp b/test/t/float/test_cases.cpp
index 718db85..9e92740 100644
--- a/test/t/float/test_cases.cpp
+++ b/test/t/float/test_cases.cpp
@@ -17,38 +17,38 @@ TEST_CASE("read float field") {
 
         SECTION("zero") {
             abuffer.append(load_data("float/data-zero"));
-            protozero::pbf_reader item(abuffer.data() + n, abuffer.size() - n);
+            protozero::pbf_reader item{abuffer.data() + n, abuffer.size() - n};
 
             REQUIRE(item.next());
             REQUIRE(double(item.get_float()) == Approx(0.0));
-            REQUIRE(!item.next());
+            REQUIRE_FALSE(item.next());
         }
 
         SECTION("positive") {
             abuffer.append(load_data("float/data-pos"));
-            protozero::pbf_reader item(abuffer.data() + n, abuffer.size() - n);
+            protozero::pbf_reader item{abuffer.data() + n, abuffer.size() - n};
 
             REQUIRE(item.next());
             REQUIRE(double(item.get_float()) == Approx(5.34));
-            REQUIRE(!item.next());
+            REQUIRE_FALSE(item.next());
         }
 
         SECTION("negative") {
             abuffer.append(load_data("float/data-neg"));
-            protozero::pbf_reader item(abuffer.data() + n, abuffer.size() - n);
+            protozero::pbf_reader item{abuffer.data() + n, abuffer.size() - n};
 
             REQUIRE(item.next());
             REQUIRE(double(item.get_float()) == Approx(-1.71));
-            REQUIRE(!item.next());
+            REQUIRE_FALSE(item.next());
         }
 
         SECTION("end_of_buffer") {
             abuffer.append(load_data("float/data-neg"));
 
             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_float(), protozero::end_of_buffer_exception);
+                REQUIRE_THROWS_AS(item.get_float(), const protozero::end_of_buffer_exception&);
             }
         }
 
diff --git a/test/t/int32/writer_test_cases.cpp b/test/t/int32/writer_test_cases.cpp
index dc3f848..9bdf634 100644
--- a/test/t/int32/writer_test_cases.cpp
+++ b/test/t/int32/writer_test_cases.cpp
@@ -6,7 +6,7 @@
 TEST_CASE("write int32 field and check with libprotobuf") {
 
     std::string buffer;
-    protozero::pbf_writer pw(buffer);
+    protozero::pbf_writer pw{buffer};
 
     TestInt32::Test msg;
 
diff --git a/test/t/message/test_cases.cpp b/test/t/message/test_cases.cpp
index c1253f3..af4b11f 100644
--- a/test/t/message/test_cases.cpp
+++ b/test/t/message/test_cases.cpp
@@ -6,43 +6,43 @@ TEST_CASE("read message field") {
     SECTION("string") {
         const std::string buffer = load_data("message/data-message");
 
-        protozero::pbf_reader item(buffer);
+        protozero::pbf_reader item{buffer};
 
         REQUIRE(item.next());
-        protozero::pbf_reader subitem { item.get_message() };
-        REQUIRE(!item.next());
+        protozero::pbf_reader subitem{item.get_message()};
+        REQUIRE_FALSE(item.next());
 
         REQUIRE(subitem.next());
         REQUIRE(subitem.get_string() == "foobar");
-        REQUIRE(!subitem.next());
+        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);
+            protozero::pbf_reader item{buffer.data(), i};
             REQUIRE(item.next());
-            REQUIRE_THROWS_AS(item.get_string(), protozero::end_of_buffer_exception);
+            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);
+        protozero::pbf_reader item{buffer};
 
-        REQUIRE(!item.next());
+        REQUIRE_FALSE(item.next());
     }
 
     SECTION("string") {
         const std::string buffer = load_data("message/data-opt-element");
 
-        protozero::pbf_reader item(buffer);
+        protozero::pbf_reader item{buffer};
 
         REQUIRE(item.next());
         REQUIRE(item.get_string() == "optional");
-        REQUIRE(!item.next());
+        REQUIRE_FALSE(item.next());
     }
 
 }
@@ -50,25 +50,25 @@ TEST_CASE("read message field") {
 TEST_CASE("write message field") {
 
     std::string buffer_test;
-    protozero::pbf_writer pbf_test(buffer_test);
+    protozero::pbf_writer pbf_test{buffer_test};
 
     SECTION("string") {
         std::string buffer_submessage;
-        protozero::pbf_writer pbf_submessage(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);
+        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);
+        protozero::pbf_writer pbf_submessage{pbf_test, 1, size};
         pbf_submessage.add_string(1, "foobar");
     }
 
@@ -79,18 +79,18 @@ TEST_CASE("write message field") {
 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);
+    protozero::pbf_writer pbf_test{buffer_test};
 
     SECTION("string") {
         std::string buffer_submessage;
-        protozero::pbf_writer pbf_submessage(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);
+        protozero::pbf_writer pbf_submessage{pbf_test, 1};
         pbf_submessage.add_string(1, "foobar");
     }
 
@@ -101,20 +101,20 @@ TEST_CASE("write message field into non-empty buffer") {
 TEST_CASE("write message field reserving memory beforehand") {
 
     std::string buffer_test;
-    protozero::pbf_writer pbf_test(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);
+        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);
+        protozero::pbf_writer pbf_submessage{pbf_test, 1};
         pbf_submessage.add_string(1, "foobar");
     }
 
@@ -125,7 +125,7 @@ TEST_CASE("write message field reserving memory beforehand") {
 TEST_CASE("write optional message field") {
 
     std::string buffer_opt;
-    protozero::pbf_writer pbf_opt(buffer_opt);
+    protozero::pbf_writer pbf_opt{buffer_opt};
 
     SECTION("add nothing") {
         REQUIRE(buffer_opt == load_data("message/data-opt-empty"));
diff --git a/test/t/message/writer_test_cases.cpp b/test/t/message/writer_test_cases.cpp
index 2f70a86..e13d661 100644
--- a/test/t/message/writer_test_cases.cpp
+++ b/test/t/message/writer_test_cases.cpp
@@ -6,18 +6,18 @@
 TEST_CASE("write message field and check with libprotobuf") {
 
     std::string buffer_test;
-    protozero::pbf_writer pbf_test(buffer_test);
+    protozero::pbf_writer pbf_test{buffer_test};
 
     SECTION("string") {
         std::string buffer_submessage;
-        protozero::pbf_writer pbf_submessage(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);
+        protozero::pbf_writer pbf_submessage{pbf_test, 1};
         pbf_submessage.add_string(1, "foobar");
     }
 
diff --git a/test/t/nested/test_cases.cpp b/test/t/nested/test_cases.cpp
index bfc4fdd..879e031 100644
--- a/test/t/nested/test_cases.cpp
+++ b/test/t/nested/test_cases.cpp
@@ -62,7 +62,7 @@ inline void check_empty(protozero::pbf_reader message) {
     while (message.next()) {
         switch (message.tag()) {
             case 1: {
-                REQUIRE(!message.get_message().next());
+                REQUIRE_FALSE(message.get_message().next());
                 break;
             }
             case 2: {
@@ -82,14 +82,14 @@ TEST_CASE("read nested message fields") {
     SECTION("string") {
         const std::string buffer = load_data("nested/data-message");
 
-        protozero::pbf_reader message(buffer);
+        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);
+        protozero::pbf_reader message{buffer};
         check_empty(message);
     }
 
@@ -98,16 +98,16 @@ TEST_CASE("read nested message fields") {
 TEST_CASE("write nested message fields") {
 
     std::string buffer_test;
-    protozero::pbf_writer pbf_test(buffer_test);
+    protozero::pbf_writer pbf_test{buffer_test};
 
     SECTION("string") {
         std::string buffer_subsub;
-        protozero::pbf_writer pbf_subsub(buffer_subsub);
+        protozero::pbf_writer pbf_subsub{buffer_subsub};
         pbf_subsub.add_string(1, "foobar");
         pbf_subsub.add_int32(2, 99);
 
         std::string buffer_sub;
-        protozero::pbf_writer pbf_sub(buffer_sub);
+        protozero::pbf_writer pbf_sub{buffer_sub};
         pbf_sub.add_string(1, buffer_subsub);
         pbf_sub.add_int32(2, 88);
 
@@ -115,9 +115,9 @@ TEST_CASE("write nested message fields") {
     }
 
     SECTION("string with subwriter") {
-        protozero::pbf_writer pbf_sub(pbf_test, 1);
+        protozero::pbf_writer pbf_sub{pbf_test, 1};
         {
-            protozero::pbf_writer pbf_subsub(pbf_sub, 1);
+            protozero::pbf_writer pbf_subsub{pbf_sub, 1};
             pbf_subsub.add_string(1, "foobar");
             pbf_subsub.add_int32(2, 99);
         }
@@ -126,14 +126,14 @@ TEST_CASE("write nested message fields") {
 
     pbf_test.add_int32(2, 77);
 
-    protozero::pbf_reader message(buffer_test);
+    protozero::pbf_reader message{buffer_test};
     check(message);
 }
 
 TEST_CASE("write nested message fields - no message") {
 
     std::string buffer_test;
-    protozero::pbf_writer pbf_test(buffer_test);
+    protozero::pbf_writer pbf_test{buffer_test};
 
     SECTION("nothing") {
     }
@@ -146,7 +146,7 @@ TEST_CASE("write nested message fields - no message") {
 
     SECTION("string with pbf_writer") {
         std::string buffer_sub;
-        protozero::pbf_writer pbf_sub(buffer_sub);
+        protozero::pbf_writer pbf_sub{buffer_sub};
 
         pbf_test.add_message(1, buffer_sub);
     }
@@ -157,7 +157,7 @@ TEST_CASE("write nested message fields - no message") {
 
     pbf_test.add_int32(2, 77);
 
-    protozero::pbf_reader message(buffer_test);
+    protozero::pbf_reader message{buffer_test};
     check_empty(message);
 }
 
diff --git a/test/t/nested/writer_test_cases.cpp b/test/t/nested/writer_test_cases.cpp
index d2e0490..b6272b4 100644
--- a/test/t/nested/writer_test_cases.cpp
+++ b/test/t/nested/writer_test_cases.cpp
@@ -6,16 +6,16 @@
 TEST_CASE("write nested message fields and check with libprotobuf") {
 
     std::string buffer_test;
-    protozero::pbf_writer pbf_test(buffer_test);
+    protozero::pbf_writer pbf_test{buffer_test};
 
     SECTION("string") {
         std::string buffer_subsub;
-        protozero::pbf_writer pbf_subsub(buffer_subsub);
+        protozero::pbf_writer pbf_subsub{buffer_subsub};
         pbf_subsub.add_string(1, "foobar");
         pbf_subsub.add_int32(2, 99);
 
         std::string buffer_sub;
-        protozero::pbf_writer pbf_sub(buffer_sub);
+        protozero::pbf_writer pbf_sub{buffer_sub};
         pbf_sub.add_string(1, buffer_subsub);
         pbf_sub.add_int32(2, 88);
 
@@ -23,7 +23,7 @@ TEST_CASE("write nested message fields and check with libprotobuf") {
     }
 
     SECTION("with subwriter") {
-        protozero::pbf_writer pbf_sub(pbf_test, 1);
+        protozero::pbf_writer pbf_sub{pbf_test, 1};
         {
             protozero::pbf_writer pbf_subsub(pbf_sub, 1);
             pbf_subsub.add_string(1, "foobar");
diff --git a/test/t/repeated/test_cases.cpp b/test/t/repeated/test_cases.cpp
index 5671dbb..6a08b18 100644
--- a/test/t/repeated/test_cases.cpp
+++ b/test/t/repeated/test_cases.cpp
@@ -8,7 +8,7 @@ TEST_CASE("read repeated fields") {
 
         protozero::pbf_reader item(buffer);
 
-        REQUIRE(!item.next());
+        REQUIRE_FALSE(item.next());
     }
 
     SECTION("one") {
@@ -18,7 +18,7 @@ TEST_CASE("read repeated fields") {
 
         REQUIRE(item.next());
         REQUIRE(item.get_int32() == 0L);
-        REQUIRE(!item.next());
+        REQUIRE_FALSE(item.next());
     }
 
     SECTION("many") {
@@ -41,7 +41,7 @@ TEST_CASE("read repeated fields") {
         REQUIRE(item.next());
         REQUIRE(item.get_int32() == std::numeric_limits<int32_t>::min());
 
-        REQUIRE(!item.next());
+        REQUIRE_FALSE(item.next());
     }
 
     SECTION("end_of_buffer") {
@@ -50,7 +50,7 @@ TEST_CASE("read repeated fields") {
         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(), protozero::end_of_buffer_exception);
+            REQUIRE_THROWS_AS(item.get_int32(), const protozero::end_of_buffer_exception&);
         }
     }
 
diff --git a/test/t/repeated_packed_bool/test_cases.cpp b/test/t/repeated_packed_bool/test_cases.cpp
index dd9ccaa..002f819 100644
--- a/test/t/repeated_packed_bool/test_cases.cpp
+++ b/test/t/repeated_packed_bool/test_cases.cpp
@@ -6,19 +6,20 @@ TEST_CASE("read repeated packed bool field") {
     SECTION("empty") {
         const std::string buffer = load_data("repeated_packed_bool/data-empty");
 
-        protozero::pbf_reader item(buffer);
+        protozero::pbf_reader item{buffer};
 
-        REQUIRE(!item.next());
+        REQUIRE_FALSE(item.next());
     }
 
     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());
-        auto it_range = item.get_packed_bool();
-        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());
@@ -28,17 +29,18 @@ TEST_CASE("read repeated packed bool field") {
     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());
-        auto it_range = item.get_packed_bool();
-        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(! *it++);
+        REQUIRE_FALSE(*it++);
         REQUIRE(*it++);
         REQUIRE(it == it_range.end());
     }
@@ -47,9 +49,9 @@ TEST_CASE("read repeated packed bool field") {
         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);
+            protozero::pbf_reader item{buffer.data(), i};
             REQUIRE(item.next());
-            REQUIRE_THROWS_AS(item.get_packed_bool(), protozero::end_of_buffer_exception);
+            REQUIRE_THROWS_AS(item.get_packed_bool(), const protozero::end_of_buffer_exception&);
         }
     }
 
@@ -58,24 +60,24 @@ TEST_CASE("read repeated packed bool field") {
 TEST_CASE("write repeated packed bool field") {
 
     std::string buffer;
-    protozero::pbf_writer pw(buffer);
+    protozero::pbf_writer pw{buffer};
 
     SECTION("empty") {
-        bool data[] = { true };
+        const bool data[] = { true };
         pw.add_packed_bool(1, std::begin(data), std::begin(data) /* !!!! */);
 
         REQUIRE(buffer == load_data("repeated_packed_bool/data-empty"));
     }
 
     SECTION("one") {
-        bool data[] = { true };
+        const bool data[] = { true };
         pw.add_packed_bool(1, std::begin(data), std::end(data));
 
         REQUIRE(buffer == load_data("repeated_packed_bool/data-one"));
     }
 
     SECTION("many") {
-        bool data[] = { true, true, false, true };
+        const bool data[] = { true, true, false, true };
         pw.add_packed_bool(1, std::begin(data), std::end(data));
 
         REQUIRE(buffer == load_data("repeated_packed_bool/data-many"));
@@ -86,7 +88,7 @@ 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);
+    protozero::pbf_writer pw{buffer};
 
     SECTION("empty - should do rollback") {
         {
@@ -126,7 +128,7 @@ TEST_CASE("write repeated packed bool field using packed_field_bool with pbf_bui
     };
 
     std::string buffer;
-    protozero::pbf_builder<msg> pw(buffer);
+    protozero::pbf_builder<msg> pw{buffer};
 
     SECTION("empty - should do rollback") {
         {
diff --git a/test/t/repeated_packed_double/test_cases.cpp b/test/t/repeated_packed_double/test_cases.cpp
index f11e797..238c77d 100644
--- a/test/t/repeated_packed_double/test_cases.cpp
+++ b/test/t/repeated_packed_double/test_cases.cpp
@@ -19,7 +19,7 @@ TEST_CASE("read repeated packed double field") {
             abuffer.append(load_data("repeated_packed_double/data-empty"));
             protozero::pbf_reader item(abuffer.data() + n, abuffer.size() - n);
 
-            REQUIRE(!item.next());
+            REQUIRE_FALSE(item.next());
         }
 
         SECTION("one") {
@@ -28,7 +28,7 @@ TEST_CASE("read repeated packed double field") {
 
             REQUIRE(item.next());
             auto it_range = item.get_packed_double();
-            REQUIRE(!item.next());
+            REQUIRE_FALSE(item.next());
 
             REQUIRE(*it_range.begin() == 17.34);
             REQUIRE(std::next(it_range.begin()) == it_range.end());
@@ -40,7 +40,7 @@ TEST_CASE("read repeated packed double field") {
 
             REQUIRE(item.next());
             auto it_range = item.get_packed_double();
-            REQUIRE(!item.next());
+            REQUIRE_FALSE(item.next());
 
             auto it = it_range.begin();
             REQUIRE(*it++ == 17.34);
@@ -57,7 +57,7 @@ TEST_CASE("read repeated packed double field") {
             for (std::string::size_type i = 1; i < abuffer.size() - n; ++i) {
                 protozero::pbf_reader item(abuffer.data() + n, i);
                 REQUIRE(item.next());
-                REQUIRE_THROWS_AS(item.get_packed_double(), protozero::end_of_buffer_exception);
+                REQUIRE_THROWS_AS(item.get_packed_double(), const protozero::end_of_buffer_exception&);
             }
         }
 
diff --git a/test/t/repeated_packed_enum/test_cases.cpp b/test/t/repeated_packed_enum/test_cases.cpp
index 1d1196a..d3b7794 100644
--- a/test/t/repeated_packed_enum/test_cases.cpp
+++ b/test/t/repeated_packed_enum/test_cases.cpp
@@ -8,7 +8,7 @@ TEST_CASE("read repeated packed enum field") {
 
         protozero::pbf_reader item(buffer);
 
-        REQUIRE(!item.next());
+        REQUIRE_FALSE(item.next());
     }
 
     SECTION("one") {
@@ -18,7 +18,7 @@ TEST_CASE("read repeated packed enum field") {
 
         REQUIRE(item.next());
         auto it_range = item.get_packed_enum();
-        REQUIRE(!item.next());
+        REQUIRE_FALSE(item.next());
 
         REQUIRE(it_range.begin() != it_range.end());
         REQUIRE(*it_range.begin() == 0 /* BLACK */);
@@ -32,7 +32,7 @@ TEST_CASE("read repeated packed enum field") {
 
         REQUIRE(item.next());
         auto it_range = item.get_packed_enum();
-        REQUIRE(!item.next());
+        REQUIRE_FALSE(item.next());
 
         auto it = it_range.begin();
         REQUIRE(it != it_range.end());
@@ -48,7 +48,7 @@ TEST_CASE("read repeated packed enum field") {
         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(), protozero::end_of_buffer_exception);
+            REQUIRE_THROWS_AS(item.get_packed_enum(), const protozero::end_of_buffer_exception&);
         }
     }
 
diff --git a/test/t/repeated_packed_float/test_cases.cpp b/test/t/repeated_packed_float/test_cases.cpp
index afc09cd..c0d9d46 100644
--- a/test/t/repeated_packed_float/test_cases.cpp
+++ b/test/t/repeated_packed_float/test_cases.cpp
@@ -19,7 +19,7 @@ TEST_CASE("read repeated packed float field") {
             abuffer.append(load_data("repeated_packed_float/data-empty"));
             protozero::pbf_reader item(abuffer.data() + n, abuffer.size() - n);
 
-            REQUIRE(!item.next());
+            REQUIRE_FALSE(item.next());
         }
 
         SECTION("one") {
@@ -28,7 +28,7 @@ TEST_CASE("read repeated packed float field") {
 
             REQUIRE(item.next());
             auto it_range = item.get_packed_float();
-            REQUIRE(!item.next());
+            REQUIRE_FALSE(item.next());
 
             REQUIRE(*it_range.begin() == 17.34f);
             REQUIRE(std::next(it_range.begin()) == it_range.end());
@@ -40,7 +40,7 @@ TEST_CASE("read repeated packed float field") {
 
             REQUIRE(item.next());
             auto it_range = item.get_packed_float();
-            REQUIRE(!item.next());
+            REQUIRE_FALSE(item.next());
 
             auto it = it_range.begin();
             REQUIRE(*it++ == 17.34f);
@@ -57,7 +57,7 @@ TEST_CASE("read repeated packed float field") {
             for (std::string::size_type i = 1; i < abuffer.size() - n; ++i) {
                 protozero::pbf_reader item(abuffer.data() + n, i);
                 REQUIRE(item.next());
-                REQUIRE_THROWS_AS(item.get_packed_float(), protozero::end_of_buffer_exception);
+                REQUIRE_THROWS_AS(item.get_packed_float(), const protozero::end_of_buffer_exception&);
             }
         }
 
diff --git a/test/t/rollback/test_cases.cpp b/test/t/rollback/test_cases.cpp
index bdf6f3d..51bf5f3 100644
--- a/test/t/rollback/test_cases.cpp
+++ b/test/t/rollback/test_cases.cpp
@@ -4,7 +4,7 @@
 TEST_CASE("rollback when using packed_field functions") {
 
     std::string buffer;
-    protozero::pbf_writer pw(buffer);
+    protozero::pbf_writer pw{buffer};
 
     pw.add_fixed64(2, 111);
     pw.add_string(3, "foo");
@@ -16,7 +16,7 @@ TEST_CASE("rollback when using packed_field functions") {
 
         pw.add_int32(4, 123);
 
-        protozero::pbf_reader msg(buffer);
+        protozero::pbf_reader msg{buffer};
 
         msg.next();
         REQUIRE(msg.tag() == 2);
@@ -39,7 +39,7 @@ TEST_CASE("rollback when using packed_field functions") {
 
         pw.add_int32(4, 123);
 
-        protozero::pbf_reader msg(buffer);
+        protozero::pbf_reader msg{buffer};
 
         msg.next();
         REQUIRE(msg.tag() == 2);
@@ -74,7 +74,7 @@ TEST_CASE("rollback when using packed_field functions") {
 
         pw.add_int32(4, 123);
 
-        protozero::pbf_reader msg(buffer);
+        protozero::pbf_reader msg{buffer};
 
         msg.next();
         REQUIRE(msg.tag() == 2);
@@ -112,7 +112,7 @@ TEST_CASE("rollback when using packed_field functions") {
 
         pw.add_int32(4, 123);
 
-        protozero::pbf_reader msg(buffer);
+        protozero::pbf_reader msg{buffer};
 
         msg.next();
         REQUIRE(msg.tag() == 2);
@@ -132,7 +132,7 @@ TEST_CASE("rollback when using packed_field functions") {
             protozero::packed_field_sint64 field{pw, 1};
             field.add_element(1L);
             field.rollback();
-            REQUIRE_THROWS_AS(field.add_element(1L), assert_error);
+            REQUIRE_THROWS_AS(field.add_element(1L), const assert_error&);
         }
     }
 }
@@ -140,20 +140,20 @@ TEST_CASE("rollback when using packed_field functions") {
 TEST_CASE("rollback when using submessages") {
 
     std::string buffer;
-    protozero::pbf_writer pw(buffer);
+    protozero::pbf_writer pw{buffer};
 
     pw.add_fixed64(2, 111);
     pw.add_string(3, "foo");
 
     {
-        protozero::pbf_writer pws(pw, 1);
+        protozero::pbf_writer pws{pw, 1};
         pws.add_string(1, "foobar");
         pws.rollback();
     }
 
     pw.add_int32(4, 123);
 
-    protozero::pbf_reader msg(buffer);
+    protozero::pbf_reader msg{buffer};
 
     msg.next();
     REQUIRE(msg.tag() == 2);
@@ -171,21 +171,21 @@ TEST_CASE("rollback when using submessages") {
 
 TEST_CASE("rollback on parent message is never allowed") {
     std::string buffer;
-    protozero::pbf_writer pw(buffer);
-    REQUIRE_THROWS_AS(pw.rollback(), assert_error);
+    protozero::pbf_writer pw{buffer};
+    REQUIRE_THROWS_AS(pw.rollback(), const assert_error&);
 }
 
 TEST_CASE("rollback on parent message is not allowed even if there is a submessage") {
     std::string buffer;
-    protozero::pbf_writer pw(buffer);
+    protozero::pbf_writer pw{buffer};
 
     pw.add_fixed64(2, 111);
     pw.add_string(3, "foo");
 
     {
-        protozero::pbf_writer pws(pw, 1);
+        protozero::pbf_writer pws{pw, 1};
         pws.add_string(1, "foobar");
-        REQUIRE_THROWS_AS(pw.rollback(), assert_error);
+        REQUIRE_THROWS_AS(pw.rollback(), const assert_error&);
     }
 }
 
@@ -197,10 +197,10 @@ TEST_CASE("rollback on message is not allowed if there is a nested submessage")
     pw.add_string(3, "foo");
 
     {
-        protozero::pbf_writer pws(pw, 1);
+        protozero::pbf_writer pws{pw, 1};
         pws.add_string(1, "foobar");
-        protozero::pbf_writer pws2(pws, 1);
-        REQUIRE_THROWS_AS(pws.rollback(), assert_error);
+        protozero::pbf_writer pws2{pws, 1};
+        REQUIRE_THROWS_AS(pws.rollback(), const assert_error&);
     }
 }
 
diff --git a/test/t/skip/test_cases.cpp b/test/t/skip/test_cases.cpp
index 50ea374..ed1a3b5 100644
--- a/test/t/skip/test_cases.cpp
+++ b/test/t/skip/test_cases.cpp
@@ -103,7 +103,7 @@ TEST_CASE("skip() skips the right amount of bytes") {
 
         REQUIRE(item.next());
         item.skip();
-        REQUIRE(!item);
+        REQUIRE_FALSE(item);
     }
 }
 
@@ -119,7 +119,7 @@ TEST_CASE("exceptional cases") {
 
         protozero::pbf_reader item{buffer};
 
-        REQUIRE_THROWS_AS(item.next(), protozero::unknown_pbf_wire_type_exception);
+        REQUIRE_THROWS_AS(item.next(), const protozero::unknown_pbf_wire_type_exception&);
     }
 
     SECTION("check that skip() throws on short buffer") {
@@ -127,7 +127,7 @@ TEST_CASE("exceptional cases") {
         protozero::pbf_reader item{buffer};
 
         REQUIRE(item.next());
-        REQUIRE_THROWS_AS(item.skip(), protozero::end_of_buffer_exception);
+        REQUIRE_THROWS_AS(item.skip(), const protozero::end_of_buffer_exception&);
     }
 
 }
diff --git a/test/t/string/test_cases.cpp b/test/t/string/test_cases.cpp
index 050c640..393c3bb 100644
--- a/test/t/string/test_cases.cpp
+++ b/test/t/string/test_cases.cpp
@@ -9,8 +9,8 @@ TEST_CASE("read string field using get_string") {
         protozero::pbf_reader item(buffer);
 
         REQUIRE(item.next());
-        REQUIRE(item.get_string() == "");
-        REQUIRE(!item.next());
+        REQUIRE(item.get_string().empty());
+        REQUIRE_FALSE(item.next());
     }
 
     SECTION("one") {
@@ -20,7 +20,7 @@ TEST_CASE("read string field using get_string") {
 
         REQUIRE(item.next());
         REQUIRE(item.get_string() == "x");
-        REQUIRE(!item.next());
+        REQUIRE_FALSE(item.next());
     }
 
     SECTION("string") {
@@ -30,7 +30,7 @@ TEST_CASE("read string field using get_string") {
 
         REQUIRE(item.next());
         REQUIRE(item.get_string() == "foobar");
-        REQUIRE(!item.next());
+        REQUIRE_FALSE(item.next());
     }
 
     SECTION("end_of_buffer") {
@@ -39,7 +39,7 @@ TEST_CASE("read string field using get_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(), protozero::end_of_buffer_exception);
+            REQUIRE_THROWS_AS(item.get_string(), const protozero::end_of_buffer_exception&);
         }
     }
 
@@ -54,8 +54,8 @@ TEST_CASE("read string field using get_view") {
 
         REQUIRE(item.next());
         auto v = item.get_view();
-        REQUIRE(v.size() == 0);
-        REQUIRE(!item.next());
+        REQUIRE(v.empty());
+        REQUIRE_FALSE(item.next());
     }
 
     SECTION("one") {
@@ -67,7 +67,7 @@ TEST_CASE("read string field using get_view") {
         auto v = item.get_view();
         REQUIRE(*v.data() == 'x');
         REQUIRE(v.size() == 1);
-        REQUIRE(!item.next());
+        REQUIRE_FALSE(item.next());
     }
 
     SECTION("string") {
@@ -77,7 +77,7 @@ TEST_CASE("read string field using get_view") {
 
         REQUIRE(item.next());
         REQUIRE(std::string(item.get_view()) == "foobar");
-        REQUIRE(!item.next());
+        REQUIRE_FALSE(item.next());
     }
 
     SECTION("end_of_buffer") {
@@ -86,7 +86,7 @@ TEST_CASE("read string field using get_view") {
         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(), protozero::end_of_buffer_exception);
+            REQUIRE_THROWS_AS(item.get_view(), const protozero::end_of_buffer_exception&);
         }
     }
 
diff --git a/test/t/tag_and_type/test_cases.cpp b/test/t/tag_and_type/test_cases.cpp
index 71851b4..35ca7b1 100644
--- a/test/t/tag_and_type/test_cases.cpp
+++ b/test/t/tag_and_type/test_cases.cpp
@@ -60,7 +60,7 @@ TEST_CASE("read not packed repeated field with tag_and_type") {
 TEST_CASE("read not packed repeated field with tag_and_type using next(...)") {
     const auto values = read_data_packed(load_data("tag_and_type/data-not-packed"));
 
-    REQUIRE(values.size() == 0);
+    REQUIRE(values.empty());
 }
 
 TEST_CASE("read packed repeated field with tag_and_type") {
diff --git a/test/t/tags/test_cases.cpp b/test/t/tags/test_cases.cpp
index f330dfd..22169ec 100644
--- a/test/t/tags/test_cases.cpp
+++ b/test/t/tags/test_cases.cpp
@@ -7,7 +7,7 @@ inline void check_tag(const std::string& buffer, protozero::pbf_tag_type tag) {
     REQUIRE(item.next());
     REQUIRE(item.tag() == tag);
     REQUIRE(item.get_int32() == 333L);
-    REQUIRE(!item.next());
+    REQUIRE_FALSE(item.next());
 }
 
 TEST_CASE("read tags") {
diff --git a/test/t/varint/test_cases.cpp b/test/t/varint/test_cases.cpp
index be8423e..a88c1af 100644
--- a/test/t/varint/test_cases.cpp
+++ b/test/t/varint/test_cases.cpp
@@ -65,11 +65,11 @@ TEST_CASE("varint") {
         REQUIRE(item.next());
 
         SECTION("get") {
-            REQUIRE_THROWS_AS(item.get_uint64(), protozero::end_of_buffer_exception);
+            REQUIRE_THROWS_AS(item.get_uint64(), const protozero::end_of_buffer_exception&);
         }
 
         SECTION("skip") {
-            REQUIRE_THROWS_AS(item.skip(), protozero::end_of_buffer_exception);
+            REQUIRE_THROWS_AS(item.skip(), const protozero::end_of_buffer_exception&);
         }
     }
 
@@ -80,11 +80,11 @@ TEST_CASE("varint") {
         REQUIRE(item.next());
 
         SECTION("get") {
-            REQUIRE_THROWS_AS(item.get_uint64(), protozero::end_of_buffer_exception);
+            REQUIRE_THROWS_AS(item.get_uint64(), const protozero::end_of_buffer_exception&);
         }
 
         SECTION("skip") {
-            REQUIRE_THROWS_AS(item.skip(), protozero::end_of_buffer_exception);
+            REQUIRE_THROWS_AS(item.skip(), const protozero::end_of_buffer_exception&);
         }
     }
 
@@ -95,11 +95,11 @@ TEST_CASE("varint") {
         REQUIRE(item.next());
 
         SECTION("get") {
-            REQUIRE_THROWS_AS(item.get_uint64(), protozero::varint_too_long_exception);
+            REQUIRE_THROWS_AS(item.get_uint64(), const protozero::varint_too_long_exception&);
         }
 
         SECTION("skip") {
-            REQUIRE_THROWS_AS(item.skip(), protozero::varint_too_long_exception);
+            REQUIRE_THROWS_AS(item.skip(), const protozero::varint_too_long_exception&);
         }
     }
 
@@ -115,7 +115,7 @@ TEST_CASE("lots of varints back and forth") {
         protozero::pbf_reader item{buffer};
         REQUIRE(item.next());
         REQUIRE(n == item.get_uint32());
-        REQUIRE(!item.next());
+        REQUIRE_FALSE(item.next());
         buffer.clear();
     }
 
@@ -125,7 +125,7 @@ TEST_CASE("lots of varints back and forth") {
         protozero::pbf_reader item{buffer};
         REQUIRE(item.next());
         REQUIRE(n == item.get_int32());
-        REQUIRE(!item.next());
+        REQUIRE_FALSE(item.next());
         buffer.clear();
     }
 
@@ -135,7 +135,7 @@ TEST_CASE("lots of varints back and forth") {
         protozero::pbf_reader item{buffer};
         REQUIRE(item.next());
         REQUIRE(n == item.get_sint32());
-        REQUIRE(!item.next());
+        REQUIRE_FALSE(item.next());
         buffer.clear();
     }
 
diff --git a/test/t/vector_tile/test_cases.cpp b/test/t/vector_tile/test_cases.cpp
index dc39c7c..f28f634 100644
--- a/test/t/vector_tile/test_cases.cpp
+++ b/test/t/vector_tile/test_cases.cpp
@@ -7,26 +7,21 @@
 // Input data.vector is encoded according to
 // https://github.com/mapbox/mapnik-vector-tile/blob/master/proto/vector_tile.proto
 
-static const std::vector<std::string> expected_layer_names = {
-    "landuse", "waterway", "water", "aeroway", "barrier_line", "building",
-    "landuse_overlay", "tunnel", "road", "bridge", "admin",
-    "country_label_line", "country_label", "marine_label", "state_label",
-    "place_label", "water_label", "area_label", "rail_station_label",
-    "airport_label", "road_label", "waterway_label", "building_label"
-};
-
-namespace {
-
-std::string get_name(protozero::pbf_reader layer) { // copy!
+static std::string get_name(protozero::pbf_reader layer) { // copy!
     while (layer.next(1)) { // required string name
         return layer.get_string();
     }
     return "";
 }
 
-} // anon namespace
-
 TEST_CASE("reading vector tiles") {
+    static const std::vector<std::string> expected_layer_names = {
+        "landuse", "waterway", "water", "aeroway", "barrier_line", "building",
+        "landuse_overlay", "tunnel", "road", "bridge", "admin",
+        "country_label_line", "country_label", "marine_label", "state_label",
+        "place_label", "water_label", "area_label", "rail_station_label",
+        "airport_label", "road_label", "waterway_label", "building_label"
+    };
 
     const std::string buffer = load_data("vector_tile/data.vector");
     protozero::pbf_reader item{buffer};
diff --git a/test/t/wrong_type_access/test_cases.cpp b/test/t/wrong_type_access/test_cases.cpp
index e372a34..377dd39 100644
--- a/test/t/wrong_type_access/test_cases.cpp
+++ b/test/t/wrong_type_access/test_cases.cpp
@@ -9,9 +9,9 @@ TEST_CASE("check assert on non-varint access to varint") {
     REQUIRE(item.next());
 
     REQUIRE(item.get_int32() == 0);
-    REQUIRE_THROWS_AS(item.get_fixed64(), assert_error);
-    REQUIRE_THROWS_AS(item.get_string(), assert_error);
-    REQUIRE_THROWS_AS(item.get_fixed32(), assert_error);
+    REQUIRE_THROWS_AS(item.get_fixed64(), const assert_error&);
+    REQUIRE_THROWS_AS(item.get_string(), const assert_error&);
+    REQUIRE_THROWS_AS(item.get_fixed32(), const assert_error&);
 }
 
 // protobuf wire type 1
@@ -21,10 +21,10 @@ TEST_CASE("check assert on non-fixed access to fixed64") {
     protozero::pbf_reader item{buffer};
     REQUIRE(item.next());
 
-    REQUIRE_THROWS_AS(item.get_int32(), assert_error);
+    REQUIRE_THROWS_AS(item.get_int32(), const assert_error&);
     REQUIRE(item.get_fixed64() == 0);
-    REQUIRE_THROWS_AS(item.get_string(), assert_error);
-    REQUIRE_THROWS_AS(item.get_fixed32(), assert_error);
+    REQUIRE_THROWS_AS(item.get_string(), const assert_error&);
+    REQUIRE_THROWS_AS(item.get_fixed32(), const assert_error&);
 }
 
 // protobuf wire type 2
@@ -34,10 +34,10 @@ TEST_CASE("check assert on non-string access to string") {
     protozero::pbf_reader item{buffer};
     REQUIRE(item.next());
 
-    REQUIRE_THROWS_AS(item.get_int32(), assert_error);
-    REQUIRE_THROWS_AS(item.get_fixed64(), assert_error);
+    REQUIRE_THROWS_AS(item.get_int32(), const assert_error&);
+    REQUIRE_THROWS_AS(item.get_fixed64(), const assert_error&);
     REQUIRE(item.get_string() == "foobar");
-    REQUIRE_THROWS_AS(item.get_fixed32(), assert_error);
+    REQUIRE_THROWS_AS(item.get_fixed32(), const assert_error&);
 }
 
 // protobuf wire type 5
@@ -47,9 +47,9 @@ TEST_CASE("check assert on non-fixed access to fixed32") {
     protozero::pbf_reader item{buffer};
     REQUIRE(item.next());
 
-    REQUIRE_THROWS_AS(item.get_int32(), assert_error);
-    REQUIRE_THROWS_AS(item.get_fixed64(), assert_error);
-    REQUIRE_THROWS_AS(item.get_string(), assert_error);
+    REQUIRE_THROWS_AS(item.get_int32(), const assert_error&);
+    REQUIRE_THROWS_AS(item.get_fixed64(), const assert_error&);
+    REQUIRE_THROWS_AS(item.get_string(), const assert_error&);
     REQUIRE(item.get_fixed32() == 0);
 }
 
diff --git a/test/tests.cpp b/test/tests.cpp
index cec22a4..35ecd98 100644
--- a/test/tests.cpp
+++ b/test/tests.cpp
@@ -7,16 +7,16 @@
 #include <test.hpp> // IWYU pragma: keep
 
 std::string load_data(const std::string& filename) {
-    std::string fullname("test/t/");
+    std::string fullname{"test/t/"};
     fullname += filename;
     fullname += ".pbf";
 
-    std::ifstream stream(fullname, std::ios_base::in|std::ios_base::binary);
-    if (!stream.is_open())
-    {
-        throw std::runtime_error("could not open: '" + filename + "'");
+    std::ifstream stream{fullname, std::ios_base::in|std::ios_base::binary};
+    if (!stream.is_open()) {
+        throw std::runtime_error{"could not open: '" + filename + "'"};
     }
-    std::string buffer(std::istreambuf_iterator<char>(stream.rdbuf()), (std::istreambuf_iterator<char>()));
+    std::string buffer{std::istreambuf_iterator<char>(stream.rdbuf()),
+                       std::istreambuf_iterator<char>()};
     stream.close();
 
     return buffer;

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