feat: project skeleton, core types and math with transform tests
This commit is contained in:
1 parent
e4051bc6b5
commit
8a7e9e97f8
21 files changed
+515
-2
No files matched your search
@@ -0,0 +1,8 @@
|
||||
add_executable(plot_tests
|
||||
main.cpp
|
||||
test_transform.cpp
|
||||
)
|
||||
target_link_libraries(plot_tests PRIVATE plot::core)
|
||||
plot_apply_warnings(plot_tests)
|
||||
|
||||
add_test(NAME plot_tests COMMAND plot_tests)
|
||||
@@ -0,0 +1,74 @@
|
||||
#pragma once
|
||||
#include <cstdio>
|
||||
#include <cmath>
|
||||
#include <chrono>
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <plot/core/types.hpp>
|
||||
|
||||
using plot::f32;
|
||||
using plot::f64;
|
||||
using plot::u32;
|
||||
using plot::u64;
|
||||
|
||||
namespace plottest {
|
||||
|
||||
struct Case {
|
||||
const char* name;
|
||||
std::function<void()> fn;
|
||||
};
|
||||
|
||||
inline std::vector<Case>& cases() {
|
||||
static std::vector<Case> c;
|
||||
return c;
|
||||
}
|
||||
|
||||
struct Reg {
|
||||
Reg(const char* n, std::function<void()> f) { cases().push_back({n, std::move(f)}); }
|
||||
};
|
||||
|
||||
struct Failure {
|
||||
std::string msg;
|
||||
};
|
||||
|
||||
inline int run_all() {
|
||||
int failed = 0;
|
||||
for (auto& c : cases()) {
|
||||
try {
|
||||
c.fn();
|
||||
std::printf("[ ok ] %s\n", c.name);
|
||||
} catch (const Failure& f) {
|
||||
std::printf("[FAIL] %s: %s\n", c.name, f.msg.c_str());
|
||||
++failed;
|
||||
}
|
||||
}
|
||||
std::printf("%zu cases, %d failed\n", cases().size(), failed);
|
||||
return failed == 0 ? 0 : 1;
|
||||
}
|
||||
|
||||
} // namespace plottest
|
||||
|
||||
#define PLOT_TEST(name) \
|
||||
static void name(); \
|
||||
static ::plottest::Reg reg_##name(#name, name); \
|
||||
static void name()
|
||||
|
||||
#define PLOT_CHECK(cond) \
|
||||
do { \
|
||||
if (!(cond)) \
|
||||
throw ::plottest::Failure{std::string(__FILE__) + ":" + std::to_string(__LINE__) + \
|
||||
" CHECK(" #cond ")"}; \
|
||||
} while (0)
|
||||
|
||||
#define PLOT_CHECK_NEAR(a, b, eps) \
|
||||
do { \
|
||||
const double _a = (a), _b = (b); \
|
||||
if (!(std::fabs(_a - _b) <= (eps))) \
|
||||
throw ::plottest::Failure{std::string(__FILE__) + ":" + std::to_string(__LINE__) + \
|
||||
" CHECK_NEAR(" #a ", " #b ") got " + std::to_string(_a) + \
|
||||
" vs " + std::to_string(_b)}; \
|
||||
} while (0)
|
||||
@@ -0,0 +1,3 @@
|
||||
#include "harness.hpp"
|
||||
|
||||
int main() { return plottest::run_all(); }
|
||||
@@ -0,0 +1,31 @@
|
||||
#include "harness.hpp"
|
||||
|
||||
#include <plot/math/transform.hpp>
|
||||
|
||||
using plot::Transform;
|
||||
|
||||
PLOT_TEST(linear_round_trip) {
|
||||
Transform t{2.0, 10.0, 3.0, -1.0, false, false};
|
||||
PLOT_CHECK_NEAR(t.to_screen_x(0.0), 10.0, 1e-12);
|
||||
PLOT_CHECK_NEAR(t.to_screen_x(5.0), 20.0, 1e-12);
|
||||
PLOT_CHECK_NEAR(t.to_data_x(20.0), 5.0, 1e-12);
|
||||
PLOT_CHECK_NEAR(t.to_data_y(t.to_screen_y(7.5)), 7.5, 1e-12);
|
||||
}
|
||||
|
||||
PLOT_TEST(log_x_round_trip) {
|
||||
Transform t{100.0, 0.0, 1.0, 0.0, true, false};
|
||||
PLOT_CHECK_NEAR(t.to_screen_x(1.0), 0.0, 1e-12);
|
||||
PLOT_CHECK_NEAR(t.to_screen_x(10.0), 100.0, 1e-12);
|
||||
PLOT_CHECK_NEAR(t.to_data_x(100.0), 10.0, 1e-9);
|
||||
}
|
||||
|
||||
PLOT_TEST(zoom_anchor_is_invariant) {
|
||||
// Anchoring a zoom at a data coordinate must leave that coordinate's screen
|
||||
// position unchanged.
|
||||
Transform t{1.0, 0.0, 1.0, 0.0, false, false};
|
||||
const double anchor_data = 3.25;
|
||||
const double before = t.to_screen_x(anchor_data);
|
||||
t.sx *= 4.0;
|
||||
t.tx = before - anchor_data * t.sx;
|
||||
PLOT_CHECK_NEAR(t.to_screen_x(anchor_data), before, 1e-12);
|
||||
}
|
||||
Reference in new issue
Block a user