From a7c430fa81c9e22dbce74869a0a27304da78855b Mon Sep 17 00:00:00 2001 From: Vasile Vilvoiu Date: Wed, 21 Jul 2021 18:43:02 +0300 Subject: Implement unit tests. ColorMap, FFT, InputParser, InputReader, ValueMap, WindowFunction. Closes #11. --- test/test-value-map.cpp | 129 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 test/test-value-map.cpp (limited to 'test/test-value-map.cpp') diff --git a/test/test-value-map.cpp b/test/test-value-map.cpp new file mode 100644 index 0000000..940e70f --- /dev/null +++ b/test/test-value-map.cpp @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2020-2021 Vasile Vilvoiu + * + * specgram is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ +#include "test.hpp" +#include "../src/value-map.hpp" +#include +#include + +static std::vector ALL_VALUE_MAP_TYPES { ValueMapType::kLinear, ValueMapType::kDecibel }; + +TEST(TestValueMap, FactoryWrongType) +{ + EXPECT_THROW_MATCH(auto ret = ValueMap::Build((ValueMapType)999, 0.0, 1.0, "V"), + std::runtime_error, "unknown value map type"); +} + +TEST(TestValueMap, FactoryBoundsOrder) +{ + for (auto type : ALL_VALUE_MAP_TYPES) { + EXPECT_THROW_MATCH(auto ret = ValueMap::Build(type, 1.0, 0.0, ""), + std::runtime_error, "lower bound cannot exceed upper bound"); + EXPECT_THROW_MATCH(auto ret = ValueMap::Build(type, std::numeric_limits::quiet_NaN(), 0.0, ""), + std::runtime_error, "bounds cannot be nan or inf"); + EXPECT_THROW_MATCH(auto ret = ValueMap::Build(type, std::numeric_limits::infinity(), 0.0, ""), + std::runtime_error, "bounds cannot be nan or inf"); + EXPECT_NO_THROW(auto ret = ValueMap::Build(type, 1.0, 1.0, "")); + } +} + +TEST(TestValueMap, FactoryBoundsNanInf) +{ + for (auto type : ALL_VALUE_MAP_TYPES) { + EXPECT_THROW_MATCH(auto ret = ValueMap::Build(type, std::numeric_limits::quiet_NaN(), 0.0, ""), + std::runtime_error, "bounds cannot be nan or inf"); + EXPECT_THROW_MATCH(auto ret = ValueMap::Build(type, std::numeric_limits::infinity(), 0.0, ""), + std::runtime_error, "bounds cannot be nan or inf"); + EXPECT_THROW_MATCH(auto ret = ValueMap::Build(type, 0.0, std::numeric_limits::quiet_NaN(), ""), + std::runtime_error, "bounds cannot be nan or inf"); + EXPECT_THROW_MATCH(auto ret = ValueMap::Build(type, 0.0, std::numeric_limits::infinity(), ""), + std::runtime_error, "bounds cannot be nan or inf"); + } +} + +TEST(TestValueMap, GetUnit) +{ + EXPECT_STREQ(ValueMap::Build(ValueMapType::kLinear, 0.0, 1.0, "")->GetUnit().c_str(), ""); + EXPECT_STREQ(ValueMap::Build(ValueMapType::kDecibel, 0.0, 1.0, "")->GetUnit().c_str(), "dB"); + EXPECT_STREQ(ValueMap::Build(ValueMapType::kLinear, 0.0, 1.0, "V")->GetUnit().c_str(), "V"); + EXPECT_STREQ(ValueMap::Build(ValueMapType::kDecibel, 0.0, 1.0, "V")->GetUnit().c_str(), "dBV"); +} + +TEST(TestValueMap, LinearMapDomain) +{ + constexpr double lower_bound = -33.0; + constexpr double upper_bound = 57.0; + constexpr double epsilon = 1e-9; + constexpr std::size_t steps = 100; + + std::unique_ptr map; + EXPECT_NO_THROW(map = ValueMap::Build(ValueMapType::kLinear, lower_bound, upper_bound, "")); + + for (std::size_t i=0; i<=steps; i++) { + double expect = (double)i / (double)steps; + double input = lower_bound + (upper_bound - lower_bound) * expect; + auto out = map->Map(RealWindow { input }); + + EXPECT_EQ(out.size(), 1); + EXPECT_LE(std::abs(out[0] - expect), epsilon); + } + + { + RealWindow expect(steps+1); + RealWindow win(steps+1); + for (std::size_t i = 0; i <= steps; i++) { + expect[i] = (double) i / (double) steps; + win[i] = lower_bound + (upper_bound - lower_bound) * expect[i]; + } + RealWindow out; + EXPECT_NO_THROW(out = map->Map(win)); + for (std::size_t i = 0; i <= steps; i++) { + EXPECT_LE(std::abs(out[i] - expect[i]), epsilon); + } + } + + EXPECT_LE(std::abs(map->Map(RealWindow { -40.0 })[0]), epsilon); + EXPECT_LE(std::abs(map->Map(RealWindow { 70.0 })[0] - 1.0), epsilon); +} + +TEST(TestValueMap, LogarithmicMapDomain) +{ + constexpr double lower_bound = -120.; + constexpr double upper_bound = 20.0; + constexpr double epsilon = 1e-9; + constexpr std::size_t steps = 100; + + std::unique_ptr map; + EXPECT_NO_THROW(map = ValueMap::Build(ValueMapType::kDecibel, lower_bound, upper_bound, "")); + + for (std::size_t i=0; i<=steps; i++) { + double expect = (double)i / (double)steps; + /* y = 20log10(x) */ + /* x = 10^(y/20) */ + double input = std::pow(10.0, (lower_bound + (upper_bound - lower_bound) * expect) / 20.0); + auto out = map->Map(RealWindow { input }); + + EXPECT_EQ(out.size(), 1); + EXPECT_LE(std::abs(out[0] - expect), epsilon); + } + + { + RealWindow expect(steps+1); + RealWindow win(steps+1); + for (std::size_t i = 0; i <= steps; i++) { + expect[i] = (double) i / (double) steps; + win[i] = std::pow(10.0, (lower_bound + (upper_bound - lower_bound) * expect[i]) / 20.0); + } + RealWindow out; + EXPECT_NO_THROW(out = map->Map(win)); + for (std::size_t i = 0; i <= steps; i++) { + EXPECT_LE(std::abs(out[i] - expect[i]), epsilon); + } + } + + EXPECT_LE(std::abs(map->Map(RealWindow { 0.0 })[0]), epsilon); + EXPECT_LE(std::abs(map->Map(RealWindow { 100.0 })[0] - 1.0), epsilon); +} \ No newline at end of file -- cgit v1.2.3