From 861914edbd69fda346ce5eb259a2b4910510262d Mon Sep 17 00:00:00 2001 From: Chip Hogg Date: Wed, 15 Jan 2025 17:37:44 -0500 Subject: [PATCH] Add unit test for XKCD 3038 alt-text See for context: . Presumably, the joke only works if the speed limit in question corresponds to a realistic speed limit for American roads, so we take the range to be from 25 MPH (many residential streets) to 75 MPH (some roads in places I have seen such as parts of MI or TX). To make this work, it was convenient to add unit definitions for `Arcminutes` and `Arcseconds`. These have various choices for unit symbol, but I decided to go with `am` and `as` because this will be the most consistent with users who form symbols for `mas` and `uas`. For the labels, in any case, I went with `'` and `"`. I could be persuaded to go with `''` for arcseconds, but I think `"` is likely to be better overall. We also now group all of our XKCD test cases into an `Xkcd` test family, because of course we do. --- au/code/au/CMakeLists.txt | 6 ++++ au/code/au/au_test.cc | 21 ++++++++++- au/code/au/units/arcminutes.hh | 44 ++++++++++++++++++++++++ au/code/au/units/arcminutes_fwd.hh | 21 +++++++++++ au/code/au/units/arcseconds.hh | 44 ++++++++++++++++++++++++ au/code/au/units/arcseconds_fwd.hh | 21 +++++++++++ au/code/au/units/test/arcminutes_test.cc | 34 ++++++++++++++++++ au/code/au/units/test/arcseconds_test.cc | 34 ++++++++++++++++++ 8 files changed, 224 insertions(+), 1 deletion(-) create mode 100644 au/code/au/units/arcminutes.hh create mode 100644 au/code/au/units/arcminutes_fwd.hh create mode 100644 au/code/au/units/arcseconds.hh create mode 100644 au/code/au/units/arcseconds_fwd.hh create mode 100644 au/code/au/units/test/arcminutes_test.cc create mode 100644 au/code/au/units/test/arcseconds_test.cc diff --git a/au/code/au/CMakeLists.txt b/au/code/au/CMakeLists.txt index 7c518bf4..d9fbcd7b 100644 --- a/au/code/au/CMakeLists.txt +++ b/au/code/au/CMakeLists.txt @@ -59,6 +59,10 @@ header_only_library( stdx/utility.hh units/amperes.hh units/amperes_fwd.hh + units/arcminutes.hh + units/arcminutes_fwd.hh + units/arcseconds.hh + units/arcseconds_fwd.hh units/bars.hh units/bars_fwd.hh units/becquerel.hh @@ -306,6 +310,8 @@ gtest_based_test( NAME units_test SRCS units/test/amperes_test.cc + units/test/arcminutes_test.cc + units/test/arcseconds_test.cc units/test/bars_test.cc units/test/becquerel_test.cc units/test/bits_test.cc diff --git a/au/code/au/au_test.cc b/au/code/au/au_test.cc index d92a7504..b25c229e 100644 --- a/au/code/au/au_test.cc +++ b/au/code/au/au_test.cc @@ -14,8 +14,10 @@ #include "au/au.hh" +#include "au/constants/speed_of_light.hh" #include "au/prefix.hh" #include "au/testing.hh" +#include "au/units/arcminutes.hh" #include "au/units/celsius.hh" #include "au/units/fahrenheit.hh" #include "au/units/fathoms.hh" @@ -26,12 +28,19 @@ #include "au/units/knots.hh" #include "au/units/meters.hh" #include "au/units/miles.hh" +#include "au/units/steradians.hh" #include "au/units/yards.hh" #include "gtest/gtest.h" using ::testing::StaticAssertTypeEq; namespace au { +namespace { +template +auto IsBetween(T lower, U upper) { + return ::testing::AllOf(::testing::Ge(lower), ::testing::Le(upper)); +} +} // namespace TEST(Conversions, SupportIntMHzToU32Hz) { constexpr QuantityU32 freq = mega(hertz)(40); @@ -54,7 +63,7 @@ constexpr auto round_sequentially(Quantity q, FirstUnit first_unit, NextUn return round_sequentially(round_as(first_unit, q), next_units...); } -TEST(RoundAs, ReproducesXkcd2585) { +TEST(Xkcd, RoundAsReproducesXkcd2585) { constexpr auto true_speed = (miles / hour)(17); const auto rounded_speed = round_sequentially(true_speed, @@ -86,6 +95,16 @@ TEST(RoundAs, ReproducesXkcd2585) { EXPECT_EQ((miles / hour)(45), rounded_speed); } +TEST(Xkcd, Xkcd3038GivesReasonableSpeedLimit) { + using symbols::h; + using symbols::mi; + + constexpr auto c = SPEED_OF_LIGHT; + constexpr auto SPEED_LIMIT = make_constant(c * squared(arcminutes) / steradian); + + EXPECT_THAT(SPEED_LIMIT, IsBetween(25.0 * mi / h, 75.0 * mi / h)); +} + TEST(QuantityPoint, DocumentationExampleIsCorrect) { EXPECT_LT(fahrenheit_pt(-40) + celsius_qty(60), kelvins_pt(300)); } diff --git a/au/code/au/units/arcminutes.hh b/au/code/au/units/arcminutes.hh new file mode 100644 index 00000000..87d48f0b --- /dev/null +++ b/au/code/au/units/arcminutes.hh @@ -0,0 +1,44 @@ +// Copyright 2025 Aurora Operations, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include "au/units/arcminutes_fwd.hh" +// Keep corresponding `_fwd.hh` file on top. + +#include "au/quantity.hh" +#include "au/unit_symbol.hh" +#include "au/units/degrees.hh" + +namespace au { + +// DO NOT follow this pattern to define your own units. This is for library-defined units. +// Instead, follow instructions at (https://aurora-opensource.github.io/au/main/howto/new-units/). +template +struct ArcminutesLabel { + static constexpr const char label[] = "'"; +}; +template +constexpr const char ArcminutesLabel::label[]; +struct Arcminutes : decltype(Degrees{} / mag<60>()), ArcminutesLabel { + using ArcminutesLabel::label; +}; +constexpr auto arcminute = SingularNameFor{}; +constexpr auto arcminutes = QuantityMaker{}; + +namespace symbols { +constexpr auto am = SymbolFor{}; +} + +} // namespace au diff --git a/au/code/au/units/arcminutes_fwd.hh b/au/code/au/units/arcminutes_fwd.hh new file mode 100644 index 00000000..3d411dab --- /dev/null +++ b/au/code/au/units/arcminutes_fwd.hh @@ -0,0 +1,21 @@ +// Copyright 2025 Aurora Operations, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +namespace au { + +struct Arcminutes; + +} // namespace au diff --git a/au/code/au/units/arcseconds.hh b/au/code/au/units/arcseconds.hh new file mode 100644 index 00000000..dc77fa92 --- /dev/null +++ b/au/code/au/units/arcseconds.hh @@ -0,0 +1,44 @@ +// Copyright 2025 Aurora Operations, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include "au/units/arcseconds_fwd.hh" +// Keep corresponding `_fwd.hh` file on top. + +#include "au/quantity.hh" +#include "au/unit_symbol.hh" +#include "au/units/degrees.hh" + +namespace au { + +// DO NOT follow this pattern to define your own units. This is for library-defined units. +// Instead, follow instructions at (https://aurora-opensource.github.io/au/main/howto/new-units/). +template +struct ArcsecondsLabel { + static constexpr const char label[] = "\""; +}; +template +constexpr const char ArcsecondsLabel::label[]; +struct Arcseconds : decltype(Degrees{} / mag<3600>()), ArcsecondsLabel { + using ArcsecondsLabel::label; +}; +constexpr auto arcsecond = SingularNameFor{}; +constexpr auto arcseconds = QuantityMaker{}; + +namespace symbols { +constexpr auto as = SymbolFor{}; +} + +} // namespace au diff --git a/au/code/au/units/arcseconds_fwd.hh b/au/code/au/units/arcseconds_fwd.hh new file mode 100644 index 00000000..61334839 --- /dev/null +++ b/au/code/au/units/arcseconds_fwd.hh @@ -0,0 +1,21 @@ +// Copyright 2025 Aurora Operations, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +namespace au { + +struct Arcseconds; + +} // namespace au diff --git a/au/code/au/units/test/arcminutes_test.cc b/au/code/au/units/test/arcminutes_test.cc new file mode 100644 index 00000000..6d7f97c4 --- /dev/null +++ b/au/code/au/units/test/arcminutes_test.cc @@ -0,0 +1,34 @@ +// Copyright 2025 Aurora Operations, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "au/units/arcminutes.hh" + +#include "au/testing.hh" +#include "au/units/degrees.hh" +#include "gtest/gtest.h" + +namespace au { + +TEST(Arcseconds, HasExpectedLabel) { expect_label("'"); } + +TEST(Arcseconds, RelatesCorrectlyToDegrees) { + EXPECT_THAT(arcseconds(120.0), QuantityEquivalent(degrees(2.0))); +} + +TEST(Arcseconds, HasExpectedSymbol) { + using symbols::am; + EXPECT_THAT(5.f * am, SameTypeAndValue(arcminutes(5.f))); +} + +} // namespace au diff --git a/au/code/au/units/test/arcseconds_test.cc b/au/code/au/units/test/arcseconds_test.cc new file mode 100644 index 00000000..6eb0d94d --- /dev/null +++ b/au/code/au/units/test/arcseconds_test.cc @@ -0,0 +1,34 @@ +// Copyright 2025 Aurora Operations, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "au/units/arcseconds.hh" + +#include "au/testing.hh" +#include "au/units/degrees.hh" +#include "gtest/gtest.h" + +namespace au { + +TEST(Arcseconds, HasExpectedLabel) { expect_label("\""); } + +TEST(Arcseconds, RelatesCorrectlyToDegrees) { + EXPECT_THAT(arcseconds(7200.0), QuantityEquivalent(degrees(2.0))); +} + +TEST(Arcseconds, HasExpectedSymbol) { + using symbols::as; + EXPECT_THAT(5.f * as, SameTypeAndValue(arcseconds(5.f))); +} + +} // namespace au