mirror of https://github.com/hmatuschek/libsdr
Added missing examples and unit tests.
parent
aeec3586bc
commit
7934a72b24
@ -0,0 +1,14 @@
|
|||||||
|
IF(SDR_WITH_QT5 AND SDR_WITH_FFTW AND SDR_WITH_PORTAUDIO)
|
||||||
|
add_executable(sdr_spec sdr_spec.cc)
|
||||||
|
target_link_libraries(sdr_spec ${LIBS} ${QT_LIBRARIES} libsdr libsdr-gui )
|
||||||
|
ENDIF(SDR_WITH_QT5 AND SDR_WITH_FFTW AND SDR_WITH_PORTAUDIO)
|
||||||
|
|
||||||
|
IF(SDR_WITH_PORTAUDIO)
|
||||||
|
add_executable(sdr_wavplay sdr_wavplay.cc)
|
||||||
|
target_link_libraries(sdr_wavplay ${LIBS} libsdr)
|
||||||
|
ENDIF(SDR_WITH_PORTAUDIO)
|
||||||
|
|
||||||
|
IF(SDR_WITH_QT5 AND SDR_WITH_FFTW AND SDR_WITH_PORTAUDIO)
|
||||||
|
add_executable(sdr_rds sdr_rds.cc)
|
||||||
|
target_link_libraries(sdr_rds ${LIBS} ${QT_LIBRARIES} libsdr libsdr-gui)
|
||||||
|
ENDIF(SDR_WITH_QT5 AND SDR_WITH_FFTW AND SDR_WITH_PORTAUDIO)
|
||||||
@ -0,0 +1,82 @@
|
|||||||
|
#include "sdr.hh"
|
||||||
|
#include "rtlsource.hh"
|
||||||
|
#include "baseband.hh"
|
||||||
|
#include "autocast.hh"
|
||||||
|
#include "gui/gui.hh"
|
||||||
|
#include "logger.hh"
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QMainWindow>
|
||||||
|
#include <QThread>
|
||||||
|
|
||||||
|
using namespace sdr;
|
||||||
|
|
||||||
|
static void __sigint_handler(int signo) {
|
||||||
|
// On SIGINT -> stop queue properly
|
||||||
|
Queue::get().stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
if (argc < 2) {
|
||||||
|
std::cerr << "USAGE: sdr_rds FREQUENCY" << std::endl;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
double freq = atof(argv[1]);
|
||||||
|
|
||||||
|
PortAudio::init();
|
||||||
|
Queue &queue = Queue::get();
|
||||||
|
|
||||||
|
// Register handler:
|
||||||
|
signal(SIGINT, __sigint_handler);
|
||||||
|
|
||||||
|
QApplication app(argc, argv);
|
||||||
|
|
||||||
|
QMainWindow *win = new QMainWindow();
|
||||||
|
gui::Spectrum *spec = new gui::Spectrum(2, 1024, 5);
|
||||||
|
gui::SpectrumView *spec_view = new gui::SpectrumView(spec);
|
||||||
|
spec_view->setMindB(-200);
|
||||||
|
win->setCentralWidget(spec_view);
|
||||||
|
win->setMinimumSize(640, 240);
|
||||||
|
|
||||||
|
win->show();
|
||||||
|
|
||||||
|
sdr::Logger::get().addHandler(new sdr::StreamLogHandler(std::cerr, sdr::LOG_DEBUG));
|
||||||
|
|
||||||
|
// Assemble processing chain
|
||||||
|
//RTLSource src(freq, 1e6);
|
||||||
|
WavSource src(argv[1]);
|
||||||
|
AutoCast< std::complex<int16_t> > cast;
|
||||||
|
IQBaseBand<int16_t> baseband(0, 200e3, 16, 5);
|
||||||
|
FMDemod<int16_t, int16_t> demod;
|
||||||
|
BaseBand<int16_t> mono(0, 15e3, 16, 6);
|
||||||
|
BaseBand<int16_t> pilot(19e3, 5e2, 16, 84);
|
||||||
|
BaseBand<int16_t> rds(57e3, 3e3, 16, 84);
|
||||||
|
PortSink sink;
|
||||||
|
|
||||||
|
src.connect(&cast, true);
|
||||||
|
cast.connect(&baseband, true);
|
||||||
|
//src.connect(&baseband, true);
|
||||||
|
baseband.connect(&demod, true);
|
||||||
|
demod.connect(&mono);
|
||||||
|
demod.connect(&pilot);
|
||||||
|
demod.connect(&rds);
|
||||||
|
|
||||||
|
mono.connect(&sink);
|
||||||
|
mono.connect(spec);
|
||||||
|
|
||||||
|
//queue.addStart(&src, &RTLSource::start);
|
||||||
|
//queue.addStop(&src, &RTLSource::stop);
|
||||||
|
queue.addIdle(&src, &WavSource::next);
|
||||||
|
|
||||||
|
queue.start();
|
||||||
|
app.exec();
|
||||||
|
queue.stop();
|
||||||
|
queue.wait();
|
||||||
|
|
||||||
|
PortAudio::terminate();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@ -0,0 +1,64 @@
|
|||||||
|
#include "sdr.hh"
|
||||||
|
#include "rtlsource.hh"
|
||||||
|
#include "baseband.hh"
|
||||||
|
#include "utils.hh"
|
||||||
|
#include "gui/gui.hh"
|
||||||
|
#include <signal.h>
|
||||||
|
#include "portaudio.hh"
|
||||||
|
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QMainWindow>
|
||||||
|
#include <QThread>
|
||||||
|
|
||||||
|
using namespace sdr;
|
||||||
|
|
||||||
|
static void __sigint_handler(int signo) {
|
||||||
|
// On SIGINT -> stop queue properly
|
||||||
|
Queue::get().stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
Queue &queue = Queue::get();
|
||||||
|
|
||||||
|
// Register handler:
|
||||||
|
signal(SIGINT, __sigint_handler);
|
||||||
|
|
||||||
|
PortAudio::init();
|
||||||
|
|
||||||
|
QApplication app(argc, argv);
|
||||||
|
|
||||||
|
QMainWindow *win = new QMainWindow();
|
||||||
|
gui::Spectrum *spec = new gui::Spectrum(2, 1024, 5);
|
||||||
|
gui::WaterFallView *spec_view = new gui::WaterFallView(spec);
|
||||||
|
win->setCentralWidget(spec_view);
|
||||||
|
win->setMinimumSize(640, 240);
|
||||||
|
|
||||||
|
win->show();
|
||||||
|
|
||||||
|
// Assemble processing chain
|
||||||
|
PortSource< int16_t > src(44100.0, 2048);
|
||||||
|
AGC<int16_t> agc;
|
||||||
|
//IQBaseBand<int16_t> baseband(0, 500e3, 8, 5);
|
||||||
|
//AMDemod<int16_t> demod;
|
||||||
|
PortSink sink;
|
||||||
|
|
||||||
|
src.connect(&agc, true);
|
||||||
|
agc.connect(&sink, true);
|
||||||
|
//baseband.connect(&demod);
|
||||||
|
//demod.connect(&sink, true);
|
||||||
|
src.connect(spec);
|
||||||
|
|
||||||
|
queue.addIdle(&src, &PortSource< int16_t >::next);
|
||||||
|
|
||||||
|
queue.start();
|
||||||
|
app.exec();
|
||||||
|
|
||||||
|
queue.stop();
|
||||||
|
queue.wait();
|
||||||
|
|
||||||
|
PortAudio::terminate();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@ -0,0 +1,41 @@
|
|||||||
|
#include "sdr.hh"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
using namespace sdr;
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
if (argc < 2) {
|
||||||
|
std::cerr << "USAGE: sdr_wavplay FILENAME" << std::endl;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Queue &queue = Queue::get();
|
||||||
|
|
||||||
|
PortAudio::init();
|
||||||
|
|
||||||
|
WavSource src(argv[1]);
|
||||||
|
if (! src.isOpen() ) {
|
||||||
|
std::cerr << "Can not open file " << argv[1] << std::endl;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
queue.addIdle(&src, &WavSource::next);
|
||||||
|
|
||||||
|
RealPart<int16_t> to_real;
|
||||||
|
PortSink sink;
|
||||||
|
|
||||||
|
if (src.isReal()) {
|
||||||
|
src.connect(&sink, true);
|
||||||
|
} else {
|
||||||
|
src.connect(&to_real, true);
|
||||||
|
to_real.connect(&sink, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// run...
|
||||||
|
queue.start();
|
||||||
|
queue.wait();
|
||||||
|
|
||||||
|
PortAudio::terminate();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
set(test_SOURCES main.cc
|
||||||
|
cputime.cc unittest.cc buffertest.cc coreutilstest.cc coretest.cc)
|
||||||
|
set(test_HEADERS
|
||||||
|
cputime.hh unittest.hh buffertest.hh coreutilstest.hh coretest.hh)
|
||||||
|
|
||||||
|
add_executable(sdr_test ${test_SOURCES})
|
||||||
|
target_link_libraries(sdr_test ${LIBS} libsdr)
|
||||||
@ -0,0 +1,136 @@
|
|||||||
|
#include "buffertest.hh"
|
||||||
|
#include <iostream>
|
||||||
|
using namespace sdr;
|
||||||
|
using namespace UnitTest;
|
||||||
|
|
||||||
|
BufferTest::~BufferTest() { }
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BufferTest::testRefcount() {
|
||||||
|
Buffer<int8_t> a(3);
|
||||||
|
|
||||||
|
// Test Direct reference counting
|
||||||
|
UT_ASSERT_EQUAL(a.refCount(), 1);
|
||||||
|
UT_ASSERT(a.isUnused());
|
||||||
|
|
||||||
|
{
|
||||||
|
Buffer<int8_t> b(a);
|
||||||
|
UT_ASSERT_EQUAL(a.refCount(), 1);
|
||||||
|
UT_ASSERT_EQUAL(b.refCount(), 1);
|
||||||
|
UT_ASSERT(a.isUnused());
|
||||||
|
UT_ASSERT(b.isUnused());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
Buffer<int8_t> b(a);
|
||||||
|
b.ref();
|
||||||
|
UT_ASSERT_EQUAL(a.refCount(), 2);
|
||||||
|
UT_ASSERT_EQUAL(b.refCount(), 2);
|
||||||
|
UT_ASSERT(!a.isUnused());
|
||||||
|
UT_ASSERT(!b.isUnused());
|
||||||
|
b.unref();
|
||||||
|
}
|
||||||
|
|
||||||
|
UT_ASSERT_EQUAL(a.refCount(), 1);
|
||||||
|
UT_ASSERT(a.isUnused());
|
||||||
|
|
||||||
|
// Test indirect reference counting
|
||||||
|
std::list<RawBuffer> buffers;
|
||||||
|
buffers.push_back(a);
|
||||||
|
|
||||||
|
UT_ASSERT_EQUAL(a.refCount(), 1);
|
||||||
|
UT_ASSERT(a.isUnused());
|
||||||
|
|
||||||
|
// check direct referenceing
|
||||||
|
UT_ASSERT_EQUAL(buffers.back().refCount(), 1);
|
||||||
|
UT_ASSERT(buffers.back().isUnused());
|
||||||
|
|
||||||
|
buffers.pop_back();
|
||||||
|
UT_ASSERT_EQUAL(a.refCount(), 1);
|
||||||
|
UT_ASSERT(a.isUnused());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BufferTest::testReinterprete() {
|
||||||
|
// Check handle interleaved numbers as real & imag part
|
||||||
|
Buffer<int8_t> real_buffer(4);
|
||||||
|
|
||||||
|
real_buffer[0] = 1;
|
||||||
|
real_buffer[1] = 2;
|
||||||
|
real_buffer[2] = 3;
|
||||||
|
real_buffer[3] = 4;
|
||||||
|
|
||||||
|
// Cast to complex char
|
||||||
|
Buffer< std::complex<int8_t> > cmplx_buffer(real_buffer);
|
||||||
|
// Check size
|
||||||
|
UT_ASSERT_EQUAL(real_buffer.size()/2, cmplx_buffer.size());
|
||||||
|
// Check content
|
||||||
|
UT_ASSERT_EQUAL(cmplx_buffer[0], std::complex<int8_t>(1,2));
|
||||||
|
UT_ASSERT_EQUAL(cmplx_buffer[1], std::complex<int8_t>(3,4));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BufferTest::testRawRingBuffer() {
|
||||||
|
RawBuffer a(3), b(3);
|
||||||
|
RawRingBuffer ring(3);
|
||||||
|
|
||||||
|
memcpy(a.data(), "abc", 3);
|
||||||
|
|
||||||
|
// Check if ring is empty
|
||||||
|
UT_ASSERT_EQUAL(ring.bytesLen(), size_t(0));
|
||||||
|
UT_ASSERT_EQUAL(ring.bytesFree(), size_t(3));
|
||||||
|
|
||||||
|
// Put a byte
|
||||||
|
UT_ASSERT(ring.put(RawBuffer(a, 0, 1)));
|
||||||
|
UT_ASSERT_EQUAL(ring.bytesLen(), size_t(1));
|
||||||
|
UT_ASSERT_EQUAL(ring.bytesFree(), size_t(2));
|
||||||
|
|
||||||
|
// Put two more bytes
|
||||||
|
UT_ASSERT(ring.put(RawBuffer(a, 1, 2)));
|
||||||
|
UT_ASSERT_EQUAL(ring.bytesLen(), size_t(3));
|
||||||
|
UT_ASSERT_EQUAL(ring.bytesFree(), size_t(0));
|
||||||
|
|
||||||
|
// Now, the ring is full, any further put should fail
|
||||||
|
UT_ASSERT(!ring.put(a));
|
||||||
|
|
||||||
|
// Take a byte from ring
|
||||||
|
UT_ASSERT(ring.take(b, 1));
|
||||||
|
UT_ASSERT_EQUAL(ring.bytesLen(), size_t(2));
|
||||||
|
UT_ASSERT_EQUAL(ring.bytesFree(), size_t(1));
|
||||||
|
UT_ASSERT_EQUAL(*(b.data()), 'a');
|
||||||
|
|
||||||
|
// Take another byte
|
||||||
|
UT_ASSERT(ring.take(b, 1));
|
||||||
|
UT_ASSERT_EQUAL(ring.bytesLen(), size_t(1));
|
||||||
|
UT_ASSERT_EQUAL(ring.bytesFree(), size_t(2));
|
||||||
|
UT_ASSERT_EQUAL(*(b.data()), 'b');
|
||||||
|
|
||||||
|
// Put two more back
|
||||||
|
UT_ASSERT(ring.put(RawBuffer(a, 0, 2)));
|
||||||
|
UT_ASSERT_EQUAL(ring.bytesLen(), size_t(3));
|
||||||
|
UT_ASSERT_EQUAL(ring.bytesFree(), size_t(0));
|
||||||
|
|
||||||
|
// Take all
|
||||||
|
UT_ASSERT(ring.take(b, 3));
|
||||||
|
UT_ASSERT_EQUAL(ring.bytesLen(), size_t(0));
|
||||||
|
UT_ASSERT_EQUAL(ring.bytesFree(), size_t(3));
|
||||||
|
UT_ASSERT(0 == memcmp(b.data(), "cab", 3));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TestSuite *
|
||||||
|
BufferTest::suite() {
|
||||||
|
TestSuite *suite = new TestSuite("Buffer Tests");
|
||||||
|
|
||||||
|
suite->addTest(new TestCaller<BufferTest>(
|
||||||
|
"reference counter", &BufferTest::testRefcount));
|
||||||
|
suite->addTest(new TestCaller<BufferTest>(
|
||||||
|
"re-interprete case", &BufferTest::testReinterprete));
|
||||||
|
suite->addTest(new TestCaller<BufferTest>(
|
||||||
|
"raw ring buffer", &BufferTest::testRawRingBuffer));
|
||||||
|
return suite;
|
||||||
|
}
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
#ifndef __SDR_TEST_BUFFERTEST_HH__
|
||||||
|
#define __SDR_TEST_BUFFERTEST_HH__
|
||||||
|
|
||||||
|
#include "buffer.hh"
|
||||||
|
#include "unittest.hh"
|
||||||
|
|
||||||
|
|
||||||
|
class BufferTest : public UnitTest::TestCase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~BufferTest();
|
||||||
|
|
||||||
|
void testRefcount();
|
||||||
|
void testReinterprete();
|
||||||
|
void testRawRingBuffer();
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
static UnitTest::TestSuite *suite();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // BUFFERTEST_HH
|
||||||
@ -0,0 +1,37 @@
|
|||||||
|
#include "coretest.hh"
|
||||||
|
#include "sdr.hh"
|
||||||
|
|
||||||
|
using namespace sdr;
|
||||||
|
|
||||||
|
|
||||||
|
CoreTest::~CoreTest() { /* pass... */ }
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
CoreTest::testShiftOperators() {
|
||||||
|
// Test if shift can be used as multiplication or division by a power of two
|
||||||
|
// (even on negative integers)
|
||||||
|
int a=128, b=-128;
|
||||||
|
// On positive integers (should work always)
|
||||||
|
UT_ASSERT_EQUAL(a>>1, 64);
|
||||||
|
UT_ASSERT_EQUAL(a<<1, 256);
|
||||||
|
UT_ASSERT_EQUAL(a>>0, 128);
|
||||||
|
UT_ASSERT_EQUAL(a<<0, 128);
|
||||||
|
|
||||||
|
UT_ASSERT_EQUAL(b>>1, -64);
|
||||||
|
UT_ASSERT_EQUAL(b<<1, -256);
|
||||||
|
UT_ASSERT_EQUAL(b>>0, -128);
|
||||||
|
UT_ASSERT_EQUAL(b<<0, -128);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
UnitTest::TestSuite *
|
||||||
|
CoreTest::suite() {
|
||||||
|
UnitTest::TestSuite *suite = new UnitTest::TestSuite("Core operations");
|
||||||
|
|
||||||
|
suite->addTest(new UnitTest::TestCaller<CoreTest>(
|
||||||
|
"shift operators", &CoreTest::testShiftOperators));
|
||||||
|
|
||||||
|
return suite;
|
||||||
|
}
|
||||||
@ -0,0 +1,18 @@
|
|||||||
|
#ifndef __SDT_TEST_CORETEST_HH__
|
||||||
|
#define __SDT_TEST_CORETEST_HH__
|
||||||
|
|
||||||
|
#include "unittest.hh"
|
||||||
|
|
||||||
|
class CoreTest : public UnitTest::TestCase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~CoreTest();
|
||||||
|
|
||||||
|
void testShiftOperators();
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
static UnitTest::TestSuite *suite();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // __SDT_TEST_CORETEST_HH__
|
||||||
@ -0,0 +1,90 @@
|
|||||||
|
#include "coreutilstest.hh"
|
||||||
|
#include "config.hh"
|
||||||
|
#include "utils.hh"
|
||||||
|
#include "combine.hh"
|
||||||
|
|
||||||
|
using namespace sdr;
|
||||||
|
using namespace UnitTest;
|
||||||
|
|
||||||
|
CoreUtilsTest::~CoreUtilsTest() { }
|
||||||
|
|
||||||
|
void
|
||||||
|
CoreUtilsTest::testUChar2Char() {
|
||||||
|
Buffer<uint8_t> uchar_buffer(3);
|
||||||
|
uchar_buffer[0] = 0u;
|
||||||
|
uchar_buffer[1] = 128u;
|
||||||
|
uchar_buffer[2] = 255u;
|
||||||
|
|
||||||
|
// Assemble cast instance and configure it
|
||||||
|
UnsignedToSigned cast;
|
||||||
|
cast.config(Config(Config::Type_u8, 1, 3, 1));
|
||||||
|
// Perform in-place operation
|
||||||
|
cast.handleBuffer(uchar_buffer, true);
|
||||||
|
|
||||||
|
// Reinterprete uchar buffer as char buffer
|
||||||
|
Buffer<int8_t> char_buffer(uchar_buffer);
|
||||||
|
// Check values
|
||||||
|
UT_ASSERT_EQUAL(char_buffer[0], (signed char)-128);
|
||||||
|
UT_ASSERT_EQUAL(char_buffer[1], (signed char)0);
|
||||||
|
UT_ASSERT_EQUAL(char_buffer[2], (signed char)127);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CoreUtilsTest::testUShort2Short() {
|
||||||
|
Buffer<uint16_t> uchar_buffer(3);
|
||||||
|
uchar_buffer[0] = 0u;
|
||||||
|
uchar_buffer[1] = 128u;
|
||||||
|
uchar_buffer[2] = 255u;
|
||||||
|
|
||||||
|
// Assemble cast instance and configure it
|
||||||
|
UnsignedToSigned cast;
|
||||||
|
cast.config(Config(Config::Type_u16, 1, 3, 1));
|
||||||
|
// Perform in-place operation
|
||||||
|
cast.handleBuffer(uchar_buffer, true);
|
||||||
|
|
||||||
|
// Reinterprete uchar buffer as char buffer
|
||||||
|
Buffer<int16_t> char_buffer(uchar_buffer);
|
||||||
|
// Check values
|
||||||
|
UT_ASSERT_EQUAL(char_buffer[0], (int16_t)-128);
|
||||||
|
UT_ASSERT_EQUAL(char_buffer[1], (int16_t)0);
|
||||||
|
UT_ASSERT_EQUAL(char_buffer[2], (int16_t)127);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
CoreUtilsTest::testInterleave() {
|
||||||
|
Interleave<int16_t> interl(2);
|
||||||
|
DebugStore<int16_t> sink;
|
||||||
|
Buffer<int16_t> a(3);
|
||||||
|
|
||||||
|
interl.sink(0)->config(Config(Config::Type_s16, 1, a.size(), 1));
|
||||||
|
interl.sink(1)->config(Config(Config::Type_s16, 1, a.size(), 1));
|
||||||
|
interl.connect(&sink, true);
|
||||||
|
|
||||||
|
// Send some data
|
||||||
|
a[0] = 1; a[1] = 2; a[2] = 3; interl.sink(0)->process(a, false);
|
||||||
|
a[0] = 4; a[1] = 5; a[2] = 6; interl.sink(1)->process(a, false);
|
||||||
|
|
||||||
|
// Check content of sink
|
||||||
|
UT_ASSERT_EQUAL(sink.buffer()[0], (int16_t)1);
|
||||||
|
UT_ASSERT_EQUAL(sink.buffer()[1], (int16_t)4);
|
||||||
|
UT_ASSERT_EQUAL(sink.buffer()[2], (int16_t)2);
|
||||||
|
UT_ASSERT_EQUAL(sink.buffer()[3], (int16_t)5);
|
||||||
|
UT_ASSERT_EQUAL(sink.buffer()[4], (int16_t)3);
|
||||||
|
UT_ASSERT_EQUAL(sink.buffer()[5], (int16_t)6);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TestSuite *
|
||||||
|
CoreUtilsTest::suite() {
|
||||||
|
TestSuite *suite = new TestSuite("Core Utils");
|
||||||
|
|
||||||
|
suite->addTest(new TestCaller<CoreUtilsTest>(
|
||||||
|
"cast uint8_t -> int8_t", &CoreUtilsTest::testUChar2Char));
|
||||||
|
suite->addTest(new TestCaller<CoreUtilsTest>(
|
||||||
|
"cast uint16_t -> int16_t", &CoreUtilsTest::testUChar2Char));
|
||||||
|
suite->addTest(new TestCaller<CoreUtilsTest>(
|
||||||
|
"Interleave", &CoreUtilsTest::testInterleave));
|
||||||
|
|
||||||
|
return suite;
|
||||||
|
}
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
#ifndef __SDR_TEST_COREUTILSTEST_HH__
|
||||||
|
#define __SDR_TEST_COREUTILSTEST_HH__
|
||||||
|
|
||||||
|
#include "unittest.hh"
|
||||||
|
|
||||||
|
class CoreUtilsTest : public UnitTest::TestCase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~CoreUtilsTest();
|
||||||
|
|
||||||
|
void testUChar2Char();
|
||||||
|
void testUShort2Short();
|
||||||
|
void testInterleave();
|
||||||
|
|
||||||
|
public:
|
||||||
|
static UnitTest::TestSuite *suite();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -0,0 +1,46 @@
|
|||||||
|
#include "cputime.hh"
|
||||||
|
|
||||||
|
using namespace UnitTest;
|
||||||
|
|
||||||
|
|
||||||
|
CpuTime::CpuTime()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
CpuTime::start()
|
||||||
|
{
|
||||||
|
this->_clocks.push_back(clock());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
double
|
||||||
|
CpuTime::stop()
|
||||||
|
{
|
||||||
|
// measure time.
|
||||||
|
clock_t end = clock();
|
||||||
|
|
||||||
|
// Get time-diff since start:
|
||||||
|
double dt = end-this->_clocks.back();
|
||||||
|
dt /= CLOCKS_PER_SEC;
|
||||||
|
|
||||||
|
// Remove start time from stack:
|
||||||
|
this->_clocks.pop_back();
|
||||||
|
|
||||||
|
// Return delta t:
|
||||||
|
return dt;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
double
|
||||||
|
CpuTime::getTime()
|
||||||
|
{
|
||||||
|
clock_t end = clock();
|
||||||
|
|
||||||
|
// get diff:
|
||||||
|
double dt = end - this->_clocks.back();
|
||||||
|
dt /= CLOCKS_PER_SEC;
|
||||||
|
|
||||||
|
return dt;
|
||||||
|
}
|
||||||
@ -0,0 +1,31 @@
|
|||||||
|
#ifndef __SDR_CPUTIME_HH__
|
||||||
|
#define __SDR_CPUTIME_HH__
|
||||||
|
|
||||||
|
#include <time.h>
|
||||||
|
#include <list>
|
||||||
|
|
||||||
|
|
||||||
|
namespace UnitTest {
|
||||||
|
|
||||||
|
/** A utility class to measure the CPU time used by some algorithms. */
|
||||||
|
class CpuTime
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/** Constructs a new CPU time clock. */
|
||||||
|
CpuTime();
|
||||||
|
|
||||||
|
/** Start the clock. */
|
||||||
|
void start();
|
||||||
|
/** Stops the clock and returns the time in seconds. */
|
||||||
|
double stop();
|
||||||
|
/** Retruns the current time of the current clock. */
|
||||||
|
double getTime();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/** The stack of start times. */
|
||||||
|
std::list< clock_t > _clocks;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // CPUTIME_HH
|
||||||
@ -0,0 +1,21 @@
|
|||||||
|
#include "coretest.hh"
|
||||||
|
#include "coreutilstest.hh"
|
||||||
|
#include "unittest.hh"
|
||||||
|
#include "buffertest.hh"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
using namespace sdr;
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
|
||||||
|
UnitTest::TestRunner runner(std::cout);
|
||||||
|
|
||||||
|
runner.addSuite(CoreTest::suite());
|
||||||
|
runner.addSuite(BufferTest::suite());
|
||||||
|
runner.addSuite(CoreUtilsTest::suite());
|
||||||
|
|
||||||
|
runner();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@ -0,0 +1,192 @@
|
|||||||
|
#include "unittest.hh"
|
||||||
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
|
#include <limits>
|
||||||
|
#include <cmath>
|
||||||
|
#include "cputime.hh"
|
||||||
|
|
||||||
|
using namespace UnitTest;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ********************************************************************************************* *
|
||||||
|
* Implementation of TestFailure
|
||||||
|
* ********************************************************************************************* */
|
||||||
|
TestFailure::TestFailure(const std::string &message) throw()
|
||||||
|
: message(message)
|
||||||
|
{
|
||||||
|
// pass...
|
||||||
|
}
|
||||||
|
|
||||||
|
TestFailure::~TestFailure() throw()
|
||||||
|
{
|
||||||
|
// Pass...
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *
|
||||||
|
TestFailure::what() const throw ()
|
||||||
|
{
|
||||||
|
return this->message.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ********************************************************************************************* *
|
||||||
|
* Implementation of TestCase
|
||||||
|
* ********************************************************************************************* */
|
||||||
|
void
|
||||||
|
TestCase::setUp()
|
||||||
|
{
|
||||||
|
// Pass...
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TestCase::tearDown()
|
||||||
|
{
|
||||||
|
// Pass...
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TestCase::assertTrue(bool test, const std::string &file, size_t line)
|
||||||
|
{
|
||||||
|
if (! test)
|
||||||
|
{
|
||||||
|
std::stringstream str;
|
||||||
|
str << "Assert failed in " << file << " in line " << line;
|
||||||
|
throw TestFailure(str.str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ********************************************************************************************* *
|
||||||
|
* Implementation of TestSuite
|
||||||
|
* ********************************************************************************************* */
|
||||||
|
TestSuite::TestSuite(const std::string &desc)
|
||||||
|
: description(desc)
|
||||||
|
{
|
||||||
|
// pass...
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TestSuite::~TestSuite()
|
||||||
|
{
|
||||||
|
// Free callers:
|
||||||
|
for (std::list<TestCallerInterface *>::iterator caller=this->tests.begin();
|
||||||
|
caller != this->tests.end(); caller++) {
|
||||||
|
delete *caller;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TestSuite::addTest(TestCallerInterface *test)
|
||||||
|
{
|
||||||
|
this->tests.push_back(test);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const std::string &
|
||||||
|
TestSuite::getDescription()
|
||||||
|
{
|
||||||
|
return this->description;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TestSuite::iterator
|
||||||
|
TestSuite::begin()
|
||||||
|
{
|
||||||
|
return this->tests.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TestSuite::iterator
|
||||||
|
TestSuite::end()
|
||||||
|
{
|
||||||
|
return this->tests.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ********************************************************************************************* *
|
||||||
|
* Implementation of TestSuite
|
||||||
|
* ********************************************************************************************* */
|
||||||
|
TestRunner::TestRunner(std::ostream &stream)
|
||||||
|
: stream(stream)
|
||||||
|
{
|
||||||
|
// Pass...
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TestRunner::~TestRunner()
|
||||||
|
{
|
||||||
|
// Free suites:
|
||||||
|
for (std::list<TestSuite *>::iterator suite = this->suites.begin();
|
||||||
|
suite != this->suites.end(); suite++)
|
||||||
|
{
|
||||||
|
delete *suite;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TestRunner::addSuite(TestSuite *suite)
|
||||||
|
{
|
||||||
|
this->suites.push_back(suite);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TestRunner::operator ()()
|
||||||
|
{
|
||||||
|
size_t tests_run = 0;
|
||||||
|
size_t tests_failed = 0;
|
||||||
|
size_t tests_error = 0;
|
||||||
|
|
||||||
|
for (std::list<TestSuite *>::iterator suite = this->suites.begin();
|
||||||
|
suite != this->suites.end(); suite++)
|
||||||
|
{
|
||||||
|
// Dump Suite description
|
||||||
|
this->stream << "Suite: " << (*suite)->getDescription() << std::endl;
|
||||||
|
|
||||||
|
// For each test in suite:
|
||||||
|
for (TestSuite::iterator test = (*suite)->begin(); test != (*suite)->end(); test++)
|
||||||
|
{
|
||||||
|
this->stream << " test: " << (*test)->getDescription() << ": ";
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
tests_run++;
|
||||||
|
CpuTime clock; clock.start();
|
||||||
|
// Run test
|
||||||
|
(**test)();
|
||||||
|
this->stream << " ok (" << clock.stop() << "s)" << std::endl;
|
||||||
|
}
|
||||||
|
catch (TestFailure &fail)
|
||||||
|
{
|
||||||
|
this->stream << " fail" << std::endl;
|
||||||
|
this->stream << " reason: " << fail.what() << std::endl;
|
||||||
|
tests_failed++;
|
||||||
|
}
|
||||||
|
catch (std::exception &err)
|
||||||
|
{
|
||||||
|
this->stream << " exception" << std::endl;
|
||||||
|
this->stream << " what(): " << err.what() << std::endl;
|
||||||
|
tests_error++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this->stream << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->stream << "Summary: " << tests_failed << " tests failed out of "
|
||||||
|
<< tests_run - tests_error
|
||||||
|
<< " (" << 100. * float((tests_run-tests_failed-tests_error))/(tests_run-tests_error)
|
||||||
|
<< "% passed)." << std::endl << " Where "
|
||||||
|
<< tests_error << " tests produced errors." << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,159 @@
|
|||||||
|
#ifndef __SDR_UNITTEST_HH__
|
||||||
|
#define __SDR_UNITTEST_HH__
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
#include <string>
|
||||||
|
#include <sstream>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
|
||||||
|
namespace UnitTest {
|
||||||
|
|
||||||
|
class TestFailure : public std::exception
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
std::string message;
|
||||||
|
|
||||||
|
public:
|
||||||
|
TestFailure(const std::string &message) throw();
|
||||||
|
virtual ~TestFailure() throw();
|
||||||
|
|
||||||
|
const char *what() const throw();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class TestCase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual void setUp();
|
||||||
|
virtual void tearDown();
|
||||||
|
|
||||||
|
void assertTrue(bool test, const std::string &file, size_t line);
|
||||||
|
|
||||||
|
template <class Scalar>
|
||||||
|
void assertEqual(Scalar t, Scalar e, const std::string &file, size_t line) {
|
||||||
|
if (e != t) {
|
||||||
|
std::stringstream str;
|
||||||
|
str << "Expected: " << +e << " but got: " << +t
|
||||||
|
<< " in file "<< file << " in line " << line;
|
||||||
|
throw TestFailure(str.str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Scalar>
|
||||||
|
void assertNear(Scalar t, Scalar e, const std::string &file, size_t line,
|
||||||
|
Scalar err_abs=Scalar(1e-8), Scalar err_rel=Scalar(1e-6))
|
||||||
|
{
|
||||||
|
if (std::abs(e-t) > (err_abs + err_rel*std::abs(e))) {
|
||||||
|
std::stringstream str;
|
||||||
|
str << "Expected: " << +e << " but got: " << +t
|
||||||
|
<< " in file "<< file << " in line " << line;
|
||||||
|
throw TestFailure(str.str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class TestCallerInterface
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
std::string description;
|
||||||
|
|
||||||
|
public:
|
||||||
|
TestCallerInterface(const std::string &desc)
|
||||||
|
: description(desc)
|
||||||
|
{
|
||||||
|
// Pass...
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~TestCallerInterface() { /* pass... */ }
|
||||||
|
|
||||||
|
virtual const std::string &getDescription()
|
||||||
|
{
|
||||||
|
return this->description;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void operator() () = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
class TestCaller : public TestCallerInterface
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
void (T::*function)(void);
|
||||||
|
|
||||||
|
public:
|
||||||
|
TestCaller(const std::string &desc, void (T::*func)(void))
|
||||||
|
: TestCallerInterface(desc), function(func)
|
||||||
|
{
|
||||||
|
// Pass...
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~TestCaller() { /* pass... */ }
|
||||||
|
|
||||||
|
virtual void operator() ()
|
||||||
|
{
|
||||||
|
// Create new test:
|
||||||
|
T *instance = new T();
|
||||||
|
|
||||||
|
// Call test
|
||||||
|
instance->setUp();
|
||||||
|
(instance->*function)();
|
||||||
|
instance->tearDown();
|
||||||
|
|
||||||
|
// free instance:
|
||||||
|
delete instance;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class TestSuite
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef std::list<TestCallerInterface *>::iterator iterator;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::string description;
|
||||||
|
std::list<TestCallerInterface *> tests;
|
||||||
|
|
||||||
|
public:
|
||||||
|
TestSuite(const std::string &desc);
|
||||||
|
virtual ~TestSuite();
|
||||||
|
|
||||||
|
void addTest(TestCallerInterface *test);
|
||||||
|
|
||||||
|
const std::string &getDescription();
|
||||||
|
|
||||||
|
iterator begin();
|
||||||
|
iterator end();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class TestRunner
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
std::ostream &stream;
|
||||||
|
std::list<TestSuite *> suites;
|
||||||
|
|
||||||
|
public:
|
||||||
|
TestRunner(std::ostream &stream);
|
||||||
|
virtual ~TestRunner();
|
||||||
|
|
||||||
|
void addSuite(TestSuite *suite);
|
||||||
|
|
||||||
|
void operator() ();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#define UT_ASSERT(t) this->assertTrue(t, __FILE__, __LINE__)
|
||||||
|
#define UT_ASSERT_EQUAL(t, e) this->assertEqual(t, e, __FILE__, __LINE__)
|
||||||
|
#define UT_ASSERT_NEAR(t, e) this->assertNear(t, e, __FILE__, __LINE__)
|
||||||
|
#define UT_ASSERT_THROW(t, e) \
|
||||||
|
try { t; throw UnitTest::TestFailure("No exception thrown!"); } catch (e &err) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif // UNITTEST_HH
|
||||||
Loading…
Reference in New Issue