public void TestSpeedConstructor()
        {
            var uomsToPass1 = GetUnitOfMeasuresTypeFullNames <NGenericDimensions.Lengths.Length1DUnitOfMeasure>(true, true).ToArray();
            var uomsToFail1 = GetUnitOfMeasuresTypeFullNames <NGenericDimensions.Lengths.Length1DUnitOfMeasure>(true, false).ToArray();
            var uomsToPass2 = GetUnitOfMeasuresTypeFullNames <DurationUnitOfMeasure>(true, true).ToArray();
            var uomsToFail2 = GetUnitOfMeasuresTypeFullNames <DurationUnitOfMeasure>(true, false).ToArray();

            // test valid and invalid units of measure for length
            Func <string, string, string> csharpCode = (l, d) => $@"_ = new NGenericDimensions.Speed<{l}, {d}, double>(4.4);";

            foreach (var uomToPass in (from length in uomsToPass1 from duration in uomsToPass2 select new { length, duration }))
            {
                AssertCompilationPasses(csharpCode(uomToPass.length, uomToPass.duration));
            }
            foreach (var uomToFail in uomsToFail1)
            {
                AssertCompilationFails("cannot be used as type parameter", csharpCode(uomToFail, "NGenericDimensions.Durations.Hours"));
            }
            foreach (var uomToFail in uomsToFail2)
            {
                AssertCompilationFails("cannot be used as type parameter", csharpCode("NGenericDimensions.Lengths.Uscs.Feet", uomToFail));
            }

            // test common constructor tests
            TestConstructor(@"_ = new NGenericDimensions.Speed<NGenericDimensions.Lengths.Uscs.Yards, NGenericDimensions.Durations.Hours, {0});");

            // test creating speed with a length and duration
            {
                var lengthA   = new NGenericDimensions.Length <NGenericDimensions.Lengths.Uscs.Miles, System.Int32>(60);
                var durationA = new NGenericDimensions.Duration <NGenericDimensions.Durations.Minutes, System.Byte>(30);
                var speedA    = new NGenericDimensions.Speed <NGenericDimensions.Lengths.Uscs.Miles, NGenericDimensions.Durations.Minutes, System.Int32>(lengthA, durationA);
                Assert.Equal(2, speedA.SpeedValue);
            }
            {
                var lengthA   = new NGenericDimensions.Length <NGenericDimensions.Lengths.Uscs.Miles, System.Int32>(60);
                var durationA = System.TimeSpan.FromMinutes(30);
                var speedA    = new NGenericDimensions.Speed <NGenericDimensions.Lengths.Uscs.Miles, NGenericDimensions.Durations.Minutes, System.Int32>(lengthA, durationA);
                Assert.Equal(2, speedA.SpeedValue);
            }

            // make sure value gets stored in member variable
            var speedB = new Speed <Miles, Hours, Int32>(3);

            Assert.Equal(3, speedB.SpeedValue);

            // make sure value can be constructed via its own kind of data type, and that it is an exact copy
            var speedC = new Speed <Miles, Hours, Int32>(speedB);

            Assert.Equal(speedB.SpeedValue, speedC.SpeedValue);
            Assert.Equal(3, speedC.SpeedValue);
            Assert.Same(speedB.LengthUnitOfMeasure, speedC.LengthUnitOfMeasure);
            Assert.Same(speedB.DurationUnitOfMeasure, speedC.DurationUnitOfMeasure);

            // make sure value of different unit converts propertly via constructor.
            Assert.Equal(8640, (new NGenericDimensions.Speed <NGenericDimensions.Lengths.Uscs.Inches, NGenericDimensions.Durations.Minutes, System.Int32>(new NGenericDimensions.Speed <NGenericDimensions.Lengths.Uscs.Feet, NGenericDimensions.Durations.Seconds, System.Double>(12))).SpeedValue);

            // test to make sure we can't use a dimension for the numeric datatype
            AssertCompilationFails("cannot be used as type parameter", @"_ = new NGenericDimensions.Speed<NGenericDimensions.Volumes.MetricNonSI.Litres, NGenericDimensions.Durations.Minutes, System.Int32>(44);");
            AssertCompilationFails("cannot be used as type parameter", @"_ = new NGenericDimensions.Speed<NGenericDimensions.Lengths.Uscs.Inches, NGenericDimensions.Volumes.MetricNonSI.Litres, System.Int32>(44);");
        }
        public void TestDurationConstructor()
        {
            // test valid units of measure for duration
            { var durationA = new NGenericDimensions.Duration <NGenericDimensions.Durations.Days, double>(4.4); }
            { var durationA = new NGenericDimensions.Duration <NGenericDimensions.Durations.Hours, double>(4.4); }
            { var durationA = new NGenericDimensions.Duration <NGenericDimensions.Durations.Minutes, double>(4.4); }
            { var durationA = new NGenericDimensions.Duration <NGenericDimensions.Durations.Seconds, double>(4.4); }
            { var durationA = new NGenericDimensions.Duration <NGenericDimensions.Durations.Milliseconds, double>(4.4); }
            { var durationA = new NGenericDimensions.Duration <NGenericDimensions.Durations.Microseconds, double>(4.4); }
            { var durationA = new NGenericDimensions.Duration <NGenericDimensions.Durations.Ticks, double>(4.4); }
            { var durationA = new NGenericDimensions.Duration <NGenericDimensions.Durations.Seconds <Deca>, double>(4.4); }
            { var durationA = new NGenericDimensions.Duration <NGenericDimensions.Durations.Seconds <Hecto>, double>(4.4); }
            { var durationA = new NGenericDimensions.Duration <NGenericDimensions.Durations.Seconds <Kilo>, double>(4.4); }
            { var durationA = new NGenericDimensions.Duration <NGenericDimensions.Durations.Seconds <Mega>, double>(4.4); }
            { var durationA = new NGenericDimensions.Duration <NGenericDimensions.Durations.Seconds <Giga>, double>(4.4); }
            { var durationA = new NGenericDimensions.Duration <NGenericDimensions.Durations.Seconds <Tera>, double>(4.4); }
            { var durationA = new NGenericDimensions.Duration <NGenericDimensions.Durations.Seconds <Peta>, double>(4.4); }
            { var durationA = new NGenericDimensions.Duration <NGenericDimensions.Durations.Seconds <Exa>, double>(4.4); }
            { var durationA = new NGenericDimensions.Duration <NGenericDimensions.Durations.Seconds <Zetta>, double>(4.4); }
            { var durationA = new NGenericDimensions.Duration <NGenericDimensions.Durations.Seconds <Yotta>, double>(4.4); }
            { var durationA = new NGenericDimensions.Duration <NGenericDimensions.Durations.Seconds <Deci>, double>(4.4); }
            { var durationA = new NGenericDimensions.Duration <NGenericDimensions.Durations.Seconds <Centi>, double>(4.4); }
            { var durationA = new NGenericDimensions.Duration <NGenericDimensions.Durations.Seconds <Milli>, double>(4.4); }
            { var durationA = new NGenericDimensions.Duration <NGenericDimensions.Durations.Seconds <Micro>, double>(4.4); }
            { var durationA = new NGenericDimensions.Duration <NGenericDimensions.Durations.Seconds <Nano>, double>(4.4); }
            { var durationA = new NGenericDimensions.Duration <NGenericDimensions.Durations.Seconds <Pico>, double>(4.4); }
            { var durationA = new NGenericDimensions.Duration <NGenericDimensions.Durations.Seconds <Femto>, double>(4.4); }
            { var durationA = new NGenericDimensions.Duration <NGenericDimensions.Durations.Seconds <Atto>, double>(4.4); }
            { var durationA = new NGenericDimensions.Duration <NGenericDimensions.Durations.Seconds <Zepto>, double>(4.4); }
            { var durationA = new NGenericDimensions.Duration <NGenericDimensions.Durations.Seconds <Yocto>, double>(4.4); }

            // test invalid units of measure of duration
            AssertCompilationFails("cannot be used as type parameter", @"var durationA = new NGenericDimensions.Duration<NGenericDimensions.Areas.MetricNonSI.Hectares, double>(4.4);");
            AssertCompilationFails("cannot be used as type parameter", @"var durationA = new NGenericDimensions.Duration<NGenericDimensions.Lengths.MetricSI.Millimetres, double>(4.4);");
            AssertCompilationFails("cannot be used as type parameter", @"var durationA = new NGenericDimensions.Duration<NGenericDimensions.Masses.MetricSI.Grams, double>(4.4);");
            AssertCompilationFails("cannot be used as type parameter", @"var durationA = new NGenericDimensions.Duration<NGenericDimensions.Masses.MetricSI.Kilograms, double>(4.4);");
            AssertCompilationFails("cannot be used as type parameter", @"var durationA = new NGenericDimensions.Duration<NGenericDimensions.Volumes.MetricNonSI.Litres, double>(4.4);");
            AssertCompilationFails("cannot be used as type parameter", @"var durationA = new NGenericDimensions.Duration<NGenericDimensions.Durations.DurationUnitOfMeasure, double>(4.4);");

            // test number data types
            { var durationA = new NGenericDimensions.Duration <NGenericDimensions.Durations.Hours, System.Double>(System.Convert.ToDouble(4.44444)); }
            { var durationA = new NGenericDimensions.Duration <NGenericDimensions.Durations.Hours, System.Double>(System.Convert.ToSingle(4.44444)); }
            { var durationA = new NGenericDimensions.Duration <NGenericDimensions.Durations.Hours, System.Single>(System.Convert.ToSingle(4.44444)); }
            { var durationA = new NGenericDimensions.Duration <NGenericDimensions.Durations.Hours, System.Decimal>(System.Convert.ToDecimal(4.44444)); }
            { var durationA = new NGenericDimensions.Duration <NGenericDimensions.Durations.Hours, System.Int64>(System.Convert.ToInt64(4)); }
            { var durationA = new NGenericDimensions.Duration <NGenericDimensions.Durations.Hours, System.Int32>(System.Convert.ToInt32(4)); }
            { var durationA = new NGenericDimensions.Duration <NGenericDimensions.Durations.Hours, System.Int16>(System.Convert.ToInt16(4)); }
            { var durationA = new NGenericDimensions.Duration <NGenericDimensions.Durations.Hours, System.Byte>(System.Convert.ToByte(4)); }
            { var durationA = new NGenericDimensions.Duration <NGenericDimensions.Durations.Hours, System.SByte>(System.Convert.ToSByte(4)); }
            { var durationA = new NGenericDimensions.Duration <NGenericDimensions.Durations.Hours, System.UInt16>(System.Convert.ToUInt16(4)); }
            { var durationA = new NGenericDimensions.Duration <NGenericDimensions.Durations.Hours, System.UInt32>(System.Convert.ToUInt32(4)); }
            { var durationA = new NGenericDimensions.Duration <NGenericDimensions.Durations.Hours, System.UInt64>(System.Convert.ToUInt64(4)); }
            AssertCompilationFails("cannot be used as type parameter", @"var durationA = new NGenericDimensions.Duration<NGenericDimensions.Durations.Hours, System.Char>(System.Convert.ToChar(4));");
            { var durationA = new NGenericDimensions.Duration <NGenericDimensions.Durations.Hours, System.DateTime>(new System.DateTime(1000)); } // can't stop this from being allowed
            AssertCompilationFails("cannot be used as type parameter", @"var durationA = new NGenericDimensions.Duration<NGenericDimensions.Durations.Hours, System.Boolean>(System.Convert.ToBoolean(4));");
            { var durationA = new NGenericDimensions.Duration <NGenericDimensions.Durations.Hours, System.Numerics.BigInteger>(new System.Numerics.BigInteger(4.4)); }
            // and prove it only allows compatible data types
            { var durationA = new NGenericDimensions.Duration <NGenericDimensions.Durations.Hours, System.Int32>(System.Convert.ToInt32(4)); }
            { var durationA = new NGenericDimensions.Duration <NGenericDimensions.Durations.Hours, System.Int32>(System.Convert.ToInt16(4)); }
            { var durationA = new NGenericDimensions.Duration <NGenericDimensions.Durations.Hours, System.Int32>(System.Convert.ToByte(4)); }
            AssertCompilationFails("has some invalid arguments", @"var durationA = new NGenericDimensions.Duration<NGenericDimensions.Durations.Hours, System.Int32>(System.Convert.ToInt64(4));");

            // make sure constructor can take a timespan
            { var durationA = new Duration <Hours, Int32>(TimeSpan.FromDays(2)); }
            Assert.AreEqual(48, (new Duration <Hours, Int32>(TimeSpan.FromDays(2))).HoursValue());
            Assert.AreEqual(777, (new Duration <Ticks, Int32>(TimeSpan.FromTicks(777))).TicksValue());
            Assert.AreEqual(TimeSpan.FromTicks(777), (new Duration <Ticks, Int32>(TimeSpan.FromTicks(777))).TimeSpan);

            // make sure value gets stored in member variable
            var durationB = new Duration <Hours, Int32>(3);

            Assert.AreEqual(3, durationB.DurationValue);

            // make sure value can be constructed via its own kind of data type, and that it is an exact copy
            var durationC = new Duration <Hours, Int32>(durationB);

            Assert.AreEqual(durationB.DurationValue, durationC.DurationValue);
            Assert.AreEqual(3, durationC.DurationValue);
            Assert.AreSame(durationB.UnitOfMeasure, durationC.UnitOfMeasure);

            // make sure value of different unit converts propertly via constructor.
            Assert.AreEqual(120, (new Duration <Seconds, Int32>(new Duration <Minutes, Int32>(2))).DurationValue);
            Assert.AreEqual(120, (new Duration <Seconds, Int32>(new Duration <Minutes, Int64>(2))).DurationValue);
            Assert.AreEqual(132, (new Duration <Seconds, Int32>(new Duration <Minutes, Decimal>(Convert.ToDecimal(2.2)))).DurationValue);
            Assert.AreEqual(132, (new Duration <Seconds, Int32>(new Duration <Minutes, Double>(2.2))).DurationValue);

            // test to make sure we can't use a dimension for the numeric datatype
            AssertCompilationFails("cannot be used as type parameter", @"var durationA = new NGenericDimensions.Duration<NGenericDimensions.Durations.Hours, NGenericDimensions.Duration<NGenericDimensions.Durations.Hours, System.Double>>(44.4);");
        }