Echo Writes Code

CHANGELOG.md

Changelog

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

Unreleased

Added

Build system

  • All executable and library targets now receive preprocessor definitions describing the target they're being compiled for
    • On Unix-like systems, the symbol CRUCIBLE_UNIX is defined in all header and source files
    • On Windows-like systems, the symbol CRUCIBLE_WINDOWS is defined in all header and source files
    • On all targets, the symbol CRUCIBLE_ROOT is defined to the path to the root of the repository

core library

  • A library-level core.hpp header that #includes all other core headers
  • A new namespace called fallible
    • Provides a very similar type to either::Either, but with better semantics and more specific names
    • Also provides analogues for either::Lhs and either::Rhs called fallible::Failure and fallible::Success
    • Also also provides a type called Error that serves as a variadic error type container
  • A new namespace called arrays
    • Provides two new types: Array, which owns a dynamically allocated buffer; and Slice, which views a subsection of an Array
    • Also provides two overloads of a function called make_array(), which constructs an Array from a C array of static or dynamic size
  • A new overload of format::format_carray() that accepts a size argument
  • A new API for formatting classes and structs: format_record() and build_fields()
    • A new type, format::Context, supplies formatting parameters and can be made with format::build_context()
    • format_record() is a utility function that is called from T::format() for any T
    • build_fields() is used to obtain a builder object that collects all of the fields in the object into a string

meta library

  • A new library for communicating meta-level information (like libc capabilities) from the build system to the source code
  • Runtime capabilities (mainly of the C library) can be checked using the CRUCIBLE_META_CAPABILITY_* macros in the capability.hpp header

process library

  • This is a new library that deals with things related to the process that Crucible is running inside of
  • So far, there is one namespace called backtrace, which deals with getting backtraces in a cross-platform way:
    • The take_detailed_snapshot() function captures as much debug information as possible in DetailedStackFrame objects
    • The take_simple_snapshot() function captures only function names in SimpleStackFrame objects
    • The terminate_handler() function can be registered as a terminate handler using std::set_terminate() to print a nice crash report
  • There is also the usual result namespace, with two error types so far:
    • EmptyBacktrace indicates that the stack walking mechanism found 0 frames above the caller in the current thread's call stack
    • MissingDebugInformation indicates that a detailed snapshot couldn't be performed because there was no debug information found

testing library

  • A library-level testing.hpp header that #includes all other testing headers
  • Two new macros: EXPECT_FAILURE() and EXPECT_SUCCESS(), which test the state of a fallible::Result object

unix library

  • A library-level unix.hpp header that #includes all other unix headers
  • A new namespace called backtrace
    • Provides a function called snapshot() which takes a snapshot of the current call stack
    • Also provides a simple type called Frame which holds the symbol associated with each frame of the call stack

windows library

  • A library-level windows.hpp header that #incudes all other windows headers
  • A new namespace called backtrace
    • Provides a function called snapshot() which takes a snapshot of the current call stack
    • Also provides a simple type called Frame which holds a semantic description of one frame of the call stack

Changed

General

  • Combined the boba library with the vm library, then renamed it to bolt
  • Changed the supported Linux variant from Arch on amd64 to Ubuntu on amd64 in the README
  • Clarified the supported versions of macOS and Windows in the README

Build system

  • Unified naming of all CMake modules, functions, and variables to make it obvious when something is part of Crucible
    • Modules are named with the convention CrucibleXyz.cmake
    • Functions are named with the convention crucible_xyz()
    • Variables are named with the convention CRUCIBLE_XYZ
  • Hid some low-level cache variables behind new CMake functions
    • crucible_configure_language_standards() handles setting language flags
    • crucible_configure_output_directory() handles setting the output directory of final artifacts
    • crucible_configure_shared_library_exports() handles setting flags for how shared library exports are handled
  • Handle platform-specific libraries in the CMakeLists.txt for those libraries

core library

  • All format functions now take T const & instead of T &&, because formatters should never change the thing they're formatting
  • arrays::Array and arrays::Slice now use the new formatting API
  • core::assert has better formatting for its messages now
  • format::format_pointer() now requires a formatting context so it can render a pointed-to record properly

testing library

  • testing::cli::execute() now sets the terminate handler to process::backtrace::terminate_handler(), which prints a crash report
  • testing::expect has better formatting for its messages now
  • testing::console_reporter has totally redone reporting for better readability
    • Failures are now collected and displayed at the end, rather than printed inline with the tests
    • Instead of indenting to show hierarchy, section headers with underlining and colors are used to flatten the output and make it easier to read

Deprecated

Removed

  • The bobadump executable is totally gone, because boba has been rolled into the bolt library
  • The os library is gone, because its only user was bobadump (which was also removed)

Fixed

  • Check the target compatibility after setting the C++ standard (so that static_assert works properly)
  • Make sure to save the CMAKE_*_OUTPUT_DIRECTORY variables to the CMake cache
  • Fixed compilation errors and failing tests when building on Linux

Security

0.6.0

Released on February 05, 2022.

Added

parsing library

  • A new combinator called Map and associated factory function make_map()
    • Accepts a parser and a function and transforms the result of the parser using the function
  • A new combinator called Bind and associated factory function make_bind()
    • Uses the result of one parser to build a new parser, then applies the new parser
  • A new combinator called Tee and associated factory function make_tee()
    • Similar to Bind, but keeps the output of both parsers and returns it in a std::pair
  • Several new factory functions and types in the bytes namespace (used to be the bits namespace):
    • Endianness, an enumeration used to distinguish big-endian and little-endian parsers from one another
    • U8Le, U16Le, U32Le, U64Be, U8Be, U16Be, U32Be, and U64Be: parsers for the appropriate type and endianness
    • make_exact() and make_take(): factory functions for creating Exact and Take parsers
    • make_u8_le(), make_u16_le(), make_u32_le(), make_u64_le(): factory functions for little-endian unsigned integer parsers
    • make_u8_be(), make_u16_be(), make_u32_be(), make_u64_be(): factory functions for big-endian unsigned integer parsers

Changed

Build system

  • Disabled the C4180 compiler warning on MSVC due to not being helpful and causing the build to fail

bobadump executable

  • Updated output to correspond with new Boba format

boba library

  • Total overhaul of the file format and internals
    • The schema block is gone; instead we have a special container metadata section
    • The from_bytes() API is exactly the same, but the Container type is now a simple record containing a vector of headers
  • New namespace: container
    • Contains simple record types for both individual block headers and the container as a whole
  • New namespace: read
    • The from_bytes() function was moved here

parsing library

  • The meaning of the Into parser combinator has changed
    • Into<T> now converts the result of its wrapped parser into a T using one of T's constructors
  • The bits namespace has been renamed to bytes, and also renamed the contents:
    • Renamed BitsState type to State
    • Renamed ByteSequence parser to Exact
    • Renamed SizedByteSequence parser to Take
    • Combined BigEndianUnsignedInteger and LittleEndianUnsignedInteger parsers into UnsignedInteger

Removed

boba library

  • The metadata namespace is gone; see the new container and read namespaces for equivalent functionality

parsing library

  • The >> operator is no longer overloaded to construct an instance of Into
    • Use make_into() instead

Fixed

bobadump executable

  • Tests were not passing on windows due to \r\n line endings not being handled correctly in the test script

parsing library

  • Compilation errors on macOS due to mis-ordered class fields and missing constructors

0.5.0

Released on January 01, 2022.

Added

bobadump executable

  • New executable for dumping Boba files
    • No options; just use crucible-bobadump BOBA_FILE
    • Prints the schema header (but not the schema entries) and each user header

core library

  • New formatter for primitive integer types called format_integral()
    • Will work on anything for which std::is_integral evaluates to true
  • New abstract method in AbstractError called describe()
    • In contrast to format(), which is intended for developers, describe() is intended for end users
  • either::Either got new methods bind_lhs() and bind_rhs()
    • Maps a value to a whole new Either instance
    • This is in contrast to map_lhs() and map_rhs(), which map a value to another value
    • Can be used to chain Either-returning functions together

os library

  • New library for abstracting over "operating-system-y" things
    • Automatically switches between unix and windows as a backend depending on the compilation target
    • The fs namespace has platform-agnostic wrapper functions for all of the utilities in unix::fs and windows::fs

Build system

  • Support for Python test drivers via add_crucible_python_test() (intended mainly for testing executables)

General

  • Added information about Python tests to the readme
  • Added information about supported compilation targets to the readme

Changed

bobadump executable

  • Renamed from boba-dump to just bobadump

core library

  • either::LHS and either::RHS renamed to either::Lhs and either::Rhs for readability

os library

  • The Windows implementation of the fs namespace now uses the bind_lhs() and bind_rhs() APIs of core::either::Either

Build system

  • Silenced the message from find_package, which could be really long and was basically just noise

General

  • All uses of Result have been changed to Either to remove duplicated code
  • Better end-user error messages across the board
  • Uses of "Boba" as a word standardized on camel-case, not uppercase (BOBA) or lowercase (boba)

Removed

  • The core::result namespace has been completely removed; use core::either instead

Fixed

parsing library

  • Compilation error on MSVC due to signed/unsigned comparison mismatch

unix library

  • Errors now have their details reported properly (we see the errno message)

windows library

  • Errors now have their details reported properly (we see the GetLastError() message)

0.4.0

Released on December 04, 2021.

Added

New libraries

  • boba, the reference implementation of the BOBA (Bunch Of Big Arrays) file format

boba library

  • The new errors namespace:
    • The main error class BobaError
    • The ParsingFailed error variant for when loading a BOBA container fails
    • A type alias BobaResult for core::result::Result
  • The new metadata namespace:
    • A POD type called Header for keeping the (almost) raw information about each block header
    • A type called Schema that wraps the very first Header of a container, providing information about the rest of the contents
    • A type called Container that holds all block headers and provides iterator access to them, as well as the schema
    • A function called from_bytes() which deserializes a byte stream into a Container

core library

  • The format namespace:
    • Lots of functions for formatting anything you can think of: STL containers, plain arrays, C strings, pointers...
    • A format_anything() function which intelligently selects a formatter based on a compile-time type check
  • Lots of new ASSERT macros, for parity with the EXPECT API
  • The errors namespace:
    • An abstract base class called AbstractError, intended to be used for the Failure alternative of Result instances
  • Support for std::tuple in format::format_anything()
  • constexpr comparison operators for none::None

parsing library

  • A new combinator called SequenceOf
    • Used to parse an exact number of repetitions of a single structure
    • Fails if there aren't enough occurrences (but it's fine to have more)
    • Has an associated error called SequenceOfError
  • The errors namespace:
    • Error variants AmbiguousMatch, UnexpectedInput, and UnexpectedEndOfInput
    • The main error class ParsingError and a Result alias named ParsingResult
  • A new combinator called Tuple
    • Used to parse a heterogeneous sequence of substructures
    • No combinator operator; use combinators::make_tuple()
  • New factory functions for each combinator: make_one_of(), make_pair(), make_into(), and make_sequence_of()

unix library

  • The errors namespace:
    • The HostError type, which is moved from the old errno_error::ErrnoError type
    • Error variants moved from the fs namespace
    • The main error class UnixError and a Result alias named UnixError

windows library

  • The errors namespace:
    • The HostError, which is moved from the old windows_error::WindowsError type
    • Error variants moved from the fs and transcoding namespaces
    • The main error class WindowsError and a Result alias named WindowsResult

testing library

  • Self tests (at least, for the parts that can be isolated and tested!)

Changed

  • ASSERT, EXPECT, and Result now use the format_anything() function to render objects
  • All error handling is now done using a combination of core::errors::AbstractError and core::result::Result
    • Each library now has an errors namespace in which it defines its own specializations of these types

core library

  • none::None now formats as "None" instead of "None {}"

parsing library

  • AndThen combinator renamed to Pair (as a special case of Tuple)

Removed

  • ASSERT_NOT_NULL is gone; use ASSERT_NE(thing, nullptr)
  • The parsing::result, unix::errno_error, and windows::windows_error namespaces are all gone
    • See the errors namespaces in each library for a standardized replacement

0.3.0

Released on November 06, 2021.

Added

core library

  • A new namespace called assert, containing functions for implementing the ASSERT macro family
  • In the assert namespace:
    • A pair of new macros called ASSERT and ASSERT_NOT_NULL, which terminate the program with a message if the assertion does not pass
    • A template function called fail, which implements the assertion failure mechanism
  • A new namespace called either, containing the Either type for holding one of two types of value
  • In the either namespace:
    • A tag type called PreventSelectionForCopyAndMove used internally
    • A pair of templates called LHS and RHS which distinguish the alternatives of an Either
    • A template called Either which can hold one of two values, which can have different types
    • A pair of functions called make_lhs() and make_rhs(), which can be used to create LHS and RHS instances to pass to an Either

parsing library

  • In the bits namespace:
    • A new parser called SizedByteSequence which extracts a specific number of bytes from the input
  • In the combinators namespace:
    • A new combinator called Into, which functions like AndThen but dynamically constructs the second parser based on the result of the first parser
    • Two new errors called AndThenError and IntoError, which serve as error types for the AndThen and Into combinators
  • In the combinators::operators namespace:
    • An overloaded >> operator, which builds Into instances from a parser and a function

testing library

  • In the expect namespace:
    • A pair of new macros called EXPECT_CONTAINER_EQ and EXPECT_CONTAINER_NE, which check for (in)equality between two iterables
  • In the abstract_reporter namespace:
    • The AbstractReporter class now has default do-nothing implementations for all of its virtual methods
    • Two new hook methods for AbstractReporter: handle_group_start() and handle_group_end(), which get the name of the group
  • In the reporter namespace:
    • Forwarding methods for the handle_group_start() and handle_group_end() hooks
  • In the console_reporter namespace:
    • An implementation of handle_group_start that prints the group name

Changed

testing library

  • Scenarios and fixtures now both accept a tag argument before the name, which groups the fixtures and scenarios together
    • Tags can be filtered on the command line with the -t or --tag option
    • Fixtures will only be run for the scenarios that have the same tag
    • BeforeAll and AfterAll fixtures will only run if their tag isn't being filtered out
  • Output rendering is much clearer
    • A count of total scenarios run is now printed
    • Fixtures are now printed at the same level as scenarios instead of inside them
    • Fixtures receive a pass/fail note (when they would be printed anyways)
    • Added icons for each keyword to make distinguishing them a little clearer
    • Removed all white and bright white to make reading output on a white background easier
  • "Tags" renamed to "Groups"
    • The option in the CLI runner has been changed from -t/--tag to -g/--group
  • Groups are now used as "containers" for scenarios
    • There are now two loops: one over each group, and another over each scenario within the group
    • BeforeAll and AfterAll fixtures now run only within their group, not at the start or end of the whole suite
    • The console reporter will show groups as the main heading now, with scenarios and fixtures underneath

unix library

  • test_fs now uses the fixture mechanism to create and delete its file structure

General

  • Turned all instances of std::u8string, std::u8string_view, char8_t, and u8"" literals back into their legacy versions due to bad support
  • Standardized constructor syntax ({} unless () is semantically required)

parsing library

  • The bits::ByteSequence and text::CharacterSequence parsers now make a deep copy of their sequences
  • The bits::ByteSequence parser has been renamed to bits::ExactByteSequence

Fixed

  • Compilation error on AppleClang: no viable constructor or deduction guide in core::assert::fail()

0.2.0

Released on October 02, 2021.

Added

New libraries

  • vm library for the virtual machine implementation
  • parsing library for parser combinators

parsing library features

  • bits namespace containing primitives for parsing binary data
    • FixedWidthUnsignedIntegerType concept, which constrains to one of the std::uintN_t types
    • ByteSequenceMismatch basic error type
    • UnexpectedEndOfInput basic error type
    • BitsError composite error type
    • BitsState type specialized for binary data
    • ByteSequence parser which matches an exact sequence of bytes
    • LittleEndianUnsignedInteger parser template
    • BigEndianUnsignedInteger parser template
  • combinators namespace containing types for combining simple parsers into more complex parsers
    • BothMatch error template
    • NeitherMatch error template
    • OneOfError composite error type
    • OneOf parser combinator, which matches exclusively one or the other of the child parsers
    • AndThen parser combinator, which matches one parser followed by another parser and returns both results
    • operators namespace containing tools for building combinator trees
      • operator^, which combines two parsers using the OneOf combinator
      • operator&, which combines two parsers using the AndThen combinator
  • result namespace containing utility types for the outcomes of individual parsers
    • Reject template for holding information about a rejected parse
    • Accept template for holding information about an accepted parse
    • reject function for building a Reject wrapped in a core::result::Failure
    • accept function for building an Accept wrapped in a core::result::Success
  • text namespace containing primitives for parsing UTF-8 data
    • CharacterSequenceMismatch basic error type
    • TextError composite error type
    • TextState type specialized for UTF-8 data
    • CharacterSequence parser which matches an exact sequence of characters

testing library features

  • New namespace: fixture for types related to test fixtures
  • In the fixture namespace:
    • FixtureFunction alias for the type of a fixture function
    • FixtureVariant template type which serves as a base class for each kind of fixture
    • BeforeAll, AfterAll, BeforeEach, and AfterEach tag types which differentiate each kind of fixture
    • The Fixture type itself, which abstracts over all of these details
    • In the FixtureVariant type:
      • A constructor accepting a FixtureFunction
      • A getter method called get_name() which returns the name of the fixture variant based on which derived class calls it
      • A method named execute() which runs the fixture and returns an outcome, just like a scenario
    • In the BeforeAll, AfterAll, BeforeEach, and AfterEach types:
      • A constant string field containing the name of the variant for reporting purposes
    • In the Fixture type:
      • A constructor which accepts a name and a fixture variant
      • A template method called has_variant() which checks what kind of fixture this is
      • A method called get_variant_name() which forwards to get_name() on the underlying variant
      • A getter method called get_name() which retrieves the fixture's name
      • A method called execute() which forwards to execute() on the underlying variant
  • In the suite namespace:
    • Four new macros which define fixtures in the same way as scenarios: BEFORE_ALL, AFTER_ALL, BEFORE_EACH, and AFTER_EACH
    • A new type called FixtureRegistrar which is used by the new macros to add fixtures to the suite
    • In the FixtureRegistrar type:
      • A constructor that forwards to add_fixture() on the suite
    • In the Suite singleton:
      • A method called add_fixture() which registers a new fixture in the suite
  • In reporter::Reporter, abstract_reporter::AbstractReporter, and console_reporter::ConsoleReporter:
    • Two new methods called handle_fixture_start() and handle_fixture_end() which are called before and after each fixture
    • Another new method called set_show_fixtures() which toggles how much information is reported about fixtures
  • In the expect namespace:
    • A new template function called fail_comparison(), which is exactly like fail() but formats its output specifically as a comparison failure

Changed

Build system

  • Upgrade the C++ version to C++20
  • Renamed the test library to testing to better fit with other library names (specifically parsing)

testing library features

  • Print a special message when there are no tests in a test suite
  • Tests can now accept a --show-fixtures argument on the command line which causes the reporter to print more information about which fixtures run and when
  • The SCENARIO macro and ScenarioRegistrar type have been moved to the suite namespace
  • The console reporter will now display a count of total fixture invocations in the suite summary
  • All reporters now require a third argument, fixture_count, to the handle_suite_end() method
  • The EXPECT family of macros now print much more detailed information when a test fails
  • In the expect namespace:
    • The fail function now takes more arguments and has been made into a template based on the type of value being EXPECTed

Fixed

parsing library

  • Compilation cast truncates constant value warning on MSVC

testing library

  • Disallow copying and moving the Suite singleton
  • Incorrect include guard symbols
  • Compilation warning on AppleClang: [[nodiscard]] on a function returning void

Build system

  • Give a nice message from CMake instead of weird errors when trying to build for non-64-bit systems

0.1.0

Released on September 04, 2021.

Added

New libraries

  • core library for fundamental types and functions used by everything else
  • test library for testing infrastructure
  • unix library for wrapping Unix-like APIs
  • windows library for wrapping Windows APIs

core library features

  • core::constant_error namespace, containing a ConstantError template for errors with a constant message
  • core::error_chain namespace, containing the ErrorChain class for building complex error types
  • core::none namespace, containing the None type to use as a placeholder
  • core::resource_warden namespace, containing a class template for cleaning up raw resources on scope exit
  • core::result namespace, containing facilities for operations that can fail

test library features

  • test::abstract_reporter namespace, containing the AbstractReporter interface
  • test::cli namespace, containing a function execute() that can be called from main()
  • test::console_reporter namespace, containing a reporter that writes to stdout
  • test::expect namespace, containing macros to express test assertions
  • test::outcome namespace, containing types representing scenario outcomes
  • test::reporter namespace, containing factories for specific reporters and also a wrapper type
  • test::scenario namespace, containing the Scenario type for representing a single test scenario
  • test::suite namespace, containing the Suite singleton used to hold all of the tests in a suite

unix library features

  • unix::errno_error namespace, containing utilities for working with errno
  • unix::fs namespace, containing wrappers for filesystem APIs on Unix-like systems

windows library features

  • windows::fs namespace, containing wrappers for filesystem APIs on Windows
  • windows::transcoding namespace, containing functions for transcoding UTF8 with UTF16 for Windows APIs
  • windows::windows_error namespace, containing functions and a type for reading and formatting Windows errors

Build system features

  • AddCrucibleExecutable module, which provides a wrapper for add_executable()
  • AddCrucibleLibrary module, which provides a wrapper for add_library()
  • AddCrucibleTest module, which provides a wrapper for add_test()
  • EnableCompilerWarnings module, which provides a function that enables common compiler warning flags
  • EnableRuntimeSanitizers module, which provides a function that enables ASAN, TSAN, and UBSAN based on options
  • Write all final build outputs (executables and libraries) to ${PROJECT_BINARY_DIR}/artifacts
  • Automatically export all symbols from all libraries when building Windows DLLs

Repository features

  • Build dependencies in the README
  • Build instructions in the README
  • Test instructions in the README
  • Attribution in the README