/** * @file llsingleton_test.cpp * @date 2011-08-11 * @brief Unit test for the LLSingleton class * * $LicenseInfo:firstyear=2011&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2011, Linden Research, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ #include "linden_common.h" #include "llunits.h" #include "../test/lltut.h" namespace LLUnits { // using powers of 2 to allow strict floating point equality LL_DECLARE_BASE_UNIT(Quatloos, "Quat"); LL_DECLARE_DERIVED_UNIT(Latinum, "Lat", Quatloos, / 4); LL_DECLARE_DERIVED_UNIT(Solari, "Sol", Latinum, * 16); } LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Quatloos); LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Latinum); LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Solari); namespace LLUnits { LL_DECLARE_BASE_UNIT(Celcius, "c"); LL_DECLARE_DERIVED_UNIT(Fahrenheit, "f", Celcius, * 9 / 5 + 32); LL_DECLARE_DERIVED_UNIT(Kelvin, "k", Celcius, + 273.15f); } LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Celcius); LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Fahrenheit); LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Kelvin); namespace tut { using namespace LLUnits; struct units { }; typedef test_group units_t; typedef units_t::object units_object_t; tut::units_t tut_singleton("LLUnit"); // storage type conversions template<> template<> void units_object_t::test<1>() { LLUnit float_quatloos; ensure("default float unit is zero", float_quatloos == F32Quatloos(0.f)); LLUnit float_initialize_quatloos(1); ensure("non-zero initialized unit", float_initialize_quatloos == F32Quatloos(1.f)); LLUnit int_quatloos; ensure("default int unit is zero", int_quatloos == S32Quatloos(0)); int_quatloos = S32Quatloos(42); ensure("int assignment is preserved", int_quatloos == S32Quatloos(42)); float_quatloos = int_quatloos; ensure("float assignment from int preserves value", float_quatloos == F32Quatloos(42.f)); int_quatloos = float_quatloos; ensure("int assignment from float preserves value", int_quatloos == S32Quatloos(42)); float_quatloos = F32Quatloos(42.1f); int_quatloos = float_quatloos; ensure("int units truncate float units on assignment", int_quatloos == S32Quatloos(42)); LLUnit unsigned_int_quatloos(float_quatloos); ensure("unsigned int can be initialized from signed int", unsigned_int_quatloos == S32Quatloos(42)); S32Solari int_solari(1); float_quatloos = int_solari; ensure("fractional units are preserved in conversion from integer to float type", float_quatloos == F32Quatloos(0.25f)); int_quatloos = S32Quatloos(1); F32Solari float_solari = int_quatloos; ensure("can convert with fractional intermediates from integer to float type", float_solari == F32Solari(4.f)); } // conversions to/from base unit template<> template<> void units_object_t::test<2>() { LLUnit quatloos(1.f); LLUnit latinum_bars(quatloos); ensure("conversion between units is automatic via initialization", latinum_bars == F32Latinum(1.f / 4.f)); latinum_bars = S32Latinum(256); quatloos = latinum_bars; ensure("conversion between units is automatic via assignment, and bidirectional", quatloos == S32Quatloos(1024)); LLUnit single_quatloo(1); LLUnit quarter_latinum = single_quatloo; ensure("division of integer unit preserves fractional values when converted to float unit", quarter_latinum == F32Latinum(0.25f)); } // conversions across non-base units template<> template<> void units_object_t::test<3>() { LLUnit quatloos(1024); LLUnit solari(quatloos); ensure("conversions can work between indirectly related units: Quatloos -> Latinum -> Solari", solari == S32Solari(4096)); LLUnit latinum_bars = solari; ensure("Non base units can be converted between each other", latinum_bars == S32Latinum(256)); } // math operations template<> template<> void units_object_t::test<4>() { // exercise math operations LLUnit quatloos(1.f); quatloos *= 4.f; ensure(quatloos == S32Quatloos(4)); quatloos = quatloos * 2; ensure(quatloos == S32Quatloos(8)); quatloos = 2.f * quatloos; ensure(quatloos == S32Quatloos(16)); quatloos += F32Quatloos(4.f); ensure(quatloos == S32Quatloos(20)); quatloos += S32Quatloos(4); ensure(quatloos == S32Quatloos(24)); quatloos = quatloos + S32Quatloos(4); ensure(quatloos == S32Quatloos(28)); quatloos = S32Quatloos(4) + quatloos; ensure(quatloos == S32Quatloos(32)); quatloos += quatloos * 3; ensure(quatloos == S32Quatloos(128)); quatloos -= quatloos / 4 * 3; ensure(quatloos == S32Quatloos(32)); quatloos = quatloos - S32Quatloos(8); ensure(quatloos == S32Quatloos(24)); quatloos -= S32Quatloos(4); ensure(quatloos == S32Quatloos(20)); quatloos -= F32Quatloos(4.f); ensure(quatloos == S32Quatloos(16)); quatloos /= 2.f; ensure(quatloos == S32Quatloos(8)); quatloos = quatloos / 4; ensure(quatloos == S32Quatloos(2)); F32 ratio = quatloos / LLUnit(2.f); ensure(ratio == 1); ratio = quatloos / LLUnit(8.f); ensure(ratio == 1); quatloos += LLUnit(8.f); ensure(quatloos == S32Quatloos(4)); quatloos -= LLUnit(1.f); ensure(quatloos == S32Quatloos(0)); } // comparison operators template<> template<> void units_object_t::test<5>() { LLUnit quatloos(1); ensure("can perform less than comparison against same type", quatloos < S32Quatloos(2)); ensure("can perform less than comparison against different storage type", quatloos < F32Quatloos(2.f)); ensure("can perform less than comparison against different units", quatloos < S32Latinum(5)); ensure("can perform less than comparison against different storage type and units", quatloos < F32Latinum(5.f)); ensure("can perform greater than comparison against same type", quatloos > S32Quatloos(0)); ensure("can perform greater than comparison against different storage type", quatloos > F32Quatloos(0.f)); ensure("can perform greater than comparison against different units", quatloos > S32Latinum(0)); ensure("can perform greater than comparison against different storage type and units", quatloos > F32Latinum(0.f)); } bool accept_explicit_quatloos(S32Quatloos q) { return true; } bool accept_implicit_quatloos(S32Quatloos q) { return true; } // signature compatibility template<> template<> void units_object_t::test<6>() { S32Quatloos quatloos(1); ensure("can pass unit values as argument", accept_explicit_quatloos(S32Quatloos(1))); ensure("can pass unit values as argument", accept_explicit_quatloos(quatloos)); } // implicit units template<> template<> void units_object_t::test<7>() { LLUnit quatloos; LLUnitImplicit quatloos_implicit = quatloos + S32Quatloos(1); ensure("can initialize implicit unit from explicit", quatloos_implicit == 1); quatloos = quatloos_implicit; ensure("can assign implicit unit to explicit unit", quatloos == S32Quatloos(1)); quatloos += quatloos_implicit; ensure("can perform math operation using mixture of implicit and explicit units", quatloos == S32Quatloos(2)); // math operations on implicits quatloos_implicit = 1; ensure(quatloos_implicit == 1); quatloos_implicit += 2; ensure(quatloos_implicit == 3); quatloos_implicit *= 2; ensure(quatloos_implicit == 6); quatloos_implicit -= 1; ensure(quatloos_implicit == 5); quatloos_implicit /= 5; ensure(quatloos_implicit == 1); quatloos_implicit = quatloos_implicit + 3 + quatloos_implicit; ensure(quatloos_implicit == 5); quatloos_implicit = 10 - quatloos_implicit - 1; ensure(quatloos_implicit == 4); quatloos_implicit = 2 * quatloos_implicit * 2; ensure(quatloos_implicit == 16); F32 one_half = quatloos_implicit / (quatloos_implicit * 2); ensure(one_half == 0.5f); // implicit conversion to POD F32 float_val = quatloos_implicit; ensure("implicit units convert implicitly to regular values", float_val == 16); S32 int_val = (S32)quatloos_implicit; ensure("implicit units convert implicitly to regular values", int_val == 16); // conversion of implicits LLUnitImplicit latinum_implicit(2); ensure("implicit units of different types are comparable", latinum_implicit * 2 == quatloos_implicit); quatloos_implicit += F32Quatloos(10); ensure("can add-assign explicit units", quatloos_implicit == 26); quatloos_implicit -= F32Quatloos(10); ensure("can subtract-assign explicit units", quatloos_implicit == 16); // comparisons ensure("can compare greater than implicit unit", quatloos_implicit > F32QuatloosImplicit(0.f)); ensure("can compare greater than non-implicit unit", quatloos_implicit > F32Quatloos(0.f)); ensure("can compare greater than or equal to implicit unit", quatloos_implicit >= F32QuatloosImplicit(0.f)); ensure("can compare greater than or equal to non-implicit unit", quatloos_implicit >= F32Quatloos(0.f)); ensure("can compare less than implicit unit", quatloos_implicit < F32QuatloosImplicit(20.f)); ensure("can compare less than non-implicit unit", quatloos_implicit < F32Quatloos(20.f)); ensure("can compare less than or equal to implicit unit", quatloos_implicit <= F32QuatloosImplicit(20.f)); ensure("can compare less than or equal to non-implicit unit", quatloos_implicit <= F32Quatloos(20.f)); } // precision tests template<> template<> void units_object_t::test<8>() { U32Bytes max_bytes(U32_MAX); S32Megabytes mega_bytes = max_bytes; ensure("max available precision is used when converting units", mega_bytes == (S32Megabytes)4095); mega_bytes = (S32Megabytes)-5 + (U32Megabytes)1; ensure("can mix signed and unsigned in units addition", mega_bytes == (S32Megabytes)-4); mega_bytes = (U32Megabytes)5 + (S32Megabytes)-1; ensure("can mix unsigned and signed in units addition", mega_bytes == (S32Megabytes)4); } // default units template<> template<> void units_object_t::test<9>() { U32Gigabytes GB(1); U32Megabytes MB(GB); U32Kilobytes KB(GB); U32Bytes B(GB); ensure("GB -> MB conversion", MB.value() == 1024); ensure("GB -> KB conversion", KB.value() == 1024 * 1024); ensure("GB -> B conversion", B.value() == 1024 * 1024 * 1024); KB = U32Kilobytes(1); U32Kilobits Kb(KB); U32Bits b(KB); ensure("KB -> Kb conversion", Kb.value() == 8); ensure("KB -> b conversion", b.value() == 8 * 1024); U32Days days(1); U32Hours hours(days); U32Minutes minutes(days); U32Seconds seconds(days); U32Milliseconds ms(days); ensure("days -> hours conversion", hours.value() == 24); ensure("days -> minutes conversion", minutes.value() == 24 * 60); ensure("days -> seconds conversion", seconds.value() == 24 * 60 * 60); ensure("days -> ms conversion", ms.value() == 24 * 60 * 60 * 1000); U32Kilometers km(1); U32Meters m(km); U32Centimeters cm(km); U32Millimeters mm(km); ensure("km -> m conversion", m.value() == 1000); ensure("km -> cm conversion", cm.value() == 1000 * 100); ensure("km -> mm conversion", mm.value() == 1000 * 1000); U32Gigahertz GHz(1); U32Megahertz MHz(GHz); U32Kilohertz KHz(GHz); U32Hertz Hz(GHz); ensure("GHz -> MHz conversion", MHz.value() == 1000); ensure("GHz -> KHz conversion", KHz.value() == 1000 * 1000); ensure("GHz -> Hz conversion", Hz.value() == 1000 * 1000 * 1000); F32Radians rad(6.2831853071795f); S32Degrees deg(rad); ensure("radians -> degrees conversion", deg.value() == 360); F32Percent percent(50); F32Ratio ratio(percent); ensure("percent -> ratio conversion", ratio.value() == 0.5f); U32Kilotriangles ktris(1); U32Triangles tris(ktris); ensure("kilotriangles -> triangles conversion", tris.value() == 1000); } bool value_near(F32 value, F32 target, F32 threshold) { return fabsf(value - target) < threshold; } // linear transforms template<> template<> void units_object_t::test<10>() { F32Celcius float_celcius(100); F32Fahrenheit float_fahrenheit(float_celcius); ensure("floating point celcius -> fahrenheit conversion using linear transform", value_near(float_fahrenheit.value(), 212, 0.1f) ); float_celcius = float_fahrenheit; ensure("floating point fahrenheit -> celcius conversion using linear transform (round trip)", value_near(float_celcius.value(), 100.f, 0.1f) ); S32Celcius int_celcius(100); S32Fahrenheit int_fahrenheit(int_celcius); ensure("integer celcius -> fahrenheit conversion using linear transform", int_fahrenheit.value() == 212); int_celcius = int_fahrenheit; ensure("integer fahrenheit -> celcius conversion using linear transform (round trip)", int_celcius.value() == 100); } }