File indexing completed on 2024-05-19 04:21:05
0001 /* 0002 * SPDX-FileCopyrightText: 2019-2023 Mattia Basaglia <dev@dragon.best> 0003 * 0004 * SPDX-License-Identifier: GPL-3.0-or-later 0005 */ 0006 0007 #pragma once 0008 #include <QtTest/QtTest> 0009 0010 #include"math/bezier/bezier.hpp" 0011 0012 #define COMPARE_MULTIBEZIER(actual, expected) \ 0013 compare_multibez(actual, expected, #actual, #expected, __FILE__, __LINE__) 0014 0015 using namespace glaxnimate; 0016 0017 class BezierTestBase 0018 { 0019 public: 0020 0021 bool compare_multibez(const math::bezier::MultiBezier& actual, const math::bezier::MultiBezier& expected, 0022 const QString& actual_name, const QString& expected_name, const char *file, int line) 0023 { 0024 std::string actual_s = build_name(actual_name, "size()"); 0025 std::string expected_s = build_name(expected_name, "size()"); 0026 0027 if ( !QTest::qCompare(actual.size(), expected.size(), actual_s.c_str(), expected_s.c_str(), file, line) ) 0028 { 0029 QString warning = "\n"; 0030 build_warning_multi(warning, actual_name, actual); 0031 build_warning_multi(warning, expected_name, expected); 0032 qWarning() << warning; 0033 return false; 0034 } 0035 0036 for ( int i = 0; i < actual.size(); i++ ) 0037 { 0038 QString name_suf = QString("[%1]").arg(i); 0039 if ( !compare_bez(actual.beziers()[i], expected.beziers()[i], actual_name + name_suf, expected_name + name_suf, file, line) ) 0040 return false; 0041 } 0042 0043 return true; 0044 } 0045 0046 using WarningCollectData = std::pair<int, std::vector<QString>>; 0047 0048 void collect_warning(const QPointF& p, WarningCollectData& out) 0049 { 0050 QString text = QTest::toString(p); 0051 if ( text.size() > out.first ) 0052 out.first = text.size(); 0053 out.second.push_back(text); 0054 } 0055 0056 void build_warning(QString& warning, const QString& name, const math::bezier::Bezier& bez) 0057 { 0058 warning += name + "\n"; 0059 WarningCollectData pos = {0, {}}; 0060 WarningCollectData tan_in = {0, {}}; 0061 WarningCollectData tan_out = {0, {}}; 0062 0063 for ( const auto& p : bez ) 0064 { 0065 collect_warning(p.pos, pos); 0066 collect_warning(p.tan_in, tan_in); 0067 collect_warning(p.tan_out, tan_out); 0068 } 0069 0070 for ( std::size_t i = 0; i < pos.second.size(); i++ ) 0071 { 0072 warning += " "; 0073 warning += pos.second[i].leftJustified(pos.first); 0074 warning += " in: "; 0075 warning += tan_in.second[i].leftJustified(tan_in.first); 0076 warning += " out: "; 0077 warning += tan_out.second[i].leftJustified(tan_out.first); 0078 warning += "\n"; 0079 } 0080 } 0081 0082 void build_warning_multi(QString& warning, const QString& name, const math::bezier::MultiBezier& bez) 0083 { 0084 warning += name + ":\n"; 0085 0086 for ( int i = 0; i < bez.size(); i++ ) 0087 build_warning(warning, name + QString("[%1]").arg(i), bez.beziers()[i]); 0088 } 0089 0090 bool compare_bez(const math::bezier::Bezier& actual, const math::bezier::Bezier& expected, 0091 const QString& actual_name, const QString& expected_name, 0092 const char *file, int line) 0093 { 0094 std::string actual_s = build_name(actual_name, "size()"); 0095 std::string expected_s = build_name(expected_name, "size()"); 0096 0097 bool ret = true; 0098 0099 if ( !QTest::qCompare(actual.size(), expected.size(), actual_s.c_str(), expected_s.c_str(), file, line) ) 0100 { 0101 ret = false; 0102 } 0103 else 0104 { 0105 actual_s = build_name(actual_name, "closed()"); 0106 expected_s = build_name(expected_name, "closed()"); 0107 if ( !QTest::qCompare(actual.closed(), expected.closed(), actual_s.c_str(), expected_s.c_str(), file, line) ) 0108 { 0109 ret = false; 0110 } 0111 0112 for ( int i = 0; i < actual.size(); i++ ) 0113 { 0114 QString name_suf = QString("[%1]").arg(i); 0115 if ( !compare_point(actual[i], expected[i], actual_name + name_suf, expected_name + name_suf, file, line) ) 0116 { 0117 ret = false; 0118 break; 0119 } 0120 } 0121 } 0122 0123 if ( !ret ) 0124 { 0125 QString warning = "\n"; 0126 build_warning(warning, actual_name, actual); 0127 build_warning(warning, expected_name, expected); 0128 qWarning() << warning; 0129 } 0130 0131 return ret; 0132 } 0133 0134 std::string build_name(const QString& base, const char* member) 0135 { 0136 return QString("%1.%2").arg(base, member).toStdString(); 0137 } 0138 0139 bool compare_point(const math::bezier::Point& actual, const math::bezier::Point& expected, 0140 const QString& actual_name, const QString& expected_name, 0141 const char *file, int line) 0142 { 0143 bool ret = true; 0144 ret = compare_qpointf(actual.pos, expected.pos, actual_name, expected_name, "pos", file, line) && ret; 0145 ret = compare_qpointf(actual.tan_in, expected.tan_in, actual_name, expected_name, "tan_in", file, line) && ret; 0146 ret = compare_qpointf(actual.tan_out, expected.tan_out, actual_name, expected_name, "tan_out", file, line) && ret; 0147 return ret; 0148 } 0149 0150 0151 bool compare_qpointf(const QPointF& actual, const QPointF& expected, 0152 const QString& actual_name, const QString& expected_name, const char* point_name, 0153 const char *file, int line) 0154 { 0155 // reduce accuracy requirements by casting to float 0156 if ( !qFuzzyCompare(float(actual.x()), float(expected.x())) || !qFuzzyCompare(float(actual.y()), float(expected.y())) ) 0157 { 0158 // actual test comparisons for output 0159 0160 std::string actual_s = build_name(actual_name, point_name); 0161 std::string expected_s = build_name(expected_name, point_name); 0162 QTest::qCompare(actual, expected, actual_s.c_str(), expected_s.c_str(), file, line); 0163 0164 QString suffix = QString(".") + point_name; 0165 compare_qpointf_component(actual.x(), expected.x(), actual_name+suffix, expected_name+suffix, "x()", file, line); 0166 compare_qpointf_component(actual.y(), expected.y(), actual_name+suffix, expected_name+suffix, "y()", file, line); 0167 return false; 0168 } 0169 0170 return true; 0171 } 0172 0173 bool compare_qpointf_component(qreal actual, qreal expected, 0174 const QString& actual_name, const QString& expected_name, const char* component, 0175 const char *file, int line) 0176 { 0177 std::string actual_s = build_name(actual_name, component); 0178 std::string expected_s = build_name(expected_name, component); 0179 return QTest::qCompare(actual, expected, actual_s.c_str(), expected_s.c_str(), file, line); 0180 } 0181 };