//
// LDASTools frameCPP - A library implementing the LIGO/Virgo frame
// specification
//
// Copyright (C) 2018 California Institute of Technology
//
// LDASTools frameCPP is free software; you may redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 (GPLv2) of the
// License or at your discretion, any later version.
//
// LDASTools frameCPP is distributed in the hope that it will be useful, but
// without any warranty or even the implied warranty of merchantability
// or fitness for a particular purpose. See the GNU General Public
// License (GPLv2) for more details.
//
// Neither the names of the California Institute of Technology (Caltech),
// The Massachusetts Institute of Technology (M.I.T), The Laser
// Interferometer Gravitational-Wave Observatory (LIGO), nor the names
// of its contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// You should have received a copy of the licensing terms for this
// software included in the file LICENSE located in the top-level
// directory of this package. If you did not, you can view a copy at
// http://dcc.ligo.org/M1500244/LICENSE
//

#if HAVE_CONFIG_H
#include <framecpp_config.h>
#endif /* HAVE_CONFIG_H */

#include <sys/types.h>
#include <dirent.h>
#include <stdarg.h>
#include <unistd.h>

#include <algorithm>
#include <fstream>
#include <iostream>
#include <sstream>

#include <boost/shared_array.hpp>
#include <boost/shared_ptr.hpp>

#if HAVE_LIBFRAME
#include "ldastoolsal/types.hh"

#define FrameCPPTypesHH

bool LIBFRAME_VERIFICATION = true;

#if DEFINE_FR_LONG_LONG
#define FR_LONG_LONG
#else
#undef FR_LONG_LONG
#endif /* DEFINE_FR_LONG_LONG */

#include "FrameL.h"

#undef DEBUG_TEST

const bool words_bigendian(
#if WORDS_BIGENDIAN
    true
#else
    false
#endif
);

inline void
EnableFrameL( bool Value )
{
    LIBFRAME_VERIFICATION = Value;
}

#define LIBFRAME_LITTLE_ENDIAN_RAW_HACK 1

#else /* HAVE_LIBFRAME */
#define EnableFrameL( a )
#endif /* HAVE_LIBFRAME */

#define TEST_FILE_COMPARISON 1

#define TEST_BUILDING_BLOCKS 1
#define TEST_RAW 1
#define TEST_GZIP 1
#define TEST_DIFF_GZIP 1
#define TEST_ZERO_SUPPRESS 1
#define TEST_ZERO_SUPPRESS_SHORT 1
#define TEST_ZERO_SUPPRESS_INT_FLOAT 1
#define TEST_ZERO_SUPPRESS_OTHERWISE_GZIP 1
#define TEST_ZSTD 1
#define TEST_DIFF_ZSTD 1
#define PROBLEM_CASES 1

#define BOOST_TEST_MAIN
#include <boost/test/included/unit_test.hpp>

#include "ldastoolsal/unordered_map.hh"
#include "ldastoolsal/regex.hh"
#include "ldastoolsal/regexmatch.hh"

#include "framecpp/Common/Compression.hh"
#include "framecpp/Common/CompressionDifferential.hh"
#include "framecpp/Common/CompressionZeroSuppress.hh"

#include "framecpp/GPSTime.hh"

#include "framecpp/FrameH.hh"
#include "framecpp/FrAdcData.hh"
#include "framecpp/FrRawData.hh"
#include "framecpp/FrVect.hh"
#include "framecpp/IFrameStream.hh"
#include "framecpp/OFrameStream.hh"

using std::filebuf;

using FrameCPP::GPSTime;
using LDASTools::AL::unordered_map;

typedef FrameCPP::Common::FrameBuffer< filebuf > FrameBuffer;
typedef FrameCPP::Compression::output_type       data_type;

using FrameCPP::IFrameStream;
using FrameCPP::OFrameStream;

static const INT_4S TEST_GZIP_LEVEL_MIN = 1;
static const INT_4S TEST_GZIP_LEVEL_MAX = 9;

static const INT_4S TEST_DIFF_GZIP_LEVEL_MIN = 1;
static const INT_4S TEST_DIFF_GZIP_LEVEL_MAX = 9;

static const INT_4S TEST_ZSTD_LEVEL_MIN = -7;
static const INT_4S TEST_ZSTD_LEVEL_MAX = 22;

static const INT_4S TEST_DIFF_ZSTD_LEVEL_MIN = -7;
static const INT_4S TEST_DIFF_ZSTD_LEVEL_MAX = 22;

inline bool
DUMP_DATA( )
{
    static bool initialized = { false };
    static bool dump_data = { false };

    if ( !initialized )
    {
        //---------------------------------------------------------------------
        // Determine if the program is to do comparisons or generate a frame
        //   file with compressed data.
        //---------------------------------------------------------------------
        if ( ::getenv( "DUMP_DATA" ) != (char*)NULL )
        {
            std::string answer( "no" );
            if ( answer.compare( ::getenv( "DUMP_DATA" ) ) != 0 )
            {
                dump_data = true;
            }
        }
        initialized = true;
    }
    return dump_data;
}

#if HAVE_LIBFRAME
extern "C" {
extern char FrBuf[];
}

#define FL_DATA_TYPE( A, B )                                                   \
    template <>                                                                \
    int fl_data_type< A >( )                                                   \
    {                                                                          \
        return B;                                                              \
    }
#else /* HAVE_LIBFRAME */
#define FL_DATA_TYPE( A, B )
#endif /* HAVE_LIBFRAME */

#define METHOD( A )                                                            \
    case FrameCPP::FrVect::A:                                                  \
        return #A
#define DATA_TYPE( A, B )                                                      \
    FL_DATA_TYPE( A, B )                                                       \
    template <>                                                                \
    std::string data_name_type< A >( )                                         \
    {                                                                          \
        return #A;                                                             \
    }

INT_2S sc1[ 256 ] = {
    6211, 6206, 6198, 6189, 6184, 6174, 6165, 6153, 6142, 6134, 6124, 6112,
    6099, 6091, 6084, 6072, 6060, 6048, 6040, 6028, 6012, 5994, 5981, 5968,
    5949, 5931, 5915, 5901, 5888, 5870, 5850, 5836, 5822, 5803, 5781, 5762,
    5746, 5727, 5709, 5690, 5678, 5668, 5654, 5642, 5630, 5623, 5612, 5599,
    5585, 5572, 5560, 5547, 5531, 5518, 5507, 5499, 5494, 5489, 5483, 5481,
    5480, 5478, 5474, 5468, 5465, 5462, 5457, 5451, 5448, 5450, 5452, 5452,
    5454, 5461, 5468, 5473, 5474, 5476, 5480, 5482, 5480, 5477, 5479, 5484,
    5484, 5485, 5489, 5496, 5502, 5504, 5507, 5515, 5521, 5525, 5528, 5531,
    5540, 5545, 5551, 5555, 5562, 5571, 5580, 5584, 5590, 5599, 5606, 5615,
    5621, 5626, 5636, 5645, 5653, 5661, 5670, 5681, 5692, 5704, 5712, 5718,
    5730, 5738, 5743, 5745, 5747, 5753, 5753, 5752, 5751, 5754, 5759, 5759,
    5761, 5764, 5771, 5775, 5773, 5774, 5778, 5782, 5784, 5784, 5786, 5795,
    5804, 5809, 5815, 5830, 5842, 5852, 5862, 5872, 5887, 5899, 5914, 5926,
    5942, 5964, 5981, 6001, 6020, 6042, 6066, 6083, 6101, 6121, 6141, 6160,
    6177, 6194, 6212, 6230, 6245, 6261, 6275, 6290, 6306, 6318, 6327, 6337,
    6350, 6358, 6364, 6373, 6383, 6393, 6402, 6407, 6415, 6426, 6431, 6433,
    6437, 6440, 6443, 6442, 6439, 6439, 6441, 6441, 6438, 6434, 6437, 6437,
    6434, 6430, 6425, 6424, 6420, 6412, 6408, 6404, 6403, 6397, 6391, 6390,
    6389, 6387, 6382, 6378, 6374, 6372, 6367, 6360, 6351, 6345, 6340, 6330,
    6322, 6313, 6307, 6304, 6297, 6289, 6283, 6282, 6275, 6268, 6259, 6255,
    6250, 6241, 6235, 6228, 6224, 6222, 6215, 6206, 6201, 6198, 6190, 6179,
    6167, 6158, 6148, 6137
};

REAL_4 sc2[] = {
    -2.0650132e-01, -2.0650132e-01, -2.0650132e-01, -2.0650132e-01,
    -2.0650132e-01, -2.0650132e-01, -2.0650132e-01, -2.0650132e-01,
    -2.0650132e-01, -2.0650132e-01, -0.0000000e+00, -0.0000000e+00,
    -0.0000000e+00, -0.0000000e+00, -0.0000000e+00, -0.0000000e+00
};

//-----------------------------------------------------------------------
// Frame information
//-----------------------------------------------------------------------
static const GPSTime      FrameStart( 6000000, 0 );
static std::ostringstream FrameName;
static const REAL_8       FrameDT = 1.0;
static const INT_4S       FrameRun = -1; /* Mock data */
static const INT_4U       FrameNumber = 1;
static const INT_4U       NBits = 16;
static INT_4U             ChannelNumber = 1;
static const char*        IFO = "Z1";
static INT_2U             FrameSpecVersion = FRAME_SPEC_CURRENT;
static std::string        SystemType =
#if SIZEOF_LONG == 4
    "32bit"
#elif SIZEOF_LONG == 8
    "64bit"
#else
    "??Bit"
#endif
    ;

boost::shared_ptr< FrameCPP::FrameH > Frame;

namespace
{
    enum wave_form_type
    {
        NO_WAVE_FORM,
        SAW_TOOTH_FALLING,
        SAW_TOOTH_PEAKS,
        SAW_TOOTH_RISING,
        SQUARE_WAVE,
        MAX_WAVE_FORM
    };

#if HAVE_LIBFRAME
    void SetDataCompressed( ::FrVect* Vector,
                            char*     Data,
                            INT_4U    NData,
                            INT_2U    WordSize,
                            INT_4U    NBytes,
                            INT_2U    Compression );
    namespace FrameL
    {
#if ( ( ( FR_VERS > 6024 ) || ( FR_VERS <= 6024 && WORDS_BIGENDIAN ) ) &&      \
      ( DEBUG_TEST ) )
        void Dump( ::FrVect* Vector );
#endif /* */

        inline void
        Decompress( ::FrVect* Vector )
        {
            ::FrVectExpand( Vector );
        }
    } // namespace FrameL
#endif /* HAVE_LIBFRAME */

    class waveform_compression
    {
    private:
        typedef unordered_map< INT_2U, INT_2U > data_type;

        data_type m_waves;

    public:
        waveform_compression(
            FrameCPP::FrVect::compression_scheme_type Default )
        {
            for ( INT_2U x = NO_WAVE_FORM; x < MAX_WAVE_FORM; x++ )
            {
                m_waves[ x ] = Default;
            }
        }

        waveform_compression( FrameCPP::FrVect::compression_scheme_type Default,
                              int                                       Wave,
                              ... )
        {
            va_list ap;
            va_start( ap, Wave );

            wave_form_type wf = wave_form_type( Wave );
            FrameCPP::FrVect::compression_scheme_type cs;

            for ( INT_2U x = NO_WAVE_FORM; x < MAX_WAVE_FORM; x++ )
            {
                m_waves[ x ] = Default;
            }

            while ( wf != NO_WAVE_FORM )
            {
                cs = (FrameCPP::FrVect::compression_scheme_type)va_arg(
                    ap, int /* FrameCPP::FrVect::compression_scheme_type */ );
                m_waves[ wf ] = cs;
                wf = (wave_form_type)va_arg( ap, int /* wave_form_type */ );
            }
            va_end( ap );
        }

        inline FrameCPP::FrVect::compression_scheme_type
        operator( )( wave_form_type WaveForm )
        {
            return (
                FrameCPP::FrVect::compression_scheme_type)m_waves[ WaveForm ];
        }
    };

#if TEST_FILE_COMPARISON
    class FrameFileSet
    {
    private:
        struct file_entry
        {
            std::string                       m_directory;
            boost::shared_ptr< IFrameStream > m_istream;

            inline file_entry( ) : m_directory( "" )
            {
            }
        };

        typedef unordered_map< std::string, struct file_entry >
                                                   frame_mapping_type;
        typedef frame_mapping_type::const_iterator const_iterator;

        frame_mapping_type m_frame_info;

    public:
        FrameFileSet( ){};

        ~FrameFileSet( )
        {
#if 0
      for ( frame_mapping_type::iterator
	      f = m_frame_info.begin( ),
	      last = m_frame_info.end( );
	    f != last;
	    ++f )
      {
	// delete f->second.m_istream;
	// delete f->second.m_buffer;
      }
#endif /* 0 */
        };

        void
        Check( const std::string& ChannelName, const FrameCPP::FrVect& Key )
        {
            data_type expanded;

            for ( const_iterator f = m_frame_info.begin( ),
                                 last = m_frame_info.end( );
                  f != last;
                  ++f )
            {
                std::ostringstream leader;

                leader << " Host["
                       << "v" << FrameSpecVersion
                       << " "
#if WORDS_BIGENDIAN
                          "BigEndian"
#else
                          "LittleEndian"
#endif
                       << " " << SystemType << "]: "
                       << "Using file: " << f->first
                       << " channel: " << ChannelName << " for comparisson: ";

                boost::shared_ptr< FrameCPP::FrAdcData > adc(
                    f->second.m_istream->ReadFrAdcData( 0, ChannelName ) );
                BOOST_TEST_MESSAGE( "DEBUG: "
                                    << " adc is referenced: "
                                    << adc.use_count( ) );
                if ( ( !adc ) || ( adc->RefData( ).size( ) <= 0 ) )
                {
                    std::ostringstream msg;
                    msg << "Unable to read channel " << ChannelName
                        << " from the file " << f->first << ".";
                    throw std::runtime_error( msg.str( ) );
                }
                boost::shared_ptr< FrameCPP::FrVect > data =
                    adc->RefData( )[ 0 ];

                BOOST_TEST_MESSAGE( "DEBUG: "
                                    << " data is referenced: "
                                    << data.use_count( ) );
#if HAVE_LIBFRAME &&                                                           \
    ( ( FR_VERS > 6024 ) || ( FR_VERS <= 6024 && WORDS_BIGENDIAN ) )
                //---------------------------------------------------------------
                // Decompress using FrameL routines.
                //---------------------------------------------------------------
                if ( LIBFRAME_VERIFICATION &&
                     ( ( data->GetCompress( ) & 0xFF ) !=
                       ( FrameCPP::FrVect::RAW & 0xFF ) ) )
                {
                    const CHAR_U* framecppdata = data->GetDataRaw( ).get( );
                    char*         bytes = (char*)malloc( data->GetNBytes( ) );
                    std::copy( framecppdata,
                               framecppdata + data->GetNBytes( ),
                               bytes );
                    const INT_4U ndata = data->GetNData( );
                    const INT_2U wsize = data->GetTypeSize( );
                    //-------------------------------------------------------------
                    // Build a compressed FrameL Vector
                    //-------------------------------------------------------------
                    *FrBuf = '\0';
                    ::FrVect* fl = ( ::FrVect*)NULL;
                    {
                        char name[] = "flversion";
                        char unitx[] = "sec";
                        char unity[] = "unity";

                        fl = ::FrVectNew1D( name,
                                            data->GetType( ),
                                            ndata,
                                            1.0 / ndata,
                                            unitx,
                                            unity );
                    }
                    if ( fl )
                    {
                        SetDataCompressed( fl,
                                           bytes,
                                           ndata,
                                           wsize,
                                           data->GetNBytes( )``,
                                           data->GetCompress( ) );
                        //-----------------------------------------------------------
                        // Decompress the FrameL Vector
                        //-----------------------------------------------------------
                        FrameL::Decompress( fl );
                        //-----------------------------------------------------------
                        // Check the output to see if it compares with the Key
                        //-----------------------------------------------------------
                        if ( Key.GetNBytes( ) == fl->nBytes )
                        {
                            INT_4U size = fl->nBytes;
                            BOOST_TEST_MESSAGE(
                                leader.str( )
                                << "Using FrameL, decompressed file data is "
                                   "the same as the Key" );
                            BOOST_CHECK( std::equal(
                                fl->data,
                                &( fl->data[ size ] ),
                                (char*)( Key.GetDataRaw( ).get( ) ) ) );

                            if ( *FrBuf )
                            {
                                if ( FrBuf[ strlen( FrBuf ) ] == '\n' )
                                {
                                    FrBuf[ strlen( FrBuf ) ] = '\0';
                                }
                                BOOST_CHECK_MESSAGE( " (" << FrBuf << ")" );
                            }
                        }
                        else
                        {
                            BOOST_TEST_MESSAGE(
                                leader.str( )
                                << "Number of bytes differs from the key when "
                                   "decompressed with FrameL" );
                            BOOST_CHECK( false );
                        }
                    }
                    if ( fl )
                    {
                        ::FrVectFree( fl );
                        fl = ( ::FrVect*)NULL;
                    }
                }
#endif /* HAVE_LIBFRAME */
                //---------------------------------------------------------------
                // Decompress using FrameCPP routines.
                //---------------------------------------------------------------
                FrameCPP::FrVect::data_const_pointer_type decompressed(
                    data->GetDataUncompressed( ).get( ) );

                if ( Key.GetNBytes( ) == data->GetNBytes( ) )
                {
                    FrameCPP::FrVect::data_type exp;

                    BOOST_TEST_MESSAGE(
                        leader.str( )
                        << "Using FrameCPP, decompressed file data is the same "
                           "as the Key" );
                    BOOST_CHECK(
                        std::equal( decompressed,
                                    &decompressed[ data->GetNBytes( ) ],
                                    Key.GetDataUncompressed( exp ) ) );
                }
                else
                {
                    BOOST_TEST_MESSAGE(
                        leader.str( )
                        << "Number of bytes differs from the "
                           "key when decompressed with FrameCPP" );
                    BOOST_CHECK( false );
                }
            }
        };

        void
        OpenDir( const std::string& Directory )
        {
            static Regex   frame_regex( "^Z-Compression_.*+[.]gwf" );
            RegexMatch     frame_compare( 1 );
            DIR*           frame_dir = opendir( Directory.c_str( ) );
            struct dirent* dir_entry;

            rewinddir( frame_dir );
            while ( ( dir_entry = readdir( frame_dir ) ) )
            {
                if ( frame_compare.match( frame_regex, dir_entry->d_name ) )
                {
                    //-------------------------------------------------------------
                    // See if this file is already in the list. Iff it is not
                    //   add it to the list of files and open it.
                    //-------------------------------------------------------------
                    if ( m_frame_info.find( dir_entry->d_name ) ==
                         m_frame_info.end( ) )
                    {
                        std::unique_ptr< FrameBuffer > buffer(
                            new FrameBuffer( std::ios::in ) );

                        if ( !buffer.get( ) )
                        {
                            throw std::bad_alloc( );
                        }
                        std::ostringstream fullpath;

                        fullpath << Directory << "/" << dir_entry->d_name;

                        buffer->open( fullpath.str( ).c_str( ),
                                      std::ios::in | std::ios::binary );

                        if ( buffer->is_open( ) )
                        {
                            struct file_entry& f(
                                m_frame_info[ dir_entry->d_name ] );
                            f.m_istream.reset(
                                new IFrameStream( buffer.release( ) ) );
                            if ( !f.m_istream )
                            {
                                throw std::bad_alloc( );
                            }
                            f.m_directory = Directory;
                        }
                        else
                        {
                            BOOST_TEST_MESSAGE( "Unable to open: "
                                                << fullpath.str( )
                                                << " system error: "
                                                << strerror( errno ) );
                        }
                    }
                }
            }
            closedir( frame_dir );
        };

    } FrameFiles;
#endif /* TEST_FILE_COMPARISON */

    inline void
    message_line( )
    {
        BOOST_TEST_MESSAGE(
            "==============================================================" );
    }

    //---------------------------------------------------------------------
    // data_type
    //---------------------------------------------------------------------
    template < class T >
    std::string
    data_name_type( )
    {
        return "";
    }

#if HAVE_LIBFRAME
    template < class T >
    int
    fl_data_type( )
    {
        return ::FR_VECT_END;
    }
#endif /* HAVE_LIBFRAME */

    DATA_TYPE( CHAR_U, ::FR_VECT_C )
    DATA_TYPE( CHAR, ::FR_VECT_C )
    DATA_TYPE( INT_2U, ::FR_VECT_2U )
    DATA_TYPE( INT_2S, ::FR_VECT_2S )
    DATA_TYPE( INT_4U, ::FR_VECT_4U )
    DATA_TYPE( INT_4S, ::FR_VECT_4S )
    DATA_TYPE( INT_8U, ::FR_VECT_8U )
    DATA_TYPE( INT_8S, ::FR_VECT_8S )
    DATA_TYPE( REAL_4, ::FR_VECT_4R )
    DATA_TYPE( REAL_8, ::FR_VECT_8R )
    DATA_TYPE( COMPLEX_8, ::FR_VECT_8C )
    DATA_TYPE( COMPLEX_16, ::FR_VECT_16C )

    //---------------------------------------------------------------------
    // method
    //---------------------------------------------------------------------
    std::string
    method( const FrameCPP::FrVect::compression_scheme_type Method )
    {
        switch ( Method )
        {
            METHOD( RAW );
            METHOD( GZIP );
            METHOD( ZSTD );
#if FRAME_SPEC_CURRENT <= 3
            METHOD( DIFF );
#endif /* FRAME_SPEC_CURRENT <= 3 */
            METHOD( DIFF_GZIP );
            METHOD( DIFF_ZSTD );
            METHOD( ZERO_SUPPRESS );
#if FRAME_SPEC_CURRENT <= 7
            METHOD( ZERO_SUPPRESS_GZIP_OTHER );
#endif /* FRAME_SPEC_CURRENT <= 7 */
            METHOD( ZERO_SUPPRESS_OTHERWISE_GZIP );
            METHOD( ZERO_SUPPRESS_OTHERWISE_ZSTD );
        default:
        {
            std::ostringstream msg;

            msg << "Unknown compression method: " << Method;
            throw std::runtime_error( msg.str( ).c_str( ) );
        }
        break;
        }
    }

    template < typename T >
    inline std::string
    canonical( T Data )
    {
        std::ostringstream retval;

        if ( Data < T( 0 ) )
        {
            retval << "_" << -Data;
        }
        else
        {
            retval << Data;
        }
        return retval.str( );
    }

    template <>
    inline std::string
    canonical< CHAR >( CHAR Data )
    {
        std::ostringstream retval;

        if ( Data < CHAR( 0 ) )
        {
            retval << "_" << (INT_2S)-Data;
        }
        else
        {
            retval << (INT_2S)Data;
        }
        return retval.str( );
    }

    template <>
    inline std::string
    canonical< CHAR_U >( CHAR_U Data )
    {
        std::ostringstream retval;

        retval << (INT_2U)Data;
        return retval.str( );
    }

    template <>
    inline std::string
    canonical< INT_2U >( INT_2U Data )
    {
        std::ostringstream retval;

        retval << Data;
        return retval.str( );
    }

    template <>
    inline std::string
    canonical< INT_4U >( INT_4U Data )
    {
        std::ostringstream retval;

        retval << Data;
        return retval.str( );
    }

    template <>
    inline std::string
    canonical< INT_8U >( INT_8U Data )
    {
        std::ostringstream retval;

        retval << Data;
        return retval.str( );
    }

    template <>
    inline std::string
    canonical< COMPLEX_8 >( COMPLEX_8 Data )
    {
        std::ostringstream retval;

        retval << canonical( Data.real( ) ) << "_" << canonical( Data.imag( ) );

        return retval.str( );
    }

    template <>
    std::string
    canonical< COMPLEX_16 >( COMPLEX_16 Data )
    {
        std::ostringstream retval;

        retval << canonical( Data.real( ) ) << "_" << canonical( Data.imag( ) );

        return retval.str( );
    }

    template < typename T >
    void
    gen_test_names( FrameCPP::FrVect::compression_scheme_type Method,
                    INT_2U                                    Level,
                    const T                                   Start,
                    const T                                   End,
                    const T                                   Inc,
                    INT_4U                                    Samples,
                    const wave_form_type                      WaveForm,
                    std::ostringstream&                       TestName,
                    std::ostringstream&                       ChannelName )
    {
        std::string wave_form;

        switch ( WaveForm )
        {
        case SAW_TOOTH_FALLING:
            wave_form = "saw_tooth_falling";
            break;
        case SAW_TOOTH_PEAKS:
            wave_form = "saw_tooth_peaks";
            break;
        case SAW_TOOTH_RISING:
            wave_form = "saw_tooth_rising";
            break;
        case SQUARE_WAVE:
            wave_form = "square_wave";
            break;
        default:
            wave_form = "unknown";
            break;
        }

        TestName.str( "" );
        TestName << "Method: " << method( Method ) << " Level: " << Level
                 << " DataType: " << data_name_type< T >( )
                 << " DataSet: " << wave_form;
        ChannelName.str( "" );
        ChannelName << IFO << ":" << method( Method ) << "_" << Level << "_"
                    << data_name_type< T >( ) << "_" << wave_form << "_"
                    << canonical( Start ) << "_" << canonical( End ) << "_"
                    << canonical( Inc );
    }
} // namespace

#if HAVE_LIBFRAME
namespace
{
    //---------------------------------------------------------------------
    // compare
    //---------------------------------------------------------------------
    bool
    compare( const FrameCPP::FrVect& FCPP, const ::FrVect* FL )
    {
        bool   retval = true;
        INT_2U fl_compress( FL->compress );

#if LIBFRAME_LITTLE_ENDIAN_RAW_HACK
        //-------------------------------------------------------------------
        // This is a hack to allow the test to pass for little endian
        //   systems.
        //-------------------------------------------------------------------
        if ( ( fl_compress == 0 ) &&
             ( FrameCPP::BYTE_ORDER_HOST ==
               FrameCPP::BYTE_ORDER_LITTLE_ENDIAN ) )
        {
            fl_compress |= 0x100;
        }
#endif /* FR_VER <= 0624 */
        const bool vcd(
            !( ( FCPP.GetCompress( ) == FrameCPP::FrVect::GZIP ) ||
               ( FCPP.GetCompress( ) == FrameCPP::FrVect::DIFF_GZIP ) ||
               ( FCPP.GetCompress( ) == FrameCPP::FrVect::ZSTD ) ||
               ( FCPP.GetCompress( ) == FrameCPP::FrVect::DIFF_ZSTD ) ) );

        retval = retval && ( FCPP.GetCompress( ) == fl_compress );
        BOOST_TEST_MESSAGE( "Compression mode: FrameCPP: "
                            << FCPP.GetCompress( ) << " FrameL: " << fl_compress
                            << " (" << FL->compress << ")" );
        BOOST_CHECK( FCPP.GetCompress( ) == fl_compress );
        if ( vcd )
        {
            //-----------------------------------------------------------------
            // Validate the number of bytes for the compressed data
            //-----------------------------------------------------------------
            retval = retval && ( FCPP.GetNBytes( ) == FL->nBytes );
            BOOST_TEST_MESSAGE( "Number of bytes in stream (FrameCPP: "
                                << FCPP.GetNBytes( )
                                << " vs FrameL: " << FL->nBytes << ")" );
            BOOST_CHECK( FCPP.GetNBytes( ) == FL->nBytes );
        }
        retval = retval && ( FCPP.GetNData( ) == FL->nData );
        BOOST_TEST_MESSAGE( "Number of Data Points: FrameCPP: "
                            << FCPP.GetNData( ) << " FrameL: " << FL->nData );
        BOOST_CHECK( FCPP.GetNData( ) == FL->nData );
        if ( vcd )
        {
            //-----------------------------------------------------------------
            // Need to do byte comparison on the two streams if the sizes
            //     are equal
            //-----------------------------------------------------------------
            const CHAR_U* data( FCPP.GetDataRaw( ).get( ) );
            const bool    data_compare(
                ( FCPP.GetNData( ) == FL->nData ) && ( data ) && ( FL->data ) &&
                ( std::equal(
                    data,
                    data + FCPP.GetNBytes( ),
                    reinterpret_cast< const CHAR_U* >( FL->data ) ) ) );

            retval = retval && data_compare;
            BOOST_TEST_MESSAGE( "Data comparison" );
            BOOST_CHECK( data_compare );
        }
        return retval;
    }

    void
    SetData( ::FrVect* Vector, char* Data, INT_4U NData, INT_2U WordSize )
    {
        if ( Vector )
        {
            if ( Vector->data )
            {
                free( Vector->data );
                Vector->data = (char*)NULL;
            }
            Vector->data = (char*)Data;
            ::FrVectMap( Vector );
            Vector->nData = NData;
            Vector->wSize = WordSize;
            Vector->nBytes = Vector->nData * Vector->wSize;
        }
    }

    void
    SetDataCompressed( ::FrVect* Vector,
                       char*     Data,
                       INT_4U    NData,
                       INT_2U    WordSize,
                       INT_4U    NBytes,
                       INT_2U    Compression )
    {
        if ( Vector->dataUnzoomed == 0 )
        {
            free( Vector->data );
        }
        else
        {
            free( Vector->dataUnzoomed );
        }

        Vector->data = Data;
        Vector->nData = NData;
        Vector->nBytes = NBytes;
        Vector->compress = Compression;

#if LIBFRAME_LITTLE_ENDIAN_RAW_HACK
        if ( ( ( 0xFF & Compression ) == ( 0xFF & FrameCPP::FrVect::RAW ) ) )
        {
            Vector->compress = 0;
        }
#endif /* LIBFRAME_LITTLE_ENDIAN_RAW_HACK */

        ::FrVectMap( Vector );
    }

    //---------------------------------------------------------------------

    template < typename T, typename UT >
    int ZComp( UT* Out, FRULONG* CompLen, T* Data, FRULONG NData );

    template <>
    inline int
    ZComp< INT_2S >( INT_2U*  Out,
                     FRULONG* CompLen,
                     INT_2S*  Data,
                     FRULONG  NData )
    {
        return ::FrVectZComp( Out, CompLen, Data, NData, 12 );
    }

    template <>
    inline int
    ZComp< INT_4S >( INT_4U*  Out,
                     FRULONG* CompLen,
                     INT_4S*  Data,
                     FRULONG  NData )
    {
        return ::FrVectZCompI( Out, CompLen, Data, NData, 8 );
    }

#if ( ( ( FR_VERS > 6024 ) || ( FR_VERS <= 6024 && WORDS_BIGENDIAN ) ) &&      \
      ( DEBUG_TEST ) )
    namespace FrameL
    {
        void
        Dump( ::FrVect* Vector )
        {
            BOOST_TEST_MESSAGE( "INFO FrameL::FrVect: "
                                << Vector->name
                                << " data: " << (void*)( Vector->data ) );
            char* p = Vector->data;
            for ( INT_4U x = 0; x < Vector->nBytes; ++x, ++p )
            {
                BOOST_TEST_MESSAGE( ( INT_2U )( *p ) << " " );
            }
        }
    } // namespace FrameL
#endif /* */
} // namespace
#endif /* HAVE_LIBFRAME */

namespace
{
    //---------------------------------------------------------------------
    //---------------------------------------------------------------------

    typedef ::data_type zero_suppress_data_type;
    typedef INT_8U      nBytes_type;

    template < class T >
    void ZeroSuppressCompress( zero_suppress_data_type& Data,
                               INT_8U&                  NBytes,
                               INT_4U                   NData );

    template <>
    inline void
    ZeroSuppressCompress< INT_2S >( zero_suppress_data_type& Data,
                                    INT_8U&                  NBytes,
                                    INT_4U                   NData )
    {
#if 0
    zero_suppress_data_type		out;
#else
        boost::shared_array< CHAR_U > out;
#endif
        nBytes_type out_len;

        FrameCPP::Compression::ZeroSuppress::Compress< 2 >(
            Data.get( ), NData, out, out_len );
        Data = out;
        NBytes = out_len;
    }

    template <>
    inline void
    ZeroSuppressCompress< INT_4S >( zero_suppress_data_type& Data,
                                    INT_8U&                  NBytes,
                                    INT_4U                   NData )
    {
        zero_suppress_data_type out;
        nBytes_type             out_len;

        FrameCPP::Compression::ZeroSuppress::Compress< 4 >(
            Data.get( ), NData, out, out_len );
        Data = out;
        NBytes = out_len;
    }

    //---------------------------------------------------------------------
    //---------------------------------------------------------------------

    template < class T >
    void ZeroSuppressUncompress( zero_suppress_data_type& Data,
                                 INT_8U&                  NBytes,
                                 INT_4U                   NData );

    template <>
    inline void
    ZeroSuppressUncompress< INT_2S >( zero_suppress_data_type& Data,
                                      INT_8U&                  NBytes,
                                      INT_4U                   NData )
    {
        zero_suppress_data_type out;
        nBytes_type             out_len;

        FrameCPP::Compression::ZeroSuppress::Expand< 2 >(
            Data.get( ), NBytes, false /* ByteSwap */, out, NData, out_len );
        Data = out;
        NBytes = out_len;
    }

    template <>
    inline void
    ZeroSuppressUncompress< INT_4S >( zero_suppress_data_type& Data,
                                      INT_8U&                  NBytes,
                                      INT_4U                   NData )
    {
        zero_suppress_data_type out;
        nBytes_type             out_len;

        FrameCPP::Compression::ZeroSuppress::Expand< 4 >(
            Data.get( ), NBytes, false /* ByteSwap */, out, NData, out_len );
        Data = out;
        NBytes = out_len;
    }

    //---------------------------------------------------------------------
    //---------------------------------------------------------------------

    template < typename T, typename UT >
    void
    ZeroSuppress( )
    {
#if HAVE_LIBFRAME
        typedef union
        {
            UT*     i;
            CHAR_U* c;
        } pointer;
#endif /* HAVE_LIBFRAME */

        const INT_2U wordsize( sizeof( UT ) );
        const INT_4U size = 65536 / 2;

        boost::shared_array< T > source_data( new T[ size ] );
        data_type                framecpp_data;
        INT_8U                   framecpp_nbytes;

        framecpp_nbytes = sizeof( T ) * size;
        framecpp_data.reset( new CHAR_U[ framecpp_nbytes ] );

        if ( !framecpp_data )
        {
            throw std::bad_alloc( );
        }
        for ( INT_4U x = 0; x < size; x++ )
        {
            UT buf( x );

            std::copy( reinterpret_cast< const CHAR_U* >( &buf ),
                       reinterpret_cast< const CHAR_U* >( &buf + 1 ),
                       framecpp_data.get( ) + ( x * wordsize ) );
            source_data[ x ] = T( x );
        }

        //-------------------------------------------------------------------
        // Compress the data
        //-------------------------------------------------------------------
        ZeroSuppressCompress< T >( framecpp_data, framecpp_nbytes, size );
#if HAVE_LIBFRAME
        FRULONG framel_nbytes( sizeof( T ) * size * 2 );
        pointer framel_data;
        pointer framel_out_data;

        framel_data.i = (UT*)calloc( sizeof( T ), size );
        framel_out_data.i = (UT*)calloc( sizeof( T ), size * 2 );

        for ( INT_4U x = 0; x < size; x++ )
        {
            framel_data.i[ x ] = UT( x );
        }

        ZComp( framel_out_data.i, &framel_nbytes, source_data.get( ), size );
        //-------------------------------------------------------------------
        // Compression check
        //-------------------------------------------------------------------
        BOOST_TEST_MESSAGE( "Buffer compression size (FrameCPP: "
                            << framecpp_nbytes << " FrameL: " << framel_nbytes
                            << ") [sizeof(T): " << sizeof( T )
                            << " sizeof(UT): " << sizeof( UT ) << " ]" );
        BOOST_CHECK( framecpp_nbytes == framel_nbytes );
#endif /* HAVE_LIBFRAME */
        //-------------------------------------------------------------------
        //-------------------------------------------------------------------
        ZeroSuppressUncompress< T >( framecpp_data, framecpp_nbytes, size );
        //-------------------------------------------------------------------
        // Uncompression Check
        //-------------------------------------------------------------------
        BOOST_TEST_MESSAGE( "Decompressed size (FrameCPP:  "
                            << framecpp_nbytes

#if HAVE_LIBFRAME
                            << " FrameL: " << framel_nbytes
#endif /* HAVE_LIBFRAME */
                            << " Origional: " << ( size * wordsize ) << ")" );
        BOOST_CHECK( framecpp_nbytes == ( size * wordsize ) );
        //-------------------------------------------------------------------
        // Return resources
        //-------------------------------------------------------------------
#if HAVE_LIBFRAME
        free( framel_data.i );
        free( framel_out_data.i );
#endif /* HAVE_LIBFRAME */
    }

    //---------------------------------------------------------------------
    //---------------------------------------------------------------------

    template < class T >
    void
    Differential( )
    {
#if HAVE_LIBFRAME
        typedef union
        {
            T*      i;
            CHAR_U* c;
        } pointer;
#endif /* HAVE_LIBFRAME */

        // const INT_4U		size = 65536 / 2;
        const INT_4U size = 16;
        data_type    framecpp_data;
        data_type    framecpp_tmp;
        const INT_2U wordsize( sizeof( T ) );
#if HAVE_LIBFRAME
        pointer framel_data;
        pointer framel_data_out;
        pointer framecpp_data_ptr;
#endif /* HAVE_LIBFRAME */
        const INT_8U NBYTES = ( size * wordsize );

        boost::shared_array< T > source_data( new T[ size ] );
        if ( !source_data )
        {
            throw std::bad_alloc( );
        }
        framecpp_data.reset( new CHAR_U[ size * wordsize ] );
        if ( !framecpp_data )
        {
            throw std::bad_alloc( );
        }
#if HAVE_LIBFRAME
        framel_data.i = (T*)calloc( sizeof( T ), size );
#endif /* HAVE_LIBFRAME */

        //-------------------------------------------------------------------
        // Create the FrameL dataset
        //-------------------------------------------------------------------

        for ( INT_4U x = 0; x < size; x++ )
        {
            T buf( x );

            source_data[ x ] = buf;
#if HAVE_LIBFRAME
            framel_data.i[ x ] = buf;
#endif /* HAVE_LIBFRAME */
        }
        std::copy(
            reinterpret_cast< const CHAR_U* >( &( source_data[ 0 ] ) ),
            reinterpret_cast< const CHAR_U* >( &( source_data[ size ] ) ),
            framecpp_data.get( ) );

#if HAVE_LIBFRAME
        static char flversion_string[] = "flversion";
        static char unity_string[] = "unity";
        static char sec_string[] = "sec";

        ::FrVect* flversion = ::FrVectNew1D( flversion_string,
                                             fl_data_type< T >( ),
                                             FRLONG( size ),
                                             1.0 / size,
                                             sec_string,
                                             unity_string );

        SetData( flversion, (char*)( framel_data.c ), size, wordsize );
#endif /* HAVE_LIBFRAME */

        //-------------------------------------------------------------------
        // Encode the data
        //-------------------------------------------------------------------
        FrameCPP::Compression::Differential::Encode< T >(
            framecpp_data.get( ), size, framecpp_tmp );
        framecpp_data = framecpp_tmp;

#if HAVE_LIBFRAME
        framecpp_data_ptr.c = framecpp_data.get( );
        framel_data_out.c = (CHAR_U*)::FrVectDiff( flversion );
        BOOST_TEST_MESSAGE( << "FrVectDiff completed successfully" );
        BOOST_CHECK( framel_data_out.c != (CHAR_U*)NULL );
        BOOST_TEST_MESSAGE( "Encoded data (FrameCPP vs FrameL )" );
        BOOST_CHECK( std::equal( framecpp_data_ptr.i,
                                 &( framecpp_data_ptr.i[ size ] ),
                                 framel_data_out.i ) );
#endif /* HAVE_LIBFRAME */
        //-------------------------------------------------------------------
        // Decode the data
        //-------------------------------------------------------------------
#if USE_TMP
        FrameCPP::Compression::Differential::Decode< T >(
            framecpp_data.get( ), size, framecpp_tmp );
        framecpp_data = framecpp_tmp;
#else
        FrameCPP::Compression::Differential::Decode< T >( framecpp_data.get( ),
                                                          size );
#endif
        //-------------------------------------------------------------------
        // Uncompression Check
        //-------------------------------------------------------------------
#if HAVE_LIBFRAME
        bool framel_result = true;
#endif /* HAVE_LIBFRAME */
        bool framecpp_result = std::equal(
            &( framecpp_data[ 0 ] ),
            &( framecpp_data[ NBYTES ] ),
            reinterpret_cast< const CHAR_U* >( source_data.get( ) ) );
        BOOST_TEST_MESSAGE( "Decode buffer is same as initial buffer "
                            << "("
                            << " FrameCPP:  " << framecpp_result
#if HAVE_LIBFRAME
                            << " FrameL: " << framel_result
#endif /* HAVE_LIBFRAME */
                            << " )"
                            << "[ NBYTES: " << NBYTES << " ]" );
        BOOST_CHECK( framecpp_result );
        //-------------------------------------------------------------------
        // Release the resources
        //-------------------------------------------------------------------
#if HAVE_LIBFRAME
        // free( framel_data.i );
        if ( flversion )
        {
            ::FrVectFree( flversion );
            flversion = ( ::FrVect*)NULL;
        }
#endif /* HAVE_LIBFRAME */
    }

} // namespace

namespace
{
    //---------------------------------------------------------------------
    // Saw Tooth Falling function
    //---------------------------------------------------------------------
    template < class T >
    class GenSawToothFalling
    {
    public:
        GenSawToothFalling( const T Start, const T End, const T Inc )
            : m_start( Start ), m_end( End ), m_inc( Inc ), m_cur( Start )
        {
        }

        inline T
        operator( )( )
        {
            T retval = m_cur;

            if ( m_cur == m_end )
            {
                m_cur = m_start;
            }
            else
            {
                m_cur -= m_inc;
            }
            return retval;
        }

    private:
        const T m_start;
        const T m_end;
        const T m_inc;
        T       m_cur;
    };

    //---------------------------------------------------------------------
    // Saw Tooth Peaks function
    //---------------------------------------------------------------------
    template < class T >
    class GenSawToothPeaks
    {
    public:
        GenSawToothPeaks( const T Min, const T Max, const T Inc )
            : m_min( Min ), m_max( Max ), m_inc( Inc ), m_cur( Min ),
              m_rising( true )
        {
        }

        inline T
        operator( )( )
        {
            T retval = m_cur;

            if ( m_rising )
            {
                if ( m_cur == m_max )
                {
                    m_rising = false;
                    m_cur -= m_inc;
                }
                else
                {
                    m_cur += m_inc;
                }
            }
            else
            {
                if ( m_cur == m_min )
                {
                    m_rising = true;
                    m_cur += m_inc;
                }
                else
                {
                    m_cur -= m_inc;
                }
            }
            return retval;
        }

    private:
        const T m_min;
        const T m_max;
        const T m_inc;
        T       m_cur;
        bool    m_rising;
    };

    //---------------------------------------------------------------------
    // Saw Tooth Rising function
    //---------------------------------------------------------------------
    template < class T >
    class GenSawToothRising
    {
    public:
        GenSawToothRising( const T Start, const T End, const T Inc )
            : m_start( Start ), m_end( End ), m_inc( Inc ), m_cur( Start )
        {
        }

        inline T
        operator( )( )
        {
            T retval = m_cur;

            if ( m_cur == m_end )
            {
                m_cur = m_start;
            }
            else
            {
                m_cur += m_inc;
            }
            return retval;
        }

    private:
        const T m_start;
        const T m_end;
        const T m_inc;
        T       m_cur;
    };

    //---------------------------------------------------------------------
    // Square wave function generator
    //---------------------------------------------------------------------
    template < class T >
    class GenSquareWave
    {
    public:
        GenSquareWave( const T Start, const T End, const T Inc, INT_4U Samples )
            : m_start( Start ), m_end( End ), m_inc( Inc ),
              m_samples( Samples ), m_stop( Samples / 2 ), m_cur( 0 )
        {
        }

        T
        operator( )( )
        {
            T retval;

            retval = ( m_cur < m_stop ) ? m_start : m_end;
            m_cur++;
            if ( m_cur == m_samples )
            {
                m_cur = 0;
            }
            return retval;
        }

    private:
        const T      m_start;
        const T      m_end;
        const T      m_inc;
        const INT_4U m_samples;
        const INT_4U m_stop;
        INT_4U       m_cur;
    };
} // namespace

template < class T >
void
compress_base( const std::string&                        TestName,
               FrameCPP::FrVect::compression_scheme_type Method,
               INT_2U                                    Level,
               T*                                        Data,
               INT_4U                                    Samples,
               FrameCPP::FrVect::compression_scheme_type OutputMethod,
               const std::string&                        ChannelName )
{
    message_line( );
    BOOST_TEST_MESSAGE( TestName );

    FrameCPP::FrVect::dimension_type dim( Samples );
    FrameCPP::FrVect                 source( ChannelName, 1, &dim, Data );

    BOOST_TEST_MESSAGE( "Correctly created source" );
    BOOST_TEST_MESSAGE( "Samples: " << Samples
                                    << " Data Type Size: " << sizeof( T ) );
    BOOST_CHECK( memcmp( source.GetDataRaw( ).get( ),
                         Data,
                         Samples * sizeof( T ) ) == 0 );

    //---------------------------------------------------------------------
    // Check to see if the data is to be dumped to a file or if the
    // data is to be used for testing purposes.
    //---------------------------------------------------------------------
    if ( DUMP_DATA( ) )
    {
        //-------------------------------------------------------------------
        //-------------------------------------------------------------------
        using FrameCPP::FrAdcData;

        //-------------------------------------------------------------------
        // Shrink the data
        //-------------------------------------------------------------------
        source.Compress( Method, Level );
        //-------------------------------------------------------------------
        // Create the adc data
        //-------------------------------------------------------------------
        ++ChannelNumber;
        boost::shared_ptr< FrAdcData > adc(
            new FrAdcData( ChannelName,
                           ChannelNumber,
                           ChannelNumber,
                           NBits,
                           1.0 / REAL_8( Samples ),
                           FrameCPP::FrAdcData::DEFAULT_BIAS,
                           FrameCPP::FrAdcData::DEFAULT_SLOPE,
                           FrameCPP::FrAdcData::DEFAULT_UNITS( ),
                           FrameCPP::FrAdcData::DEFAULT_FSHIFT,
                           FrameCPP::FrAdcData::DEFAULT_TIME_OFFSET,
                           FrameCPP::FrAdcData::DEFAULT_DATA_VALID,
                           FrameCPP::FrAdcData::DEFAULT_PHASE ) );
        if ( !adc )
        {
            throw std::runtime_error( "Unable to allocate adc" );
        }
        adc->RefData( ).append( source );
        //-------------------------------------------------------------------
        // Make part of frame
        //-------------------------------------------------------------------
        Frame->GetRawData( )->RefFirstAdc( ).append( adc );
    }
    else /* DUMP_DATA( ) */
    {
        FrameCPP::FrVect copy( source );

        //-------------------------------------------------------------------
        // Verify the origional copy
        //-------------------------------------------------------------------
        BOOST_TEST_MESSAGE( "Compression Test: " << TestName
                                                 << ": Origional Copy" );
        BOOST_CHECK( source == copy );
        //-------------------------------------------------------------------
        // Compare uncompressed data to data that is in a frame file.
        //-------------------------------------------------------------------
#if TEST_FILE_COMPARISON
        FrameFiles.Check( ChannelName, source );
#endif /* TEST_FILE_COMPARISON */
#if HAVE_LIBFRAME
        ::FrVect* flversion = ( ::FrVect*)NULL;
        T*        fldata = (T*)NULL;

        if ( LIBFRAME_VERIFICATION )
        {
            //------------------------------------------------------------------
            // In the case where we have the C Frame library for comparison,
            //   setup by creating an appropriate Vector and then do the
            //   compression on the same data set.
            //-------------------------------------------------------------------
            fldata = (T*)calloc( sizeof( T ), Samples );
            double dx = ( 1.0 / double( Samples ) );
            {
                char name[] = "flversion";
                char unitx[] = "sec";
                char unity[] = "unity";

                flversion = ::FrVectNew1D(
                    name, fl_data_type< T >( ), Samples, dx, unitx, unity );
            }

            if ( flversion )
            {
                std::copy( Data, &( Data[ Samples ] ), fldata );
                SetData( flversion, (char*)fldata, Samples, sizeof( T ) );
                fldata = (T*)NULL;

                BOOST_TEST_MESSAGE( "Correctly flversion created source" );
                BOOST_CHECK( memcmp( flversion->data,
                                     Data,
                                     Samples * sizeof( T ) ) == 0 );

                BOOST_TEST_MESSAGE( "source: " << __LINE__ << " " << __FILE__ );
                BOOST_CHECK( memcmp( source.GetDataRaw( ).get( ),
                                     Data,
                                     Samples * sizeof( T ) ) == 0 );
                BOOST_TEST_MESSAGE( "copy: " << __LINE__ << " " << __FILE__ );
                BOOST_CHECK( memcmp( copy.GetDataRaw( ).get( ),
                                     Data,
                                     Samples * sizeof( T ) ) == 0 );

                BOOST_TEST_MESSAGE(
                    "flversion->data =?= copy.GetData( false )" );
                BOOST_CHECK( memcmp( flversion->data,
                                     copy.GetDataRaw( ).get( ),
                                     Samples * sizeof( T ) ) == 0 );

                if ( ( Method != FrameCPP::FrVect::GZIP ) ||
                     ( Method != FrameCPP::FrVect::ZSTD ) ||
                     ( FR_VERS > 6020 ) )
                {
                    BOOST_TEST_MESSAGE(
                        "Compared FrameCPP::FrVect with FrameL::FrVect "
                        "after Creation" );
                    BOOST_CHECK( compare( copy, flversion ) );

                    ::FrVectCompress( flversion, ( 0xFF & Method ), Level );
                }
            }
        }
#endif /* HAVE_LIBFRAME */

        copy.Compress( Method, Level );
        BOOST_TEST_MESSAGE(
            "Compression Test: "
            << TestName << " Output compression method[expected]: "
            << OutputMethod << "(0x0" << std::hex << OutputMethod << ")"
            << " =?= [generated]" << std::dec << copy.GetCompress( ) << "(0x0"
            << std::hex << copy.GetCompress( ) << ")" );
        BOOST_CHECK( OutputMethod == copy.GetCompress( ) );
#if HAVE_LIBFRAME
        if ( LIBFRAME_VERIFICATION && flversion )
        {
            if ( ( ( Method != FrameCPP::FrVect::GZIP ) &&
                   ( Method != FrameCPP::FrVect::ZSTD ) ) ||
                 ( FR_VERS > 6024 ) )
            {
                BOOST_TEST_MESSAGE(
                    "Compared FrameCPP::FrVect with FrameL::FrVect after "
                    "Compression" );
                BOOST_CHECK( compare( copy, flversion ) );
            }
        }
#endif /* HAVE_LIBFRAME */
        copy.Uncompress( );

        BOOST_TEST_MESSAGE( "Compression Test: " << TestName );
        BOOST_CHECK( source == copy );
#if HAVE_LIBFRAME
        if ( LIBFRAME_VERIFICATION && flversion )
        {
            if ( ( FR_VERS <= 6020 ) ||
                 ( ( FR_VERS <= 6024 ) &&
                   ( Method == FrameCPP::FrVect::ZERO_SUPPRESS ) &&
                   ( sizeof( T ) == 2 ) && ( !words_bigendian ) ) )
            {
                //---------------------------------------------------------------
                // Skip the comparison test under these conditions
                //---------------------------------------------------------------
            }
            else
            {
                ::FrameL::Decompress( flversion );
                BOOST_TEST_MESSAGE(
                    "Compared FrameCPP::FrVect with FrameL::FrVect after "
                    "Uncompression" );
                BOOST_CHECK( compare( copy, flversion ) );
            }
        }
        if ( fldata )
        {
            free( fldata );
            fldata = (T*)NULL;
        }
        if ( flversion )
        {
            ::FrVectFree( flversion );
            flversion = ( ::FrVect*)NULL;
        }
#endif /* HAVE_LIBFRAME */
    } /* DUMP_DATA( ) */
}

template < class T >
void
compress( FrameCPP::FrVect::compression_scheme_type Method,
          INT_2U                                    Level,
          const T                                   Start,
          const T                                   End,
          const T                                   Inc,
          INT_4U                                    Samples,
          waveform_compression                      OutputMethod,
          int                                       cycles = 4 )
{
    std::ostringstream test_name;
    std::ostringstream channel_name;

    try
    {
        INT_4U len( cycles * Samples );

        BOOST_TEST_MESSAGE( "Looking to create of length: " << len );

        boost::shared_array< T > data( new T[ len ] );

        if ( !data )
        {
            throw std::bad_alloc( );
        }

        //-------------------------------------------------------------------
        // Saw Tooth Rising
        //-------------------------------------------------------------------
        gen_test_names( Method,
                        Level,
                        Start,
                        End,
                        Inc,
                        Samples,
                        SAW_TOOTH_RISING,
                        test_name,
                        channel_name );
        GenSawToothRising< T > str( Start, End, Inc );
        std::generate( &( data[ 0 ] ), &( data[ len ] ), str );
        compress_base( test_name.str( ),
                       Method,
                       Level,
                       data.get( ),
                       len,
                       OutputMethod( SAW_TOOTH_RISING ),
                       channel_name.str( ) );
        //-------------------------------------------------------------------
        // Saw Tooth Falling
        //-------------------------------------------------------------------
        gen_test_names( Method,
                        Level,
                        Start,
                        End,
                        Inc,
                        Samples,
                        SAW_TOOTH_FALLING,
                        test_name,
                        channel_name );
        GenSawToothFalling< T > stf( End, Start, Inc );
        std::generate( &( data[ 0 ] ), &( data[ len ] ), stf );
        compress_base( test_name.str( ),
                       Method,
                       Level,
                       data.get( ),
                       Samples * cycles,
                       OutputMethod( SAW_TOOTH_FALLING ),
                       channel_name.str( ) );
        //-------------------------------------------------------------------
        // Saw Tooth Peaks
        //-------------------------------------------------------------------
        gen_test_names( Method,
                        Level,
                        Start,
                        End,
                        Inc,
                        Samples,
                        SAW_TOOTH_PEAKS,
                        test_name,
                        channel_name );
#if 1
        GenSawToothPeaks< T > stp( Start, End, Inc );
        std::generate( &( data[ 0 ] ), &( data[ len ] ), stp );
#else
        data = saw_tooth_peaks( Start, End, Inc, Samples, cycles );
#endif
        compress_base( test_name.str( ),
                       Method,
                       Level,
                       data.get( ),
                       Samples * cycles,
                       OutputMethod( SAW_TOOTH_PEAKS ),
                       channel_name.str( ) );
        //-------------------------------------------------------------------
        // Square wave
        //-------------------------------------------------------------------
        gen_test_names( Method,
                        Level,
                        Start,
                        End,
                        Inc,
                        Samples,
                        SQUARE_WAVE,
                        test_name,
                        channel_name );
        GenSquareWave< T > sw( End, Start, Inc, Samples );
        std::generate( &( data[ 0 ] ), &( data[ len ] ), sw );
        compress_base( test_name.str( ),
                       Method,
                       Level,
                       data.get( ),
                       Samples * cycles,
                       OutputMethod( SQUARE_WAVE ),
                       channel_name.str( ) );
    }
    catch ( const std::exception& e )
    {
        BOOST_TEST_MESSAGE( test_name.str( )
                            << ": Caught exception: " << e.what( ) );
        BOOST_CHECK( false );
    }
    catch ( ... )
    {
        BOOST_TEST_MESSAGE( test_name.str( ) << ": Caught unknown exception" );
        BOOST_CHECK( false );
    }
}

template < typename T >
void
compress( FrameCPP::FrVect::compression_scheme_type Method,
          INT_2U                                    Level,
          T*                                        Data,
          INT_4U                                    Samples,
          FrameCPP::FrVect::compression_scheme_type OutputMethod,
          const char*                               ChannelName )
{
    std::ostringstream test_name;

    test_name << "Method: " << method( Method ) << " Level: " << Level
              << " DataType: " << data_name_type< T >( );

    try
    {
        compress_base( test_name.str( ),
                       Method,
                       Level,
                       Data,
                       Samples,
                       OutputMethod,
                       ChannelName );
    }
    catch ( const std::exception& e )
    {
        BOOST_TEST_MESSAGE( test_name.str( )
                            << ": Caught exception: " << e.what( ) );
        BOOST_CHECK( false );
    }
    catch ( ... )
    {
        BOOST_TEST_MESSAGE( test_name.str( ) << ": Caught unknown exception" );
        BOOST_CHECK( false );
    }
}

template < class T >
inline void
compress( FrameCPP::FrVect::compression_scheme_type Method,
          INT_2U                                    Level,
          const T                                   Start,
          const T                                   End,
          const T                                   Inc,
          FrameCPP::FrVect::compression_scheme_type OutputMethod )
{
    compress( Method,
              Level,
              Start,
              End,
              Inc,
              INT_4U( ( End - Start ) / Inc ),
              OutputMethod );
}

template < class T >
inline void
compress( FrameCPP::FrVect::compression_scheme_type Method,
          INT_2U                                    Level,
          const T                                   Start,
          const T                                   End,
          const T                                   Inc,
          waveform_compression                      OutputMethod )
{
    compress( Method,
              Level,
              Start,
              End,
              Inc,
              INT_4U( ( End - Start ) / Inc ),
              OutputMethod );
}

void
test_building_blocks( )
{
    //---------------------------------------------------------------------
    // Building blocks
    //---------------------------------------------------------------------
#if TEST_BUILDING_BLOCKS
    if ( DUMP_DATA( ) == false )
    {
        ZeroSuppress< INT_2S, INT_2U >( );
        ZeroSuppress< INT_4S, INT_4U >( );
        Differential< INT_2U >( );
        Differential< INT_4U >( );
    }
#endif /* TEST_BUILDING_BLOCKS */
}

void
test_gzip( )
{
#if TEST_GZIP
    //---------------------------------------------------------------------
    // Test all compression levels for gzip.
    //---------------------------------------------------------------------
    for ( INT_2U level = TEST_GZIP_LEVEL_MIN; level <= TEST_GZIP_LEVEL_MAX;
          ++level )
    {
        compress< CHAR_U >( FrameCPP::FrVect::GZIP,
                            level,
                            0,
                            0,
                            1,
                            1,
                            FrameCPP::FrVect::RAW,
                            1 );
        compress< CHAR_U >( FrameCPP::FrVect::GZIP,
                            level,
                            0,
                            255,
                            1,
                            256,
                            FrameCPP::FrVect::GZIP );
        compress< CHAR >( FrameCPP::FrVect::GZIP,
                          level,
                          0,
                          0,
                          1,
                          1,
                          FrameCPP::FrVect::RAW,
                          1 );
        compress< CHAR >( FrameCPP::FrVect::GZIP,
                          level,
                          -128,
                          127,
                          1,
                          256,
                          FrameCPP::FrVect::GZIP );
        compress< INT_2U >( FrameCPP::FrVect::GZIP,
                            level,
                            0,
                            0,
                            1,
                            1,
                            FrameCPP::FrVect::RAW,
                            1 );
        compress< INT_2U >( FrameCPP::FrVect::GZIP,
                            level,
                            0,
                            65535,
                            1,
                            65536,
                            FrameCPP::FrVect::GZIP );
        compress< INT_2S >( FrameCPP::FrVect::GZIP,
                            level,
                            0,
                            0,
                            1,
                            1,
                            FrameCPP::FrVect::RAW,
                            1 );
        compress< INT_2S >( FrameCPP::FrVect::GZIP,
                            level,
                            -32768,
                            32767,
                            1,
                            65536,
                            FrameCPP::FrVect::GZIP );
        compress< INT_4U >( FrameCPP::FrVect::GZIP,
                            level,
                            0,
                            0,
                            1,
                            1,
                            FrameCPP::FrVect::RAW,
                            1 );
        compress< INT_4U >( FrameCPP::FrVect::GZIP,
                            level,
                            0,
                            65536,
                            1,
                            FrameCPP::FrVect::GZIP );
        compress< INT_4S >( FrameCPP::FrVect::GZIP,
                            level,
                            0,
                            0,
                            1,
                            1,
                            FrameCPP::FrVect::RAW,
                            1 );
        compress< INT_4S >( FrameCPP::FrVect::GZIP,
                            level,
                            -32768,
                            32767,
                            1,
                            FrameCPP::FrVect::GZIP );
        compress< INT_8U >( FrameCPP::FrVect::GZIP,
                            level,
                            0,
                            0,
                            1,
                            1,
                            FrameCPP::FrVect::RAW,
                            1 );
        compress< INT_8U >( FrameCPP::FrVect::GZIP,
                            level,
                            0,
                            65535,
                            1,
                            FrameCPP::FrVect::GZIP );
        compress< INT_8S >( FrameCPP::FrVect::GZIP,
                            level,
                            0,
                            0,
                            1,
                            1,
                            FrameCPP::FrVect::RAW,
                            1 );
        compress< INT_8S >( FrameCPP::FrVect::GZIP,
                            level,
                            -32768,
                            32767,
                            1,
                            FrameCPP::FrVect::GZIP );
        compress< REAL_4 >( FrameCPP::FrVect::GZIP,
                            level,
                            0.0,
                            0.0,
                            1.0,
                            1,
                            FrameCPP::FrVect::RAW,
                            1 );
        compress< REAL_4 >( FrameCPP::FrVect::GZIP,
                            level,
                            -32768.0,
                            32767.0,
                            1.0,
                            FrameCPP::FrVect::GZIP );
        compress< REAL_8 >( FrameCPP::FrVect::GZIP,
                            level,
                            0.0,
                            0.0,
                            1.0,
                            1,
                            FrameCPP::FrVect::RAW,
                            1 );
        compress< REAL_8 >( FrameCPP::FrVect::GZIP,
                            level,
                            -32768.0,
                            32767.0,
                            1.0,
                            FrameCPP::FrVect::GZIP );
        compress< COMPLEX_8 >( FrameCPP::FrVect::GZIP,
                               level,
                               COMPLEX_8( 1.0, 0.0 ),
                               COMPLEX_8( 1.0, 0.0 ),
                               COMPLEX_8( 1.0, 0.0 ),
                               1,
                               FrameCPP::FrVect::RAW,
                               1 );
        compress< COMPLEX_8 >( FrameCPP::FrVect::GZIP,
                               level,
                               COMPLEX_8( -32768.0, 0.0 ),
                               COMPLEX_8( 32767.0, 0.0 ),
                               COMPLEX_8( 1.0, 0.0 ),
                               65636,
                               FrameCPP::FrVect::GZIP );
        compress< COMPLEX_16 >( FrameCPP::FrVect::GZIP,
                                level,
                                COMPLEX_16( 1.0, 0.0 ),
                                COMPLEX_16( 1.0, 0.0 ),
                                COMPLEX_16( 1.0, 0.0 ),
                                1,
                                FrameCPP::FrVect::RAW,
                                1 );
        compress< COMPLEX_16 >( FrameCPP::FrVect::GZIP,
                                level,
                                COMPLEX_16( -32768.0, 0.0 ),
                                COMPLEX_16( 32767.0, 0.0 ),
                                COMPLEX_16( 1.0, 0.0 ),
                                65636,
                                FrameCPP::FrVect::GZIP );
    }
#endif /* TEST_GZIP */
}

void
test_zstd( )
{
#if TEST_ZSTD
    //---------------------------------------------------------------------
    // Test all compression levels for zstd.
    //---------------------------------------------------------------------
    for ( INT_2U level = TEST_ZSTD_LEVEL_MIN; level <= TEST_ZSTD_LEVEL_MAX;
          ++level )
    {
        compress< CHAR_U >( FrameCPP::FrVect::ZSTD,
                            level,
                            0,
                            0,
                            1,
                            1,
                            FrameCPP::FrVect::RAW,
                            1 );
        compress< CHAR_U >( FrameCPP::FrVect::ZSTD,
                            level,
                            0,
                            255,
                            1,
                            256,
                            FrameCPP::FrVect::ZSTD );
        compress< CHAR >( FrameCPP::FrVect::ZSTD,
                          level,
                          0,
                          0,
                          1,
                          1,
                          FrameCPP::FrVect::RAW,
                          1 );
        compress< CHAR >( FrameCPP::FrVect::ZSTD,
                          level,
                          -128,
                          127,
                          1,
                          256,
                          FrameCPP::FrVect::ZSTD );
        compress< INT_2U >( FrameCPP::FrVect::ZSTD,
                            level,
                            0,
                            0,
                            1,
                            1,
                            FrameCPP::FrVect::RAW,
                            1 );
        compress< INT_2U >( FrameCPP::FrVect::ZSTD,
                            level,
                            0,
                            65535,
                            1,
                            65536,
                            FrameCPP::FrVect::ZSTD );
        compress< INT_2S >( FrameCPP::FrVect::ZSTD,
                            level,
                            0,
                            0,
                            1,
                            1,
                            FrameCPP::FrVect::RAW,
                            1 );
        compress< INT_2S >( FrameCPP::FrVect::ZSTD,
                            level,
                            -32768,
                            32767,
                            1,
                            65536,
                            FrameCPP::FrVect::ZSTD );
        compress< INT_4U >( FrameCPP::FrVect::ZSTD,
                            level,
                            0,
                            0,
                            1,
                            1,
                            FrameCPP::FrVect::RAW,
                            1 );
        compress< INT_4U >( FrameCPP::FrVect::ZSTD,
                            level,
                            0,
                            65536,
                            1,
                            FrameCPP::FrVect::ZSTD );
        compress< INT_4S >( FrameCPP::FrVect::ZSTD,
                            level,
                            0,
                            0,
                            1,
                            1,
                            FrameCPP::FrVect::RAW,
                            1 );
        compress< INT_4S >( FrameCPP::FrVect::ZSTD,
                            level,
                            -32768,
                            32767,
                            1,
                            FrameCPP::FrVect::ZSTD );
        compress< INT_8U >( FrameCPP::FrVect::ZSTD,
                            level,
                            0,
                            0,
                            1,
                            1,
                            FrameCPP::FrVect::RAW,
                            1 );
        compress< INT_8U >( FrameCPP::FrVect::ZSTD,
                            level,
                            0,
                            65535,
                            1,
                            FrameCPP::FrVect::ZSTD );
        compress< INT_8S >( FrameCPP::FrVect::ZSTD,
                            level,
                            0,
                            0,
                            1,
                            1,
                            FrameCPP::FrVect::RAW,
                            1 );
        compress< INT_8S >( FrameCPP::FrVect::ZSTD,
                            level,
                            -32768,
                            32767,
                            1,
                            FrameCPP::FrVect::ZSTD );
        compress< REAL_4 >( FrameCPP::FrVect::ZSTD,
                            level,
                            0.0,
                            0.0,
                            1.0,
                            1,
                            FrameCPP::FrVect::RAW,
                            1 );
        compress< REAL_4 >( FrameCPP::FrVect::ZSTD,
                            level,
                            -32768.0,
                            32767.0,
                            1.0,
                            FrameCPP::FrVect::ZSTD );
        compress< REAL_8 >( FrameCPP::FrVect::ZSTD,
                            level,
                            0.0,
                            0.0,
                            1.0,
                            1,
                            FrameCPP::FrVect::RAW,
                            1 );
        compress< REAL_8 >( FrameCPP::FrVect::ZSTD,
                            level,
                            -32768.0,
                            32767.0,
                            1.0,
                            FrameCPP::FrVect::ZSTD );
        compress< COMPLEX_8 >( FrameCPP::FrVect::ZSTD,
                               level,
                               COMPLEX_8( 1.0, 0.0 ),
                               COMPLEX_8( 1.0, 0.0 ),
                               COMPLEX_8( 1.0, 0.0 ),
                               1,
                               FrameCPP::FrVect::RAW,
                               1 );
        compress< COMPLEX_8 >( FrameCPP::FrVect::ZSTD,
                               level,
                               COMPLEX_8( -32768.0, 0.0 ),
                               COMPLEX_8( 32767.0, 0.0 ),
                               COMPLEX_8( 1.0, 0.0 ),
                               65636,
                               FrameCPP::FrVect::ZSTD );
        compress< COMPLEX_16 >( FrameCPP::FrVect::ZSTD,
                                level,
                                COMPLEX_16( 1.0, 0.0 ),
                                COMPLEX_16( 1.0, 0.0 ),
                                COMPLEX_16( 1.0, 0.0 ),
                                1,
                                FrameCPP::FrVect::RAW,
                                1 );
        compress< COMPLEX_16 >( FrameCPP::FrVect::ZSTD,
                                level,
                                COMPLEX_16( -32768.0, 0.0 ),
                                COMPLEX_16( 32767.0, 0.0 ),
                                COMPLEX_16( 1.0, 0.0 ),
                                65636,
                                FrameCPP::FrVect::ZSTD );
    }
#endif /* TEST_ZSTD */
}

void
test_raw( )
{
#if TEST_RAW
    //---------------------------------------------------------------------
    // RAW
    //---------------------------------------------------------------------
    compress< CHAR_U >(
        FrameCPP::FrVect::RAW, 0, 0, 255, 1, 256, FrameCPP::FrVect::RAW );
    compress< CHAR >(
        FrameCPP::FrVect::RAW, 0, -128, 127, 1, 256, FrameCPP::FrVect::RAW );
    compress< INT_2U >(
        FrameCPP::FrVect::RAW, 0, 0, 65535, 1, 65536, FrameCPP::FrVect::RAW );
    compress< INT_2S >( FrameCPP::FrVect::RAW,
                        0,
                        -32768,
                        32767,
                        1,
                        65536,
                        FrameCPP::FrVect::RAW );
    compress< INT_4U >(
        FrameCPP::FrVect::RAW, 0, 0, 65535, 1, FrameCPP::FrVect::RAW );
    compress< INT_4S >(
        FrameCPP::FrVect::RAW, 0, -32768, 32768, 1, FrameCPP::FrVect::RAW );
    compress< INT_8U >(
        FrameCPP::FrVect::RAW, 0, 0, 65535, 1, FrameCPP::FrVect::RAW );
    compress< INT_8S >(
        FrameCPP::FrVect::RAW, 0, -32768, 32767, 1, FrameCPP::FrVect::RAW );
    compress< REAL_4 >( FrameCPP::FrVect::RAW,
                        0,
                        -32768.0,
                        32767.0,
                        1.0,
                        FrameCPP::FrVect::RAW );
    compress< REAL_8 >( FrameCPP::FrVect::RAW,
                        0,
                        -32768.0,
                        32767.0,
                        1.0,
                        FrameCPP::FrVect::RAW );
    compress< COMPLEX_8 >( FrameCPP::FrVect::RAW,
                           0,
                           COMPLEX_8( -32768.0, 0.0 ),
                           COMPLEX_8( 32768.0, 0.0 ),
                           COMPLEX_8( 1.0, 0.0 ),
                           65636,
                           FrameCPP::FrVect::RAW );
    compress< COMPLEX_16 >( FrameCPP::FrVect::RAW,
                            0,
                            COMPLEX_8( -32768.0, 0.0 ),
                            COMPLEX_8( 32767.0, 0.0 ),
                            COMPLEX_8( 1.0, 0.0 ),
                            65636,
                            FrameCPP::FrVect::RAW );
#endif /* TEST_RAW */
}

void
test_diff_gzip( )
{
#if TEST_DIFF_GZIP
    //---------------------------------------------------------------------
    // Test all compression levels for gzip_diff.
    //---------------------------------------------------------------------
    for ( INT_2U level = TEST_DIFF_GZIP_LEVEL_MIN;
          level <= TEST_DIFF_GZIP_LEVEL_MAX;
          ++level )
    {
        BOOST_TEST_MESSAGE( "DEBUG: test_diff_gzip: " << __LINE__ );
        compress< CHAR_U >( FrameCPP::FrVect::GZIP,
                            level,
                            0,
                            0,
                            1,
                            1,
                            FrameCPP::FrVect::RAW,
                            1 );
        BOOST_TEST_MESSAGE( "DEBUG: test_diff_gzip: " << __LINE__ );
        compress< CHAR_U >( FrameCPP::FrVect::DIFF_GZIP,
                            level,
                            0,
                            255,
                            1,
                            256,
                            FrameCPP::FrVect::DIFF_GZIP );
        BOOST_TEST_MESSAGE( "DEBUG: test_diff_gzip: " << __LINE__ );
        compress< CHAR >( FrameCPP::FrVect::GZIP,
                          level,
                          0,
                          0,
                          1,
                          1,
                          FrameCPP::FrVect::RAW,
                          1 );
        BOOST_TEST_MESSAGE( "DEBUG: test_diff_gzip: " << __LINE__ );
        compress< CHAR >( FrameCPP::FrVect::DIFF_GZIP,
                          level,
                          -128,
                          127,
                          1,
                          256,
                          FrameCPP::FrVect::DIFF_GZIP );
        BOOST_TEST_MESSAGE( "DEBUG: test_diff_gzip: " << __LINE__ );
        compress< INT_2U >( FrameCPP::FrVect::GZIP,
                            level,
                            0,
                            0,
                            1,
                            1,
                            FrameCPP::FrVect::RAW,
                            1 );
        BOOST_TEST_MESSAGE( "DEBUG: test_diff_gzip: " << __LINE__ );
        compress< INT_2U >( FrameCPP::FrVect::DIFF_GZIP,
                            level,
                            0,
                            65535,
                            1,
                            65536,
                            FrameCPP::FrVect::DIFF_GZIP );
        BOOST_TEST_MESSAGE( "DEBUG: test_diff_gzip: " << __LINE__ );
        compress< INT_2S >( FrameCPP::FrVect::GZIP,
                            level,
                            0,
                            0,
                            1,
                            1,
                            FrameCPP::FrVect::RAW,
                            1 );
        BOOST_TEST_MESSAGE( "DEBUG: test_diff_gzip: " << __LINE__ );
        compress< INT_2S >( FrameCPP::FrVect::DIFF_GZIP,
                            level,
                            -32768,
                            32767,
                            1,
                            65536,
                            FrameCPP::FrVect::DIFF_GZIP );
        BOOST_TEST_MESSAGE( "DEBUG: test_diff_gzip: " << __LINE__ );
        compress< INT_4U >( FrameCPP::FrVect::GZIP,
                            level,
                            0,
                            0,
                            1,
                            1,
                            FrameCPP::FrVect::RAW,
                            1 );
        BOOST_TEST_MESSAGE( "DEBUG: test_diff_gzip: " << __LINE__ );
        compress< INT_4U >( FrameCPP::FrVect::DIFF_GZIP,
                            level,
                            0,
                            65535,
                            1,
                            65536,
                            FrameCPP::FrVect::DIFF_GZIP );
        BOOST_TEST_MESSAGE( "DEBUG: test_diff_gzip: " << __LINE__ );
        compress< INT_4S >( FrameCPP::FrVect::GZIP,
                            level,
                            0,
                            0,
                            1,
                            1,
                            FrameCPP::FrVect::RAW,
                            1 );
        BOOST_TEST_MESSAGE( "DEBUG: test_diff_gzip: " << __LINE__ );
        compress< INT_4S >( FrameCPP::FrVect::DIFF_GZIP,
                            level,
                            -32768,
                            32767,
                            1,
                            FrameCPP::FrVect::DIFF_GZIP );
        BOOST_TEST_MESSAGE( "DEBUG: test_diff_gzip: " << __LINE__ );
        compress< INT_8U >( FrameCPP::FrVect::GZIP,
                            level,
                            0,
                            0,
                            1,
                            1,
                            FrameCPP::FrVect::RAW,
                            1 );
        BOOST_TEST_MESSAGE( "DEBUG: test_diff_gzip: " << __LINE__ );
        compress< INT_8U >( FrameCPP::FrVect::DIFF_GZIP,
                            level,
                            0,
                            65535,
                            1,
                            FrameCPP::FrVect::GZIP );
        BOOST_TEST_MESSAGE( "DEBUG: test_diff_gzip: " << __LINE__ );
        compress< INT_8S >( FrameCPP::FrVect::GZIP,
                            level,
                            0,
                            0,
                            1,
                            1,
                            FrameCPP::FrVect::RAW,
                            1 );
        BOOST_TEST_MESSAGE( "DEBUG: test_diff_gzip: " << __LINE__ );
        compress< INT_8S >( FrameCPP::FrVect::DIFF_GZIP,
                            level,
                            -32768,
                            32765,
                            1,
                            FrameCPP::FrVect::GZIP );
        BOOST_TEST_MESSAGE( "DEBUG: test_diff_gzip: " << __LINE__ );
        compress< REAL_4 >( FrameCPP::FrVect::GZIP,
                            level,
                            0.0,
                            0.0,
                            1.0,
                            1,
                            FrameCPP::FrVect::RAW,
                            1 );
        BOOST_TEST_MESSAGE( "DEBUG: test_diff_gzip: " << __LINE__ );
        compress< REAL_4 >( FrameCPP::FrVect::DIFF_GZIP,
                            level,
                            -32768.0,
                            32767.0,
                            1.0,
                            FrameCPP::FrVect::GZIP );
        BOOST_TEST_MESSAGE( "DEBUG: test_diff_gzip: " << __LINE__ );
        compress< REAL_8 >( FrameCPP::FrVect::GZIP,
                            level,
                            0.0,
                            0.0,
                            1.0,
                            1,
                            FrameCPP::FrVect::RAW,
                            1 );
        BOOST_TEST_MESSAGE( "DEBUG: test_diff_gzip: " << __LINE__ );
        compress< REAL_8 >( FrameCPP::FrVect::DIFF_GZIP,
                            level,
                            -32768.0,
                            32767.0,
                            1.0,
                            FrameCPP::FrVect::GZIP );
        BOOST_TEST_MESSAGE( "DEBUG: test_diff_gzip: " << __LINE__ );
        compress< COMPLEX_8 >( FrameCPP::FrVect::GZIP,
                               level,
                               COMPLEX_8( 1.0, 0.0 ),
                               COMPLEX_8( 1.0, 0.0 ),
                               COMPLEX_8( 1.0, 0.0 ),
                               1,
                               FrameCPP::FrVect::RAW,
                               1 );
        BOOST_TEST_MESSAGE( "DEBUG: test_diff_gzip: " << __LINE__ );
        compress< COMPLEX_8 >( FrameCPP::FrVect::DIFF_GZIP,
                               level,
                               COMPLEX_8( -32768.0, 0.0 ),
                               COMPLEX_8( 32767.0, 0.0 ),
                               COMPLEX_8( 1.0, 0.0 ),
                               65636,
                               FrameCPP::FrVect::GZIP );
        BOOST_TEST_MESSAGE( "DEBUG: test_diff_gzip: " << __LINE__ );
        compress< COMPLEX_16 >( FrameCPP::FrVect::GZIP,
                                level,
                                COMPLEX_16( 1.0, 0.0 ),
                                COMPLEX_16( 1.0, 0.0 ),
                                COMPLEX_16( 1.0, 0.0 ),
                                1,
                                FrameCPP::FrVect::RAW,
                                1 );
        BOOST_TEST_MESSAGE( "DEBUG: test_diff_gzip: " << __LINE__ );
        compress< COMPLEX_16 >( FrameCPP::FrVect::DIFF_GZIP,
                                level,
                                COMPLEX_16( -32768.0, 0.0 ),
                                COMPLEX_16( 32767.0, 0.0 ),
                                COMPLEX_16( 1.0, 0.0 ),
                                65636,
                                FrameCPP::FrVect::GZIP );
    }
#endif /* DIFF_GZIP */
}

void
test_diff_zstd( )
{
#if TEST_DIFF_ZSTD
    //---------------------------------------------------------------------
    // Test all compression levels for zstd_diff.
    //---------------------------------------------------------------------
    for ( INT_2U level = TEST_DIFF_ZSTD_LEVEL_MIN;
          level <= TEST_DIFF_ZSTD_LEVEL_MAX;
          ++level )
    {
        compress< CHAR_U >( FrameCPP::FrVect::ZSTD,
                            level,
                            0,
                            0,
                            1,
                            1,
                            FrameCPP::FrVect::RAW,
                            1 );
        compress< CHAR_U >( FrameCPP::FrVect::DIFF_ZSTD,
                            level,
                            0,
                            255,
                            1,
                            256,
                            FrameCPP::FrVect::DIFF_ZSTD );
        compress< CHAR >( FrameCPP::FrVect::ZSTD,
                          level,
                          0,
                          0,
                          1,
                          1,
                          FrameCPP::FrVect::RAW,
                          1 );
        compress< CHAR >( FrameCPP::FrVect::DIFF_ZSTD,
                          level,
                          -128,
                          127,
                          1,
                          256,
                          FrameCPP::FrVect::DIFF_ZSTD );
        compress< INT_2U >( FrameCPP::FrVect::ZSTD,
                            level,
                            0,
                            0,
                            1,
                            1,
                            FrameCPP::FrVect::RAW,
                            1 );
        compress< INT_2U >( FrameCPP::FrVect::DIFF_ZSTD,
                            level,
                            0,
                            65535,
                            1,
                            65536,
                            FrameCPP::FrVect::DIFF_ZSTD );
        compress< INT_2S >( FrameCPP::FrVect::ZSTD,
                            level,
                            0,
                            0,
                            1,
                            1,
                            FrameCPP::FrVect::RAW,
                            1 );
        compress< INT_2S >( FrameCPP::FrVect::DIFF_ZSTD,
                            level,
                            -32768,
                            32767,
                            1,
                            65536,
                            FrameCPP::FrVect::DIFF_ZSTD );
        compress< INT_4U >( FrameCPP::FrVect::ZSTD,
                            level,
                            0,
                            0,
                            1,
                            1,
                            FrameCPP::FrVect::RAW,
                            1 );
        compress< INT_4U >( FrameCPP::FrVect::DIFF_ZSTD,
                            level,
                            0,
                            65535,
                            1,
                            65536,
                            FrameCPP::FrVect::DIFF_ZSTD );
        compress< INT_4S >( FrameCPP::FrVect::ZSTD,
                            level,
                            0,
                            0,
                            1,
                            1,
                            FrameCPP::FrVect::RAW,
                            1 );
        compress< INT_4S >( FrameCPP::FrVect::DIFF_ZSTD,
                            level,
                            -32768,
                            32767,
                            1,
                            FrameCPP::FrVect::DIFF_ZSTD );
        compress< INT_8U >( FrameCPP::FrVect::ZSTD,
                            level,
                            0,
                            0,
                            1,
                            1,
                            FrameCPP::FrVect::RAW,
                            1 );
        compress< INT_8U >( FrameCPP::FrVect::DIFF_ZSTD,
                            level,
                            0,
                            65535,
                            1,
                            FrameCPP::FrVect::ZSTD );
        compress< INT_8S >( FrameCPP::FrVect::ZSTD,
                            level,
                            0,
                            0,
                            1,
                            1,
                            FrameCPP::FrVect::RAW,
                            1 );
        compress< INT_8S >( FrameCPP::FrVect::DIFF_ZSTD,
                            level,
                            -32768,
                            32765,
                            1,
                            FrameCPP::FrVect::ZSTD );
        compress< REAL_4 >( FrameCPP::FrVect::ZSTD,
                            level,
                            0.0,
                            0.0,
                            1.0,
                            1,
                            FrameCPP::FrVect::RAW,
                            1 );
        compress< REAL_4 >( FrameCPP::FrVect::DIFF_ZSTD,
                            level,
                            -32768.0,
                            32767.0,
                            1.0,
                            FrameCPP::FrVect::ZSTD );
        compress< REAL_8 >( FrameCPP::FrVect::ZSTD,
                            level,
                            0.0,
                            0.0,
                            1.0,
                            1,
                            FrameCPP::FrVect::RAW,
                            1 );
        compress< REAL_8 >( FrameCPP::FrVect::DIFF_ZSTD,
                            level,
                            -32768.0,
                            32767.0,
                            1.0,
                            FrameCPP::FrVect::ZSTD );
        compress< COMPLEX_8 >( FrameCPP::FrVect::ZSTD,
                               level,
                               COMPLEX_8( 1.0, 0.0 ),
                               COMPLEX_8( 1.0, 0.0 ),
                               COMPLEX_8( 1.0, 0.0 ),
                               1,
                               FrameCPP::FrVect::RAW,
                               1 );
        compress< COMPLEX_8 >( FrameCPP::FrVect::DIFF_ZSTD,
                               level,
                               COMPLEX_8( -32768.0, 0.0 ),
                               COMPLEX_8( 32767.0, 0.0 ),
                               COMPLEX_8( 1.0, 0.0 ),
                               65636,
                               FrameCPP::FrVect::ZSTD );
        compress< COMPLEX_16 >( FrameCPP::FrVect::ZSTD,
                                level,
                                COMPLEX_16( 1.0, 0.0 ),
                                COMPLEX_16( 1.0, 0.0 ),
                                COMPLEX_16( 1.0, 0.0 ),
                                1,
                                FrameCPP::FrVect::RAW,
                                1 );
        compress< COMPLEX_16 >( FrameCPP::FrVect::DIFF_ZSTD,
                                level,
                                COMPLEX_16( -32768.0, 0.0 ),
                                COMPLEX_16( 32767.0, 0.0 ),
                                COMPLEX_16( 1.0, 0.0 ),
                                65636,
                                FrameCPP::FrVect::ZSTD );
    }
#endif /* DIFF_ZSTD */
}
void
test_zero_suppress( )
{
#if TEST_ZERO_SUPPRESS
    //---------------------------------------------------------------------
    // ZERO_SUPPRESS
    //---------------------------------------------------------------------
    compress< CHAR_U >( FrameCPP::FrVect::ZERO_SUPPRESS,
                        0,
                        1,
                        1,
                        1,
                        1,
                        FrameCPP::FrVect::RAW,
                        1 );
    compress< CHAR_U >( FrameCPP::FrVect::ZERO_SUPPRESS,
                        0,
                        0,
                        255,
                        1,
                        256,
                        FrameCPP::FrVect::RAW );
    compress< CHAR >( FrameCPP::FrVect::ZERO_SUPPRESS,
                      0,
                      1,
                      1,
                      1,
                      1,
                      FrameCPP::FrVect::RAW,
                      1 );
    compress< CHAR >( FrameCPP::FrVect::ZERO_SUPPRESS,
                      0,
                      -128,
                      127,
                      1,
                      256,
                      FrameCPP::FrVect::RAW );
    compress< INT_2U >( FrameCPP::FrVect::ZERO_SUPPRESS,
                        0,
                        1,
                        1,
                        1,
                        1,
                        FrameCPP::FrVect::RAW,
                        1 );
    compress< INT_2U >( FrameCPP::FrVect::ZERO_SUPPRESS,
                        0,
                        0,
                        65534,
                        2,
                        65534 / 2,
                        FrameCPP::FrVect::ZERO_SUPPRESS );
    compress< INT_2S >( FrameCPP::FrVect::ZERO_SUPPRESS,
                        0,
                        1,
                        1,
                        1,
                        1,
                        FrameCPP::FrVect::RAW,
                        1 );
    compress< INT_2S >( FrameCPP::FrVect::ZERO_SUPPRESS,
                        0,
                        -1024 * 4,
                        1024 * 4,
                        4,
                        1024 * 2,
                        FrameCPP::FrVect::ZERO_SUPPRESS );
    compress< INT_2S >( FrameCPP::FrVect::ZERO_SUPPRESS,
                        0,
                        -32768,
                        32767,
                        1,
                        65536,
                        waveform_compression( FrameCPP::FrVect::ZERO_SUPPRESS,
                                              SAW_TOOTH_RISING,
                                              FrameCPP::FrVect::RAW,
                                              SAW_TOOTH_PEAKS,
                                              FrameCPP::FrVect::RAW,
                                              NO_WAVE_FORM ) );
    compress< INT_4U >( FrameCPP::FrVect::ZERO_SUPPRESS,
                        0,
                        1,
                        1,
                        1,
                        1,
                        FrameCPP::FrVect::RAW,
                        1 );
    compress< INT_4U >( FrameCPP::FrVect::ZERO_SUPPRESS,
                        0,
                        0,
                        65535,
                        1,
                        FrameCPP::FrVect::ZERO_SUPPRESS );
    compress< INT_4S >( FrameCPP::FrVect::ZERO_SUPPRESS,
                        0,
                        1,
                        1,
                        1,
                        1,
                        FrameCPP::FrVect::RAW,
                        1 );
    compress< INT_4S >( FrameCPP::FrVect::ZERO_SUPPRESS,
                        0,
                        -32768,
                        32767,
                        1,
                        FrameCPP::FrVect::ZERO_SUPPRESS );
    compress< INT_8U >( FrameCPP::FrVect::ZERO_SUPPRESS,
                        0,
                        1,
                        1,
                        1,
                        1,
                        FrameCPP::FrVect::RAW,
                        1 );
    compress< INT_8U >( FrameCPP::FrVect::ZERO_SUPPRESS,
                        0,
                        0,
                        65535,
                        1,
                        FrameCPP::FrVect::ZERO_SUPPRESS );
    compress< INT_8S >( FrameCPP::FrVect::ZERO_SUPPRESS,
                        0,
                        1,
                        1,
                        1,
                        1,
                        FrameCPP::FrVect::RAW,
                        1 );
    compress< INT_8S >( FrameCPP::FrVect::ZERO_SUPPRESS,
                        0,
                        -32768,
                        32767,
                        1,
                        FrameCPP::FrVect::ZERO_SUPPRESS );
    compress< REAL_4 >( FrameCPP::FrVect::ZERO_SUPPRESS,
                        0,
                        1.0,
                        1.0,
                        1.0,
                        1,
                        FrameCPP::FrVect::RAW,
                        1 );
    compress< REAL_4 >( FrameCPP::FrVect::ZERO_SUPPRESS,
                        0,
                        -32768.0,
                        32767.0,
                        1.0,
                        FrameCPP::FrVect::ZERO_SUPPRESS );
    compress< REAL_8 >( FrameCPP::FrVect::ZERO_SUPPRESS,
                        0,
                        1.0,
                        1.0,
                        1.0,
                        1,
                        FrameCPP::FrVect::RAW,
                        1 );
    compress< REAL_8 >( FrameCPP::FrVect::ZERO_SUPPRESS,
                        0,
                        -32768.0,
                        32767.0,
                        1.0,
                        FrameCPP::FrVect::ZERO_SUPPRESS );
    compress< COMPLEX_8 >( FrameCPP::FrVect::ZERO_SUPPRESS,
                           0,
                           COMPLEX_8( 1.0, 0.0 ),
                           COMPLEX_8( 1.0, 0.0 ),
                           COMPLEX_8( 1.0, 0.0 ),
                           1,
                           FrameCPP::FrVect::RAW,
                           1 );
    compress< COMPLEX_8 >( FrameCPP::FrVect::ZERO_SUPPRESS,
                           0,
                           COMPLEX_8( -32768.0, 0.0 ),
                           COMPLEX_8( 32767.0, 0.0 ),
                           COMPLEX_8( 1.0, 0.0 ),
                           65636,
                           FrameCPP::FrVect::ZERO_SUPPRESS );
    compress< COMPLEX_16 >( FrameCPP::FrVect::ZERO_SUPPRESS,
                            0,
                            COMPLEX_16( 1.0, 0.0 ),
                            COMPLEX_16( 1.0, 0.0 ),
                            COMPLEX_16( 1.0, 0.0 ),
                            1,
                            FrameCPP::FrVect::RAW,
                            1 );
    compress< COMPLEX_16 >( FrameCPP::FrVect::ZERO_SUPPRESS,
                            0,
                            COMPLEX_16( -32768.0, 0.0 ),
                            COMPLEX_16( 32767.0, 0.0 ),
                            COMPLEX_16( 1.0, 0.0 ),
                            65636,
                            FrameCPP::FrVect::ZERO_SUPPRESS );
#endif /* TEST_ZERO_SUPPRESS */
}

void
test_zero_suppress_short( )
{
#if TEST_ZERO_SUPPRESS_SHORT
    //---------------------------------------------------------------------
    // ZERO_SUPPRESS_SHORT
    //---------------------------------------------------------------------
    compress< CHAR_U >( FrameCPP::FrVect::ZERO_SUPPRESS,
                        0,
                        1,
                        1,
                        1,
                        1,
                        FrameCPP::FrVect::RAW,
                        1 );
    compress< CHAR_U >( FrameCPP::FrVect::ZERO_SUPPRESS,
                        0,
                        0,
                        255,
                        1,
                        256,
                        FrameCPP::FrVect::RAW );
    compress< CHAR >( FrameCPP::FrVect::ZERO_SUPPRESS,
                      0,
                      1,
                      1,
                      1,
                      1,
                      FrameCPP::FrVect::RAW,
                      1 );
    compress< CHAR >( FrameCPP::FrVect::ZERO_SUPPRESS,
                      0,
                      -128,
                      127,
                      1,
                      256,
                      FrameCPP::FrVect::RAW );
    compress< INT_2U >( FrameCPP::FrVect::ZERO_SUPPRESS,
                        0,
                        1,
                        1,
                        1,
                        1,
                        FrameCPP::FrVect::RAW,
                        1 );
    compress< INT_2U >( FrameCPP::FrVect::ZERO_SUPPRESS,
                        0,
                        0,
                        65534,
                        2,
                        65534 / 2,
                        FrameCPP::FrVect::ZERO_SUPPRESS );
    compress< INT_2S >( FrameCPP::FrVect::ZERO_SUPPRESS,
                        0,
                        1,
                        1,
                        1,
                        1,
                        FrameCPP::FrVect::RAW,
                        1 );
    compress< INT_2S >( FrameCPP::FrVect::ZERO_SUPPRESS,
                        0,
                        -1024 * 4,
                        1024 * 4,
                        4,
                        1024 * 2,
                        FrameCPP::FrVect::ZERO_SUPPRESS );
    compress< INT_2S >( FrameCPP::FrVect::ZERO_SUPPRESS,
                        0,
                        -32768,
                        32767,
                        1,
                        65536,
                        waveform_compression( FrameCPP::FrVect::RAW,
                                              SAW_TOOTH_FALLING,
                                              FrameCPP::FrVect::ZERO_SUPPRESS,
                                              SQUARE_WAVE,
                                              FrameCPP::FrVect::ZERO_SUPPRESS,
                                              NO_WAVE_FORM ) );
    compress< INT_4U >( FrameCPP::FrVect::ZERO_SUPPRESS,
                        0,
                        1,
                        1,
                        1,
                        1,
                        FrameCPP::FrVect::RAW,
                        1 );
    compress< INT_4U >( FrameCPP::FrVect::ZERO_SUPPRESS,
                        0,
                        0,
                        65535,
                        1,
                        FrameCPP::FrVect::RAW );
    compress< INT_4S >( FrameCPP::FrVect::ZERO_SUPPRESS,
                        0,
                        1,
                        1,
                        1,
                        1,
                        FrameCPP::FrVect::RAW,
                        1 );
    compress< INT_4S >( FrameCPP::FrVect::ZERO_SUPPRESS,
                        0,
                        -32768,
                        32767,
                        1,
                        FrameCPP::FrVect::RAW );
    compress< INT_8U >( FrameCPP::FrVect::ZERO_SUPPRESS,
                        0,
                        1,
                        1,
                        1,
                        1,
                        FrameCPP::FrVect::RAW,
                        1 );
    compress< INT_8U >( FrameCPP::FrVect::ZERO_SUPPRESS,
                        0,
                        0,
                        65535,
                        1,
                        FrameCPP::FrVect::RAW );
    compress< INT_8S >( FrameCPP::FrVect::ZERO_SUPPRESS,
                        0,
                        1,
                        1,
                        1,
                        1,
                        FrameCPP::FrVect::RAW,
                        1 );
    compress< INT_8S >( FrameCPP::FrVect::ZERO_SUPPRESS,
                        0,
                        -32768,
                        32767,
                        1,
                        FrameCPP::FrVect::RAW );
    compress< REAL_4 >( FrameCPP::FrVect::ZERO_SUPPRESS,
                        0,
                        1.0,
                        1.0,
                        1.0,
                        1,
                        FrameCPP::FrVect::RAW,
                        1 );
    compress< REAL_4 >( FrameCPP::FrVect::ZERO_SUPPRESS,
                        0,
                        -32768.0,
                        32767.0,
                        1.0,
                        FrameCPP::FrVect::RAW );
    compress< REAL_8 >( FrameCPP::FrVect::ZERO_SUPPRESS,
                        0,
                        1.0,
                        1.0,
                        1.0,
                        1,
                        FrameCPP::FrVect::RAW,
                        1 );
    compress< REAL_8 >( FrameCPP::FrVect::ZERO_SUPPRESS,
                        0,
                        -32768.0,
                        32767.0,
                        1.0,
                        FrameCPP::FrVect::RAW );
    compress< COMPLEX_8 >( FrameCPP::FrVect::ZERO_SUPPRESS,
                           0,
                           COMPLEX_8( 1.0, 0.0 ),
                           COMPLEX_8( 1.0, 0.0 ),
                           COMPLEX_8( 1.0, 0.0 ),
                           1,
                           FrameCPP::FrVect::RAW,
                           1 );
    compress< COMPLEX_8 >( FrameCPP::FrVect::ZERO_SUPPRESS,
                           0,
                           COMPLEX_8( -32768.0, 0.0 ),
                           COMPLEX_8( 32767.0, 0.0 ),
                           COMPLEX_8( 1.0, 0.0 ),
                           65636,
                           FrameCPP::FrVect::RAW );
    compress< COMPLEX_16 >( FrameCPP::FrVect::ZERO_SUPPRESS,
                            0,
                            COMPLEX_16( 1.0, 0.0 ),
                            COMPLEX_16( 1.0, 0.0 ),
                            COMPLEX_16( 1.0, 0.0 ),
                            1,
                            FrameCPP::FrVect::RAW,
                            1 );
    compress< COMPLEX_16 >( FrameCPP::FrVect::ZERO_SUPPRESS,
                            0,
                            COMPLEX_16( -32768.0, 0.0 ),
                            COMPLEX_16( 32767.0, 0.0 ),
                            COMPLEX_16( 1.0, 0.0 ),
                            65636,
                            FrameCPP::FrVect::RAW );
#endif /* TEST_ZERO_SUPPRESS_SHORT */
}

void
test_zero_suppress_int_float( )
{
#if TEST_ZERO_SUPPRESS_INT_FLOAT
    //---------------------------------------------------------------------
    // ZERO_SUPPRESS_INT_FLOAT
    //---------------------------------------------------------------------
    compress< CHAR_U >( FrameCPP::FrVect::ZERO_SUPPRESS,
                        0,
                        1,
                        1,
                        1,
                        1,
                        FrameCPP::FrVect::RAW,
                        1 );
    compress< CHAR_U >( FrameCPP::FrVect::ZERO_SUPPRESS,
                        0,
                        0,
                        255,
                        1,
                        256,
                        FrameCPP::FrVect::RAW );
    compress< CHAR >( FrameCPP::FrVect::ZERO_SUPPRESS,
                      0,
                      1,
                      1,
                      1,
                      1,
                      FrameCPP::FrVect::RAW,
                      1 );
    compress< CHAR >( FrameCPP::FrVect::ZERO_SUPPRESS,
                      0,
                      -128,
                      127,
                      1,
                      256,
                      FrameCPP::FrVect::RAW );
    compress< INT_2U >( FrameCPP::FrVect::ZERO_SUPPRESS,
                        0,
                        1,
                        1,
                        1,
                        1,
                        FrameCPP::FrVect::RAW,
                        1 );
    compress< INT_2U >( FrameCPP::FrVect::ZERO_SUPPRESS,
                        0,
                        0,
                        1024 * 4,
                        4,
                        1024 * 4,
                        FrameCPP::FrVect::ZERO_SUPPRESS );
    compress< INT_2S >( FrameCPP::FrVect::ZERO_SUPPRESS,
                        0,
                        1,
                        1,
                        1,
                        1,
                        FrameCPP::FrVect::RAW,
                        1 );
    compress< INT_2S >( FrameCPP::FrVect::ZERO_SUPPRESS,
                        0,
                        -1024 * 4,
                        1024 * 4,
                        4,
                        1024 * 2,
                        FrameCPP::FrVect::ZERO_SUPPRESS );
    compress< INT_2S >( FrameCPP::FrVect::ZERO_SUPPRESS,
                        0,
                        -32768,
                        32767,
                        1,
                        65536,
                        waveform_compression( FrameCPP::FrVect::RAW,
                                              SAW_TOOTH_FALLING,
                                              FrameCPP::FrVect::ZERO_SUPPRESS,
                                              SQUARE_WAVE,
                                              FrameCPP::FrVect::ZERO_SUPPRESS,
                                              NO_WAVE_FORM ) );
    compress< INT_4U >( FrameCPP::FrVect::ZERO_SUPPRESS,
                        0,
                        1,
                        1,
                        1,
                        1,
                        FrameCPP::FrVect::RAW,
                        1 );
    compress< INT_4U >( FrameCPP::FrVect::ZERO_SUPPRESS,
                        0,
                        0,
                        16,
                        2,
                        FrameCPP::FrVect::ZERO_SUPPRESS );
    compress< INT_4S >( FrameCPP::FrVect::ZERO_SUPPRESS,
                        0,
                        1,
                        1,
                        1,
                        1,
                        FrameCPP::FrVect::RAW,
                        1 );
#if 0
  compress< INT_4U >( FrameCPP::FrVect::ZERO_SUPPRESS, 0,
		      0, 65534, 2,
		      FrameCPP::FrVect::ZERO_SUPPRESS );
  compress< INT_4S >( FrameCPP::FrVect::ZERO_SUPPRESS, 0,
		      -32766, 32767, 4,
		      FrameCPP::FrVect::ZERO_SUPPRESS );
  compress< INT_8U >( FrameCPP::FrVect::ZERO_SUPPRESS, 0,
		      0, 65535, 1, FrameCPP::FrVect::RAW );
  compress< INT_8S >( FrameCPP::FrVect::ZERO_SUPPRESS, 0,
		      -32768, 32767, 1, FrameCPP::FrVect::RAW );
  compress< REAL_4 >( FrameCPP::FrVect::ZERO_SUPPRESS, 0,
		      -32.0, 32.0, 1.0,
		      waveform_compression( FrameCPP::FrVect::RAW,
					    SAW_TOOTH_PEAKS,
					    FrameCPP::FrVect::ZERO_SUPPRESS,
					    NO_WAVE_FORM ) );

  compress< REAL_8 >( FrameCPP::FrVect::ZERO_SUPPRESS, 0,
		      -32768.0, 32768.0, 1.0, FrameCPP::FrVect::RAW );
  compress< COMPLEX_8 >( FrameCPP::FrVect::ZERO_SUPPRESS, 0,
			 COMPLEX_8( -32768.0, 0.0 ),
			 COMPLEX_8( 32767.0, 0.0 ),
			 COMPLEX_8( 1.0, 0.0 ),
			 65636, FrameCPP::FrVect::RAW );
  compress< COMPLEX_16 >( FrameCPP::FrVect::ZERO_SUPPRESS, 0,
			  COMPLEX_8( -32768.0, 0.0 ),
			  COMPLEX_8( 32767.0, 0.0 ),
			  COMPLEX_8( 1.0, 0.0 ),
			  65636, FrameCPP::FrVect::RAW );
  compress< CHAR_U >( FrameCPP::FrVect::ZERO_SUPPRESS,
                      0,
                      1,
                      1,
                      1,
                      1,
                      FrameCPP::FrVect::RAW,
                      1 );
#endif /* 0 */
#endif /* ZERO_SUPPRESS_INT_FLOAT */
}

BOOST_AUTO_TEST_CASE( frame_compression )
{
    if ( DUMP_DATA( ) )
    {
        //-------------------------------------------------------------------
        // Setup the frame which will contain all of the
        //-------------------------------------------------------------------
        FrameName << "Compression_FrameSpec_" << FrameSpecVersion << "_"
                  <<
#if WORDS_BIGENDIAN
            "BigEndian"
#else
            "LittleEndian"
#endif
                  << "_" << SystemType;
        Frame.reset( new FrameCPP::FrameH( FrameName.str( ),
                                           FrameRun,
                                           FrameNumber,
                                           FrameStart,
                                           FrameStart.GetLeapSeconds( ),
                                           FrameDT ) );
        if ( !Frame )
        {
            throw std::bad_alloc( );
        }
        {
            FrameCPP::FrameH::rawData_type raw_data(
                new FrameCPP::FrameH::rawData_type::element_type( "Raw" ) );
            if ( !raw_data )
            {
                throw std::bad_alloc( );
            }
            Frame->SetRawData( raw_data );
        }
    }
#if TEST_FILE_COMPARISON
    else
    {
        //-------------------------------------------------------------------
        // :TODO: Need to scan the current directory and the source directory
        // :TODO:  for frame files.
        //-------------------------------------------------------------------
        if ( ( ::getenv( "COMPRESSION_FRAME_PREFIX" ) != (char*)NULL ) &&
             ( ::access( ::getenv( "COMPRESSION_FRAME_PREFIX" ),
                         R_OK | X_OK ) == 0 ) )
        {
            FrameFiles.OpenDir( ::getenv( "COMPRESSION_FRAME_PREFIX" ) );
        }
    }
#endif /* TEST_FILE_COMPARISON */

    test_building_blocks( );
    test_raw( );
    test_gzip( );
    test_diff_gzip( );
    if ( FRAME_SPEC_CURRENT >= 9 )
    {
        test_zero_suppress( );
        test_zstd( );
        test_diff_zstd( );
    }
    else
    {
        test_zero_suppress_short( );
        test_zero_suppress_int_float( );
    }
#if TEST_ZERO_SUPPRESS_OTHERWISE_GZIP
    //---------------------------------------------------------------------
    // ZERO_SUPPRESS_OTHERWISE_GZIP
    //---------------------------------------------------------------------
    EnableFrameL( false );
    compress< CHAR_U >( FrameCPP::FrVect::ZERO_SUPPRESS_OTHERWISE_GZIP,
                        9,
                        0,
                        0,
                        1,
                        1,
                        FrameCPP::FrVect::RAW,
                        1 );
    compress< CHAR_U >( FrameCPP::FrVect::ZERO_SUPPRESS_OTHERWISE_GZIP,
                        1,
                        0,
                        255,
                        1,
                        256,
                        FrameCPP::FrVect::GZIP );
    compress< CHAR >( FrameCPP::FrVect::ZERO_SUPPRESS_OTHERWISE_GZIP,
                      9,
                      0,
                      0,
                      1,
                      1,
                      FrameCPP::FrVect::RAW,
                      1 );
    compress< CHAR >( FrameCPP::FrVect::ZERO_SUPPRESS_OTHERWISE_GZIP,
                      1,
                      -128,
                      127,
                      1,
                      256,
                      FrameCPP::FrVect::GZIP );
    compress< INT_2U >( FrameCPP::FrVect::ZERO_SUPPRESS_OTHERWISE_GZIP,
                        9,
                        0,
                        0,
                        1,
                        1,
                        FrameCPP::FrVect::RAW,
                        1 );
    compress< INT_2U >( FrameCPP::FrVect::ZERO_SUPPRESS_OTHERWISE_GZIP,
                        1,
                        0,
                        1024 * 4,
                        4,
                        1024 * 4,
                        FrameCPP::FrVect::ZERO_SUPPRESS );
    compress< INT_2S >( FrameCPP::FrVect::ZERO_SUPPRESS_OTHERWISE_GZIP,
                        9,
                        0,
                        0,
                        1,
                        1,
                        FrameCPP::FrVect::RAW,
                        1 );
    compress< INT_2S >( FrameCPP::FrVect::ZERO_SUPPRESS_OTHERWISE_GZIP,
                        1,
                        -1024 * 4,
                        1024 * 4,
                        4,
                        1024 * 2,
                        FrameCPP::FrVect::ZERO_SUPPRESS );
    compress< INT_2S >( FrameCPP::FrVect::ZERO_SUPPRESS_OTHERWISE_GZIP,
                        1,
                        -32768,
                        32767,
                        1,
                        65536,
                        waveform_compression( FrameCPP::FrVect::GZIP,
                                              SAW_TOOTH_FALLING,
                                              FrameCPP::FrVect::ZERO_SUPPRESS,
                                              SQUARE_WAVE,
                                              FrameCPP::FrVect::ZERO_SUPPRESS,
                                              NO_WAVE_FORM ) );
    compress< INT_4U >( FrameCPP::FrVect::ZERO_SUPPRESS_OTHERWISE_GZIP,
                        9,
                        0,
                        0,
                        1,
                        1,
                        FrameCPP::FrVect::RAW,
                        1 );
    compress< INT_4U >( FrameCPP::FrVect::ZERO_SUPPRESS_OTHERWISE_GZIP,
                        1,
                        0,
                        16,
                        2,
                        FrameCPP::FrVect::ZERO_SUPPRESS );
    compress< INT_4U >( FrameCPP::FrVect::ZERO_SUPPRESS_OTHERWISE_GZIP,
                        1,
                        0,
                        65534,
                        2,
                        FrameCPP::FrVect::ZERO_SUPPRESS );
    compress< INT_4S >( FrameCPP::FrVect::ZERO_SUPPRESS_OTHERWISE_GZIP,
                        9,
                        0,
                        0,
                        1,
                        1,
                        FrameCPP::FrVect::RAW,
                        1 );
    compress< INT_4S >( FrameCPP::FrVect::ZERO_SUPPRESS_OTHERWISE_GZIP,
                        1,
                        -32766,
                        32767,
                        4,
                        FrameCPP::FrVect::ZERO_SUPPRESS );
    compress< INT_8U >( FrameCPP::FrVect::ZERO_SUPPRESS_OTHERWISE_GZIP,
                        9,
                        0,
                        0,
                        1,
                        1,
                        FrameCPP::FrVect::RAW,
                        1 );
    compress< INT_8U >( FrameCPP::FrVect::ZERO_SUPPRESS_OTHERWISE_GZIP,
                        1,
                        0,
                        65535,
                        1,
#if FRAME_SPEC_CURRENT < 8
                        FrameCPP::FrVect::GZIP
#elif FRAME_SPEC_CURRENT < 9
                        FrameCPP::FrVect::ZERO_SUPPRESS_WORD_8
#else /* FRAME_SPEC_CURRENT < 8 */
                        FrameCPP::FrVect::ZERO_SUPPRESS
#endif /* FRAME_SPEC_CURRENT < 8 */
    );
    compress< INT_8S >( FrameCPP::FrVect::ZERO_SUPPRESS_OTHERWISE_GZIP,
                        9,
                        0,
                        0,
                        1,
                        1,
                        FrameCPP::FrVect::RAW,
                        1 );
    compress< INT_8S >( FrameCPP::FrVect::ZERO_SUPPRESS_OTHERWISE_GZIP,
                        1,
                        -32768,
                        32767,
                        1,
#if FRAME_SPEC_CURRENT < 8
                        FrameCPP::FrVect::GZIP
#elif FRAME_SPEC_CURRENT < 9
                        FrameCPP::FrVect::ZERO_SUPPRESS_WORD_8
#else /* FRAME_SPEC_CURRENT < 8 */
                        FrameCPP::FrVect::ZERO_SUPPRESS
#endif /* FRAME_SPEC_CURRENT < 8 */
    );
    compress< REAL_4 >( FrameCPP::FrVect::ZERO_SUPPRESS_OTHERWISE_GZIP,
                        9,
                        1.0,
                        1.0,
                        1.0,
                        1,
                        FrameCPP::FrVect::RAW,
                        1 );
    compress< REAL_4 >( FrameCPP::FrVect::ZERO_SUPPRESS_OTHERWISE_GZIP,
                        1,
                        -32.0,
                        32.0,
                        1.0,
                        waveform_compression( FrameCPP::FrVect::GZIP,
                                              SAW_TOOTH_PEAKS,
                                              FrameCPP::FrVect::ZERO_SUPPRESS,
                                              NO_WAVE_FORM ) );

    compress< REAL_8 >( FrameCPP::FrVect::ZERO_SUPPRESS_OTHERWISE_GZIP,
                        9,
                        1.0,
                        1.0,
                        1.0,
                        1,
                        FrameCPP::FrVect::RAW,
                        1 );
    compress< REAL_8 >( FrameCPP::FrVect::ZERO_SUPPRESS_OTHERWISE_GZIP,
                        1,
                        -32768.0,
                        32768.0,
                        1.0,
#if FRAME_SPEC_CURRENT < 8
                        FrameCPP::FrVect::GZIP
#else /* FRAME_SPEC_CURRENT < 8 */
                        waveform_compression(
#if FRAME_SPEC_CURRENT <= 8
                            FrameCPP::FrVect::ZERO_SUPPRESS_WORD_8,
#else /* FRAME_SPEC_CURRENT <= 8 */
                            FrameCPP::FrVect::ZERO_SUPPRESS,
#endif /* FRAME_SPEC_CURRENT <= 8 */
                            SAW_TOOTH_RISING,
                            FrameCPP::FrVect::GZIP,
                            SAW_TOOTH_FALLING,
                            FrameCPP::FrVect::GZIP,
                            SQUARE_WAVE,
                            FrameCPP::FrVect::GZIP,
                            NO_WAVE_FORM )
#endif /* FRAME_SPEC_CURRENT < 8 */
    );
    compress< COMPLEX_8 >( FrameCPP::FrVect::ZERO_SUPPRESS_OTHERWISE_GZIP,
                           9,
                           COMPLEX_8( 1.0, 0.0 ),
                           COMPLEX_8( 1.0, 0.0 ),
                           COMPLEX_8( 1.0, 0.0 ),
                           1,
                           FrameCPP::FrVect::RAW,
                           1 );
    compress< COMPLEX_8 >( FrameCPP::FrVect::ZERO_SUPPRESS_OTHERWISE_GZIP,
                           1,
                           COMPLEX_8( -32768.0, 0.0 ),
                           COMPLEX_8( 32767.0, 0.0 ),
                           COMPLEX_8( 1.0, 0.0 ),
                           65636,
#if FRAME_SPEC_CURRENT < 8
                           FrameCPP::FrVect::GZIP
#elif FRAME_SPEC_CURRENT < 9
                           FrameCPP::FrVect::ZERO_SUPPRESS_WORD_4
#else /* FRAME_SPEC_CURRENT < 8 */
                           FrameCPP::FrVect::ZERO_SUPPRESS
#endif /* FRAME_SPEC_CURRENT < 8 */
    );
    compress< COMPLEX_16 >( FrameCPP::FrVect::ZERO_SUPPRESS_OTHERWISE_GZIP,
                            1,
                            COMPLEX_8( -32768.0, 0.0 ),
                            COMPLEX_8( 32767.0, 0.0 ),
                            COMPLEX_8( 1.0, 0.0 ),
                            65636,
#if FRAME_SPEC_CURRENT < 8
                            FrameCPP::FrVect::GZIP
#elif FRAME_SPEC_CURRENT < 9
                            FrameCPP::FrVect::ZERO_SUPPRESS_WORD_8
#else /* FRAME_SPEC_CURRENT < 8 */
                            FrameCPP::FrVect::ZERO_SUPPRESS
#endif /* FRAME_SPEC_CURRENT < 8 */
    );
    EnableFrameL( true );
#endif /* TEST_ZERO_SUPPRESS_OTHERWISE_GZIP */
#if 0
  //---------------------------------------------------------------------
  // Problem since there are only 3 data points. Does not compare with
  //   FrameL implementation as FrameL requires 8 data points before
  //   it will compress the data.
  //---------------------------------------------------------------------
  compress< INT_4U >( FrameCPP::FrVect::ZERO_SUPPRESS, 0,
		      0, 6, 2,
		      FrameCPP::FrVect::ZERO_SUPPRESS );
#endif /* 0 */
#if TEST_PROBLEM_CASES
    //---------------------------------------------------------------------
    // Test some problem cases
    //---------------------------------------------------------------------
    message_line( );
    BOOST_TEST_MESSAGE( "%%% Problem cases %%%" );
    compress( FrameCPP::FrVect::ZERO_SUPPRESS,
              0,
              sc1,
              sizeof( sc1 ) / sizeof( *sc1 ),
              FrameCPP::FrVect::ZERO_SUPPRESS,
              "SC1_DataSet" );

    compress( FrameCPP::FrVect::ZERO_SUPPRESS,
              0,
              sc2,
              sizeof( sc2 ) / sizeof( *sc2 ),
              FrameCPP::FrVect::ZERO_SUPPRESS,
              "SC2_DataSet" );

    compress< REAL_8 >( FrameCPP::FrVect::ZERO_SUPPRESS,
                        0,
                        -32768.0 / 3.0,
                        32767.0 / 3.0,
                        1.0 / 3.0,
                        FrameCPP::FrVect::RAW );

    compress< REAL_8 >( FrameCPP::FrVect::ZERO_SUPPRESS,
                        0,
                        -32768.0 / 3.0,
                        32767.0 / 3.0,
                        1.0 / 3.0,
                        FrameCPP::FrVect::RAW );
#endif /* TEST_PROBLEM_CASES */

    //---------------------------------------------------------------------
    // Do some cleanup before leaving
    //---------------------------------------------------------------------
    if ( DUMP_DATA( ) )
    {
        //-------------------------------------------------------------------
        // When in the dumping data mode, need to write out the frame before
        //   leaving
        //-------------------------------------------------------------------
        std::ostringstream filename;

        filename << "Z-" << FrameName.str( ) << "-" << FrameStart.GetSeconds( )
                 << "-" << FrameDT << ".gwf";
        std::ofstream file( filename.str( ).c_str( ) );

        std::unique_ptr< FrameBuffer > obuf( new FrameBuffer( std::ios::out ) );

        if ( !obuf.get( ) )
        {
            throw std::bad_alloc( );
        }
        obuf->open( filename.str( ).c_str( ),
                    std::ios::out | std::ios::binary );

        OFrameStream ofs( obuf.release( ) );

        ofs.WriteFrame( Frame );
        ofs.Close( );
    }
    else
    {
        //-------------------------------------------------------------------
        // :TODO: Close out any frame files that were opened for testing
        // purposes
        //-------------------------------------------------------------------
    }
}
