diff --git a/app/common/rational.cpp b/app/common/rational.cpp
index c5b537af3..f835fa904 100644
--- a/app/common/rational.cpp
+++ b/app/common/rational.cpp
@@ -5,12 +5,14 @@
namespace olive {
+const rational rational::NaN = rational(0, 0);
+
rational rational::fromDouble(const double &flt, bool* ok)
{
if (qIsNaN(flt)) {
// Return NaN rational
if (ok) *ok = false;
- return rational(0, 0);
+ return NaN;
}
// Use FFmpeg function for the time being
@@ -45,7 +47,7 @@ rational rational::fromString(const QString &str, bool* ok)
if (ok) {
*ok = false;
}
- return rational(0, 0);
+ return NaN;
}
}
@@ -57,16 +59,12 @@ void rational::fix_signs()
if (denom_ < 0) {
denom_ = -denom_;
numer_ = -numer_;
- }
-
- // Normalize to 0/1 if numerator is zero
- if (numer_ == intType(0)) {
- denom_ = intType(1);
- }
-
- // Normalize to 0/0 (aka NaN) if denominator is zero
- if (denom_ == intType(0)) {
+ } else if (denom_ == intType(0)) {
+ // Normalize to 0/0 (aka NaN) if denominator is zero
numer_ = intType(0);
+ } else if (numer_ == intType(0)) {
+ // Normalize to 0/1 if numerator is zero
+ denom_ = intType(1);
}
}
@@ -438,5 +436,9 @@ uint qHash(const rational &r, uint seed)
QDebug operator<<(QDebug debug, const olive::rational &r)
{
- return debug.space() << r.toDouble();
+ if (r.isNaN()) {
+ return debug.space() << "NaN";
+ } else {
+ return debug.space() << r.toDouble();
+ }
}
diff --git a/app/common/rational.h b/app/common/rational.h
index 3a3d19411..673988eea 100644
--- a/app/common/rational.h
+++ b/app/common/rational.h
@@ -58,9 +58,10 @@ public:
}
static rational fromDouble(const double& flt, bool *ok = nullptr);
-
static rational fromString(const QString& str, bool* ok = nullptr);
+ static const rational NaN;
+
//Assignment Operators
const rational& operator=(const rational &rhs);
const rational& operator+=(const rational &rhs);
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index d64bc20f5..926af5116 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -66,4 +66,5 @@ function(olive_add_test GROUP NAME SOURCE)
endfunction()
add_subdirectory(compositing)
+add_subdirectory(general)
add_subdirectory(timeline)
diff --git a/tests/general/CMakeLists.txt b/tests/general/CMakeLists.txt
new file mode 100644
index 000000000..4b2c84b44
--- /dev/null
+++ b/tests/general/CMakeLists.txt
@@ -0,0 +1,17 @@
+# Olive - Non-Linear Video Editor
+# Copyright (C) 2021 Olive Team
+#
+# This program 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.
+#
+# This program 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 this program. If not, see .
+
+olive_add_test(General rational-tests rational-tests.cpp)
diff --git a/tests/general/rational-tests.cpp b/tests/general/rational-tests.cpp
new file mode 100644
index 000000000..8e9de8122
--- /dev/null
+++ b/tests/general/rational-tests.cpp
@@ -0,0 +1,64 @@
+/***
+
+ Olive - Non-Linear Video Editor
+ Copyright (C) 2021 Olive Team
+
+ This program 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.
+
+ This program 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 this program. If not, see .
+
+***/
+
+#include "testutil.h"
+
+#include "common/rational.h"
+
+namespace olive {
+
+OLIVE_ADD_TEST(RationalDefaults)
+{
+ // By default, rationals are valid 0/1
+ rational basic_constructor;
+ OLIVE_ASSERT(basic_constructor.isNull());
+ OLIVE_ASSERT(!basic_constructor.isNaN());
+
+ OLIVE_TEST_END;
+}
+
+OLIVE_ADD_TEST(RationalNaN)
+{
+ // Create a NaN with a 0 denominator
+ rational nan = rational(0, 0);
+ OLIVE_ASSERT(nan.isNaN());
+ OLIVE_ASSERT(nan.isNull());
+
+ // Create a non-NaN with a zero numerator
+ rational zero_nonnan(0, 999);
+ OLIVE_ASSERT(zero_nonnan.isNull());
+ OLIVE_ASSERT(!zero_nonnan.isNaN());
+
+ // Create a non-NaN with a non-zero numerator
+ rational nonzer_nonnan(1, 30);
+ OLIVE_ASSERT(!nonzer_nonnan.isNull());
+ OLIVE_ASSERT(!nonzer_nonnan.isNaN());
+
+ OLIVE_TEST_END;
+}
+
+OLIVE_ADD_TEST(RationalNaNConstant)
+{
+ OLIVE_ASSERT(rational::NaN.isNaN());
+
+ OLIVE_TEST_END;
+}
+
+}