Skip to content

Commit ba8e7fe

Browse files
committed
Add new unit tests
- Cherrypicked from #273. ***NO_CI***
1 parent 6cf6098 commit ba8e7fe

1 file changed

Lines changed: 137 additions & 0 deletions

File tree

Tests/NFUnitTestConversions/UnitTestConvertTests.cs

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,143 @@ public static string FloatToHex(float f)
476476
return returnValue;
477477
}
478478

479+
[TestMethod]
480+
public void Cast_UIntToFloat()
481+
{
482+
// Regression test for https://github.com/nanoframework/Home/issues/1730
483+
// Conversion from a uint expression (I4 on stack) to float via conv.r.un + conv.r4
484+
// must produce the unsigned result even when no intermediate uint local is used.
485+
486+
ushort[] us = { 0x0000, 0x8000 }; // 0x80000000 = 2147483648u
487+
488+
float f1 = DecodeNumberToFloat1(us); // direct cast of expression
489+
float f2 = DecodeNumberToFloat2(us); // via uint local
490+
491+
Assert.AreEqual(2147483648f, f1, "Direct cast of (uint expression) to float should be 2147483648, not -2147483648");
492+
Assert.AreEqual(2147483648f, f2, "Indirect cast via uint local to float should be 2147483648");
493+
Assert.AreEqual(f2, f1, "Direct and indirect uint-to-float conversions should produce equal results");
494+
495+
us = new ushort[] { 0xFFFF, 0xFFFF }; // 0xFFFFFFFF = 4294967295u
496+
f1 = DecodeNumberToFloat1(us);
497+
f2 = DecodeNumberToFloat2(us);
498+
Assert.AreEqual(f2, f1, "Direct and indirect uint-to-float should be equal for 0xFFFFFFFF");
499+
500+
us = new ushort[] { 0x1234, 0x8765 }; // 0x87651234, high bit set
501+
f1 = DecodeNumberToFloat1(us);
502+
f2 = DecodeNumberToFloat2(us);
503+
Assert.AreEqual(f2, f1, "Direct and indirect uint-to-float should be equal for 0x87651234");
504+
505+
us = new ushort[] { 0xABCD, 0x1234 }; // 0x1234ABCD, high bit clear
506+
f1 = DecodeNumberToFloat1(us);
507+
f2 = DecodeNumberToFloat2(us);
508+
Assert.AreEqual(f2, f1, "Direct and indirect uint-to-float should be equal for 0x1234ABCD");
509+
}
510+
511+
[TestMethod]
512+
public void Cast_ULongToDouble()
513+
{
514+
// Regression test for https://github.com/nanoframework/Home/issues/1730
515+
// ulong arithmetic results land on the eval stack as I8 (signed).
516+
// conv.r.un must treat the I8 bits as unsigned; before the fix the
517+
// interpreter ignored the fUnsigned flag and produced a negative double.
518+
519+
uint[] ui = { 0x00000000, 0x80000000 }; // 0x8000000000000000 = 9223372036854775808uL
520+
521+
double d1 = DecodeULong1(ui); // expression result (I8) → conv.r.un: was broken
522+
double d2 = DecodeULong2(ui); // via ulong local (U8) → conv.r.un: was correct
523+
524+
Assert.AreEqual(9223372036854775808d, d1, "Direct cast of (ulong expression) to double should be 9223372036854775808, not negative");
525+
Assert.AreEqual(9223372036854775808d, d2, "Indirect cast via ulong local to double should be 9223372036854775808");
526+
Assert.AreEqual(d2, d1, "Direct and indirect ulong-to-double conversions should produce equal results");
527+
528+
ui = new uint[] { 0xFFFFFFFF, 0xFFFFFFFF }; // ulong.MaxValue = 18446744073709551615
529+
d1 = DecodeULong1(ui);
530+
d2 = DecodeULong2(ui);
531+
Assert.AreEqual(18446744073709551615d, d1, "Direct cast of ulong.MaxValue expression to double should be 18446744073709551615");
532+
Assert.AreEqual(d2, d1, "Direct and indirect ulong-to-double should be equal for ulong.MaxValue");
533+
534+
ui = new uint[] { 0x12345678, 0x87654321 }; // 0x8765432112345678, high bit set
535+
d1 = DecodeULong1(ui);
536+
d2 = DecodeULong2(ui);
537+
Assert.AreEqual(d2, d1, "Direct and indirect ulong-to-double should be equal for 0x8765432112345678");
538+
539+
ui = new uint[] { 0x12345678, 0x01234567 }; // 0x0123456712345678, high bit clear
540+
d1 = DecodeULong1(ui);
541+
d2 = DecodeULong2(ui);
542+
Assert.AreEqual(d2, d1, "Direct and indirect ulong-to-double should be equal for 0x0123456712345678");
543+
}
544+
545+
[TestMethod]
546+
public void Cast_ULongToFloat()
547+
{
548+
// Regression test for https://github.com/nanoframework/Home/issues/1730
549+
// Same sign-interpretation bug as Cast_ULongToDouble but for float (conv.r.un + conv.r4).
550+
551+
uint[] ui = { 0x00000000, 0x80000000 }; // 0x8000000000000000 = 9223372036854775808uL
552+
553+
float f1 = DecodeULong1Float(ui); // expression result (I8) → conv.r.un: was broken
554+
float f2 = DecodeULong2Float(ui); // via ulong local (U8) → conv.r.un: was correct
555+
556+
Assert.AreEqual(9223372036854775808f, f1, "Direct cast of (ulong expression) to float should be 9223372036854775808, not negative");
557+
Assert.AreEqual(9223372036854775808f, f2, "Indirect cast via ulong local to float should be 9223372036854775808");
558+
Assert.AreEqual(f2, f1, "Direct and indirect ulong-to-float conversions should produce equal results");
559+
560+
ui = new uint[] { 0xFFFFFFFF, 0xFFFFFFFF }; // ulong.MaxValue
561+
f1 = DecodeULong1Float(ui);
562+
f2 = DecodeULong2Float(ui);
563+
Assert.AreEqual(f2, f1, "Direct and indirect ulong-to-float should be equal for ulong.MaxValue");
564+
565+
ui = new uint[] { 0x12345678, 0x87654321 }; // 0x8765432112345678, high bit set
566+
f1 = DecodeULong1Float(ui);
567+
f2 = DecodeULong2Float(ui);
568+
Assert.AreEqual(f2, f1, "Direct and indirect ulong-to-float should be equal for 0x8765432112345678");
569+
570+
ui = new uint[] { 0x12345678, 0x01234567 }; // high bit clear
571+
f1 = DecodeULong1Float(ui);
572+
f2 = DecodeULong2Float(ui);
573+
Assert.AreEqual(f2, f1, "Direct and indirect ulong-to-float should be equal for 0x0123456712345678");
574+
}
575+
576+
private static float DecodeNumberToFloat1(ushort[] us)
577+
{
578+
// Returns the uint expression directly as float, exercising conv.r.un on an I4 stack value.
579+
return ((uint)us[1] << 16) + us[0];
580+
}
581+
582+
private static float DecodeNumberToFloat2(ushort[] us)
583+
{
584+
// Stores in a uint local first, so conv.r.un sees a correctly typed U4 local.
585+
uint u = ((uint)us[1] << 16) + us[0];
586+
return u;
587+
}
588+
589+
private static double DecodeULong1(uint[] ui)
590+
{
591+
// Returns the ulong expression directly as double.
592+
// conv.r.un is applied to an I8 arithmetic result on the eval stack,
593+
// which had a sign-interpretation bug before the fix.
594+
return ((ulong)ui[1] << 32) | ui[0];
595+
}
596+
597+
private static double DecodeULong2(uint[] ui)
598+
{
599+
// Stores in a ulong local first, so conv.r.un sees a correctly typed U8 local.
600+
ulong u = ((ulong)ui[1] << 32) | ui[0];
601+
return u;
602+
}
603+
604+
private static float DecodeULong1Float(uint[] ui)
605+
{
606+
// Returns the ulong expression directly as float (conv.r.un on I8, then conv.r4).
607+
return (float)(((ulong)ui[1] << 32) | ui[0]);
608+
}
609+
610+
private static float DecodeULong2Float(uint[] ui)
611+
{
612+
// Stores in a ulong local first, so conv.r.un sees a correctly typed U8 local.
613+
ulong u = ((ulong)ui[1] << 32) | ui[0];
614+
return (float)u;
615+
}
479616

480617
#endregion
481618

0 commit comments

Comments
 (0)