text:
// Boost.Geometry (aka GGL, Generic Geometry Library)

// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.

// This file was modified by Oracle on 2013, 2014, 2015.
// Modifications copyright (c) 2013-2015, Oracle and/or its affiliates.

// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.

// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle

#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_WITHIN_POINT_IN_GEOMETRY_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_WITHIN_POINT_IN_GEOMETRY_HPP

#include <boost/core/ignore_unused.hpp>
#include <boost/mpl/assert.hpp>
#include <boost/range.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/type_traits/remove_reference.hpp>

#include <boost/geometry/core/assert.hpp>

#include <boost/geometry/algorithms/detail/equals/point_point.hpp>
#include <boost/geometry/algorithms/detail/interior_iterator.hpp>

#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/strategies/concepts/within_concept.hpp>
#include <boost/geometry/strategies/default_strategy.hpp>
#include <boost/geometry/strategies/within.hpp>
#include <boost/geometry/strategies/covered_by.hpp>

#include <boost/geometry/util/range.hpp>
#include <boost/geometry/views/detail/normalized_view.hpp>

namespace boost { namespace geometry {

#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace within {

// TODO: is this needed?
inline int check_result_type(int result)
{
    return result;
}

template <typename T>
inline T check_result_type(T result)
{
    BOOST_GEOMETRY_ASSERT(false);
    return result;
}

template <typename Point, typename Range, typename Strategy> inline
int point_in_range(Point const& point, Range const& range, Strategy const& strategy)
{
    boost::ignore_unused(strategy);

    typedef typename boost::range_iterator<Range const>::type iterator_type;
    typename Strategy::state_type state;
    iterator_type it = boost::begin(range);
    iterator_type end = boost::end(range);

    for ( iterator_type previous = it++ ; it != end ; ++previous, ++it )
    {
        if ( ! strategy.apply(point, *previous, *it, state) )
        {
            break;
        }
    }

    return check_result_type(strategy.result(state));
}

template <typename Geometry, typename Point, typename Range>
inline int point_in_range(Point const& point, Range const& range)
{
    typedef typename point_type<Point>::type point_type1;
    typedef typename point_type<Geometry>::type point_type2;

    typedef typename strategy::within::services::default_strategy
        <
            typename tag<Point>::type,
            typename tag<Geometry>::type,
            typename tag<Point>::type,
            typename tag_cast<typename tag<Geometry>::type, areal_tag>::type,
            typename tag_cast
                <
                    typename cs_tag<point_type1>::type, spherical_tag
                >::type,
            typename tag_cast
                <
                    typename cs_tag<point_type2>::type, spherical_tag
                >::type,
            Point,
            Geometry
        >::type strategy_type;

    typedef typename strategy::covered_by::services::default_strategy
        <
            typename tag<Point>::type,
            typename tag<Geometry>::type,
            typename tag<Point>::type,
            typename tag_cast<typename tag<Geometry>::type, areal_tag>::type,
            typename tag_cast
                <
                    typename cs_tag<point_type1>::type, spherical_tag
                >::type,
            typename tag_cast
                <
                    typename cs_tag<point_type2>::type, spherical_tag
                >::type,
            Point,
            Geometry
        >::type strategy_type2;

    static const bool same_strategies = boost::is_same<strategy_type, strategy_type2>::value;
    BOOST_MPL_ASSERT_MSG((same_strategies),
                         DEFAULT_WITHIN_AND_COVERED_BY_STRATEGIES_NOT_COMPATIBLE,
                         (strategy_type, strategy_type2));

    return point_in_range(point, range, strategy_type());
}

}} // namespace detail::within

namespace detail_dispatch { namespace within {

// checks the relation between a point P and geometry G
// returns 1 if P is in the interior of G
// returns 0 if P is on the boundry of G
// returns -1 if P is in the exterior of G

template <typename Geometry,
          typename Tag = typename geometry::tag<Geometry>::type>
struct point_in_geometry
    : not_implemented<Tag>
{};

template <typename Point2>
struct point_in_geometry<Point2, point_tag>
{
    template <typename Point1, typename Strategy> static inline
    int apply(Point1 const& point1, Point2 const& point2, Strategy const& strategy)
    {
        boost::ignore_unused(strategy);
        return strategy.apply(point1, point2) ? 1 : -1;
    }
};

template <typename Segment>
struct point_in_geometry<Segment, segment_tag>
{
    template <typename Point, typename Strategy> static inline
    int apply(Point const& point, Segment const& segment, Strategy const& strategy)
    {
        boost::ignore_unused(strategy);

        typedef typename geometry::point_type<Segment>::type point_type;
        point_type p0, p1;
// TODO: don't copy points
        detail::assign_point_from_index<0>(segment, p0);
        detail::assign_point_from_index<1>(segment, p1);

        typename Strategy::state_type state;
        strategy.apply(point, p0, p1, state);
        int r = detail::within::check_result_type(strategy.result(state));

        if ( r != 0 )
            return -1; // exterior

        // if the point is equal to the one of the terminal points
        if ( detail::equals::equals_point_point(point, p0)
          || detail::equals::equals_point_point(point, p1) )
            return 0; // boundary
        else
            return 1; // interior
    }
};

template <typename Linestring>
struct point_in_geometry<Linestring, linestring_tag>
{
    template <typename Point, typename Strategy> static inline
    int apply(Point const& point, Linestring const& linestring, Strategy const& strategy)
    {
        std::size_t count = boost::size(linestring);
        if ( count > 1 )
        {
            if ( detail::within::point_in_range(point, linestring, strategy) != 0 )
                return -1; // exterior

            // if the linestring doesn't have a boundary
            if (detail::equals::equals_point_point(range::front(linestring), range::back(linestring)))
                return 1; // interior
            // else if the point is equal to the one of the terminal points
            else if (detail::equals::equals_point_point(point, range::front(linestring))
                || detail::equals::equals_point_point(point, range::back(linestring)))
                return 0; // boundary
            else
                return 1; // interior
        }
// TODO: for now degenerated linestrings are ignored
//       throw an exception here?
        /*else if ( count == 1 )
        {
            if ( detail::equals::equals_point_point(point, range::front(linestring)) )
                return 1;
        }*/

        return -1; // exterior
    }
};

template <typename Ring>
struct point_in_geometry<Ring, ring_tag>
{
    template <typename Point, typename Strategy> static inline
    int apply(Point const& point, Ring const& ring, Strategy const& strategy)
    {
        if ( boost::size(ring) < core_detail::closure::minimum_ring_size
                                    <
                                        geometry::closure<Ring>::value
                                    >::value )
        {
            return -1;
        }

        detail::normalized_view<Ring const> view(ring);
        return detail::within::point_in_range(point, view, strategy);
    }
};

// Polygon: in exterior ring, and if so, not within interior ring(s)
template <typename Polygon>
struct point_in_geometry<Polygon, polygon_tag>
{
    template <typename Point, typename Strategy>
    static inline int apply(Point const& point, Polygon const& polygon,
                            Strategy const& strategy)
    {
        int const code = point_in_geometry
            <
                typename ring_type<Polygon>::type
            >::apply(point, exterior_ring(polygon), strategy);

        if (code == 1)
        {
            typename interior_return_type<Polygon const>::type
                rings = interior_rings(polygon);

            for (typename detail::interior_iterator<Polygon const>::type
                 it = boost::begin(rings);
                 it != boost::end(rings);
                 ++it)
            {
                int const interior_code = point_in_geometry
                    <
                        typename ring_type<Polygon>::type
                    >::apply(point, *it, strategy);

                if (interior_code != -1)
                {
                    // If 0, return 0 (touch)
                    // If 1 (inside hole) return -1 (outside polygon)
                    // If -1 (outside hole) check other holes if any
                    return -interior_code;
                }
            }
        }
        return code;
    }
};

template <typename Geometry>
struct point_in_geometry<Geometry, multi_point_tag>
{
    template <typename Point, typename Strategy> static inline
    int apply(Point const& point, Geometry const& geometry, Strategy const& strategy)
    {
        typedef typename boost::range_value<Geometry>::type point_type;
        typedef typename boost::range_const_iterator<Geometry>::type iterator;
        for ( iterator it = boost::begin(geometry) ; it != boost::end(geometry) ; ++it )
        {
            int pip = point_in_geometry<point_type>::apply(point, *it, strategy);

            //BOOST_GEOMETRY_ASSERT(pip != 0);
            if ( pip > 0 ) // inside
                return 1;
        }

        return -1; // outside
    }
};

template <typename Geometry>
struct point_in_geometry<Geometry, multi_linestring_tag>
{
    template <typename Point, typename Strategy> static inline
    int apply(Point const& point, Geometry const& geometry, Strategy const& strategy)
    {
        int pip = -1; // outside

        typedef typename boost::range_value<Geometry>::type linestring_type;
        typedef typename boost::range_value<linestring_type>::type point_type;
        typedef typename boost::range_iterator<Geometry const>::type iterator;
        iterator it = boost::begin(geometry);
        for ( ; it != boost::end(geometry) ; ++it )
        {
            pip = point_in_geometry<linestring_type>::apply(point, *it, strategy);

            // inside or on the boundary
            if ( pip >= 0 )
            {
                ++it;
                break;
            }
        }

        // outside
        if ( pip < 0 )
            return -1;

        // TODO: the following isn't needed for covered_by()

        unsigned boundaries = pip == 0 ? 1 : 0;

        for ( ; it != boost::end(geometry) ; ++it )
        {
            if ( boost::size(*it) < 2 )
                continue;

            point_type const& front = range::front(*it);
            point_type const& back = range::back(*it);

            // is closed_ring - no boundary
            if ( detail::equals::equals_point_point(front, back) )
                continue;

            // is point on boundary
            if ( detail::equals::equals_point_point(point, front)
              || detail::equals::equals_point_point(point, back) )
            {
                ++boundaries;
            }
        }

        // if the number of boundaries is odd, the point is on the boundary
        return boundaries % 2 ? 0 : 1;
    }
};

template <typename Geometry>
struct point_in_geometry<Geometry, multi_polygon_tag>
{
    template <typename Point, typename Strategy> static inline
    int apply(Point const& point, Geometry const& geometry, Strategy const& strategy)
    {
        // For invalid multipolygons
        //int res = -1; // outside

        typedef typename boost::range_value<Geometry>::type polygon_type;
        typedef typename boost::range_const_iterator<Geometry>::type iterator;
        for ( iterator it = boost::begin(geometry) ; it != boost::end(geometry) ; ++it )
        {
            int pip = point_in_geometry<polygon_type>::apply(point, *it, strategy);

            // inside or on the boundary
            if ( pip >= 0 )
                return pip;

            // For invalid multi-polygons
            //if ( 1 == pip ) // inside polygon
            //    return 1;
            //else if ( res < pip ) // point must be inside at least one polygon
            //    res = pip;
        }

        return -1; // for valid multipolygons
        //return res; // for invalid multipolygons
    }
};

}} // namespace detail_dispatch::within

namespace detail { namespace within {

// 1 - in the interior
// 0 - in the boundry
// -1 - in the exterior
template <typename Point, typename Geometry, typename Strategy>
inline int point_in_geometry(Point const& point, Geometry const& geometry, Strategy const& strategy)
{
    concepts::within::check
        <
            typename tag<Point>::type,
            typename tag<Geometry>::type,
            typename tag_cast<typename tag<Geometry>::type, areal_tag>::type,
            Strategy
        >();

    return detail_dispatch::within::point_in_geometry<Geometry>::apply(point, geometry, strategy);
}

template <typename Point, typename Geometry>
inline int point_in_geometry(Point const& point, Geometry const& geometry)
{
    typedef typename point_type<Point>::type point_type1;
    typedef typename point_type<Geometry>::type point_type2;

    typedef typename strategy::within::services::default_strategy
        <
            typename tag<Point>::type,
            typename tag<Geometry>::type,
            typename tag<Point>::type,
            typename tag_cast<typename tag<Geometry>::type, areal_tag>::type,
            typename tag_cast
                <
                    typename cs_tag<point_type1>::type, spherical_tag
                >::type,
            typename tag_cast
                <
                    typename cs_tag<point_type2>::type, spherical_tag
                >::type,
            Point,
            Geometry
        >::type strategy_type;

    typedef typename strategy::covered_by::services::default_strategy
        <
            typename tag<Point>::type,
            typename tag<Geometry>::type,
            typename tag<Point>::type,
            typename tag_cast<typename tag<Geometry>::type, areal_tag>::type,
            typename tag_cast
                <
                    typename cs_tag<point_type1>::type, spherical_tag
                >::type,
            typename tag_cast
                <
                    typename cs_tag<point_type2>::type, spherical_tag
                >::type,
            Point,
            Geometry
        >::type strategy_type2;

    static const bool same_strategies = boost::is_same<strategy_type, strategy_type2>::value;
    BOOST_MPL_ASSERT_MSG((same_strategies),
                         DEFAULT_WITHIN_AND_COVERED_BY_STRATEGIES_NOT_COMPATIBLE,
                         (strategy_type, strategy_type2));

    return point_in_geometry(point, geometry, strategy_type());
}

}} // namespace detail::within
#endif // DOXYGEN_NO_DETAIL

}} // namespace boost::geometry

#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_WITHIN_POINT_IN_GEOMETRY_HPP

max_stars_repo_name: EuroLine/nheqminer


text:
//---------------------------------------------------------------------------//
//!
//! \file   tstMeasurement.cpp
//! \author Alex Robinson
//! \brief  Measurement unit test
//!
//---------------------------------------------------------------------------//

// Std Lib Includes
#include <iostream>
#include <sstream>

// Boost Includes
#include <boost/units/io.hpp>
#include <boost/units/quantity.hpp>
#include <boost/units/systems/si.hpp>
#include <boost/units/cmath.hpp>
#include <boost/units/static_rational.hpp>

// FRENSIE Includes
#include "Utility_Measurement.hpp"
#include "Utility_UnitTestHarnessWithMain.hpp"

//---------------------------------------------------------------------------//
// Testing Types
//---------------------------------------------------------------------------//
typedef std::tuple<float,double> TestTypes;

//---------------------------------------------------------------------------//
// Tests.
//---------------------------------------------------------------------------//
// Check that a measurement can be constructed
FRENSIE_UNIT_TEST_TEMPLATE( Measurement, constructor, TestTypes )
{
  FETCH_TEMPLATE_PARAM( 0, T );

  // The default constructor
  Utility::Measurement<T> measurement;

  FRENSIE_CHECK_EQUAL( measurement.getValue(), T(0) );
  FRENSIE_CHECK_EQUAL( measurement.getUncertainty(), T(0) );

  // Default uncertainty constructor
  measurement = Utility::Measurement<T>( T(1) );

  FRENSIE_CHECK_EQUAL( measurement.getValue(), T(1) );
  FRENSIE_CHECK_EQUAL( measurement.getUncertainty(), T(0) );

  // Full constructor
  measurement = Utility::Measurement<T>( T(1), T(1)/T(10) );

  FRENSIE_CHECK_EQUAL( measurement.getValue(), T(1) );
  FRENSIE_CHECK_EQUAL( measurement.getUncertainty(), T(1)/T(10) );

  // Copy constructor
  Utility::Measurement<T> measurement_2( measurement );

  FRENSIE_CHECK_EQUAL( measurement_2.getValue(), T(1) );
  FRENSIE_CHECK_EQUAL( measurement_2.getUncertainty(), T(1)/T(10) );
}

//---------------------------------------------------------------------------//
// Check that the relative uncertainty can be calculated
FRENSIE_UNIT_TEST_TEMPLATE( Measurement, getRelativeUncertainty, TestTypes )
{
  FETCH_TEMPLATE_PARAM( 0, T );

  T tol;

  if( std::is_same<T,float>::value )
    tol = T(1e-6);
  else
    tol = T(1e-15);

  Utility::Measurement<T> measurement;

  FRENSIE_CHECK_EQUAL( measurement.getRelativeUncertainty(), T(0) );

  measurement = Utility::Measurement<T>( T(1) );

  FRENSIE_CHECK_EQUAL( measurement.getRelativeUncertainty(), T(0) );

  measurement = Utility::Measurement<T>( T(0.1), T(0.01) );

  FRENSIE_CHECK_FLOATING_EQUALITY( measurement.getRelativeUncertainty(), T(0.1), tol );

  measurement = Utility::Measurement<T>( T(0), T(0.01) );

  FRENSIE_CHECK_EQUAL( measurement.getRelativeUncertainty(), T(0) );

  measurement = Utility::Measurement<T>( -T(1), T(0.01) );

  FRENSIE_CHECK_FLOATING_EQUALITY( measurement.getRelativeUncertainty(), T(0.01), tol );
}

//---------------------------------------------------------------------------//
// Check that the lower bound of the measurement can be calculated
FRENSIE_UNIT_TEST_TEMPLATE( Measurement, getLowerBound, TestTypes )
{
  FETCH_TEMPLATE_PARAM( 0, T );

  Utility::Measurement<T> measurement( T(1), T(0.1) );

  FRENSIE_CHECK_EQUAL( measurement.getLowerBound(), T(0.9) );
}

//---------------------------------------------------------------------------//
// Check that the upper bound of the measurement can be calculated
FRENSIE_UNIT_TEST_TEMPLATE( Measurement, getUpperBound, TestTypes )
{
  FETCH_TEMPLATE_PARAM( 0, T );

  Utility::Measurement<T> measurement( T(1), T(0.1) );

  FRENSIE_CHECK_EQUAL( measurement.getUpperBound(), T(1.1) );
}

//---------------------------------------------------------------------------//
// Check measurement addition
FRENSIE_UNIT_TEST_TEMPLATE( Measurement, addition, TestTypes )
{
  FETCH_TEMPLATE_PARAM( 0, T );

  Utility::Measurement<T> measurement( T(1), T(0.1) );

  T tol;

  if( std::is_same<T,float>::value )
    tol = T(1e-6);
  else
    tol = T(1e-15);

  // Addition of measurement and scalar
  Utility::Measurement<T> new_measurement = measurement + T(1);

  FRENSIE_CHECK_EQUAL( new_measurement.getValue(), T(2.0) );
  FRENSIE_CHECK_EQUAL( new_measurement.getUncertainty(), T(0.1) );

  new_measurement = measurement + -T(1);

  FRENSIE_CHECK_EQUAL( new_measurement.getValue(), T(0) );
  FRENSIE_CHECK_EQUAL( new_measurement.getUncertainty(), T(0.1) );

  // Addition of scalar and measurement
  new_measurement = T(2.0) + measurement;

  FRENSIE_CHECK_EQUAL( new_measurement.getValue(), T(3.0) );
  FRENSIE_CHECK_EQUAL( new_measurement.getUncertainty(), T(0.1) );

  new_measurement = -T(2.0) + measurement;

  FRENSIE_CHECK_EQUAL( new_measurement.getValue(), -T(1) );
  FRENSIE_CHECK_EQUAL( new_measurement.getUncertainty(), T(0.1) );

  // Addition of two measurements
  new_measurement = measurement + Utility::Measurement<T>( T(1), T(0) );

  FRENSIE_CHECK_EQUAL( new_measurement.getValue(), T(2.0) );
  FRENSIE_CHECK_EQUAL( new_measurement.getUncertainty(), T(0.1) );

  new_measurement = measurement + Utility::Measurement<T>( -T(1), T(0) );

  FRENSIE_CHECK_EQUAL( new_measurement.getValue(), T(0) );
  FRENSIE_CHECK_EQUAL( new_measurement.getUncertainty(), T(0.1) );

  // In-place addition of measurement and scalar
  measurement += T(1);

  FRENSIE_CHECK_EQUAL( measurement.getValue(), T(2.0) );
  FRENSIE_CHECK_EQUAL( measurement.getUncertainty(), T(0.1) );

  measurement = Utility::Measurement<T>( T(1), T(0.1) );
  measurement += -T(1);

  FRENSIE_CHECK_EQUAL( measurement.getValue(), T(0) );
  FRENSIE_CHECK_EQUAL( measurement.getUncertainty(), T(0.1) );

  // In-place addition of measurement and another measurement
  measurement = Utility::Measurement<T>( T(1), T(0.1) );
  measurement += Utility::Measurement<T>( T(2.0), T(0.3) );

  FRENSIE_CHECK_EQUAL( measurement.getValue(), T(3.0) );
  FRENSIE_CHECK_FLOATING_EQUALITY( measurement.getUncertainty(),
                                   sqrt( T(0.1*0.1)+T(0.3*0.3) ),
                                   tol );

  measurement = Utility::Measurement<T>( T(1), T(0.1) );
  measurement += Utility::Measurement<T>( T(-2.0), T(0.3) );

  FRENSIE_CHECK_EQUAL( measurement.getValue(), -T(1) );
  FRENSIE_CHECK_FLOATING_EQUALITY( measurement.getUncertainty(),
                                   sqrt( T(0.1*0.1)+T(0.3*0.3) ),
                                   tol );
}

//---------------------------------------------------------------------------//
// Check measurement subtraction
FRENSIE_UNIT_TEST_TEMPLATE( Measurement, subtraction, TestTypes )
{
  FETCH_TEMPLATE_PARAM( 0, T );

  Utility::Measurement<T> measurement( T(1), T(0.1) );

  T tol;

  if( std::is_same<T,float>::value )
    tol = T(1e-6);
  else
    tol = T(1e-15);

  // Subtraction of measurement to scaler
  Utility::Measurement<T> new_measurement = measurement - T(1);

  FRENSIE_CHECK_EQUAL( new_measurement.getValue(), T(0) );
  FRENSIE_CHECK_EQUAL( new_measurement.getUncertainty(), T(0.1) );

  new_measurement = measurement - -T(1);

  FRENSIE_CHECK_EQUAL( new_measurement.getValue(), T(2.0) );
  FRENSIE_CHECK_EQUAL( new_measurement.getUncertainty(), T(0.1) );

  // Subtraction of scalar and measurement
  new_measurement = T(1) - measurement;

  FRENSIE_CHECK_EQUAL( new_measurement.getValue(), T(0) );
  FRENSIE_CHECK_EQUAL( new_measurement.getUncertainty(), T(0.1) );

  new_measurement = -T(1) - measurement;

  FRENSIE_CHECK_EQUAL( new_measurement.getValue(), -T(2.0) );
  FRENSIE_CHECK_EQUAL( new_measurement.getUncertainty(), T(0.1) );

  // Subtraction of two measurements
  new_measurement = measurement - Utility::Measurement<T>( T(1), T(0) );

  FRENSIE_CHECK_EQUAL( new_measurement.getValue(), T(0) );
  FRENSIE_CHECK_EQUAL( new_measurement.getUncertainty(), T(0.1) );

  new_measurement = measurement - Utility::Measurement<T>( -T(1), T(0) );

  FRENSIE_CHECK_EQUAL( new_measurement.getValue(), 2.0 );
  FRENSIE_CHECK_EQUAL( new_measurement.getUncertainty(), T(0.1) );

  // In-place subtraction of measurement and scalar
  measurement -= T(1);

  FRENSIE_CHECK_EQUAL( measurement.getValue(), T(0) );
  FRENSIE_CHECK_EQUAL( measurement.getUncertainty(), T(0.1) );

  measurement = Utility::Measurement<T>( T(1), T(0.1) );
  measurement -= -T(1);

  FRENSIE_CHECK_EQUAL( measurement.getValue(), 2.0 );
  FRENSIE_CHECK_EQUAL( measurement.getUncertainty(), T(0.1) );

  // In-place subtraction of measurement and another measurement
  measurement = Utility::Measurement<T>( T(1), 0.1 );
  measurement -= Utility::Measurement<T>( 2.0, 0.3 );

  FRENSIE_CHECK_EQUAL( measurement.getValue(), -T(1) );
  FRENSIE_CHECK_FLOATING_EQUALITY( measurement.getUncertainty(),
                                   sqrt( T(0.1*0.1) + T(0.3*0.3) ),
                                   tol );

  measurement = Utility::Measurement<T>( T(1), T(0.1) );
  measurement -= Utility::Measurement<T>( -T(2.0), T(0.3) );

  FRENSIE_CHECK_EQUAL( measurement.getValue(), T(3.0) );
  FRENSIE_CHECK_FLOATING_EQUALITY( measurement.getUncertainty(),
                                   sqrt( T(0.1*0.1) + T(0.3*0.3) ),
                                   tol );
}

//---------------------------------------------------------------------------//
// Check measurement multiplication
FRENSIE_UNIT_TEST_TEMPLATE( Measurement, multiplication, TestTypes )
{
  FETCH_TEMPLATE_PARAM( 0, T );

  Utility::Measurement<T> measurement( T(1), T(0.1) );

  T tol;

  if( std::is_same<T,float>::value )
    tol = T(1e-6);
  else
    tol = T(1e-15);

  // Multiplication of measurement and scalar
  Utility::Measurement<T> new_measurement = measurement*T(2.0);

  FRENSIE_CHECK_EQUAL( new_measurement.getValue(), T(2.0) );
  FRENSIE_CHECK_EQUAL( new_measurement.getUncertainty(), T(0.2) );

  new_measurement = measurement*T(-2.0);

  FRENSIE_CHECK_EQUAL( new_measurement.getValue(), T(-2.0) );
  FRENSIE_CHECK_EQUAL( new_measurement.getUncertainty(), T(0.2) );

  // Multiplication of scalar and measurement
  new_measurement = T(2.0)*measurement;

  FRENSIE_CHECK_EQUAL( new_measurement.getValue(), T(2.0) );
  FRENSIE_CHECK_EQUAL( new_measurement.getUncertainty(), T(0.2) );

  new_measurement = T(-2.0)*measurement;

  FRENSIE_CHECK_EQUAL( new_measurement.getValue(), T(-2.0) );
  FRENSIE_CHECK_EQUAL( new_measurement.getUncertainty(), T(0.2) );

  // Multiplication of two measurements
  new_measurement = measurement*Utility::Measurement<T>( T(2.0), T(0) );

  FRENSIE_CHECK_EQUAL( new_measurement.getValue(), T(2.0) );
  FRENSIE_CHECK_EQUAL( new_measurement.getUncertainty(), T(0.2) );

  new_measurement = measurement*Utility::Measurement<T>( T(-2.0), T(0) );

  FRENSIE_CHECK_EQUAL( new_measurement.getValue(), T(-2.0) );
  FRENSIE_CHECK_EQUAL( new_measurement.getUncertainty(), T(0.2) );

  new_measurement = measurement*Utility::Measurement<T>( T(2.0), T(0.2) );

  FRENSIE_CHECK_EQUAL( new_measurement.getValue(), T(2.0) );
  FRENSIE_CHECK_FLOATING_EQUALITY( new_measurement.getUncertainty(),
                                   sqrt( T(0.1*0.1*2.0*2.0) + T(0.2*0.2) ),
                                   tol );

  new_measurement = measurement*Utility::Measurement<T>( T(-2.0), T(0.2) );

  FRENSIE_CHECK_EQUAL( new_measurement.getValue(), T(-2.0) );
  FRENSIE_CHECK_FLOATING_EQUALITY( new_measurement.getUncertainty(),
                                   sqrt( T(0.1*0.1*2.0*2.0) + T(0.2*0.2) ),
                                   tol );

  // In-place multiplication of measurement and scalar
  measurement *= T(2.0);

  FRENSIE_CHECK_EQUAL( measurement.getValue(), T(2.0) );
  FRENSIE_CHECK_EQUAL( measurement.getUncertainty(), T(0.2) );

  measurement = Utility::Measurement<T>( T(1), T(0.1) );
  measurement *= T(-2.0);

  FRENSIE_CHECK_EQUAL( measurement.getValue(), T(-2.0) );
  FRENSIE_CHECK_EQUAL( measurement.getUncertainty(), T(0.2) );

  // In-place multiplication of measurement and another measurement
  measurement = Utility::Measurement<T>( T(1), T(0.1) );
  measurement *= Utility::Measurement<T>( T(2.0), T(0) );

  FRENSIE_CHECK_EQUAL( measurement.getValue(), T(2.0) );
  FRENSIE_CHECK_EQUAL( measurement.getUncertainty(), T(0.2) );

  measurement = Utility::Measurement<T>( T(1), T(0.1) );
  measurement *= Utility::Measurement<T>( T(-2.0), T(0) );

  FRENSIE_CHECK_EQUAL( measurement.getValue(), T(-2.0) );
  FRENSIE_CHECK_EQUAL( measurement.getUncertainty(), T(0.2) );

  measurement = Utility::Measurement<T>( T(1), T(0.1) );
  measurement *= Utility::Measurement<T>( T(2.0), T(0.2) );

  FRENSIE_CHECK_EQUAL( measurement.getValue(), T(2.0) );
  FRENSIE_CHECK_FLOATING_EQUALITY( measurement.getUncertainty(),
                                   sqrt( T(0.1*0.1*2.0*2.0) + T(0.2*0.2) ),
                                   tol );

  measurement = Utility::Measurement<T>( T(1), T(0.1) );
  measurement *= Utility::Measurement<T>( T(-2.0), T(0.2) );

  FRENSIE_CHECK_EQUAL( measurement.getValue(), T(-2.0) );
  FRENSIE_CHECK_FLOATING_EQUALITY( measurement.getUncertainty(),
                                   sqrt( T(0.1*0.1*2.0*2.0) + T(0.2*0.2) ),
                                   tol );
}

//---------------------------------------------------------------------------//
// Check measurement division
FRENSIE_UNIT_TEST_TEMPLATE( Measurement, division, TestTypes )
{
  FETCH_TEMPLATE_PARAM( 0, T );

  Utility::Measurement<T> measurement( T(1), T(0.1) );

  T tol;

  if( std::is_same<T,float>::value )
    tol = T(1e-6);
  else
    tol = T(1e-15);

  // Division of measurement and scalar
  Utility::Measurement<T> new_measurement = measurement/T(2.0);

  FRENSIE_CHECK_EQUAL( new_measurement.getValue(), T(0.5) );
  FRENSIE_CHECK_EQUAL( new_measurement.getUncertainty(), T(0.05) );

  new_measurement = measurement/T(-2.0);

  FRENSIE_CHECK_EQUAL( new_measurement.getValue(), T(-0.5) );
  FRENSIE_CHECK_EQUAL( new_measurement.getUncertainty(), T(0.05) );

  // Division of scalar and measurement
  new_measurement = T(2.0)/measurement;

  FRENSIE_CHECK_EQUAL( new_measurement.getValue(), T(2.0) );
  FRENSIE_CHECK_EQUAL( new_measurement.getUncertainty(), T(0.2) );

  new_measurement = -T(2.0)/measurement;

  FRENSIE_CHECK_EQUAL( new_measurement.getValue(), T(-2.0) );
  FRENSIE_CHECK_EQUAL( new_measurement.getUncertainty(), T(0.2) );

  // Division of two measurements
  new_measurement = measurement/Utility::Measurement<T>( T(2), T(0) );

  FRENSIE_CHECK_EQUAL( new_measurement.getValue(), T(0.5) );
  FRENSIE_CHECK_EQUAL( new_measurement.getUncertainty(), T(0.05) );

  new_measurement = measurement/Utility::Measurement<T>( -T(2), T(0) );

  FRENSIE_CHECK_EQUAL( new_measurement.getValue(), T(-0.5) );
  FRENSIE_CHECK_EQUAL( new_measurement.getUncertainty(), T(0.05) );

  new_measurement = measurement/Utility::Measurement<T>( T(2), T(0.2) );

  FRENSIE_CHECK_EQUAL( new_measurement.getValue(), T(0.5) );
  FRENSIE_CHECK_FLOATING_EQUALITY( new_measurement.getUncertainty(),
                                   sqrt( T(0.1*0.1/4.0) + T(0.2*0.2/16.0) ),
                                   tol );

  new_measurement = measurement/Utility::Measurement<T>( -T(2), T(0.2) );

  FRENSIE_CHECK_EQUAL( new_measurement.getValue(), T(-0.5) );
  FRENSIE_CHECK_FLOATING_EQUALITY( new_measurement.getUncertainty(),
                                   sqrt( T(0.1*0.1/4.0) + T(0.2*0.2/16.0) ),
                                   tol );

  // In-place division of measurement and scalar
  measurement /= T(2);

  FRENSIE_CHECK_EQUAL( measurement.getValue(), T(0.5) );
  FRENSIE_CHECK_EQUAL( measurement.getUncertainty(), T(0.05) );

  measurement = Utility::Measurement<T>( T(1), T(0.1) );
  measurement /= -T(2);

  FRENSIE_CHECK_EQUAL( measurement.getValue(), T(-0.5) );
  FRENSIE_CHECK_EQUAL( measurement.getUncertainty(), T(0.05) );

  // In-place division of measurement and another measurement
  measurement = Utility::Measurement<T>( T(1), T(0.1) );
  measurement /= Utility::Measurement<T>( T(2), T(0) );

  FRENSIE_CHECK_EQUAL( measurement.getValue(), T(0.5) );
  FRENSIE_CHECK_EQUAL( measurement.getUncertainty(), T(0.05) );

  measurement = Utility::Measurement<T>( T(1), T(0.1) );
  measurement /= Utility::Measurement<T>( -T(2), T(0) );

  FRENSIE_CHECK_EQUAL( measurement.getValue(), T(-0.5) );
  FRENSIE_CHECK_EQUAL( measurement.getUncertainty(), T(0.05) );

  measurement = Utility::Measurement<T>( T(1), T(0.1) );
  measurement /= Utility::Measurement<T>( T(2), T(0.2) );

  FRENSIE_CHECK_EQUAL( measurement.getValue(), T(0.5) );
  FRENSIE_CHECK_FLOATING_EQUALITY( measurement.getUncertainty(),
                                   sqrt( T(0.1*0.1/4.0) + T(0.2*0.2/16.0) ),
                                   tol );

  measurement = Utility::Measurement<T>( T(1), T(0.1) );
  measurement /= Utility::Measurement<T>( -T(2), T(0.2) );

  FRENSIE_CHECK_EQUAL( measurement.getValue(), T(-0.5) );
  FRENSIE_CHECK_FLOATING_EQUALITY( measurement.getUncertainty(),
                                   sqrt( T(0.1*0.1/4.0) + T(0.2*0.2/16.0) ),
                                   tol );
}

//---------------------------------------------------------------------------//
// Check that a measurement can be converted to a string
FRENSIE_UNIT_TEST_TEMPLATE( Measurement, toString, TestTypes )
{
  FETCH_TEMPLATE_PARAM( 0, T );

  Utility::Measurement<T> measurement( T(2), T(0.1) );

  std::string measurement_string = Utility::toString( measurement );

  FRENSIE_CHECK_EQUAL( measurement_string,
                       Utility::toString( measurement.getValue() ) + " +/- " +
                       Utility::toString( measurement.getUncertainty() ) );
}

//---------------------------------------------------------------------------//
// Check that a measurement can be placed in a stream
FRENSIE_UNIT_TEST_TEMPLATE( Measurement, toStream, TestTypes )
{
  FETCH_TEMPLATE_PARAM( 0, T );

  Utility::Measurement<T> measurement( T(2), T(0.1) );

  std::ostringstream oss;

  Utility::toStream( oss, measurement );

  FRENSIE_CHECK_EQUAL( oss.str(),
                       Utility::toString( measurement.getValue() ) + " +/- " +
                       Utility::toString( measurement.getUncertainty() ) );
}

//---------------------------------------------------------------------------//
// Check that a measurement can be placed in a stream
FRENSIE_UNIT_TEST_TEMPLATE( Measurement, ostream_operator, TestTypes )
{
  FETCH_TEMPLATE_PARAM( 0, T );

  Utility::Measurement<T> measurement( T(2), T(0.1) );

  std::ostringstream oss;

  oss << measurement;

  FRENSIE_CHECK_EQUAL( oss.str(),
                       Utility::toString( measurement.getValue() ) + " +/- " +
                       Utility::toString( measurement.getUncertainty() ) );
}

//---------------------------------------------------------------------------//
// Check measurement sqrt
FRENSIE_UNIT_TEST_TEMPLATE( Measurement, sqrt_std, TestTypes )
{
  FETCH_TEMPLATE_PARAM( 0, T );

  Utility::Measurement<T> measurement( T(2), T(0.1) );

  T tol;

  if( std::is_same<T,float>::value )
    tol = T(1e-6);
  else
    tol = T(1e-15);

  // Std namespace sqrt
  Utility::Measurement<T> new_measurement = std::sqrt( measurement );

  FRENSIE_CHECK_FLOATING_EQUALITY( new_measurement.getValue(),
                                   sqrt( T(2) ),
                                   tol );
  FRENSIE_CHECK_FLOATING_EQUALITY( new_measurement.getUncertainty(),
                                   T(0.1)/(2*sqrt(T(2))),
                                   tol );

  // Default sqrt (should be the same as the std namespace sqrt)
  new_measurement = sqrt( measurement );

  FRENSIE_CHECK_FLOATING_EQUALITY( new_measurement.getValue(),
                                   sqrt( T(2) ),
                                   tol );
  FRENSIE_CHECK_FLOATING_EQUALITY( new_measurement.getUncertainty(),
                                   T(0.1)/(2*sqrt(T(2))),
                                   tol );
}

//---------------------------------------------------------------------------//
// Check measurement sqrt
FRENSIE_UNIT_TEST_TEMPLATE( Measurement, sqrt, TestTypes )
{
  FETCH_TEMPLATE_PARAM( 0, T );

  Utility::Measurement<T> measurement( T(2), T(0.1) );

  T tol;

  if( std::is_same<T,float>::value )
    tol = T(1e-6);
  else
    tol = T(1e-15);

  Utility::Measurement<T> new_measurement = Utility::sqrt( measurement );

  FRENSIE_CHECK_FLOATING_EQUALITY( new_measurement.getValue(),
                                   sqrt( T(2) ),
                                   tol );
  FRENSIE_CHECK_FLOATING_EQUALITY( new_measurement.getUncertainty(),
                                   T(0.1)/(2*sqrt(T(2))),
                                   tol );
}

//---------------------------------------------------------------------------//
// Check quantity measurement sqrt
FRENSIE_UNIT_TEST_TEMPLATE( Measurement, sqrt_quantity, TestTypes )
{
  FETCH_TEMPLATE_PARAM( 0, T );

  namespace si = boost::units::si;
  using boost::units::quantity;

  quantity<si::area,Utility::Measurement<T> > area_measurement(
		   Utility::Measurement<T>( T(2), 0.1 )*si::square_meter );

  T tol;

  if( std::is_same<T,float>::value )
    tol = T(1e-6);
  else
    tol = T(1e-15);

  quantity<si::length,Utility::Measurement<T> > length_measurement =
    Utility::sqrt( area_measurement );

  FRENSIE_CHECK_FLOATING_EQUALITY( length_measurement.value().getValue(),
                                   sqrt( T(2) ),
                                   tol );
  FRENSIE_CHECK_FLOATING_EQUALITY( length_measurement.value().getUncertainty(),
                                   T(0.1)/(2*sqrt(T(2))),
                                   tol );
}

//---------------------------------------------------------------------------//
// Check measurement cbrt
FRENSIE_UNIT_TEST_TEMPLATE( Measurement, cbrt_std, TestTypes )
{
  FETCH_TEMPLATE_PARAM( 0, T );

  Utility::Measurement<T> measurement( T(2), 0.1 );

  T tol;

  if( std::is_same<T,float>::value )
    tol = T(1e-6);
  else
    tol = T(1e-15);

  // Std namespace cbrt
  Utility::Measurement<T> new_measurement = std::cbrt( measurement );

  FRENSIE_CHECK_FLOATING_EQUALITY( new_measurement.getValue(),
                                   cbrt( T(2) ),
                                   tol );
  FRENSIE_CHECK_FLOATING_EQUALITY( new_measurement.getUncertainty(),
                                   T(0.1)/(3*pow(T(2), T(2.0/3))),
                                   tol );

  // Default sqrt (should be the same as the std namespace sqrt)
  new_measurement = cbrt( measurement );

  FRENSIE_CHECK_FLOATING_EQUALITY( new_measurement.getValue(),
                                   cbrt( T(2) ),
                                   1e-15 );
  FRENSIE_CHECK_FLOATING_EQUALITY( new_measurement.getUncertainty(),
                                   0.1/(3*pow(T(2), 2.0/3)),
                                   tol );
}

//---------------------------------------------------------------------------//
// Check measurement cbrt
FRENSIE_UNIT_TEST_TEMPLATE( Measurement, cbrt, TestTypes )
{
  FETCH_TEMPLATE_PARAM( 0, T );

  Utility::Measurement<T> measurement( T(2), 0.1 );

  T tol;

  if( std::is_same<T,float>::value )
    tol = T(1e-6);
  else
    tol = T(1e-15);

  Utility::Measurement<T> new_measurement = Utility::cbrt( measurement );

  FRENSIE_CHECK_FLOATING_EQUALITY( new_measurement.getValue(),
                                   cbrt( T(2) ),
                                   tol );
  FRENSIE_CHECK_FLOATING_EQUALITY( new_measurement.getUncertainty(),
                                   T(0.1)/(3*pow(T(2), T(2.0/3))),
                                   tol );
}

//---------------------------------------------------------------------------//
// Check quantity measurement cbrt
FRENSIE_UNIT_TEST_TEMPLATE( Measurement, cbrt_quantity, TestTypes )
{
  FETCH_TEMPLATE_PARAM( 0, T );

  namespace si = boost::units::si;
  using boost::units::quantity;

  quantity<si::volume,Utility::Measurement<T> > volume_measurement(
		   Utility::Measurement<T>( T(2), 0.1 )*si::cubic_meter );

  T tol;

  if( std::is_same<T,float>::value )
    tol = T(1e-6);
  else
    tol = T(1e-15);

  quantity<si::length,Utility::Measurement<T> > length_measurement =
    Utility::cbrt( volume_measurement );

  FRENSIE_CHECK_FLOATING_EQUALITY( length_measurement.value().getValue(),
                                   cbrt( T(2) ),
                                   tol );
  FRENSIE_CHECK_FLOATING_EQUALITY( length_measurement.value().getUncertainty(),
                                   T(0.1)/(3*pow(T(2), T(2.0/3))),
                                   tol );
}

//---------------------------------------------------------------------------//
// Check measurement pow
FRENSIE_UNIT_TEST_TEMPLATE( Measurement, pow_std, TestTypes )
{
  FETCH_TEMPLATE_PARAM( 0, T );

  Utility::Measurement<T> measurement( T(2), 0.1 );

  T tol;

  if( std::is_same<T,float>::value )
    tol = T(1e-6);
  else
    tol = T(1e-15);

  // Std namespace pow
  Utility::Measurement<T> new_measurement = std::pow( measurement, 1.5 );

  FRENSIE_CHECK_FLOATING_EQUALITY( new_measurement.getValue(),
                                   pow( T(2), T(1.5) ),
                                   tol );
  FRENSIE_CHECK_FLOATING_EQUALITY( new_measurement.getUncertainty(),
                                   T(1.5*0.1)*pow( T(2), T(0.5) ),
                                   tol );

  // Default pow (should be the same as the std namespace pow)
  new_measurement = pow( measurement, T(0.5) );

  FRENSIE_CHECK_FLOATING_EQUALITY( new_measurement.getValue(),
                                   sqrt( T(2) ),
                                   tol );
  FRENSIE_CHECK_FLOATING_EQUALITY( new_measurement.getUncertainty(),
                                   T(0.1)/(2*sqrt(T(2))),
                                   tol );

  new_measurement = pow( measurement, T(-0.5) );

  FRENSIE_CHECK_FLOATING_EQUALITY( new_measurement.getValue(),
                                   pow( T(2), T(-0.5) ),
                                   tol );
  FRENSIE_CHECK_FLOATING_EQUALITY( new_measurement.getUncertainty(),
                                   T(0.5*0.1)*pow( T(2), T(-1.5) ),
                                   tol );
}

//---------------------------------------------------------------------------//
// Check measurement rpow
FRENSIE_UNIT_TEST_TEMPLATE( Measurement, rpow, TestTypes )
{
  FETCH_TEMPLATE_PARAM( 0, T );

  Utility::Measurement<T> measurement( T(2), 0.1 );

  T tol;

  if( std::is_same<T,float>::value )
    tol = T(1e-6);
  else
    tol = T(1e-15);

  Utility::Measurement<T> new_measurement =
    Utility::rpow<3,2>( measurement );

  FRENSIE_CHECK_FLOATING_EQUALITY( new_measurement.getValue(),
                                   pow( T(2), T(1.5) ),
                                   tol );
  FRENSIE_CHECK_FLOATING_EQUALITY( new_measurement.getUncertainty(),
                                   T(1.5*0.1)*pow( T(2), T(0.5) ),
                                   tol );

  new_measurement = Utility::rpow<1,2>( measurement );

  FRENSIE_CHECK_FLOATING_EQUALITY( new_measurement.getValue(),
                                   sqrt( T(2) ),
                                   tol );
  FRENSIE_CHECK_FLOATING_EQUALITY( new_measurement.getUncertainty(),
                                   T(0.1)/(2*sqrt(T(2))),
                                   tol );

  new_measurement = Utility::rpow<-1,2>( measurement );

  FRENSIE_CHECK_FLOATING_EQUALITY( new_measurement.getValue(),
                                   pow( T(2), T(-0.5) ),
                                   tol );
  FRENSIE_CHECK_FLOATING_EQUALITY( new_measurement.getUncertainty(),
                                   T(0.5*0.1)*pow( T(2), T(-1.5) ),
                                   tol );

  new_measurement = Utility::rpow<1,-2>( measurement );

  FRENSIE_CHECK_FLOATING_EQUALITY( new_measurement.getValue(),
                                   pow( T(2), T(-0.5) ),
                                   tol );
  FRENSIE_CHECK_FLOATING_EQUALITY( new_measurement.getUncertainty(),
                                   T(0.5*0.1)*pow( T(2), T(-1.5) ),
                                   tol );
}

//---------------------------------------------------------------------------//
// Check quantity measurement rpow
FRENSIE_UNIT_TEST_TEMPLATE( Measurement, rpow_quantity, TestTypes )
{
  FETCH_TEMPLATE_PARAM( 0, T );

  namespace si = boost::units::si;
  using boost::units::quantity;

  quantity<si::volume,Utility::Measurement<T> > volume_measurement(
		   Utility::Measurement<T>( T(2), 0.1 )*si::cubic_meter );

  T tol;

  if( std::is_same<T,float>::value )
    tol = T(1e-6);
  else
    tol = T(1e-15);

  quantity<si::length,Utility::Measurement<T> > length_measurement =
    Utility::rpow<1,3>( volume_measurement );

  FRENSIE_CHECK_FLOATING_EQUALITY( length_measurement.value().getValue(),
                                   cbrt( T(2) ),
                                   tol );
  FRENSIE_CHECK_FLOATING_EQUALITY( length_measurement.value().getUncertainty(),
                                   T(0.1)/(3*pow(T(2), T(2.0/3))),
                                   tol );

  // Reverse the operation
  volume_measurement = Utility::rpow<3,1>( length_measurement );

  FRENSIE_CHECK_FLOATING_EQUALITY( volume_measurement.value().getValue(),
                                   T(2),
                                   tol );
  FRENSIE_CHECK_FLOATING_EQUALITY( volume_measurement.value().getUncertainty(),
                                   0.1,
                                   tol );
}

//---------------------------------------------------------------------------//
// end tstMeasurement.cpp
//---------------------------------------------------------------------------//

ext: cpp


text:
// test/html/simple_html_sample_grouping.cpp

#include <boost/test/unit_test.hpp>

#include <wordring/html/simple_html.hpp>

#include <wordring/compatibility.hpp>

#include <iostream>
#include <iterator>
#include <string>

namespace
{
	inline std::u32string parse(std::u32string_view in)
	{
		using namespace wordring::html;

        simple_parser<u8simple_tree> sp;
		for (char32_t cp : in) sp.push_code_point(cp);
		sp.push_eof();
		std::u32string out;
		to_string(sp.get_document(), std::back_inserter(out));

		std::cout << wordring::encoding_cast<std::u8string>(out);

		return out;
	}
}

BOOST_AUTO_TEST_SUITE(simple_html_sample_grouping_test)

/*
4.4.1 The p element

https://html.spec.whatwg.org/multipage/grouping-content.html#the-p-element
*/
BOOST_AUTO_TEST_CASE(simple_html_sample_grouping_1)
{
	char32_t const* in = UR"(
The little kitten gently seated herself on a piece of
carpet. Later in her life, this would be referred to as the time the
cat sat on the mat.
)";

	char32_t const* s = UR"(
The little kitten gently seated herself on a piece of
carpet. Later in her life, this would be referred to as the time the
cat sat on the mat.
)";

	BOOST_CHECK(parse(in) == s);
}

BOOST_AUTO_TEST_CASE(simple_html_sample_grouping_2)
{
	char32_t const* in = UR"(<fieldset>
 <legend>Personal information</legend>

   Name: <input name="n">
   <input name="anon" type="checkbox"> Hide from other users

Address: <textarea name="a"></textarea>

</fieldset>)";

	char32_t const* s = UR"(<fieldset>
 <legend>Personal information</legend>

   Name: <input name="n">
   <input name="anon" type="checkbox"> Hide from other users

Address: <textarea name="a"></textarea>

</fieldset>)";

	BOOST_CHECK(parse(in) == s);
}

BOOST_AUTO_TEST_CASE(simple_html_sample_grouping_3)
{
	char32_t const* in = UR"(
There was once an example from Femley,

Whose markup was of dubious quality.

The validator complained,

So the author was pained,

To move the error from the markup to the rhyming.
)";

	char32_t const* s = UR"(
There was once an example from Femley,

Whose markup was of dubious quality.

The validator complained,

So the author was pained,

To move the error from the markup to the rhyming.
)";

	BOOST_CHECK(parse(in) == s);
}

BOOST_AUTO_TEST_CASE(simple_html_sample_grouping_4)
{
	char32_t const* in = UR"(

Last modified: 2001-04-23

Author: fred@example.com

)";

	char32_t const* s = UR"(

Last modified: 2001-04-23

Author: fred@example.com

)";

	BOOST_CHECK(parse(in) == s);
}

BOOST_AUTO_TEST_CASE(simple_html_sample_grouping_5)
{
	char32_t const* in = UR"(

 Last modified: 2001-04-23
 <address>Author: fred@example.com</address>

)";

	char32_t const* s = UR"(

 Last modified: 2001-04-23
 <address>Author: fred@example.com</address>

)";

	BOOST_CHECK(parse(in) == s);
}

BOOST_AUTO_TEST_CASE(simple_html_sample_grouping_6)
{
	char32_t const* in = UR"(

Last modified: 2001-04-23

  <address>Author: fred@example.com</address>

)";

	char32_t const* s = UR"(

Last modified: 2001-04-23

  <address>Author: fred@example.com</address>

)";

	BOOST_CHECK(parse(in) == s);
}

BOOST_AUTO_TEST_CASE(simple_html_sample_grouping_7)
{
	char32_t const* in = UR"(
For instance, this fantastic sentence has bullets relating to

wizards,

faster-than-light travel, and

telepathy,

and is further discussed below.
)";

	char32_t const* s = UR"(
For instance, this fantastic sentence has bullets relating to

wizards,

faster-than-light travel, and

telepathy,

and is further discussed below.
)";

	BOOST_CHECK(parse(in) == s);
}

BOOST_AUTO_TEST_CASE(simple_html_sample_grouping_8)
{
	char32_t const* in = UR"(
For instance, this fantastic sentence has bullets relating to

wizards,

faster-than-light travel, and

telepathy,

and is further discussed below.
)";

	char32_t const* s = UR"(
For instance, this fantastic sentence has bullets relating to

wizards,

faster-than-light travel, and

telepathy,

and is further discussed below.
)";

	BOOST_CHECK(parse(in) == s);
}

/*
4.4.2 The hr element

https://html.spec.whatwg.org/multipage/grouping-content.html#the-hr-element
*/
BOOST_AUTO_TEST_CASE(simple_html_sample_grouping_9)
{
    char32_t const* in = UR"(

Communication

There are various methods of communication. This section
 covers a few of the important ones used by the project.

Communication stones seem to come in pairs and have mysterious
 properties:

They can transfer thoughts in two directions once activated
  if used alone.

If used with another device, they can transfer one's
  consciousness to another body.

If both stones are used with another device, the
  consciousnesses switch bodies.

Radios use the electromagnetic spectrum in the meter range and
 longer.

Signal flares use the electromagnetic spectrum in the
 nanometer range.

Food

All food at the project is rationed:

Potatoes

Two per day

Soup

One bowl per day

Cooking is done by the chefs on a set rotation.

)";

    char32_t const* s = UR"(

Communication

There are various methods of communication. This section
 covers a few of the important ones used by the project.

Communication stones seem to come in pairs and have mysterious
 properties:

They can transfer thoughts in two directions once activated
  if used alone.

If used with another device, they can transfer one's
  consciousness to another body.

If both stones are used with another device, the
  consciousnesses switch bodies.

Radios use the electromagnetic spectrum in the meter range and
 longer.

Signal flares use the electromagnetic spectrum in the
 nanometer range.

Food

All food at the project is rationed:

Potatoes

Two per day

Soup

One bowl per day

Cooking is done by the chefs on a set rotation.

)";

    BOOST_CHECK(parse(in) == s);
}

BOOST_AUTO_TEST_CASE(simple_html_sample_grouping_10)
{
    char32_t const* in = UR"(
Dudley was ninety-two, in his second life, and fast approaching
time for another rejuvenation. Despite his body having the physical
age of a standard fifty-year-old, the prospect of a long degrading
campaign within academia was one he regarded with dread. For a
supposedly advanced civilization, the Intersolar Commonwealth could be
appallingly backward at times, not to mention cruel.

Maybe it won't be that bad, he told himself. The lie was
comforting enough to get him through the rest of the night's
shift.

The Carlton AllLander drove Dudley home just after dawn. Like the
astronomer, the vehicle was old and worn, but perfectly capable of
doing its job. It had a cheap diesel engine, common enough on a
semi-frontier world like Gralmond, although its drive array was a
thoroughly modern photoneural processor. With its high suspension and
deep-tread tyres it could plough along the dirt track to the
observatory in all weather and seasons, including the metre-deep snow
of Gralmond's winters.
)";

    char32_t const* s = UR"(
Dudley was ninety-two, in his second life, and fast approaching
time for another rejuvenation. Despite his body having the physical
age of a standard fifty-year-old, the prospect of a long degrading
campaign within academia was one he regarded with dread. For a
supposedly advanced civilization, the Intersolar Commonwealth could be
appallingly backward at times, not to mention cruel.

Maybe it won't be that bad, he told himself. The lie was
comforting enough to get him through the rest of the night's
shift.

The Carlton AllLander drove Dudley home just after dawn. Like the
astronomer, the vehicle was old and worn, but perfectly capable of
doing its job. It had a cheap diesel engine, common enough on a
semi-frontier world like Gralmond, although its drive array was a
thoroughly modern photoneural processor. With its high suspension and
deep-tread tyres it could plough along the dirt track to the
observatory in all weather and seasons, including the metre-deep snow
of Gralmond's winters.
)";

    BOOST_CHECK(parse(in) == s);
}

/*
4.4.3 The pre element

https://html.spec.whatwg.org/multipage/grouping-content.html#the-pre-element
*/
BOOST_AUTO_TEST_CASE(simple_html_sample_grouping_11)
{
    char32_t const* in = UR"(
This is the Panel constructor:

function Panel(element, canClose, closeHandler) {
  this.element = element;
  this.canClose = canClose;
  this.closeHandler = function () { if (closeHandler) closeHandler() };
}
)";

    char32_t const* s = UR"(
This is the Panel constructor:

function Panel(element, canClose, closeHandler) {
  this.element = element;
  this.canClose = canClose;
  this.closeHandler = function () { if (closeHandler) closeHandler() };
}
)";

    BOOST_CHECK(parse(in) == s);
}

BOOST_AUTO_TEST_CASE(simple_html_sample_grouping_12)
{
    char32_t const* in = UR"(
<samp>You are in an open field west of a big white house with a boarded
front door.
There is a small mailbox here.

></samp> open mailbox

<samp>Opening the mailbox reveals:
A leaflet.

></samp>
)";

    char32_t const* s = UR"(
<samp>You are in an open field west of a big white house with a boarded
front door.
There is a small mailbox here.

></samp> open mailbox

<samp>Opening the mailbox reveals:
A leaflet.

></samp>
)";

    BOOST_CHECK(parse(in) == s);
}

BOOST_AUTO_TEST_CASE(simple_html_sample_grouping_13)
{
    char32_t const* in = UR"(
                maxling

it is with a          heart
               heavy

that i admit loss of a feline
        so           loved

a friend lost to the
        unknown
                                (night)

~cdr 11dec07
)";

    char32_t const* s = UR"(
                maxling

it is with a          heart
               heavy

that i admit loss of a feline
        so           loved

a friend lost to the
        unknown
                                (night)

~cdr 11dec07
)";

    BOOST_CHECK(parse(in) == s);
}

/*
4.4.4 The blockquote element

https://html.spec.whatwg.org/multipage/grouping-content.html#the-blockquote-element
*/
BOOST_AUTO_TEST_CASE(simple_html_sample_grouping_14)
{
    char32_t const* in = UR"(

[Jane] then said she liked [...] fish.

)";

    char32_t const* s = UR"(

[Jane] then said she liked [...] fish.

)";

    BOOST_CHECK(parse(in) == s);
}

BOOST_AUTO_TEST_CASE(simple_html_sample_grouping_15)
{
    char32_t const* in = UR"(

I contend that we are both atheists. I just believe in one fewer
 god than you do. When you understand why you dismiss all the other
 possible gods, you will understand why I dismiss yours.

— Stephen Roberts
)";

    char32_t const* s = UR"(

I contend that we are both atheists. I just believe in one fewer
 god than you do. When you understand why you dismiss all the other
 possible gods, you will understand why I dismiss yours.

— Stephen Roberts
)";

    BOOST_CHECK(parse(in) == s);
}

BOOST_AUTO_TEST_CASE(simple_html_sample_grouping_16)
{
    char32_t const* in = UR"(

The truth may be puzzling. It may take some work to grapple with.
  It may be counterintuitive. It may contradict deeply held
  prejudices. It may not be consonant with what we desperately want to
  be true. But our preferences do not determine what's true. We have a
  method, and that method helps us to reach not absolute truth, only
  asymptotic approaches to the truth — never there, just closer
  and closer, always finding vast new oceans of undiscovered
  possibilities. Cleverly designed experiments are the key.

Carl Sagan, in "Wonder and Skepticism", from
 the Skeptical Inquirer Volume 19, Issue 1 (January-February
 1995)

)";

    char32_t const* s = UR"(

The truth may be puzzling. It may take some work to grapple with.
  It may be counterintuitive. It may contradict deeply held
  prejudices. It may not be consonant with what we desperately want to
  be true. But our preferences do not determine what's true. We have a
  method, and that method helps us to reach not absolute truth, only
  asymptotic approaches to the truth — never there, just closer
  and closer, always finding vast new oceans of undiscovered
  possibilities. Cleverly designed experiments are the key.

Carl Sagan, in "Wonder and Skepticism", from
 the Skeptical Inquirer Volume 19, Issue 1 (January-February
 1995)

)";

    BOOST_CHECK(parse(in) == s);
}

BOOST_AUTO_TEST_CASE(simple_html_sample_grouping_17)
{
    char32_t const* in = UR"(
His next piece was the aptly named Sonnet 130:

My mistress' eyes are nothing like the sun,

  Coral is far more red, than her lips red,

  ...)";

    char32_t const* s = UR"(
His next piece was the aptly named Sonnet 130:

My mistress' eyes are nothing like the sun,

  Coral is far more red, than her lips red,

  ...

)";

    BOOST_CHECK(parse(in) == s);
}

BOOST_AUTO_TEST_CASE(simple_html_sample_grouping_18)
{
    char32_t const* in = UR"(

Bacon on a crowbar

  t3yw 12 points 1 hour ago

I bet a narwhal would love that.

  permalink

   greg 8 points 1 hour ago

I bet a narwhal would love that.

Dude narwhals don't eat bacon.

   permalink

    t3yw 15 points 1 hour ago

I bet a narwhal would love that.

Dude narwhals don't eat bacon.

Next thing you'll be saying they don't get capes and wizard
    hats either!

    permalink

      boing -5 points 1 hour ago

narwhals are worse than ceiling cat

      permalink

   fred 1 points 23 minutes ago

I bet a narwhal would love that.

I bet they'd love to peel a banana too.

   permalink

)";

    char32_t const* s = UR"(

Bacon on a crowbar

  t3yw 12 points 1 hour ago

I bet a narwhal would love that.

  permalink

   greg 8 points 1 hour ago

I bet a narwhal would love that.

Dude narwhals don't eat bacon.

   permalink

    t3yw 15 points 1 hour ago

I bet a narwhal would love that.

Dude narwhals don't eat bacon.

Next thing you'll be saying they don't get capes and wizard
    hats either!

    permalink

      boing -5 points 1 hour ago

narwhals are worse than ceiling cat

      permalink

   fred 1 points 23 minutes ago

I bet a narwhal would love that.

I bet they'd love to peel a banana too.

   permalink

)";

    BOOST_CHECK(parse(in) == s);
}

BOOST_AUTO_TEST_CASE(simple_html_sample_grouping_19)
{
    char32_t const* in = UR"(
He began his list of "lessons" with the following:

One should never assume that his side of
the issue will be recognized, let alone that it will
be conceded to have merits.

He continued with a number of similar points, ending with:

Finally, one should be prepared for the threat
of breakdown in negotiations at any given moment and not
be cowed by the possibility.

We shall now discuss these points...)";

    char32_t const* s = UR"(
He began his list of "lessons" with the following:

One should never assume that his side of
the issue will be recognized, let alone that it will
be conceded to have merits.

He continued with a number of similar points, ending with:

Finally, one should be prepared for the threat
of breakdown in negotiations at any given moment and not
be cowed by the possibility.

We shall now discuss these points...
)";

    BOOST_CHECK(parse(in) == s);
}

/*
4.4.5 The ol element

https://html.spec.whatwg.org/multipage/grouping-content.html#the-ol-element
*/
BOOST_AUTO_TEST_CASE(simple_html_sample_grouping_20)
{
    char32_t const* in = UR"(
I have lived in the following countries (given in the order of when
I first lived there):

Switzerland

United Kingdom

United States

Norway

)";

    char32_t const* s = UR"(
I have lived in the following countries (given in the order of when
I first lived there):

Switzerland

United Kingdom

United States

Norway

)";

    BOOST_CHECK(parse(in) == s);
}

BOOST_AUTO_TEST_CASE(simple_html_sample_grouping_21)
{
    char32_t const* in = UR"(
I have lived in the following countries (given in the order of when
I first lived there):

United Kingdom

Switzerland

United States

Norway

)";

    char32_t const* s = UR"(
I have lived in the following countries (given in the order of when
I first lived there):

United Kingdom

Switzerland

United States

Norway

)";

    BOOST_CHECK(parse(in) == s);
}

/*
4.4.6 The ul element

https://html.spec.whatwg.org/multipage/grouping-content.html#the-ul-element
*/
BOOST_AUTO_TEST_CASE(simple_html_sample_grouping_22)
{
    char32_t const* in = UR"(
I have lived in the following countries:

Norway

Switzerland

United Kingdom

United States

)";

    char32_t const* s = UR"(
I have lived in the following countries:

Norway

Switzerland

United Kingdom

United States

)";

    BOOST_CHECK(parse(in) == s);
}

BOOST_AUTO_TEST_CASE(simple_html_sample_grouping_23)
{
    char32_t const* in = UR"(
I have lived in the following countries:

Switzerland

Norway

United Kingdom

United States

)";

    char32_t const* s = UR"(
I have lived in the following countries:

Switzerland

Norway

United Kingdom

United States

)";

    BOOST_CHECK(parse(in) == s);
}

/*
4.4.7 The menu element

https://html.spec.whatwg.org/multipage/grouping-content.html#the-menu-element
*/
BOOST_AUTO_TEST_CASE(simple_html_sample_grouping_24)
{
    char32_t const* in = UR"*(<menu>

<button onclick="copy()"></button>

<button onclick="cut()"></button>

<button onclick="paste()"></button>

</menu>)*";

    char32_t const* s = UR"*(<menu>

<button onclick="copy()"></button>

<button onclick="cut()"></button>

<button onclick="paste()"></button>

</menu>)*";

    BOOST_CHECK(parse(in) == s);
}

/*
4.4.8 The li element

https://html.spec.whatwg.org/multipage/grouping-content.html#the-li-element
*/
BOOST_AUTO_TEST_CASE(simple_html_sample_grouping_25)
{
    char32_t const* in = UR"(

Item 1

Item 3

Item 4

)";

    char32_t const* s = UR"(

Item 1

Item 3

Item 4

)";

    BOOST_CHECK(parse(in) == s);
}

BOOST_AUTO_TEST_CASE(simple_html_sample_grouping_26)
{
    char32_t const* in = UR"(

The top 10 movies of all time

Josie and the Pussycats, 2001

Црна мачка, бели мачор, 1998

A Bug's Life, 1998

Toy Story, 1995

Monsters, Inc, 2001

Cars, 2006

Toy Story 2, 1999

Finding Nemo, 2003

The Incredibles, 2004

Ratatouille, 2007

)";

    char32_t const* s = UR"(

The top 10 movies of all time

Josie and the Pussycats, 2001

Црна мачка, бели мачор, 1998

A Bug's Life, 1998

Toy Story, 1995

Monsters, Inc, 2001

Cars, 2006

Toy Story 2, 1999

Finding Nemo, 2003

The Incredibles, 2004

Ratatouille, 2007

)";

    BOOST_CHECK(parse(in) == s);
}

BOOST_AUTO_TEST_CASE(simple_html_sample_grouping_27)
{
    char32_t const* in = UR"(

The top 10 movies of all time

Josie and the Pussycats, 2001

Црна мачка, бели мачор, 1998

A Bug's Life, 1998

Toy Story, 1995

Monsters, Inc, 2001

Cars, 2006

Toy Story 2, 1999

Finding Nemo, 2003

The Incredibles, 2004

Ratatouille, 2007

)";

    char32_t const* s = UR"(

The top 10 movies of all time

Josie and the Pussycats, 2001

Црна мачка, бели мачор, 1998

A Bug's Life, 1998

Toy Story, 1995

Monsters, Inc, 2001

Cars, 2006

Toy Story 2, 1999

Finding Nemo, 2003

The Incredibles, 2004

Ratatouille, 2007

)";

    BOOST_CHECK(parse(in) == s);
}

/*
4.4.9 The dl element

https://html.spec.whatwg.org/multipage/grouping-content.html#the-dl-element
*/
BOOST_AUTO_TEST_CASE(simple_html_sample_grouping_28)
{
    char32_t const* in = UR"(

 Authors

 John

 Luke

 Editor

 Frank

)";

    char32_t const* s = UR"(

 Authors

 John

 Luke

 Editor

 Frank

)";

    BOOST_CHECK(parse(in) == s);
}

BOOST_AUTO_TEST_CASE(simple_html_sample_grouping_29)
{
    char32_t const* in = UR"(

 <dfn>color</dfn>

 <dfn>colour</dfn>

 A sensation which (in humans) derives from the ability of
 the fine structure of the eye to distinguish three differently
 filtered analyses of a view.

)";

    char32_t const* s = UR"(

 <dfn>color</dfn>

 <dfn>colour</dfn>

 A sensation which (in humans) derives from the ability of
 the fine structure of the eye to distinguish three differently
 filtered analyses of a view.

)";

    BOOST_CHECK(parse(in) == s);
}

BOOST_AUTO_TEST_CASE(simple_html_sample_grouping_30)
{
    char32_t const* in = UR"(

 Last modified time

 2004-12-23T23:33Z

 Recommended update interval

 60s

 Authors

 Editors

 Robert Rothman

 Daniel Jackson

)";

    char32_t const* s = UR"(

 Last modified time

 2004-12-23T23:33Z

 Recommended update interval

 60s

 Authors

 Editors

 Robert Rothman

 Daniel Jackson

)";

    BOOST_CHECK(parse(in) == s);
}

BOOST_AUTO_TEST_CASE(simple_html_sample_grouping_31)
{
    char32_t const* in = UR"(
Determine the victory points as follows (use the
first matching case):

 If you have exactly five gold coins

 You get five victory points

 If you have one or more gold coins, and you have one or more silver coins

 You get two victory points

 If you have one or more silver coins

 You get one victory point

 Otherwise

 You get no victory points

)";

    char32_t const* s = UR"(
Determine the victory points as follows (use the
first matching case):

 If you have exactly five gold coins

 You get five victory points

 If you have one or more gold coins, and you have one or more silver coins

 You get two victory points

 If you have one or more silver coins

 You get one victory point

 Otherwise

 You get no victory points

)";

    BOOST_CHECK(parse(in) == s);
}

BOOST_AUTO_TEST_CASE(simple_html_sample_grouping_32)
{
    char32_t const* in = UR"(

<dfn>Apartment</dfn>, n.

An execution context grouping one or more threads with one or
 more COM objects.

<dfn>Flat</dfn>, n.

A deflated tire.

<dfn>Home</dfn>, n.

The user's login directory.

)";

    char32_t const* s = UR"(

<dfn>Apartment</dfn>, n.

An execution context grouping one or more threads with one or
 more COM objects.

<dfn>Flat</dfn>, n.

A deflated tire.

<dfn>Home</dfn>, n.

The user's login directory.

)";

    BOOST_CHECK(parse(in) == s);
}

BOOST_AUTO_TEST_CASE(simple_html_sample_grouping_33)
{
    char32_t const* in = UR"(

Café ou Chocolat Liégeois

   3.50
   <data itemprop="priceCurrency" value="EUR">€</data>

   2 boules Café ou Chocolat, 1 boule Vanille, sause café ou chocolat, chantilly

Américaine

   3.50
   <data itemprop="priceCurrency" value="EUR">€</data>

   1 boule Crème brûlée, 1 boule Vanille, 1 boule Caramel, chantilly

)";

    char32_t const* s = UR"(

Café ou Chocolat Liégeois

   3.50
   <data itemprop="priceCurrency" value="EUR">€</data>

   2 boules Café ou Chocolat, 1 boule Vanille, sause café ou chocolat, chantilly

Américaine

   3.50
   <data itemprop="priceCurrency" value="EUR">€</data>

   1 boule Crème brûlée, 1 boule Vanille, 1 boule Caramel, chantilly

)";

    BOOST_CHECK(parse(in) == s);
}

BOOST_AUTO_TEST_CASE(simple_html_sample_grouping_34)
{
    char32_t const* in = UR"(

Café ou Chocolat Liégeois

   3.50
   <data itemprop="priceCurrency" value="EUR">€</data>

   2 boules Café ou Chocolat, 1 boule Vanille, sause café ou chocolat, chantilly

Américaine

   3.50
   <data itemprop="priceCurrency" value="EUR">€</data>

   1 boule Crème brûlée, 1 boule Vanille, 1 boule Caramel, chantilly

)";

    char32_t const* s = UR"(

Café ou Chocolat Liégeois

   3.50
   <data itemprop="priceCurrency" value="EUR">€</data>

   2 boules Café ou Chocolat, 1 boule Vanille, sause café ou chocolat, chantilly

Américaine

   3.50
   <data itemprop="priceCurrency" value="EUR">€</data>

   1 boule Crème brûlée, 1 boule Vanille, 1 boule Caramel, chantilly

)";

    BOOST_CHECK(parse(in) == s);
}

BOOST_AUTO_TEST_CASE(simple_html_sample_grouping_35)
{
    char32_t const* in = UR"(

  Café ou Chocolat Liégeois

  3.50
  <data itemprop="priceCurrency" value="EUR">€</data>

  2 boules Café ou Chocolat, 1 boule Vanille, sause café ou chocolat, chantilly

  Américaine

  3.50
  <data itemprop="priceCurrency" value="EUR">€</data>

  1 boule Crème brûlée, 1 boule Vanille, 1 boule Caramel, chantilly

)";

    char32_t const* s = UR"(

  Café ou Chocolat Liégeois

  3.50
  <data itemprop="priceCurrency" value="EUR">€</data>

  2 boules Café ou Chocolat, 1 boule Vanille, sause café ou chocolat, chantilly

  Américaine

  3.50
  <data itemprop="priceCurrency" value="EUR">€</data>

  1 boule Crème brûlée, 1 boule Vanille, 1 boule Caramel, chantilly

)";

    BOOST_CHECK(parse(in) == s);
}

/*
4.4.10 The dt element

https://html.spec.whatwg.org/multipage/grouping-content.html#the-dt-element
*/
BOOST_AUTO_TEST_CASE(simple_html_sample_grouping_36)
{
    char32_t const* in = UR"(

FAQ

What do we want?

Our data.

When do we want it?

Now.

Where is it?

We are not sure.

)";

    char32_t const* s = UR"(

FAQ

What do we want?

Our data.

When do we want it?

Now.

Where is it?

We are not sure.

)";

    BOOST_CHECK(parse(in) == s);
}

/*
4.4.11 The dd element

https://html.spec.whatwg.org/multipage/grouping-content.html#the-dd-element
*/
BOOST_AUTO_TEST_CASE(simple_html_sample_grouping_37)
{
    char32_t const* in = UR"(

<dfn>happiness</dfn>

/'hæ p. nes/

n.

The state of being happy.

Good fortune; success. <q>Oh happiness! It worked!</q>

<dfn>rejoice</dfn>

/ri jois'/

v.intr. To be delighted oneself.

v.tr. To cause one to be delighted.

)";

    char32_t const* s = UR"(

<dfn>happiness</dfn>

/'hæ p. nes/

n.

The state of being happy.

Good fortune; success. <q>Oh happiness! It worked!</q>

<dfn>rejoice</dfn>

/ri jois'/

v.intr. To be delighted oneself.

v.tr. To cause one to be delighted.

)";

    BOOST_CHECK(parse(in) == s);
}

/*
4.4.12 The figure element

https://html.spec.whatwg.org/multipage/grouping-content.html#the-figure-element
*/
BOOST_AUTO_TEST_CASE(simple_html_sample_grouping_38)
{
    char32_t const* in = UR"(
In listing 4 we see the primary core interface
API declaration.

Listing 4. The primary core interface API declaration.

interface PrimaryCore {
 boolean verifyDataLine();
 void sendData(in sequence<byte> data);
 void initSelfDestruct();
}

The API is designed to use UTF-8.
)";

    char32_t const* s = UR"(
In listing 4 we see the primary core interface
API declaration.

Listing 4. The primary core interface API declaration.

interface PrimaryCore {
 boolean verifyDataLine();
 void sendData(in sequence<byte> data);
 void initSelfDestruct();
}

The API is designed to use UTF-8.
)";

    BOOST_CHECK(parse(in) == s);
}

BOOST_AUTO_TEST_CASE(simple_html_sample_grouping_39)
{
    char32_t const* in = UR"(<!DOCTYPE HTML>

<title>Bubbles at work — My Gallery™</title>

Bubbles at work

Prev — Next)";

    char32_t const* s = UR"(<!DOCTYPE html><title>Bubbles at work — My Gallery™</title>

Bubbles at work

Prev — Next)";

    BOOST_CHECK(parse(in) == s);
}

BOOST_AUTO_TEST_CASE(simple_html_sample_grouping_40)
{
    char32_t const* in = UR"(
Malinko's comics

This case centered on some sort of "intellectual property"
infringement related to a comic (see Exhibit A). The suit started
after a trailer ending with these words:

...was aired. A lawyer, armed with a Bigger Notebook, launched a
preemptive strike using snowballs. A complete copy of the trailer is
included with Exhibit B.

Exhibit A. The alleged rough copy comic.

 <video src="ex-b.mov"></video>

Exhibit B. The Rough Copy trailer.

The case was resolved out of court.)";

    char32_t const* s = UR"(
Malinko's comics

This case centered on some sort of "intellectual property"
infringement related to a comic (see Exhibit A). The suit started
after a trailer ending with these words:

...was aired. A lawyer, armed with a Bigger Notebook, launched a
preemptive strike using snowballs. A complete copy of the trailer is
included with Exhibit B.

Exhibit A. The alleged rough copy comic.

 <video src="ex-b.mov"></video>

Exhibit B. The Rough Copy trailer.

The case was resolved out of court.
)";

    BOOST_CHECK(parse(in) == s);
}

BOOST_AUTO_TEST_CASE(simple_html_sample_grouping_41)
{
    char32_t const* in = UR"(

'Twas brillig, and the slithy toves

 Did gyre and gimble in the wabe;

 All mimsy were the borogoves,

 And the mome raths outgrabe.

Jabberwocky (first verse). Lewis Carroll, 1832-98

)";

    char32_t const* s = UR"(

'Twas brillig, and the slithy toves

 Did gyre and gimble in the wabe;

 All mimsy were the borogoves,

 And the mome raths outgrabe.

Jabberwocky (first verse). Lewis Carroll, 1832-98

)";

    BOOST_CHECK(parse(in) == s);
}

BOOST_AUTO_TEST_CASE(simple_html_sample_grouping_42)
{
    char32_t const* in = UR"(

The castle through the ages: 1423, 1858, and 1999 respectively.

Etching. Anonymous, ca. 1423.

Oil-based paint on canvas. Maria Towle, 1858.

Film photograph. Peter Jankle, 1999.

)";

    char32_t const* s = UR"(

The castle through the ages: 1423, 1858, and 1999 respectively.

Etching. Anonymous, ca. 1423.

Oil-based paint on canvas. Maria Towle, 1858.

Film photograph. Peter Jankle, 1999.

)";

    BOOST_CHECK(parse(in) == s);
}

BOOST_AUTO_TEST_CASE(simple_html_sample_grouping_43)
{
    char32_t const* in = UR"(

The castle through the ages: 1423, 1858, and 1999 respectively.

)";

    char32_t const* s = UR"(

The castle through the ages: 1423, 1858, and 1999 respectively.

)";

    BOOST_CHECK(parse(in) == s);
}

BOOST_AUTO_TEST_CASE(simple_html_sample_grouping_44)
{
    char32_t const* in = UR"(

Fiscal negotiations stumble in Congress as deadline nears

Barack Obama and Harry Reid. White House press photograph.

Negotiations in Congress to end the fiscal impasse sputtered on Tuesday, leaving both chambers
 grasping for a way to reopen the government and raise the country's borrowing authority with a
 Thursday deadline drawing near.

 ...

)";

    char32_t const* s = UR"(

Fiscal negotiations stumble in Congress as deadline nears

Barack Obama and Harry Reid. White House press photograph.

Negotiations in Congress to end the fiscal impasse sputtered on Tuesday, leaving both chambers
 grasping for a way to reopen the government and raise the country's borrowing authority with a
 Thursday deadline drawing near.

 ...

)";

    BOOST_CHECK(parse(in) == s);
}

/*
4.4.13 The figcaption element

https://html.spec.whatwg.org/multipage/grouping-content.html#the-figcaption-element
*/
BOOST_AUTO_TEST_CASE(simple_html_sample_grouping_45)
{
    char32_t const* in = UR"(

A duck.

Photograph courtesy of 🌟 News.

)";

    char32_t const* s = UR"(

A duck.

Photograph courtesy of 🌟 News.

)";

    BOOST_CHECK(parse(in) == s);
}

BOOST_AUTO_TEST_CASE(simple_html_sample_grouping_46)
{
    char32_t const* in = UR"(

Average rent for 3-room apartments, excluding non-profit apartments

Zürich’s Statistics Office — <time datetime=2017-11-14>14 November 2017</time>

)";

    char32_t const* s = UR"(

Average rent for 3-room apartments, excluding non-profit apartments

Zürich’s Statistics Office — <time datetime="2017-11-14">14 November 2017</time>

)";

    BOOST_CHECK(parse(in) == s);
}

/*
4.4.14 The main element

https://html.spec.whatwg.org/multipage/grouping-content.html#the-main-element
*/
BOOST_AUTO_TEST_CASE(simple_html_sample_grouping_47)
{
    char32_t const* in = UR"(<!DOCTYPE html>

<title>RPG System 17</title>

System Eighteen

 ← System 17
 RPXIX →

This system has no HP mechanic, so there's no healing.

Character creation

Attributes (magic, strength, agility) are purchased at the cost of one point per level.

Rolls

Each encounter, roll the dice for all your skills. If you roll more than the opponent, you win.

Copyright © 2013

)";

    char32_t const* s = UR"(<!DOCTYPE html><title>RPG System 17</title>

System Eighteen

 ← System 17
 RPXIX →

This system has no HP mechanic, so there's no healing.

Character creation

Attributes (magic, strength, agility) are purchased at the cost of one point per level.

Rolls

Each encounter, roll the dice for all your skills. If you roll more than the opponent, you win.

Copyright © 2013

)";

    BOOST_CHECK(parse(in) == s);
}

BOOST_AUTO_TEST_CASE(simple_html_sample_grouping_48)
{
    char32_t const* in = UR"(<!doctype html>

<meta charset=utf-8>
<title> … </title>
<link rel=stylesheet href=spa.css>

 Home
 About
 Contact

Home

 …

About

 …

Contact

 …

Made with ❤ by Example 👻.)";

    char32_t const* s = UR"(<!DOCTYPE html><meta charset="utf-8">
<title> … </title>
<link rel="stylesheet" href="spa.css">

 Home
 About
 Contact

Home

 …

About

 …

Contact

 …

Made with ❤ by Example 👻.)";

    BOOST_CHECK(parse(in) == s);
}

/*
4.4.15 The div element

https://html.spec.whatwg.org/multipage/grouping-content.html#the-div-element
*/
BOOST_AUTO_TEST_CASE(simple_html_sample_grouping_49)
{
    char32_t const* in = UR"(

My use of language and my cats

My cat's behavior hasn't changed much since her absence, except
 that she plays her new physique to the neighbors regularly, in an
 attempt to get pets.

My other cat, coloured black and white, is a sweetie. He followed
  us to the pool today, walking down the pavement with us. Yesterday
  he apparently visited our neighbours. I wonder if he recognises that
  their flat is a mirror image of ours.

Hm, I just noticed that in the last paragraph I used British
  English. But I'm supposed to write in American English. So I
  shouldn't say "pavement" or "flat" or "colour"...

I should say "sidewalk" and "apartment" and "color"!

)";

    char32_t const* s = UR"(

My use of language and my cats

My cat's behavior hasn't changed much since her absence, except
 that she plays her new physique to the neighbors regularly, in an
 attempt to get pets.

My other cat, coloured black and white, is a sweetie. He followed
  us to the pool today, walking down the pavement with us. Yesterday
  he apparently visited our neighbours. I wonder if he recognises that
  their flat is a mirror image of ours.

Hm, I just noticed that in the last paragraph I used British
  English. But I'm supposed to write in American English. So I
  shouldn't say "pavement" or "flat" or "colour"...

I should say "sidewalk" and "apartment" and "color"!

)";

    BOOST_CHECK(parse(in) == s);
}

BOOST_AUTO_TEST_SUITE_END()

max_stars_repo_name: wordring/wordring

max_issues_repo_name: wordring/libwordring

max_forks_repo_name: wordring/libwordring


text: #include <boost/signals2/mutex.hpp>

ext: hpp

max_stars_repo_name: miathedev/BoostForArduino

max_issues_repo_name: miathedev/BoostForArduino

max_forks_repo_name: miathedev/BoostForArduino


text:
//          Copyright Gavin Band 2008 - 2012.
// Distributed under the Boost Software License, Version 1.0.
//    (See accompanying file LICENSE_1_0.txt or copy at
//          http://www.boost.org/LICENSE_1_0.txt)

#include <iostream>
#include <string>
#include "../config.hpp"
#if HAVE_BOOST_FILESYSTEM
	#include <boost/filesystem.hpp>
	namespace BFS = boost::filesystem ;
#endif
#include "genfile/snp_data_utils.hpp"
#include "genfile/gen.hpp"
#include "genfile/SNPDataSource.hpp"
#include "genfile/ImputeHaplotypesSNPDataSource.hpp"
#include "genfile/string_utils/slice.hpp"
#include "genfile/FileUtils.hpp"
#include "genfile/VariantDataReader.hpp"

namespace genfile {
	ImputeHaplotypesSNPDataSource::ImputeHaplotypesSNPDataSource( std::string const& filename, Chromosome chromosome )
		: m_legend_filename( find_legend_file( filename ) ),
		  m_haplotypes_filename( filename ),
		  m_compression_type( get_compression_type_indicated_by_filename( m_haplotypes_filename ) ),
		  m_number_of_samples( 0 ),
		  m_chromosome( chromosome ),
		  m_good( true )
	{
		setup( filename, m_compression_type ) ;
	}

	ImputeHaplotypesSNPDataSource::ImputeHaplotypesSNPDataSource( std::string const& filename, Chromosome chromosome, CompressionType compression_type )
		: m_legend_filename( find_legend_file( filename ) ),
		  m_haplotypes_filename( filename ),
		  m_compression_type( compression_type ),
		  m_number_of_samples( 0 ),
		  m_chromosome( chromosome ),
		  m_good( true )
	{
		setup( filename, m_compression_type ) ;
	}

	namespace impl {
		// borrowed this code from http://stackoverflow.com/questions/874134/find-if-string-endswith-another-string-in-c.
		bool has_ending( std::string const& a_string, std::string const& ending )
		{
			bool result = false ;
		    if( a_string.length() >= ending.length() ) {
		        result = ( 0 == a_string.compare( a_string.length() - ending.length(), ending.length(), ending ) ) ;
		    }
			return result ;
		}

		std::vector< VariantIdentifyingData > read_legend( std::string const& filename, Chromosome const& chromosome, std::istream& stream ) {
			using string_utils::slice ;
			std::string line ;
			std::getline( stream, line ) ;
			if( !stream ) {
				throw MalformedInputError( filename, 0 ) ;
			}
			std::vector< slice > header_elts = slice( line ).split( " " ) ;
			if( header_elts.size() < 4 ) {
				throw MalformedInputError( filename, 0 ) ;
			}

			std::vector< VariantIdentifyingData > result ;
			while( std::getline( stream, line )) {
				std::vector< slice > elts = slice( line ).split( " " ) ;
				if( elts.size() != header_elts.size() ) {
					throw MalformedInputError( filename, result.size() + 1 ) ;
				}
				std::string allele1 = elts[2] ;
				std::string allele2 = elts[3] ;

				result.push_back(
					VariantIdentifyingData(
						elts[0],
						GenomePosition( chromosome, string_utils::to_repr< Position >( elts[1] ) ),
						allele1,
						allele2
					)
				) ;
			}
			return result ;
		}
	}

	std::string ImputeHaplotypesSNPDataSource::find_legend_file( std::string const& haps_filename ) const {
		std::string result ;
#if HAVE_BOOST_FILESYSTEM
		// look for a similar-named file
		if( impl::has_ending( haps_filename, ".haps" ) ) {
			result = haps_filename.substr( 0, haps_filename.size() - 5 ) ;
		} else if( impl::has_ending( haps_filename, ".haps.gz" ) ) {
			result = haps_filename.substr( 0, haps_filename.size() - 8 ) ;
		} else if( impl::has_ending( haps_filename, ".hap" ) ) {
			result = haps_filename.substr( 0, haps_filename.size() - 4 ) ;
		} else if( impl::has_ending( haps_filename, ".hap.gz" ) ) {
			result = haps_filename.substr( 0, haps_filename.size() - 7 ) ;
		}

		if( BFS::exists( result + ".legend" ) ) {
			result += ".legend" ;
		} else if( BFS::exists( result + ".legend.gz" )) {
			result += ".legend.gz" ;
		}
		else {
			throw genfile::InputError( result + ".legend[.gz]", "I could not find a legend file matching \"" + haps_filename + "\"." ) ;
		}
#else
		result = replace_or_add_extension( filename, ".legend" ) ;
#endif
		return result ;
	}

	void ImputeHaplotypesSNPDataSource::setup( std::string const& filename, CompressionType compression_type ) {
		std::auto_ptr< std::istream > legend_file = open_text_file_for_input( m_legend_filename ) ;
		m_snps = impl::read_legend( m_legend_filename, m_chromosome, *legend_file ) ;
		m_stream_ptr = open_text_file_for_input( m_haplotypes_filename, compression_type ) ;
		read_header_data() ;
		reset_to_start() ;
	}

	void ImputeHaplotypesSNPDataSource::setup( std::auto_ptr< std::istream > stream_ptr ) {
		m_stream_ptr = stream_ptr ;
		read_header_data() ;
		reset_to_start() ;
	}

	void ImputeHaplotypesSNPDataSource::read_header_data() {
		std::string line ;
		std::getline( *m_stream_ptr, line ) ;
		if( *m_stream_ptr ) {
			// deal with trailing space which is sometimes found in IMPUTE haplotype files
			if( line.size() > 0 && line[ line.size() - 1 ] == ' ' ) {
				line.resize( line.size() - 1 ) ;
			}
			using string_utils::slice ;
			std::vector< slice > elts = slice( line ).split( " " ) ;
			if( elts.size() % 2 != 0 ) {
				throw MalformedInputError( m_haplotypes_filename, 0 ) ;
			}

			m_number_of_samples = elts.size() / 2 ;
		}
		else {
			m_number_of_samples = 0 ;
		}
	}

	void ImputeHaplotypesSNPDataSource::reset_to_start_impl() {
		stream().clear() ;
		stream().seekg( 0 ) ;
		if( !stream() ) {
			// oh, dear, seeking failed.  Reopen the file instead
			m_stream_ptr = open_text_file_for_input( m_haplotypes_filename, m_compression_type ) ;
		}
		if( !stream() ) {
			throw OperationFailedError( "genfile::ImputeHaplotypesSNPDataSource::reset_to_start_impl()", get_source_spec(), "reset to start" ) ;
		}
		m_good = true ;
	}

	SNPDataSource::Metadata ImputeHaplotypesSNPDataSource::get_metadata() const {
		std::map< std::string, std::string > format ;
		format[ "ID" ] = "GT" ;
		format[ "Type" ] = "String" ;
		format[ "Number" ] = "1" ;
		format[ "Description" ] = "Genotype" ;
		SNPDataSource::Metadata result ;
		result.insert( std::make_pair( "FORMAT", format )) ;
		return result ;
	}

	void ImputeHaplotypesSNPDataSource::get_snp_identifying_data_impl(
		VariantIdentifyingData* result
	) {
		if( number_of_snps_read() < m_snps.size() ) {
			VariantIdentifyingData const& snp = m_snps[ number_of_snps_read() ] ;
			*result = snp ;
		} else {
			m_good = false ;
		}
	}

	namespace impl {
		struct ImputeHaplotypesSNPDataSourceReader: public VariantDataReader {
			typedef string_utils::slice slice ;

			ImputeHaplotypesSNPDataSourceReader(
				ImputeHaplotypesSNPDataSource const& source,
				std::size_t snp_index,
				std::string& line
			):
				m_source( source ),
				m_snp_index( snp_index )
			{
				line.swap( m_line ) ;
			}

			ImputeHaplotypesSNPDataSourceReader& get( std::string const& spec, PerSampleSetter& setter ) {
				if( m_elts.size() != 2 * m_source.number_of_samples() ) {
					m_elts = slice( m_line ).split( " " ) ;
				}
				if( m_elts.size() != 2 * m_source.number_of_samples() ) {
					throw MalformedInputError( m_source.get_source_spec(), m_snp_index ) ;
				}

				setter.initialise( m_source.number_of_samples(), 2 ) ;
				for( std::size_t i = 0; i < m_source.number_of_samples(); ++i ) {
					if( m_elts[2*i].size() != 1 ) {
						throw MalformedInputError( m_source.get_source_spec(), m_snp_index, 2*i ) ;
					}
					if( m_elts[(2*i)+1].size() != 1 ) {
						throw MalformedInputError( m_source.get_source_spec(), m_snp_index, 2*i ) ;
					}
					setter.set_sample( i ) ;
					uint32_t ploidy = ( m_elts[(2*i)+1] == "-" ) ? 1 : 2 ;
					setter.set_number_of_entries( ploidy, ploidy, ePerOrderedHaplotype, eAlleleIndex ) ;
					for( std::size_t j = 0; j < ploidy; ++j ) {
						try {
							if( m_elts[2*i+j][0] == '.' || m_elts[2*i+j] == "NA" ) {
								setter.set_value( j, MissingValue() ) ;
							} else {
								setter.set_value( j, string_utils::to_repr< Integer >( m_elts[ 2*i+j ] )) ;
							}
						}
						catch( string_utils::StringConversionError const& e ) {
							throw MalformedInputError( m_source.get_source_spec(), m_snp_index, 2*i + j ) ;
						}
					}
				}
				return *this ;
			}

			std::size_t get_number_of_samples() const { return m_source.number_of_samples() ; }

			bool supports( std::string const& spec ) const {
				return spec == "GT" || spec == ":genotypes:" ;
			}

			void get_supported_specs( SpecSetter setter ) const {
				setter( "GT", "Float" ) ;
				setter( ":genotypes:", "Float" ) ;
			}

			private:
				ImputeHaplotypesSNPDataSource const& m_source ;
				std::size_t const m_snp_index ;
				std::string m_line ;
				std::vector< slice > m_elts ;
		} ;
	}

	VariantDataReader::UniquePtr ImputeHaplotypesSNPDataSource::read_variant_data_impl() {
		assert( m_good ) ;
		std::size_t snp_index = number_of_snps_read() ;

		using string_utils::slice ;
		std::string line ;
		std::getline( *m_stream_ptr, line ) ;

		if( !*this ) {
			throw MalformedInputError( get_source_spec(), snp_index ) ;
		}

		return VariantDataReader::UniquePtr(
			new impl::ImputeHaplotypesSNPDataSourceReader(
				*this,
				snp_index,
				line
			)
		) ;
	}

	void ImputeHaplotypesSNPDataSource::ignore_snp_probability_data_impl() {
		std::string line ;
		std::getline( *m_stream_ptr, line ) ;
	}

}

max_stars_repo_name: gavinband/bingwa

max_issues_repo_name: gavinband/bingwa

max_forks_repo_name: gavinband/bingwa