diff --git a/tests/test.cpp b/tests/test.cpp new file mode 100644 --- /dev/null +++ b/tests/test.cpp @@ -0,0 +1,359 @@ +/* + Copyright © 2018 Hasan Yavuz Özderya + + This file is part of serialplot. + + serialplot is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + serialplot is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with serialplot. If not, see . +*/ + +#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one cpp file +#include "catch.hpp" + +#include "samplepack.h" +#include "source.h" +#include "indexbuffer.h" +#include "linindexbuffer.h" +#include "ringbuffer.h" +#include "readonlybuffer.h" + +#include "test_helpers.h" + +TEST_CASE("samplepack with no X", "[memory]") +{ + SamplePack pack(100, 3, false); + + REQUIRE_FALSE(pack.hasX()); + REQUIRE(pack.numChannels() == 3); + REQUIRE(pack.numSamples() == 100); + + double* chan0 = pack.data(0); + double* chan1 = pack.data(1); + double* chan2 = pack.data(2); + + REQUIRE(chan0 == chan1 - 100); + REQUIRE(chan1 == chan2 - 100); +} + +TEST_CASE("samplepack with X", "[memory]") +{ + SamplePack pack(100, 3, true); + + REQUIRE(pack.hasX()); + REQUIRE(pack.numChannels() == 3); + REQUIRE(pack.numSamples() == 100); + REQUIRE(pack.xData() != nullptr); +} + +TEST_CASE("sink", "[memory, stream]") +{ + TestSink sink; + SamplePack pack(100, 3, false); + + sink.setNumChannels(3, false); + REQUIRE(sink.numChannels() == 3); + + sink.feedIn(pack); + REQUIRE(sink.totalFed == 100); + sink.feedIn(pack); + REQUIRE(sink.totalFed == 200); + + TestSink follower; + + sink.connectFollower(&follower); + REQUIRE(follower.numChannels() == 3); + REQUIRE(follower.hasX() == false); + + sink.feedIn(pack); + REQUIRE(sink.totalFed == 300); + REQUIRE(follower.totalFed == 100); + + sink.setNumChannels(2, true); + REQUIRE(follower.numChannels() == 2); + REQUIRE(follower.hasX() == true); +} + +TEST_CASE("sink must be created unconnected", "[memory, stream]") +{ + TestSink sink; + REQUIRE(sink.connectedSource() == NULL); +} + +TEST_CASE("source", "[memory, stream]") +{ + TestSink sink; + + TestSource source(3, false); + + REQUIRE(source.numChannels() == 3); + REQUIRE(source.hasX() == false); + + source.connectSink(&sink); + REQUIRE(sink.numChannels() == 3); + REQUIRE(sink.hasX() == false); + + source._setNumChannels(5, true); + REQUIRE(sink.numChannels() == 5); + REQUIRE(sink.hasX() == true); + + SamplePack pack(100, 5, true); + source._feed(pack); + REQUIRE(sink.totalFed == 100); + + source.disconnect(&sink); + source._feed(pack); + REQUIRE(sink.totalFed == 100); +} + +TEST_CASE("source must set/unset sink 'source'", "[memory, stream]") +{ + TestSink sink; + TestSource source(3, false); + + source.connectSink(&sink); + REQUIRE(sink.connectedSource() == &source); + + source.disconnect(&sink); + REQUIRE(sink.connectedSource() == NULL); +} + +TEST_CASE("source disconnect all sinks", "[memory, stream]") +{ + TestSink sinks[3]; + TestSource source(3, false); + + // connect sinks + for (int i = 0; i < 3; i++) + { + source.connectSink(&sinks[i]); + } + + source.disconnectSinks(); + for (int i = 0; i < 3; i++) + { + REQUIRE(sinks[i].connectedSource() == NULL); + } +} + +TEST_CASE("IndexBuffer", "[memory, buffer]") +{ + IndexBuffer buf(10); + + REQUIRE(buf.size() == 10); + for (unsigned i = 0; i < 10; i++) + { + REQUIRE(buf.sample(i) == i); + } + auto l = buf.limits(); + REQUIRE(l.start == 0); + REQUIRE(l.end == 9); + + buf.resize(20); + REQUIRE(buf.size() == 20); + REQUIRE(buf.sample(15) == 15); + l = buf.limits(); + REQUIRE(l.start == 0); + REQUIRE(l.end == 19); +} + +TEST_CASE("LinIndexBuffer", "[memory, buffer]") +{ + LinIndexBuffer buf(10, 0., 3.0); + + REQUIRE(buf.size() == 10); + REQUIRE(buf.sample(0) == 0.); + REQUIRE(buf.sample(9) == 3.0); + REQUIRE(buf.sample(4) == Approx(1+1/3.)); + + auto l = buf.limits(); + REQUIRE(l.start == 0.); + REQUIRE(l.end == 3.); + + buf.resize(20); + REQUIRE(buf.size() == 20); + REQUIRE(buf.sample(0) == 0.); + REQUIRE(buf.sample(9) == Approx(9.*3./19.)); + REQUIRE(buf.sample(4) == Approx(4.*3./19.)); + REQUIRE(buf.sample(19) == 3.0); + + l = buf.limits(); + REQUIRE(l.start == 0.); + REQUIRE(l.end == 3.0); + + buf.setLimits({-5., 5.}); + l = buf.limits(); + REQUIRE(l.start == -5.0); + REQUIRE(l.end == 5.0); + + REQUIRE(buf.sample(0) == -5.0); + REQUIRE(buf.sample(19) == 5.0); +} + +TEST_CASE("RingBuffer sizing", "[memory, buffer]") +{ + RingBuffer buf(10); + + REQUIRE(buf.size() == 10); + + buf.resize(5); + REQUIRE(buf.size() == 5); + + buf.resize(15); + REQUIRE(buf.size() == 15); +} + +TEST_CASE("RingBuffer initial values should be 0", "[memory, buffer]") +{ + RingBuffer buf(10); + + for (unsigned i = 0; i < 10; i++) + { + REQUIRE(buf.sample(i) == 0.); + } +} + +TEST_CASE("RingBuffer data access", "[memory, buffer]") +{ + RingBuffer buf(10); + double values[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + + buf.addSamples(values, 10); + + REQUIRE(buf.size() == 10); + for (unsigned i = 0; i < 10; i++) + { + REQUIRE(buf.sample(i) == values[i]); + } + + buf.addSamples(values, 5); + + REQUIRE(buf.size() == 10); + for (unsigned i = 0; i < 5; i++) + { + REQUIRE(buf.sample(i) == values[i+5]); + } + for (unsigned i = 5; i < 10; i++) + { + REQUIRE(buf.sample(i) == values[i-5]); + } +} + +TEST_CASE("making RingBuffer bigger should keep end values", "[memory, buffer]") +{ + RingBuffer buf(5); + double values[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + + buf.addSamples(values, 5); + buf.resize(10); + + REQUIRE(buf.size() == 10); + for (unsigned i = 0; i < 5; i++) + { + REQUIRE(buf.sample(i) == 0); + } + for (unsigned i = 5; i < 10; i++) + { + REQUIRE(buf.sample(i) == values[i-5]); + } +} + +TEST_CASE("making RingBuffer smaller should keep end values", "[memory, buffer]") +{ + RingBuffer buf(10); + double values[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + + buf.addSamples(values, 10); + buf.resize(5); + + REQUIRE(buf.size() == 5); + for (unsigned i = 0; i < 5; i++) + { + REQUIRE(buf.sample(i) == values[i+5]); + } +} + +TEST_CASE("RingBuffer limits", "[memory, buffer]") +{ + RingBuffer buf(10); + double values[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + + auto lim = buf.limits(); + REQUIRE(lim.start == 0.); + REQUIRE(lim.end == 0.); + + buf.addSamples(values, 10); + lim = buf.limits(); + REQUIRE(lim.start == 1.); + REQUIRE(lim.end == 10.); + + buf.addSamples(&values[9], 1); + lim = buf.limits(); + REQUIRE(lim.start == 2.); + REQUIRE(lim.end == 10.); + + buf.addSamples(values, 9); + buf.addSamples(values, 1); + lim = buf.limits(); + REQUIRE(lim.start == 1.); + REQUIRE(lim.end == 9.); +} + +TEST_CASE("RingBuffer clear", "[memory, buffer]") +{ + RingBuffer buf(10); + double values[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + + buf.addSamples(values, 10); + buf.clear(); + + REQUIRE(buf.size() == 10); + for (unsigned i = 0; i < 10; i++) + { + REQUIRE(buf.sample(i) == 0.); + } + auto lim = buf.limits(); + REQUIRE(lim.start == 0.); + REQUIRE(lim.end == 0.); +} + +TEST_CASE("ReadOnlyBuffer", "[memory, buffer]") +{ + IndexBuffer source(10); + + ReadOnlyBuffer buf(&source); + + REQUIRE(buf.size() == 10); + auto lim = buf.limits(); + REQUIRE(lim.start == 0.); + REQUIRE(lim.end == 9.); + for (unsigned i = 0; i < 10; i++) + { + REQUIRE(buf.sample(i) == i); + } +} + +TEST_CASE("ReadOnlyBuffer sliced constructor", "[memory, buffer]") +{ + IndexBuffer source(10); + + ReadOnlyBuffer buf(&source, 5, 4); + + REQUIRE(buf.size() == 4); + auto lim = buf.limits(); + REQUIRE(lim.start == 5.); + REQUIRE(lim.end == 8.); + for (unsigned i = 0; i < 4; i++) + { + REQUIRE(buf.sample(i) == (i + 5)); + } +}