diff --git a/.runsettings b/.runsettings
index 3d17b679..536c73fb 100644
--- a/.runsettings
+++ b/.runsettings
@@ -1,4 +1,4 @@
-
+
@@ -12,5 +12,6 @@
Verbose
False
--forcegc
+ True
-
\ No newline at end of file
+
diff --git a/Tests/NFUnitTestGC/TestGC.cs b/Tests/NFUnitTestGC/TestGC.cs
index 0bec97a8..bf52e121 100644
--- a/Tests/NFUnitTestGC/TestGC.cs
+++ b/Tests/NFUnitTestGC/TestGC.cs
@@ -1,7 +1,8 @@
-// Licensed to the .NET Foundation under one or more agreements.
+// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+using System;
using nanoFramework.TestFramework;
namespace NFUnitTestGC
@@ -15,8 +16,6 @@ public void TestGCStress()
int maxArraySize = 1024 * 32;
object[] arrays = new object[600];
- // Starting TestGCStress
-
for (int loop = 0; loop < 100; loop++)
{
OutputHelper.WriteLine($"Running iteration {loop}");
@@ -24,7 +23,7 @@ public void TestGCStress()
for (int i = 0; i < arrays.Length - 1;)
{
OutputHelper.WriteLine($"Alloc array of {maxArraySize} bytes @ pos {i}");
- arrays[i++] = new byte[maxArraySize]; ;
+ arrays[i++] = new byte[maxArraySize];
OutputHelper.WriteLine($"Alloc array of 64 bytes @ pos {i}");
arrays[i++] = new byte[64];
@@ -37,8 +36,35 @@ public void TestGCStress()
arrays[i] = null;
}
}
+ }
+
+ [TestMethod]
+ public void TestGetTotalMemory()
+ {
+ // create several objects
+ object[] objects = new object[100];
+
+ for (int i = 0; i < objects.Length; i++)
+ {
+ objects[i] = new object();
+ }
+
+ // get total memory
+ long totalMemory = GC.GetTotalMemory(false);
+ OutputHelper.WriteLine($"Total memory: {totalMemory} bytes");
+
+ // release objects
+ for (int i = 0; i < objects.Length; i++)
+ {
+ objects[i] = null;
+ }
+
+ // get total memory, forcing full collection
+ long totalMemoryAfterCollection = GC.GetTotalMemory(true);
+ OutputHelper.WriteLine($"Total memory: {totalMemoryAfterCollection} bytes");
- // Completed TestGCStress
+ // check if memory was released
+ Assert.IsTrue(totalMemory > totalMemoryAfterCollection, "Memory was not released");
}
}
}
diff --git a/Tests/NFUnitTestSystemLib/NFUnitTestSystemLib.nfproj b/Tests/NFUnitTestSystemLib/NFUnitTestSystemLib.nfproj
index 593d741a..95da98f9 100644
--- a/Tests/NFUnitTestSystemLib/NFUnitTestSystemLib.nfproj
+++ b/Tests/NFUnitTestSystemLib/NFUnitTestSystemLib.nfproj
@@ -21,9 +21,12 @@
true
UnitTest
v1.0
+ 13.0
+
+
@@ -61,4 +64,4 @@
-
\ No newline at end of file
+
diff --git a/Tests/NFUnitTestSystemLib/RuntimeHelpersTests.cs b/Tests/NFUnitTestSystemLib/RuntimeHelpersTests.cs
new file mode 100644
index 00000000..d02d1c00
--- /dev/null
+++ b/Tests/NFUnitTestSystemLib/RuntimeHelpersTests.cs
@@ -0,0 +1,68 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.Runtime.CompilerServices;
+using nanoFramework.TestFramework;
+
+namespace NFUnitTestSystemLib
+{
+ [TestClass]
+ class RuntimeHelpersTests
+ {
+ [TestMethod]
+ public static void IsReferenceOrContainsReferences()
+ {
+ Assert.IsFalse(RuntimeHelpers.IsReferenceOrContainsReferences());
+ Assert.IsTrue(RuntimeHelpers.IsReferenceOrContainsReferences());
+ Assert.IsFalse(RuntimeHelpers.IsReferenceOrContainsReferences());
+ Assert.IsFalse(RuntimeHelpers.IsReferenceOrContainsReferences());
+ Assert.IsTrue(RuntimeHelpers.IsReferenceOrContainsReferences());
+ Assert.IsFalse(RuntimeHelpers.IsReferenceOrContainsReferences());
+ Assert.IsTrue(RuntimeHelpers.IsReferenceOrContainsReferences());
+ Assert.IsTrue(RuntimeHelpers.IsReferenceOrContainsReferences>());
+ Assert.IsTrue(RuntimeHelpers.IsReferenceOrContainsReferences>());
+ //Assert.IsTrue(RuntimeHelpers.IsReferenceOrContainsReferences());
+ //Assert.IsTrue(RuntimeHelpers.IsReferenceOrContainsReferences());
+ }
+
+ private struct StructWithoutReferences
+ {
+ public int a, b, c;
+ }
+
+ private struct StructWithReferences
+ {
+ public int a, b, c;
+ public object d;
+ }
+
+ private ref struct RefStructWithoutReferences
+ {
+ public int a;
+ public long b;
+ }
+
+ private ref struct RefStructWithReferences
+ {
+ public int a;
+ public object b;
+ }
+
+ // TODO: add after checking viability of ref fields in ref structs
+ //private ref struct RefStructWithRef
+ //{
+ // public ref int a;
+
+ // internal RefStructWithRef(ref int aVal)
+ // {
+ // a = ref aVal;
+ // }
+ //}
+
+ //private ref struct RefStructWithNestedRef
+ //{
+ // public Span a;
+ //}
+ }
+}
diff --git a/Tests/NFUnitTestSystemLib/UnitTestGCTest.cs b/Tests/NFUnitTestSystemLib/UnitTestGCTest.cs
index 05c73642..42a3e8f0 100644
--- a/Tests/NFUnitTestSystemLib/UnitTestGCTest.cs
+++ b/Tests/NFUnitTestSystemLib/UnitTestGCTest.cs
@@ -9,6 +9,11 @@ namespace NFUnitTestSystemLib
[TestClass]
public class UnitTestGCTest
{
+#pragma warning disable S1215 // this is intended to test the GC
+#pragma warning disable S1854 // this is intended to test the GC
+#pragma warning disable S2696 // this is intended to test the GC
+#pragma warning disable S3971 // this is intended to test the GC
+
internal class FinalizeObject
{
public static FinalizeObject m_currentInstance = null;
@@ -54,17 +59,20 @@ public void SystemGC1_Test()
/// 6. Verify that object has been collected
///
///
- // Tests ReRegisterForFinalize
- // Create a FinalizeObject.
+
+ OutputHelper.WriteLine("Tests ReRegisterForFinalize");
+ OutputHelper.WriteLine("Create a FinalizeObject.");
+
FinalizeObject mfo = new FinalizeObject();
m_hasFinalized1 = false;
m_hasFinalized2 = false;
// Release reference
+ OutputHelper.WriteLine("Release reference");
mfo = null;
- // Allow GC
- GC.WaitForPendingFinalizers();
+ OutputHelper.WriteLine("Allow GC");
+ GC.Collect();
int sleepTime = 1000;
int slept = 0;
@@ -85,10 +93,10 @@ public void SystemGC1_Test()
// FinalizeObject.m_currentInstance field. Setting this value
// to null and forcing another garbage collection will now
// cause the object to Finalize permanently.
- // Reregister and allow for GC
- FinalizeObject.m_currentInstance = null;
- GC.WaitForPendingFinalizers();
+ OutputHelper.WriteLine("Reregister and allow for GC");
+ FinalizeObject.m_currentInstance = null;
+ GC.Collect();
sleepTime = 1000;
slept = 0;
@@ -119,18 +127,19 @@ public void SystemGC2_Test()
/// 6. Verify that object has not been collected
///
///
- // Tests SuppressFinalize
- // Create a FinalizeObject.
+
+ OutputHelper.WriteLine("Tests SuppressFinalize");
+ OutputHelper.WriteLine("Create a FinalizeObject");
FinalizeObject mfo = new FinalizeObject();
m_hasFinalized1 = false;
m_hasFinalized2 = false;
- // Releasing
+ OutputHelper.WriteLine("Releasing");
GC.SuppressFinalize(mfo);
mfo = null;
- // Allow GC
- GC.WaitForPendingFinalizers();
+ OutputHelper.WriteLine("Allow GC");
+ GC.Collect();
int sleepTime = 1000;
int slept = 0;
@@ -138,7 +147,7 @@ public void SystemGC2_Test()
while (!m_hasFinalized1 && slept < sleepTime)
{
// force GC run caused by memory allocation
- var dummyArray = new byte[1024 * 1024 * 1];
+ _ = new byte[1024 * 1024 * 1];
System.Threading.Thread.Sleep(10);
slept += 10;
@@ -161,59 +170,35 @@ public void SystemGC3_Test()
///
///
- // Tests WaitForPendingFinalizers, dependant on test 1
- // will auto-fail if test 1 fails.
OutputHelper.Write("Tests WaitForPendingFinalizers, dependant on test 1");
- OutputHelper.WriteLine("will auto-fail if test 1 fails.");
+ OutputHelper.WriteLine("will fail if test 1 fails.");
- Assert.IsTrue(m_Test1Result);
+ Assert.IsTrue(m_Test1Result, "Can't run this test as SystemGC1_Test has failed.");
- // Create a FinalizeObject.
+ OutputHelper.WriteLine("Create a FinalizeObject");
FinalizeObject mfo = new FinalizeObject();
m_hasFinalized1 = false;
m_hasFinalized2 = false;
- // Releasing
+ OutputHelper.WriteLine("Releasing");
mfo = null;
- int sleepTime = 1000;
- int slept = 0;
-
- while (!m_hasFinalized1 && slept < sleepTime)
- {
- // force GC run caused by memory allocation
- var dummyArray = new byte[1024 * 1024 * 1];
-
- System.Threading.Thread.Sleep(10);
- slept += 10;
- }
-
- OutputHelper.WriteLine($"GC took {slept}");
-
- // Wait for GC
+ OutputHelper.WriteLine("Wait for GC");
+ GC.Collect();
GC.WaitForPendingFinalizers();
- // Releasing again
+ OutputHelper.WriteLine("Releasing again");
FinalizeObject.m_currentInstance = null;
- sleepTime = 1000;
- slept = 0;
-
- while (!m_hasFinalized2 && slept < sleepTime)
- {
- // force GC run caused by memory allocation
- var dummyArray = new byte[1024 * 1024 * 1];
-
- System.Threading.Thread.Sleep(10);
- slept += 10;
- }
-
- OutputHelper.WriteLine($"GC took {slept}");
-
- // Wait for GC
+ OutputHelper.WriteLine("Wait for GC");
+ GC.Collect();
GC.WaitForPendingFinalizers();
Assert.IsTrue(m_hasFinalized2);
}
}
+#pragma warning restore S1215 // "GC.Collect" should not be called
+#pragma warning restore S1854 // Unused assignments should be removed
+#pragma warning restore S2696 // Instance members should not write to "static" fields
+#pragma warning restore S3971 // "GC.SuppressFinalize" should not be called
}
diff --git a/Tests/NFUnitTestSystemLib/UnitTestInitLocalTests.cs b/Tests/NFUnitTestSystemLib/UnitTestInitLocalTests.cs
index fea53af7..a26039e7 100644
--- a/Tests/NFUnitTestSystemLib/UnitTestInitLocalTests.cs
+++ b/Tests/NFUnitTestSystemLib/UnitTestInitLocalTests.cs
@@ -49,6 +49,9 @@ public void SystemType1_GetType_Test()
// ConstructorInfo)
// NOTE: We add the reflection items to the ArrayList to assure that they can be properly
// assigned to a object container (this used to lead to a access violation)
+
+ OutputHelper.WriteLine("Testing Int32");
+
Type type = typeof(int);
list.Add(type);
string name = ((Type)list[i]).Name;
@@ -68,12 +71,16 @@ public void SystemType1_GetType_Test()
//fRes &= name.ToLower() == "mscorlib";
//i++;
+ OutputHelper.WriteLine("Testing NFUnitTestSystemLib.UnitTestInitLocalTests+TestObj");
+
type = Type.GetType("NFUnitTestSystemLib.UnitTestInitLocalTests+TestObj");
list.Add(type);
name = ((Type)list[i]).Name;
Assert.AreEqual(name, "TestObj");
i++;
+ OutputHelper.WriteLine("Testing IEmptyInterface");
+
Type iface = type.GetInterfaces()[0];
list.Add(iface);
name = ((Type)list[i]).Name;
@@ -81,6 +88,8 @@ public void SystemType1_GetType_Test()
Assert.AreEqual(iface.Name, "IEmptyInterface");
i++;
+ OutputHelper.WriteLine("Testing FieldInfo");
+
FieldInfo fi = type.GetField("Field1");
list.Add(fi);
name = ((FieldInfo)list[i]).Name;
@@ -88,6 +97,8 @@ public void SystemType1_GetType_Test()
Assert.AreEqual(fi.Name, "Field1");
i++;
+ OutputHelper.WriteLine("Testing MethodInfo");
+
MethodInfo mi = type.GetMethod("Method1");
list.Add(mi);
name = ((MethodInfo)list[i]).Name;
@@ -95,6 +106,8 @@ public void SystemType1_GetType_Test()
Assert.AreEqual(mi.Name, "Method1");
i++;
+ OutputHelper.WriteLine("Testing ConstructorInfo");
+
ConstructorInfo ci = type.GetConstructor(new Type[] { });
list.Add(ci);
name = ((ConstructorInfo)list[i]).Name;
@@ -104,7 +117,10 @@ public void SystemType1_GetType_Test()
//
// Now test arrays of reflection types
- //
+ //
+
+ OutputHelper.WriteLine("Testing Array of Type");
+
Type[] types = new Type[] { typeof(int), typeof(bool), Type.GetType("NFUnitTestSystemLib.UnitTestInitLocalTests+TestObj") };
list.Add(types[2]);
name = ((Type)list[i]).Name;
@@ -127,6 +143,8 @@ public void SystemType1_GetType_Test()
//fRes &= asms[0].GetName().Name == "Microsoft.SPOT.Platform.Tests.Systemlib2";
//i++;
+ OutputHelper.WriteLine("Testing Array of FieldInfo");
+
FieldInfo[] fis = new FieldInfo[] { types[2].GetField("Field1"), type.GetFields()[0] };
list.Add(fis[0]);
name = ((FieldInfo)list[i]).Name;
@@ -134,6 +152,8 @@ public void SystemType1_GetType_Test()
Assert.AreEqual(fis[0].Name, "Field1");
i++;
+ OutputHelper.WriteLine("Testing Array of MethodInfo");
+
MethodInfo[] mis = new MethodInfo[] { type.GetMethods()[2], types[2].GetMethod("Method2", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public) };
list.Add(mis[1]);
name = ((MethodInfo)list[i]).Name;
@@ -141,6 +161,8 @@ public void SystemType1_GetType_Test()
Assert.AreEqual(mis[1].Name, "Method2");
i++;
+ OutputHelper.WriteLine("Testing Array of ConstructorInfo");
+
ConstructorInfo[] cis = new ConstructorInfo[] { types[2].GetConstructor(new Type[] { }), typeof(TestObj).GetConstructor(new Type[] { typeof(int) }) };
list.Add(cis[0]);
name = ((ConstructorInfo)list[i]).Name;
@@ -148,6 +170,8 @@ public void SystemType1_GetType_Test()
Assert.AreEqual(cis[0].Name, ".ctor");
i++;
+ OutputHelper.WriteLine("Testing Array of System.Collections.ArrayList");
+
Array ar = Array.CreateInstance(typeof(Type), 3);
((IList)ar)[0] = typeof(Type);
((IList)ar)[1] = Type.GetType("System.Collections.ArrayList");
@@ -157,7 +181,6 @@ public void SystemType1_GetType_Test()
Assert.AreEqual(name, "ArrayList");
Assert.AreEqual(((Type)((IList)ar)[0]).Name, "Type");
Assert.AreEqual(((Type)ar.GetValue(1)).Name, "ArrayList");
- i++;
list.Clear();
}
@@ -192,14 +215,24 @@ public void SystemType1_ArrayListToArrayForStruct_Test()
// make sure boxing of struct value type (Guid) is handled properly
// this test was a result of a bug found by a customer.
Guid ret = new Guid();
+
ArrayList guidList = new ArrayList();
guidList.Add(Guid.NewGuid());
guidList.Add(Guid.NewGuid());
+
Guid[] guidArray = (Guid[])guidList.ToArray(typeof(Guid));
+ // Verify the array has the correct length
+ Assert.AreEqual(2, guidArray.Length);
+
+ // Verify each element is not empty and matches the source list
+ int i = 0;
foreach (Guid g in guidArray)
{
+ Assert.IsFalse(Guid.Empty.Equals(g), "Guid should not be empty");
+ Assert.AreEqual(guidList[i], g, "Guid should match the source ArrayList element");
ret = g;
+ i++;
}
}
diff --git a/Tests/NFUnitTestSystemLib/UnitTestNullable.cs b/Tests/NFUnitTestSystemLib/UnitTestNullable.cs
new file mode 100644
index 00000000..74a98741
--- /dev/null
+++ b/Tests/NFUnitTestSystemLib/UnitTestNullable.cs
@@ -0,0 +1,266 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using nanoFramework.TestFramework;
+
+namespace NFUnitTestSystemLib
+{
+ [TestClass]
+ public class UnitTestNullable
+ {
+ [TestMethod]
+ public void Ctor_Empty()
+ {
+ // Nullable and Nullable are mostly verbatim ports so we don't test much here.
+
+ int? n = default(int?);
+ Assert.IsFalse(n.HasValue);
+
+ // TODO replace with Assert.ThrowsException when available
+ Assert.ThrowsException(
+ typeof(InvalidOperationException),
+ () => _ = n.Value);
+ Assert.ThrowsException(
+ typeof(InvalidOperationException),
+ () => _ = (int)n);
+
+ Assert.IsNull(n);
+ Assert.AreNotEqual(7, n);
+ Assert.AreEqual(0, n.GetHashCode());
+ Assert.AreEqual("", n.ToString());
+ Assert.AreEqual(default(int), n.GetValueOrDefault());
+ Assert.AreEqual(999, n.GetValueOrDefault(999));
+
+ n = new int?(42);
+ Assert.IsTrue(n.HasValue);
+ Assert.AreEqual(42, n.Value);
+ Assert.AreEqual(42, (int)n);
+ Assert.IsNotNull(n);
+ Assert.AreNotEqual(7, n);
+ Assert.AreEqual(42, n);
+ Assert.AreEqual(42.GetHashCode(), n.GetHashCode());
+ Assert.AreEqual(42.ToString(), n.ToString());
+ Assert.AreEqual(42, n.GetValueOrDefault());
+ Assert.AreEqual(42, n.GetValueOrDefault(999));
+
+ n = 88;
+ Assert.IsTrue(n.HasValue);
+ Assert.AreEqual(88, n.Value);
+ }
+
+ [TestMethod]
+ public static void Boxing()
+ {
+ int? n = new int?(42);
+ Unbox(n);
+ }
+
+ private static void Unbox(object o)
+ {
+ Type t = o.GetType();
+
+ // TOOD: replace with Assert.IsNotType(t); when available
+ Assert.IsNotInstanceOfType(typeof(int?), t);
+
+ Assert.AreEqual(typeof(int), t);
+ }
+
+ [TestMethod]
+ public static void ExplicitCast_T()
+ {
+ int? nullable = 5;
+ int value = (int)nullable;
+ Assert.AreEqual(5, value);
+
+ nullable = null;
+ // TODO replace with Assert.Throws(() => (int)nullable); when available
+ Assert.ThrowsException(
+ typeof(InvalidOperationException),
+ () => _ = (int)nullable);
+ }
+
+ [TestMethod]
+ public static void GetUnderlyingType()
+ {
+ Assert.AreEqual(typeof(int), Nullable.GetUnderlyingType(typeof(int?)));
+ Assert.AreEqual(null, Nullable.GetUnderlyingType(typeof(int)));
+ Assert.AreEqual(null, Nullable.GetUnderlyingType(typeof(G)));
+ }
+
+ [TestMethod]
+ public static void GetUnderlyingType_NullType_ThrowsArgumentNullException()
+ {
+ // TODO replace with Assert.Throws("nullableType", () => Nullable.GetUnderlyingType(null)); when available
+ Assert.ThrowsException(
+ typeof(ArgumentNullException),
+ () => Nullable.GetUnderlyingType(null)
+ );
+ }
+
+ // TODO: Uncomment when available
+ //[TestMethod]
+ //public static void GetValueRefOrDefaultRef_WithValue()
+ //{
+ // static void Test(T before, T after)
+ // where T : struct
+ // {
+ // T? nullable = before;
+ // ref readonly T reference = ref Nullable.GetValueRefOrDefaultRef(in nullable);
+
+ // Assert.AreEqual(before, nullable!.Value);
+
+ // Unsafe.AsRef(in reference) = after;
+
+ // Assert.Equal(after, nullable.Value);
+ // }
+
+ // Test((byte)0, (byte)42);
+ // Test(0, 42);
+ // Test(1.3f, 3.14f);
+ // Test(0.555, 8.49);
+ // Test(Guid.NewGuid(), Guid.NewGuid());
+ //}
+
+ // TODO: Uncomment when available
+ //[TestMethod]
+ //public static void GetValueRefOrDefaultRef_WithDefault()
+ //{
+ // static void Test()
+ // where T : struct
+ // {
+ // T? nullable = null;
+ // ref readonly T reference = ref Nullable.GetValueRefOrDefaultRef(in nullable);
+
+ // Assert.Equal(nullable!.GetValueOrDefault(), reference);
+ // }
+
+ // Test();
+ // Test();
+ // Test();
+ // Test();
+ // Test();
+ //}
+
+ // TODO: Uncomment when available
+ //[TestMethod]
+ //public static void GetValueRefOrDefaultRef_UnsafeWriteToNullMaintainsExpectedBehavior()
+ //{
+ // static void Test(T after)
+ // where T : struct
+ // {
+ // T? nullable = null;
+ // ref readonly T reference = ref Nullable.GetValueRefOrDefaultRef(in nullable);
+
+ // Unsafe.AsRef(in reference) = after;
+
+ // Assert.Equal(after, nullable.GetValueOrDefault()); // GetValueOrDefault() unconditionally returns the field
+ // Assert.False(nullable.HasValue);
+ // Assert.Equal(0, nullable.GetHashCode()); // GetHashCode() returns 0 if HasValue is false, without reading the field
+ // Assert.Throws(() => nullable.Value); // Accessing the value should still throw despite the write
+ // Assert.Throws(() => (T)nullable);
+ // }
+
+ // Test((byte)42);
+ // Test(42);
+ // Test(3.14f);
+ // Test(8.49);
+ // Test(Guid.NewGuid());
+ //}
+
+ [TestMethod]
+ public static void Compare_Equals()
+ {
+ // Case 1: (null, null, 0)
+ int? n1 = null;
+ int? n2 = null;
+ int expected = 0;
+ Assert.AreEqual(expected == 0, Nullable.Equals(n1, n2));
+ Assert.AreEqual(expected == 0, n1.Equals(n2));
+ // TODO Assert.AreEqual(expected, Nullable.Compare(n1, n2));
+
+ // Case 2: (7, null, 1)
+ n1 = 7;
+ n2 = null;
+ expected = 1;
+ Assert.AreEqual(expected == 0, Nullable.Equals(n1, n2));
+ Assert.AreEqual(expected == 0, n1.Equals(n2));
+ // TODO Assert.AreEqual(expected, Nullable.Compare(n1, n2));
+
+ // Case 3: (null, 7, -1)
+ n1 = null;
+ n2 = 7;
+ expected = -1;
+ Assert.AreEqual(expected == 0, Nullable.Equals(n1, n2));
+ Assert.AreEqual(expected == 0, n1.Equals(n2));
+ // TODO Assert.AreEqual(expected, Nullable.Compare(n1, n2));
+
+ // Case 4: (7, 7, 0)
+ n1 = 7;
+ n2 = 7;
+ expected = 0;
+ Assert.AreEqual(expected == 0, Nullable.Equals(n1, n2));
+ Assert.AreEqual(expected == 0, n1.Equals(n2));
+ // TODO Assert.AreEqual(expected, Nullable.Compare(n1, n2));
+
+ // Case 5: (7, 5, 1)
+ n1 = 7;
+ n2 = 5;
+ expected = 1;
+ Assert.AreEqual(expected == 0, Nullable.Equals(n1, n2));
+ Assert.AreEqual(expected == 0, n1.Equals(n2));
+ // TODO Assert.AreEqual(expected, Nullable.Compare(n1, n2));
+
+ // Case 6: (5, 7, -1)
+ n1 = 5;
+ n2 = 7;
+ expected = -1;
+ Assert.AreEqual(expected == 0, Nullable.Equals(n1, n2));
+ Assert.AreEqual(expected == 0, n1.Equals(n2));
+ // TODO Assert.AreEqual(expected, Nullable.Compare(n1, n2));
+ }
+
+ //[TestMethod]
+ //public static void MutatingMethods_MutationsAffectOriginal()
+ //{
+ // MutatingStruct? ms = new MutatingStruct() { Value = 1 };
+
+ // for (int i = 1; i <= 2; i++)
+ // {
+ // Assert.AreEqual(i.ToString(), ms.Value.ToString());
+ // Assert.AreEqual(i, ms.Value.Value);
+
+ // Assert.AreEqual(i.ToString(), ms.ToString());
+ // Assert.AreEqual(i + 1, ms.Value.Value);
+ // }
+
+ // for (int i = 3; i <= 4; i++)
+ // {
+ // Assert.AreEqual(i, ms.Value.GetHashCode());
+ // Assert.AreEqual(i, ms.Value.Value);
+
+ // Assert.AreEqual(i, ms.GetHashCode());
+ // Assert.AreEqual(i + 1, ms.Value.Value);
+ // }
+
+ // for (int i = 5; i <= 6; i++)
+ // {
+ // ms.Value.Equals(new object());
+ // Assert.AreEqual(i, ms.Value.Value);
+
+ // ms.Equals(new object());
+ // Assert.AreEqual(i + 1, ms.Value.Value);
+ // }
+ //}
+
+ //private struct MutatingStruct
+ //{
+ // public int Value;
+ // public override string ToString() => Value++.ToString();
+ // public override bool Equals(object obj) => Value++.Equals(null);
+ // public override int GetHashCode() => Value++.GetHashCode();
+ //}
+
+ public class G { }
+ }
+}
diff --git a/Tests/NFUnitTestSystemLib/UnitTestReflectionTypeTest.cs b/Tests/NFUnitTestSystemLib/UnitTestReflectionTypeTest.cs
index 709f2122..805c2b93 100644
--- a/Tests/NFUnitTestSystemLib/UnitTestReflectionTypeTest.cs
+++ b/Tests/NFUnitTestSystemLib/UnitTestReflectionTypeTest.cs
@@ -5,6 +5,7 @@
using System.Collections;
using System.Reflection;
using nanoFramework.TestFramework;
+using static NFUnitTestSystemLib.UnitTestNullable;
namespace NFUnitTestSystemLib
{
@@ -52,85 +53,103 @@ public void SystemReflectionType_RuntimeType_Test1()
///
TestClass cls = new TestClass();
+ OutputHelper.WriteLine("Testing Type members for a class type");
+
// Test Type members for a class type
Type t = cls.GetType();
Assembly asm = t.Assembly;
list.Add(asm);
- Assert.AreEqual(((Assembly)list[i]).GetName().Name, "NFUnitTest");
- Assert.AreEqual(asm.GetName().Name, "NFUnitTest");
- Assert.AreEqual(t.Name, "TestClass");
- Assert.AreEqual(t.FullName, "NFUnitTestSystemLib.UnitTestReflectionTypeTest+TestClass");
+ Assert.AreEqual("NFUnitTest", ((Assembly)list[i]).GetName().Name);
+ Assert.AreEqual("NFUnitTest", asm.GetName().Name);
+ Assert.AreEqual("TestClass", t.Name);
+ Assert.AreEqual("NFUnitTestSystemLib.UnitTestReflectionTypeTest+TestClass", t.FullName);
Assert.IsInstanceOfType(t.BaseType, typeof(object));
Assert.IsNull(t.GetElementType());
+ OutputHelper.WriteLine("Testing methods of class type");
+
MethodInfo[] mis = t.GetMethods();
- Assert.AreEqual(mis[0].Name, "Method1");
+ Assert.AreEqual("Method1", mis[0].Name);
mis = t.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic);
- Assert.AreEqual(mis[0].Name, "Method2");
+ Assert.AreEqual("Method2", mis[0].Name);
Assert.IsNotNull(t.GetMethod("Method1"));
Assert.IsNotNull(t.GetMethod("Method2", BindingFlags.Instance | BindingFlags.NonPublic));
+ OutputHelper.WriteLine("Testing fields of class type");
+
FieldInfo[] fis = t.GetFields();
- Assert.AreEqual(fis[0].Name, "m_Field1");
+ Assert.AreEqual("m_Field1", fis[0].Name);
fis = t.GetFields(BindingFlags.Instance | BindingFlags.NonPublic);
- Assert.AreEqual(fis[0].Name, "m_Field2");
+ Assert.AreEqual("m_Field2", fis[0].Name);
Assert.IsNotNull(t.GetField("m_Field1"));
Assert.IsNotNull(t.GetField("m_Field2", BindingFlags.NonPublic | BindingFlags.Instance));
Assert.IsNotNull(t.GetConstructor(new Type[] { }));
+ OutputHelper.WriteLine("Testing interfaces of class type");
+
Type[] ifaces = t.GetInterfaces();
- Assert.AreEqual(ifaces.Length, 2);
- Assert.AreEqual(ifaces[0].Name, "IInterface1");
- Assert.AreEqual(ifaces[1].Name, "IInterface2");
+ Assert.AreEqual(2, ifaces.Length);
+ Assert.AreEqual("IInterface1", ifaces[0].Name);
+ Assert.AreEqual("IInterface2", ifaces[1].Name);
Assert.IsTrue(t.IsSubclassOf(typeof(object)));
i++;
+ OutputHelper.WriteLine("Testing Type members for a struct valuetype");
+
// test Type members for a struct valuetype
TestStruct str = new TestStruct();
t = str.GetType();
asm = t.Assembly;
list.Add(asm);
- Assert.AreEqual(((Assembly)list[i]).GetName().Name, "NFUnitTest");
- Assert.AreEqual(asm.GetName().Name, "NFUnitTest");
- Assert.AreEqual(t.Name, "TestStruct");
- Assert.AreEqual(t.FullName, "NFUnitTestSystemLib.UnitTestReflectionTypeTest+TestStruct");
+ Assert.AreEqual("NFUnitTest", ((Assembly)list[i]).GetName().Name);
+ Assert.AreEqual("NFUnitTest", asm.GetName().Name);
+ Assert.AreEqual("TestStruct", t.Name);
+ Assert.AreEqual("NFUnitTestSystemLib.UnitTestReflectionTypeTest+TestStruct", t.FullName);
Assert.IsInstanceOfType(t.BaseType, typeof(ValueType));
- Assert.AreEqual(t.GetInterfaces().Length, 0);
+ Assert.AreEqual(0, t.GetInterfaces().Length);
Assert.IsNull(t.GetElementType());
i++;
+ OutputHelper.WriteLine("Testing Type members for an Assembly reflection type");
+
// test Type members for an Assembly reflection type
//Assembly asmObj = typeof(TestClass).Assembly;
//t = asmObj.GetType();
//asm = t.Assembly;
//list.Add(asm);
- //Assert.AreEqual(((Assembly)list[i]).GetName().Name, "mscorlib");
- //Assert.AreEqual(asm.GetName().Name, "mscorlib");
- //Assert.AreEqual(t.Name, "Assembly");
- //Assert.AreEqual(t.FullName, "System.Reflection.Assembly");
+ //Assert.AreEqual("mscorlib", ((Assembly)list[i]).GetName().Name);
+ //Assert.AreEqual("mscorlib", asm.GetName().Name);
+ //Assert.AreEqual("Assembly", t.Name);
+ //Assert.AreEqual("System.Reflection.Assembly", t.FullName);
//Assert.IsInstanceOfType(t.BaseType, typeof(Object));
- //Assert.AreEqual(t.GetInterfaces().Length, 0);
+ //Assert.AreEqual(0, t.GetInterfaces().Length);
//Assert.IsNull(t.GetElementType());
+ OutputHelper.WriteLine("Testing Type members for a MethodInfo reflection type");
+
mis = typeof(TestClass).GetMethods(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
t = mis.GetType();
- Assert.AreEqual(t.Name, "RuntimeMethodInfo[]");
- Assert.AreEqual(t.FullName, "System.Reflection.RuntimeMethodInfo[]");
+ Assert.AreEqual("RuntimeMethodInfo[]", t.Name);
+ Assert.AreEqual("System.Reflection.RuntimeMethodInfo[]", t.FullName);
Assert.IsInstanceOfType(t.BaseType, typeof(Array));
Assert.IsTrue(t.GetInterfaces().Length > 0);
- Assert.AreEqual(t.GetElementType().Name, "RuntimeMethodInfo");
+ Assert.AreEqual("RuntimeMethodInfo", t.GetElementType().Name);
+
+ OutputHelper.WriteLine("Testing Type members for a delegate");
// test Type members for a delegate
Delegate del = new MyDelegate(MyDelegateImpl);
t = del.GetType();
Assert.IsNotNull(t.DeclaringType);
- Assert.AreEqual(t.Name, "MyDelegate");
+ Assert.AreEqual("MyDelegate", t.Name);
Assert.IsInstanceOfType(t.BaseType, typeof(MulticastDelegate));
+ OutputHelper.WriteLine("Testing Type members for an enum");
+
// test Type members for an enum
TestEnum en = TestEnum.Item1;
t = en.GetType();
- Assert.IsInstanceOfType(t.DeclaringType, typeof(UnitTestReflectionTypeTest));
+ Assert.IsInstanceOfType(typeof(UnitTestReflectionTypeTest), t.DeclaringType);
Assert.IsTrue(t.IsEnum);
Assert.IsFalse(t.IsAbstract);
Assert.IsFalse(t.IsClass);
@@ -145,10 +164,11 @@ public void SystemReflectionType_SystemType_Test2()
Assert.IsTrue(typeof(Array).IsInstanceOfType(blah));
Assert.IsTrue(typeof(TestStruct[]).IsArray);
+ Assert.IsTrue(typeof(G[]).IsArray);
Assert.IsFalse(typeof(Array).IsValueType);
Assert.IsTrue(typeof(TestStruct).IsValueType);
Assert.IsTrue(typeof(Type).IsSubclassOf(typeof(MemberInfo)));
- Assert.AreEqual(typeof(Type).GetInterfaces()[0].Name, "IReflect");
+ Assert.AreEqual("IReflect", typeof(Type).GetInterfaces()[0].Name);
Assert.IsTrue(typeof(MyDelegate).IsInstanceOfType(new MyDelegate(MyDelegateImpl)));
// Get known type from assembly qualified type name Culture and PublicKeyToken are used by debugger to identify types
diff --git a/Tests/NFUnitTestTypes/NFUnitTestTypes.nfproj b/Tests/NFUnitTestTypes/NFUnitTestTypes.nfproj
index 7ede25bb..4b9ae628 100644
--- a/Tests/NFUnitTestTypes/NFUnitTestTypes.nfproj
+++ b/Tests/NFUnitTestTypes/NFUnitTestTypes.nfproj
@@ -24,6 +24,7 @@
+
@@ -47,4 +48,4 @@
-
+
\ No newline at end of file
diff --git a/Tests/NFUnitTestTypes/UnitTestGuid.cs b/Tests/NFUnitTestTypes/UnitTestGuid.cs
new file mode 100644
index 00000000..886207cb
--- /dev/null
+++ b/Tests/NFUnitTestTypes/UnitTestGuid.cs
@@ -0,0 +1,140 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using nanoFramework.TestFramework;
+
+namespace NFUnitTestTypes
+{
+ [TestClass]
+ class UnitTestGuid
+ {
+ [TestMethod]
+ public void Guid_Compare_To_Empty()
+ {
+ var empty = Guid.Empty;
+ var notEmpty = Guid.NewGuid();
+ Assert.IsFalse(empty == notEmpty);
+ }
+
+ [TestMethod]
+ public void Guid_Empty_IsAllZeros()
+ {
+ var empty = Guid.Empty;
+ var bytes = empty.ToByteArray();
+ foreach (var b in bytes)
+ {
+ Assert.AreEqual((byte)0, b);
+ }
+ }
+
+ [TestMethod]
+ public void Guid_Constructor_ByteArray_RoundTrip()
+ {
+ var original = Guid.NewGuid();
+ var bytes = original.ToByteArray();
+ var roundTrip = new Guid(bytes);
+ Assert.AreEqual(original, roundTrip);
+ }
+
+ [TestMethod]
+ public void Guid_Equals_And_Operator()
+ {
+ var g1 = Guid.NewGuid();
+ var g2 = new Guid(g1.ToByteArray());
+ Assert.IsTrue(g1.Equals(g2));
+ Assert.IsTrue(g1 == g2);
+ Assert.IsFalse(g1 != g2);
+ }
+
+ [TestMethod]
+ public void Guid_NotEquals_And_Operator()
+ {
+ var g1 = Guid.NewGuid();
+ var g2 = Guid.NewGuid();
+ Assert.IsFalse(g1.Equals(g2));
+ Assert.IsFalse(g1 == g2);
+ Assert.IsTrue(g1 != g2);
+ }
+
+ [TestMethod]
+ public void Guid_ToString_And_Parse()
+ {
+ var g1 = Guid.NewGuid();
+ var str = g1.ToString();
+ var g2 = new Guid(str);
+ Assert.AreEqual(g1, g2);
+ }
+
+ [TestMethod]
+ public void Guid_GetHashCode_Consistent()
+ {
+ var g1 = Guid.NewGuid();
+ var g2 = new Guid(g1.ToByteArray());
+ Assert.AreEqual(g1.GetHashCode(), g2.GetHashCode());
+ }
+
+ [TestMethod]
+ public void Guid_CompareTo_Object_And_Self()
+ {
+ var g1 = Guid.NewGuid();
+ var g2 = new Guid(g1.ToByteArray());
+ Assert.AreEqual(0, g1.CompareTo(g2));
+ Assert.AreEqual(0, g1.CompareTo((object)g2));
+ Assert.AreEqual(1, g1.CompareTo(null));
+ }
+
+ [TestMethod]
+ public void Guid_CompareTo_InvalidType_Throws()
+ {
+ var g1 = Guid.NewGuid();
+ Assert.ThrowsException(typeof(ArgumentException), () =>
+ {
+ g1.CompareTo("not a guid");
+ });
+ }
+
+ [TestMethod]
+ public void Guid_TryParseGuidWithDashes_Valid()
+ {
+ var g1 = Guid.NewGuid();
+ var str = g1.ToString();
+ bool parsed = Guid.TryParse(str, out var g2);
+ Assert.IsTrue(parsed);
+ Assert.AreEqual(g1, g2);
+ }
+
+ [TestMethod]
+ public void Guid_TryParseGuidWithDashes_Invalid()
+ {
+ bool parsed = Guid.TryParse("invalid-guid", out var g2);
+ Assert.IsFalse(parsed);
+ Assert.AreEqual(Guid.Empty, g2);
+ }
+
+ [TestMethod]
+ public void Guid_Constructor_String_WithBraces()
+ {
+ var g1 = Guid.NewGuid();
+ var str = "{" + g1.ToString() + "}";
+ var g2 = new Guid(str);
+ Assert.AreEqual(g1, g2);
+ }
+
+ [TestMethod]
+ public void Guid_Constructor_String_Invalid_Throws()
+ {
+ Assert.ThrowsException(typeof(ArgumentException), () =>
+ {
+ var g = new Guid("invalid-guid");
+ });
+ }
+
+ [TestMethod]
+ public void Guid_GetHashCode_Empty()
+ {
+ var empty = Guid.Empty;
+ Assert.AreEqual(0, empty.GetHashCode());
+ }
+ }
+}
diff --git a/Tests/NFUnitTestTypes/UnitTestsSpanByte.cs b/Tests/NFUnitTestTypes/UnitTestsSpanByte.cs
index e4ffde13..9ed5dec8 100644
--- a/Tests/NFUnitTestTypes/UnitTestsSpanByte.cs
+++ b/Tests/NFUnitTestTypes/UnitTestsSpanByte.cs
@@ -13,13 +13,15 @@ public class UnitTestsSpanByte
public void EmptySpanTests()
{
// Empty span
- SpanByte span = SpanByte.Empty;
+ Span span = Span.Empty;
// Create a destination span larger
- SpanByte destination = new byte[1];
+ Span destination = new Span(new byte[1]);
+
span.CopyTo(destination);
// Now also empty
- destination = SpanByte.Empty;
+ destination = Span.Empty;
+
span.CopyTo(destination);
}
@@ -27,54 +29,56 @@ public void EmptySpanTests()
public void RaisingExceptionsOfAllKindsTests()
{
// Should raise an exception on creation
- Assert.ThrowsException(typeof(ArgumentOutOfRangeException), () => { SpanByte span = new SpanByte(null, 1, 2); }, "ArgumentOutOfRangeException when array is null, start is 1 and length is 2");
- Assert.ThrowsException(typeof(ArgumentOutOfRangeException), () => { SpanByte span = new SpanByte(new byte[1], 1, 2); }, "ArgumentOutOfRangeException when array is new byte[1], start is 1 and length is 2");
- Assert.ThrowsException(typeof(ArgumentOutOfRangeException), () => { SpanByte span = new SpanByte(new byte[1], 0, 2); }, "ArgumentOutOfRangeException when array is new byte[1], start is 0 and length is 2");
- Assert.ThrowsException(typeof(ArgumentOutOfRangeException), () => { SpanByte span = new SpanByte(new byte[1], 2, 0); }, "ArgumentOutOfRangeException when array is new byte[1], start is 2 and length is 0");
+ Assert.ThrowsException(typeof(ArgumentOutOfRangeException), () => { Span span = new Span(null, 1, 2); }, "ArgumentOutOfRangeException when array is null, start is 1 and length is 2");
+ Assert.ThrowsException(typeof(ArgumentOutOfRangeException), () => { Span span = new Span(new byte[1], 1, 2); }, "ArgumentOutOfRangeException when array is new byte[1], start is 1 and length is 2");
+ Assert.ThrowsException(typeof(ArgumentOutOfRangeException), () => { Span span = new Span(new byte[1], 0, 2); }, "ArgumentOutOfRangeException when array is new byte[1], start is 0 and length is 2");
+ Assert.ThrowsException(typeof(ArgumentOutOfRangeException), () => { Span span = new Span(new byte[1], 2, 0); }, "ArgumentOutOfRangeException when array is new byte[1], start is 2 and length is 0");
// Exception on index access
byte[] array = new byte[16] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F };
Assert.ThrowsException(typeof(ArgumentOutOfRangeException), () =>
{
- SpanByte span = new SpanByte(array);
- var data = span[span.Length];
+ Span span = new Span(array);
+ _ = span[span.Length];
});
- Assert.ThrowsException(typeof(IndexOutOfRangeException), () =>
+
+ Assert.ThrowsException(typeof(ArgumentOutOfRangeException), () =>
{
- SpanByte span = new SpanByte(array);
- var data = span[-1];
+ Span span = new Span(array);
+ _ = span[-1];
});
// Copy to with too small destination
Assert.ThrowsException(typeof(ArgumentException), () =>
{
- SpanByte span = new SpanByte(array);
- SpanByte destination = new byte[span.Length - 1];
+ Span span = new Span(array);
+ Span destination = new Span(new byte[span.Length - 1]);
+
span.CopyTo(destination);
});
// Slicing arguments
Assert.ThrowsException(typeof(ArgumentOutOfRangeException), () =>
{
- SpanByte span = new SpanByte(array);
- var sliced = span.Slice(span.Length + 1);
+ Span span = new Span(array);
+ _ = span.Slice(span.Length + 1);
});
Assert.ThrowsException(typeof(ArgumentOutOfRangeException), () =>
{
- SpanByte span = new SpanByte(array);
- var sliced = span.Slice(1, span.Length);
+ Span span = new Span(array);
+ _ = span.Slice(1, span.Length);
});
Assert.ThrowsException(typeof(ArgumentOutOfRangeException), () =>
{
- SpanByte span = new SpanByte(array);
- var sliced = span.Slice(-1, span.Length);
+ Span span = new Span(array);
+ _ = span.Slice(-1, span.Length);
});
Assert.ThrowsException(typeof(ArgumentOutOfRangeException), () =>
{
- SpanByte span = new SpanByte(array);
- var sliced = span.Slice(1, -1);
+ Span span = new Span(array);
+ _ = span.Slice(1, -1);
});
}
@@ -84,7 +88,7 @@ public void ToArrayTest()
{
byte[] array = new byte[16] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F };
- SpanByte span = new(array);
+ Span span = new(array);
byte[] toArray = span.ToArray();
@@ -95,28 +99,33 @@ public void ToArrayTest()
public void ConstructorsOfAllKindsTests()
{
// Empty span
- SpanByte span = new SpanByte();
+ Span span = new Span();
+
Assert.AreEqual(span.Length, 0, "Empty SpanByte should have length of 0");
Assert.IsTrue(span.IsEmpty, "Empty SpanByte should be IsEmpty");
// Empty span
- span = new SpanByte(null, 0, 0);
+ span = new Span(null, 0, 0);
+
Assert.AreEqual(span.Length, 0, "Empty SpanByte should have length of 0");
Assert.IsTrue(span.IsEmpty, "Empty SpanByte should be IsEmpty");
// Empty span
- span = SpanByte.Empty;
+ span = Span.Empty;
+
Assert.AreEqual(span.Length, 0, "Empty SpanByte should have length of 0");
Assert.IsTrue(span.IsEmpty, "Empty SpanByte should be IsEmpty");
- // Span from normal array
+ // Spanfrom normal array
byte[] array = new byte[16] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F };
- span = new SpanByte(array);
+ span = new Span(array);
+
Assert.AreEqual(span.Length, array.Length, $"SpanByte should have length of the array it takes: {array.Length}");
Assert.IsFalse(span.IsEmpty, "SpanByte should NOT be IsEmpty");
- // Span from normal array with different start and length
- span = new SpanByte(array, 2, 8);
+ // Spanfrom normal array with different start and length
+ span = new Span(array, 2, 8);
+
Assert.AreEqual(span.Length, 8, $"SpanByte should have length of 8");
Assert.IsFalse(span.IsEmpty, "SpanByte should NOT be IsEmpty");
}
@@ -124,17 +133,20 @@ public void ConstructorsOfAllKindsTests()
[TestMethod]
public void SliceTests()
{
- // Span from normal array
+ // Spanfrom normal array
byte[] array = new byte[16] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F };
- SpanByte span = new SpanByte(array);
+ Span span = new Span(array);
+
// Slice 2 elements and check
- var sliced = span.Slice(0, 2);
+ Span sliced = span.Slice(0, 2);
+
Assert.AreEqual(sliced.Length, 2, "Sliced span lenght must be 2");
Assert.AreEqual(sliced[0], (byte)0x00, "Sliced first element must be value 0");
Assert.AreEqual(sliced[1], (byte)0x01, "Sliced first element must be value 1");
// Slide 4 elements starting at index 2 and check
sliced = span.Slice(2, 4);
+
Assert.AreEqual(sliced.Length, 4, "Sliced span lenght must be 4");
Assert.AreEqual(sliced[0], (byte)0x02, "Sliced first element must be value 2");
Assert.AreEqual(sliced[1], (byte)0x03, "Sliced first element must be value 3");
@@ -143,22 +155,27 @@ public void SliceTests()
// Slide starting 4 at element check
sliced = span.Slice(4);
+
Assert.AreEqual(sliced.Length, 12, "Sliced span lenght must be 12");
+
for (int i = 0; i < sliced.Length; i++)
{
Assert.AreEqual(sliced[i], span[i + 4], "SpanByte value should be the same as from the original span");
}
// Slice of slice
- var secondSliced = sliced.Slice(2, 4);
+ Span secondSliced = sliced.Slice(2, 4);
+
Assert.AreEqual(secondSliced.Length, 4, "Sliced span lenght must be 12");
+
for (int i = 0; i < secondSliced.Length; i++)
{
Assert.AreEqual(secondSliced[i], sliced[i + 2], "SpanByte value should be the same as from the original span");
}
// Should be an empty one
- var empty = span.Slice(span.Length);
+ Span empty = span.Slice(span.Length);
+
Assert.AreEqual(empty.Length, 0, "slicing all the span should result in an empty span");
Assert.IsTrue(empty.IsEmpty, "Empty span should be empty");
}
@@ -167,39 +184,42 @@ public void SliceTests()
public void CopyToTests()
{
byte[] array = new byte[16] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F };
- SpanByte span = new SpanByte(array);
+ Span span = new Span(array);
+
// First a copy to with the full span
- SpanByte toCopy = new byte[span.Length];
+ Span toCopy = new Span(new byte[span.Length]);
+
span.CopyTo(toCopy);
- for (int i = 0; i < span.Length; i++)
- {
- Assert.AreEqual(toCopy[i], span[i], "SpanByte value should be the same as from the original array");
- }
+
+ CollectionAssert.AreEqual(array, toCopy.ToArray(), "Original array and SpanByte.CopyTo should be the same");
// Now create a larger span
- toCopy = new byte[span.Length + 1];
+ toCopy = new Span(new byte[span.Length + 1]);
span.CopyTo(toCopy);
- for (int i = 0; i < span.Length; i++)
- {
- Assert.AreEqual(toCopy[i], span[i], "SpanByte value should be the same as from the original array");
- }
- Assert.AreEqual(toCopy[span.Length], (byte)0);
+ Assert.AreEqual(toCopy.Length, span.Length + 1);
+
+ byte[] tempArray = new byte[span.Length + 1];
+ Array.Copy(array, tempArray, array.Length);
+
+ CollectionAssert.AreEqual(tempArray, toCopy.ToArray(), "Original array and SpanByte.CopyTo should be the same with larger destination");
+
+ Assert.AreEqual(toCopy[toCopy.Length - 1], (byte)0, "Last byte should be 0 (byte default)");
}
[TestMethod]
public void GetElementsTests()
{
- // Span from normal array
+ // Spanfrom normal array
byte[] array = new byte[16] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F };
- SpanByte span = new SpanByte(array);
+ Span span = new Span(array);
for (int i = 0; i < span.Length; i++)
{
Assert.AreEqual(span[i], array[i], "SpanByte value should be the same as from the original array");
}
// Partial span
- span = new SpanByte(array, 2, 8);
+ span = new Span(array, 2, 8);
for (int i = 0; i < span.Length; i++)
{
Assert.AreEqual(span[i], array[i + 2], "SpanByte value should be the same as from the original array");
@@ -210,11 +230,13 @@ public void GetElementsTests()
public void SetElementsTests()
{
// Create a span, and set the data
- SpanByte span = new byte[12];
+ Span span = new Span(new byte[12]);
+
// All should be 0
for (int i = 0; i < span.Length; i++)
{
Assert.AreEqual(span[i], (byte)0, "SpanByte value should be 0");
+
// Set a value
span[i] = (byte)i;
}
diff --git a/Tests/UnitTestLauncher/UnitTestLauncher.nfproj b/Tests/UnitTestLauncher/UnitTestLauncher.nfproj
index b03d676e..646eace2 100644
--- a/Tests/UnitTestLauncher/UnitTestLauncher.nfproj
+++ b/Tests/UnitTestLauncher/UnitTestLauncher.nfproj
@@ -27,7 +27,7 @@
-
+
diff --git a/azure-pipelines-templates/check-nf-interpreter-to-test.yml b/azure-pipelines-templates/check-nf-interpreter-to-test.yml
new file mode 100644
index 00000000..3f1eabcc
--- /dev/null
+++ b/azure-pipelines-templates/check-nf-interpreter-to-test.yml
@@ -0,0 +1,71 @@
+# Copyright (c) .NET Foundation and Contributors
+# See LICENSE file in the project root for full license information.
+
+steps:
+ - task: PowerShell@2
+ displayName: Check nf-interpreter to test
+ condition: ne(variables['System.PullRequest.PullRequestNumber'], '')
+ inputs:
+ failOnStderr: false
+ targetType: "inline"
+ script: |
+
+ # prepare GitHub API headers using token auth
+ $headers = @{
+ Authorization = "token $env:GITHUB_TOKEN"
+ 'User-Agent' = 'azure-pipelines'
+ Accept = 'application/vnd.github+json'
+ }
+
+ # find PR
+ "Getting PR #$env:System_PullRequest_PullRequestNumber details..." | Write-Host -ForegroundColor White -NoNewline
+ $pr = Invoke-RestMethod `
+ -Uri "https://api.github.com/repos/$env:Build_Repository_Name/pulls/$env:System_PullRequest_PullRequestNumber" `
+ -Headers $headers `
+ -Method GET
+
+ if($($pr.number) -eq "$env:System_PullRequest_PullRequestNumber")
+ {
+ 'OK' | Write-Host -ForegroundColor Green
+ }
+
+ # grab PR commit message
+ $prCommitMessage = $($pr.body)
+
+ # look for test prompt in PR commit message
+ # pattern is "[tested against nanoclr buildId NNN]"
+
+ if($prCommitMessage -match "\[tested against nanoclr buildId (\d+)\]")
+ {
+ $buildId = $matches[1]
+ "AZDO build ID found: $buildId" | Write-Host -ForegroundColor White
+
+ echo "##vso[task.setvariable variable=NFINTERPRETER_BUILDID]$buildId"
+ }
+ else
+ {
+ "No build ID found" | Write-Host -ForegroundColor Red
+ }
+ env:
+ GITHUB_TOKEN: $(GitHubToken)
+
+ - task: DownloadPipelineArtifact@2
+ condition: ne(variables['NFINTERPRETER_BUILDID'], '')
+ displayName: Download nanoCLR preview
+ inputs:
+ buildType: specific
+ project: 'nf-interpreter'
+ definition: '34'
+ buildVersionToDownload: specific
+ allowFailedBuilds: true
+ buildId: $(NFINTERPRETER_BUILDID)
+ artifactName: 'nanoclr_cli'
+ targetPath: '$(Pipeline.Workspace)/nanoclr'
+
+ - task: PowerShell@2
+ condition: ne(variables['NFINTERPRETER_BUILDID'], '')
+ displayName: Set nanoCLR preview path
+ inputs:
+ targetType: 'inline'
+ script: |
+ Write-Host "##vso[task.setvariable variable=NF_MDP_NANOCLR_INSTANCE_PATH]$(Pipeline.Workspace)/nanoclr/nanoFramework.nanoCLR.dll"
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
index 552271dd..e24c2aac 100644
--- a/azure-pipelines.yml
+++ b/azure-pipelines.yml
@@ -20,10 +20,6 @@ trigger:
- assets/*
- nanoFramework.TestFramework/*
- tags:
- include:
- - v*
-
# PR always trigger build
pr:
autoCancel: true
@@ -60,6 +56,8 @@ jobs:
variables:
- group: sign-client-credentials
+ - name: DOTNET_NOLOGO
+ value: true
- name: buildPlatform
value: 'Any CPU'
- name: buildConfiguration
@@ -71,6 +69,8 @@ jobs:
- template: azure-pipelines-templates/process-pr-labels.yml@templates
+ - template: azure-pipelines-templates/check-nf-interpreter-to-test.yml
+
# build steps only
- template: azure-pipelines-templates/class-lib-build-only.yml@templates
parameters:
@@ -78,6 +78,7 @@ jobs:
runUnitTests: ${{ ne(variables['processPrLabels.SKIP_UNIT_TESTS'], 'true') }}
unitTestRunsettings: '$(System.DefaultWorkingDirectory)\.runsettings'
skipNuGetCache: true
+ usePreviewBuild: true
# rebuild CoreLibrary project to get the assembly checksum
- task: MSBuild@1
@@ -120,17 +121,21 @@ jobs:
parameters:
nugetPackageName: 'nanoFramework.CoreLibrary.NoReflection'
- - template: azure-pipelines-templates/class-lib-publish.yml@templates
+ - template: azure-pipelines-templates/class-lib-publish.yml@templates
+ parameters:
+ baseBranchName: 'develop'
- # create or update GitHub release ON tags from release
+ # create or update GitHub release ON tags
- task: GithubRelease@1
condition: >-
and(
succeeded(),
eq(variables['System.PullRequest.PullRequestId'], ''),
- startsWith(variables['Build.SourceBranch'], 'refs/heads/main'),
- not(contains(variables['Build.SourceBranch'], 'preview')),
- eq(variables['StartReleaseCandidate'], false)
+ eq(variables['StartReleaseCandidate'], false),
+ or(
+ eq(variables['Build.SourceBranchName'], 'main'),
+ eq(variables['Build.SourceBranchName'], 'develop')
+ )
)
displayName: Create/Update GitHub stable release
inputs:
@@ -143,7 +148,7 @@ jobs:
releaseNotesInline: 'Check the [changelog]($(Build.Repository.Uri)/blob/$(Build.SourceBranchName)/CHANGELOG.md).
Install from NuGet
The following NuGet packages are available for download from this release:
:package: [.NET](https://www.nuget.org/packages/$(nugetPackageName)/$(MY_NUGET_VERSION)) v$(MY_NUGET_VERSION).
:package: [.NET (without Reflection)](https://www.nuget.org/packages/$(nugetPackageName).NoReflection/$(MY_NUGET_VERSION)) v$(MY_NUGET_VERSION)'
assets: '$(Build.ArtifactStagingDirectory)/*.nupkg'
assetUploadMode: replace
- isPreRelease: false
+ isPreRelease: $[eq(variables['Build.SourceBranchName'], 'develop')]
addChangeLog: false
##############################
diff --git a/nanoFramework.CoreLibrary.Benchmarks.sln b/nanoFramework.CoreLibrary.Benchmarks.sln
new file mode 100644
index 00000000..777b30d6
--- /dev/null
+++ b/nanoFramework.CoreLibrary.Benchmarks.sln
@@ -0,0 +1,27 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.14.36623.8
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{11A8DD76-328B-46DF-9F39-F559912D0360}") = "nanoFramework.CoreLibrary.Benchmarks", "nanoFramework.CoreLibrary.Benchmarks\nanoFramework.CoreLibrary.Benchmarks.nfproj", "{DFF849AB-F56C-4173-9E3C-5FD551914B0F}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {DFF849AB-F56C-4173-9E3C-5FD551914B0F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {DFF849AB-F56C-4173-9E3C-5FD551914B0F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {DFF849AB-F56C-4173-9E3C-5FD551914B0F}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
+ {DFF849AB-F56C-4173-9E3C-5FD551914B0F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {DFF849AB-F56C-4173-9E3C-5FD551914B0F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {DFF849AB-F56C-4173-9E3C-5FD551914B0F}.Release|Any CPU.Deploy.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {B0D58340-A787-48A6-B53F-1678A4E57960}
+ EndGlobalSection
+EndGlobal
diff --git a/nanoFramework.CoreLibrary.Benchmarks/Program.cs b/nanoFramework.CoreLibrary.Benchmarks/Program.cs
new file mode 100644
index 00000000..99428e3e
--- /dev/null
+++ b/nanoFramework.CoreLibrary.Benchmarks/Program.cs
@@ -0,0 +1,40 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Diagnostics;
+using System.Threading;
+using nanoFramework.Benchmark;
+using nanoFramework.CoreLibrary.Benchmarks.ToString;
+using nanoFramework.Runtime.Native;
+
+namespace nanoFramework.CoreLibrary.Benchmarks
+{
+ public class Program
+ {
+ public static void Main()
+ {
+ // Display header with system information
+ Debug.WriteLine("================================================");
+ Debug.WriteLine(" nanoFramework Core Library Benchmarks");
+ Debug.WriteLine("================================================");
+ Debug.WriteLine("");
+
+ Debug.WriteLine($"Target Name: {SystemInfo.TargetName}");
+ Debug.WriteLine($"Firmware: {SystemInfo.Version}");
+ var coreLibVersion = typeof(object).Assembly.GetName().Version;
+ Debug.WriteLine($"CoreLibrary Version: {coreLibVersion}");
+
+ Debug.WriteLine("");
+ Debug.WriteLine("================================================");
+ Debug.WriteLine("");
+
+ // Run benchmarks
+ BenchmarkRunner.RunClass(typeof(ToStringPlain));
+ BenchmarkRunner.RunClass(typeof(ToStringConcatenation));
+ BenchmarkRunner.RunClass(typeof(ToStringInterpolation));
+ BenchmarkRunner.RunClass(typeof(ToStringFormat));
+
+ Thread.Sleep(Timeout.Infinite);
+ }
+ }
+}
diff --git a/nanoFramework.CoreLibrary.Benchmarks/Properties/AssemblyInfo.cs b/nanoFramework.CoreLibrary.Benchmarks/Properties/AssemblyInfo.cs
new file mode 100644
index 00000000..d459bd32
--- /dev/null
+++ b/nanoFramework.CoreLibrary.Benchmarks/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("CSharp.BlankApplication")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("CSharp.BlankApplication")]
+[assembly: AssemblyCopyright("Copyright © 2025")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/nanoFramework.CoreLibrary.Benchmarks/ToString/ToStringConcatenation.cs b/nanoFramework.CoreLibrary.Benchmarks/ToString/ToStringConcatenation.cs
new file mode 100644
index 00000000..184c0af1
--- /dev/null
+++ b/nanoFramework.CoreLibrary.Benchmarks/ToString/ToStringConcatenation.cs
@@ -0,0 +1,99 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using nanoFramework.Benchmark;
+using nanoFramework.Benchmark.Attributes;
+
+namespace nanoFramework.CoreLibrary.Benchmarks.ToString
+{
+ [IterationCount(5)]
+ public class ToStringConcatenation
+ {
+ private int _intValue;
+ private long _longValue;
+ private double _doubleValue;
+ private bool _boolValue;
+ private byte _byteValue;
+ private DateTime _dateTimeValue;
+ private string _stringValue;
+
+ [Setup]
+ public void Setup()
+ {
+ _intValue = 12345;
+ _longValue = 1234567890123456L;
+ _doubleValue = 123.456;
+ _boolValue = true;
+ _byteValue = 255;
+ _dateTimeValue = new DateTime(2024, 1, 15, 10, 30, 45);
+ _stringValue = "test";
+ }
+
+ [Benchmark]
+ public void Int32Concatenation()
+ {
+ _ = "Value: " + _intValue;
+ }
+
+ [Benchmark]
+ public void Int64Concatenation()
+ {
+ _ = "Value: " + _longValue;
+ }
+
+ [Benchmark]
+ public void DoubleConcatenation()
+ {
+ _ = "Value: " + _doubleValue;
+ }
+
+ [Benchmark]
+ public void BooleanConcatenation()
+ {
+ _ = "Value: " + _boolValue;
+ }
+
+ [Benchmark]
+ public void ByteConcatenation()
+ {
+ _ = "Value: " + _byteValue;
+ }
+
+ [Benchmark]
+ public void DateTimeConcatenation()
+ {
+ _ = "Value: " + _dateTimeValue;
+ }
+
+ [Benchmark]
+ public void MultipleValuesConcatenation()
+ {
+ _ = "Int: " + _intValue + ", Double: " + _doubleValue + ", Bool: " + _boolValue;
+ }
+
+ [Benchmark]
+ public void MixedConcatenation()
+ {
+ _ = "String: " + _stringValue + ", Int: " + _intValue + ", DateTime: " + _dateTimeValue;
+ }
+
+ [Benchmark]
+ public void ComplexConcatenation()
+ {
+ _ = "Values - Byte: " + _byteValue + ", Long: " + _longValue + ", Double: " + _doubleValue + ", Bool: " + _boolValue;
+ }
+
+ [Benchmark]
+ public void ExplicitToStringConcatenation()
+ {
+ _ = "Value: " + _intValue.ToString();
+ }
+
+ [Benchmark]
+ public void MultipleExplicitToStringConcatenation()
+ {
+ _ = "Int: " + _intValue.ToString() + ", Double: " + _doubleValue.ToString() + ", Bool: " + _boolValue.ToString();
+ }
+ }
+}
diff --git a/nanoFramework.CoreLibrary.Benchmarks/ToString/ToStringFormat.cs b/nanoFramework.CoreLibrary.Benchmarks/ToString/ToStringFormat.cs
new file mode 100644
index 00000000..605a83ac
--- /dev/null
+++ b/nanoFramework.CoreLibrary.Benchmarks/ToString/ToStringFormat.cs
@@ -0,0 +1,99 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using nanoFramework.Benchmark;
+using nanoFramework.Benchmark.Attributes;
+
+namespace nanoFramework.CoreLibrary.Benchmarks.ToString
+{
+ [IterationCount(5)]
+ public class ToStringFormat
+ {
+ private int _intValue;
+ private long _longValue;
+ private double _doubleValue;
+ private bool _boolValue;
+ private byte _byteValue;
+ private DateTime _dateTimeValue;
+ private string _stringValue;
+
+ [Setup]
+ public void Setup()
+ {
+ _intValue = 12345;
+ _longValue = 1234567890123456L;
+ _doubleValue = 123.456;
+ _boolValue = true;
+ _byteValue = 255;
+ _dateTimeValue = new DateTime(2024, 1, 15, 10, 30, 45);
+ _stringValue = "test";
+ }
+
+ [Benchmark]
+ public void Int32Format()
+ {
+ _ = string.Format("Value: {0}", _intValue);
+ }
+
+ [Benchmark]
+ public void Int64Format()
+ {
+ _ = string.Format("Value: {0}", _longValue);
+ }
+
+ [Benchmark]
+ public void DoubleFormat()
+ {
+ _ = string.Format("Value: {0}", _doubleValue);
+ }
+
+ [Benchmark]
+ public void BooleanFormat()
+ {
+ _ = string.Format("Value: {0}", _boolValue);
+ }
+
+ [Benchmark]
+ public void ByteFormat()
+ {
+ _ = string.Format("Value: {0}", _byteValue);
+ }
+
+ [Benchmark]
+ public void DateTimeFormat()
+ {
+ _ = string.Format("Value: {0}", _dateTimeValue);
+ }
+
+ [Benchmark]
+ public void MultipleValuesFormat()
+ {
+ _ = string.Format("Int: {0}, Double: {1}, Bool: {2}", _intValue, _doubleValue, _boolValue);
+ }
+
+ [Benchmark]
+ public void MixedFormat()
+ {
+ _ = string.Format("String: {0}, Int: {1}, DateTime: {2}", _stringValue, _intValue, _dateTimeValue);
+ }
+
+ [Benchmark]
+ public void ComplexFormat()
+ {
+ _ = string.Format("Values - Byte: {0}, Long: {1}, Double: {2}, Bool: {3}", _byteValue, _longValue, _doubleValue, _boolValue);
+ }
+
+ [Benchmark]
+ public void ReorderedFormat()
+ {
+ _ = string.Format("Values: {2}, {1}, {0}", _intValue, _doubleValue, _boolValue);
+ }
+
+ [Benchmark]
+ public void RepeatedFormat()
+ {
+ _ = string.Format("Value {0} repeated: {0}, {0}", _intValue);
+ }
+ }
+}
diff --git a/nanoFramework.CoreLibrary.Benchmarks/ToString/ToStringInterpolation.cs b/nanoFramework.CoreLibrary.Benchmarks/ToString/ToStringInterpolation.cs
new file mode 100644
index 00000000..98bccbb6
--- /dev/null
+++ b/nanoFramework.CoreLibrary.Benchmarks/ToString/ToStringInterpolation.cs
@@ -0,0 +1,87 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using nanoFramework.Benchmark;
+using nanoFramework.Benchmark.Attributes;
+
+namespace nanoFramework.CoreLibrary.Benchmarks.ToString
+{
+ [IterationCount(5)]
+ public class ToStringInterpolation
+ {
+ private int _intValue;
+ private long _longValue;
+ private double _doubleValue;
+ private bool _boolValue;
+ private byte _byteValue;
+ private DateTime _dateTimeValue;
+ private string _stringValue;
+
+ [Setup]
+ public void Setup()
+ {
+ _intValue = 12345;
+ _longValue = 1234567890123456L;
+ _doubleValue = 123.456;
+ _boolValue = true;
+ _byteValue = 255;
+ _dateTimeValue = new DateTime(2024, 1, 15, 10, 30, 45);
+ _stringValue = "test";
+ }
+
+ [Benchmark]
+ public void Int32Interpolation()
+ {
+ _ = $"Value: {_intValue}";
+ }
+
+ [Benchmark]
+ public void Int64Interpolation()
+ {
+ _ = $"Value: {_longValue}";
+ }
+
+ [Benchmark]
+ public void DoubleInterpolation()
+ {
+ _ = $"Value: {_doubleValue}";
+ }
+
+ [Benchmark]
+ public void BooleanInterpolation()
+ {
+ _ = $"Value: {_boolValue}";
+ }
+
+ [Benchmark]
+ public void ByteInterpolation()
+ {
+ _ = $"Value: {_byteValue}";
+ }
+
+ [Benchmark]
+ public void DateTimeInterpolation()
+ {
+ _ = $"Value: {_dateTimeValue}";
+ }
+
+ [Benchmark]
+ public void MultipleValuesInterpolation()
+ {
+ _ = $"Int: {_intValue}, Double: {_doubleValue}, Bool: {_boolValue}";
+ }
+
+ [Benchmark]
+ public void MixedInterpolation()
+ {
+ _ = $"String: {_stringValue}, Int: {_intValue}, DateTime: {_dateTimeValue}";
+ }
+
+ [Benchmark]
+ public void ComplexInterpolation()
+ {
+ _ = $"Values - Byte: {_byteValue}, Long: {_longValue}, Double: {_doubleValue}, Bool: {_boolValue}";
+ }
+ }
+}
diff --git a/nanoFramework.CoreLibrary.Benchmarks/ToString/ToStringPlain.cs b/nanoFramework.CoreLibrary.Benchmarks/ToString/ToStringPlain.cs
new file mode 100644
index 00000000..53ff1286
--- /dev/null
+++ b/nanoFramework.CoreLibrary.Benchmarks/ToString/ToStringPlain.cs
@@ -0,0 +1,67 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using nanoFramework.Benchmark;
+using nanoFramework.Benchmark.Attributes;
+
+namespace nanoFramework.CoreLibrary.Benchmarks.ToString
+{
+ [IterationCount(5)]
+ public class ToStringPlain
+ {
+ private int _intValue;
+ private long _longValue;
+ private double _doubleValue;
+ private bool _boolValue;
+ private byte _byteValue;
+ private DateTime _dateTimeValue;
+
+ [Setup]
+ public void Setup()
+ {
+ _intValue = 12345;
+ _longValue = 1234567890123456L;
+ _doubleValue = 123.456;
+ _boolValue = true;
+ _byteValue = 255;
+ _dateTimeValue = new DateTime(2024, 1, 15, 10, 30, 45);
+ }
+
+ [Benchmark]
+ public void Int32ToString()
+ {
+ _ = _intValue.ToString();
+ }
+
+ [Benchmark]
+ public void Int64ToString()
+ {
+ _ = _longValue.ToString();
+ }
+
+ [Benchmark]
+ public void DoubleToString()
+ {
+ _ = _doubleValue.ToString();
+ }
+
+ [Benchmark]
+ public void BooleanToString()
+ {
+ _ = _boolValue.ToString();
+ }
+
+ [Benchmark]
+ public void ByteToString()
+ {
+ _ = _byteValue.ToString();
+ }
+
+ [Benchmark]
+ public void DateTimeToString()
+ {
+ _ = _dateTimeValue.ToString();
+ }
+ }
+}
diff --git a/nanoFramework.CoreLibrary.Benchmarks/nanoFramework.CoreLibrary.Benchmarks.nfproj b/nanoFramework.CoreLibrary.Benchmarks/nanoFramework.CoreLibrary.Benchmarks.nfproj
new file mode 100644
index 00000000..1be68daf
--- /dev/null
+++ b/nanoFramework.CoreLibrary.Benchmarks/nanoFramework.CoreLibrary.Benchmarks.nfproj
@@ -0,0 +1,60 @@
+
+
+
+ $(MSBuildExtensionsPath)\nanoFramework\v1.0\
+
+
+
+ Debug
+ AnyCPU
+ {11A8DD76-328B-46DF-9F39-F559912D0360};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+ dff849ab-f56c-4173-9e3c-5fd551914b0f
+ Exe
+ Properties
+ 512
+ nanoFramework.CoreLibrary.Benchmarks
+ nanoFramework.CoreLibrary.Benchmarks
+ v1.0
+
+
+
+
+
+
+
+
+
+
+
+
+ packages\nanoFramework.CoreLibrary.1.17.11\lib\mscorlib.dll
+
+
+ packages\nanoFramework.Benchmark.1.0.113\lib\nanoFramework.Benchmark.dll
+
+
+ packages\nanoFramework.Logging.1.1.161\lib\nanoFramework.Logging.dll
+
+
+ packages\nanoFramework.Runtime.Native.1.7.11\lib\nanoFramework.Runtime.Native.dll
+
+
+ packages\nanoFramework.System.Collections.1.5.67\lib\nanoFramework.System.Collections.dll
+
+
+ packages\nanoFramework.System.Text.1.3.42\lib\nanoFramework.System.Text.dll
+
+
+ packages\nanoFramework.System.Diagnostics.Stopwatch.1.2.862\lib\System.Diagnostics.Stopwatch.dll
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/nanoFramework.CoreLibrary.Benchmarks/packages.config b/nanoFramework.CoreLibrary.Benchmarks/packages.config
new file mode 100644
index 00000000..b2e69209
--- /dev/null
+++ b/nanoFramework.CoreLibrary.Benchmarks/packages.config
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/nanoFramework.CoreLibrary.nuspec b/nanoFramework.CoreLibrary.nuspec
index 63518a26..6b612a06 100644
--- a/nanoFramework.CoreLibrary.nuspec
+++ b/nanoFramework.CoreLibrary.nuspec
@@ -13,17 +13,14 @@
https://github.com/nanoframework/CoreLibrary
images\nf-logo.png
- Copyright (c) .NET Foundation and Contributors
+ Copyright (c) .NET Foundation and Contributors
This package includes the CoreLibrary assembly for .NET nanoFramework C# projects.
This package requires a target with mscorlib v$nativeVersion$ (checksum $checksum$).
In case you don't need the System.Reflection API there is another NuGet package without this API.
nanoFramework C# csharp netmf netnf nanoFramework.CoreLibrary
-
-
-
-
-
-
+
+
+
diff --git a/nanoFramework.CoreLibrary/CoreLibrary.nfproj b/nanoFramework.CoreLibrary/CoreLibrary.nfproj
index c44da984..0bd250ab 100644
--- a/nanoFramework.CoreLibrary/CoreLibrary.nfproj
+++ b/nanoFramework.CoreLibrary/CoreLibrary.nfproj
@@ -38,7 +38,7 @@
$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb
true
true
- default
+ 13.0
true
@@ -66,6 +66,16 @@
+
+
+
+
+
+
+
+
+
+
@@ -188,7 +198,9 @@
-
+
+
+
@@ -251,4 +263,4 @@
-
+
\ No newline at end of file
diff --git a/nanoFramework.CoreLibrary/System/Array.Enumerators.cs b/nanoFramework.CoreLibrary/System/Array.Enumerators.cs
new file mode 100644
index 00000000..532e4483
--- /dev/null
+++ b/nanoFramework.CoreLibrary/System/Array.Enumerators.cs
@@ -0,0 +1,101 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Collections;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+#nullable enable
+
+namespace System
+{
+ internal abstract class SZGenericArrayEnumeratorBase : IDisposable
+ {
+ protected int _index;
+ protected readonly int _endIndex;
+
+ protected SZGenericArrayEnumeratorBase(int endIndex)
+ {
+ _index = -1;
+ _endIndex = endIndex;
+ }
+
+ public bool MoveNext()
+ {
+ int index = _index + 1;
+
+ if ((uint)index < (uint)_endIndex)
+ {
+ _index = index;
+
+ return true;
+ }
+
+ _index = _endIndex;
+
+ return false;
+ }
+
+ public void Reset() => _index = -1;
+
+ public void Dispose()
+ {
+ }
+ }
+
+ internal sealed class SZGenericArrayEnumerator : SZGenericArrayEnumeratorBase, IEnumerator
+ {
+ private readonly T[]? _array;
+
+ /// Provides an empty enumerator singleton.
+ ///
+ /// If the consumer is using SZGenericArrayEnumerator elsewhere or is otherwise likely
+ /// to be using T[] elsewhere, this singleton should be used. Otherwise, GenericEmptyEnumerator's
+ /// singleton should be used instead, as it doesn't reference T[] in order to reduce footprint.
+ ///
+ internal static readonly SZGenericArrayEnumerator Empty = new SZGenericArrayEnumerator(null, 0);
+
+ internal SZGenericArrayEnumerator(T[]? array, int endIndex)
+ : base(endIndex)
+ {
+ Debug.Assert(array == null || endIndex == array.Length);
+ _array = array;
+ }
+
+ public T Current
+ {
+ get
+ {
+ if ((uint)_index >= (uint)_endIndex)
+ {
+ throw new InvalidOperationException();
+ }
+
+ return _array![_index];
+ }
+ }
+
+ object? IEnumerator.Current => Current;
+ }
+
+ internal abstract class GenericEmptyEnumeratorBase : IDisposable, IEnumerator
+ {
+#pragma warning disable CA1822 // https://github.com/dotnet/roslyn-analyzers/issues/5911
+ public bool MoveNext() => false;
+
+ public object Current
+ {
+ get
+ {
+ return default;
+ }
+ }
+
+ public void Reset() { }
+
+ public void Dispose() { }
+#pragma warning restore CA1822
+ }
+}
diff --git a/nanoFramework.CoreLibrary/System/Array.cs b/nanoFramework.CoreLibrary/System/Array.cs
index 1256a436..c9cf7254 100644
--- a/nanoFramework.CoreLibrary/System/Array.cs
+++ b/nanoFramework.CoreLibrary/System/Array.cs
@@ -1,8 +1,12 @@
-// Licensed to the .NET Foundation under one or more agreements.
+// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Collections;
using System.Runtime.CompilerServices;
+#if NANOCLR_REFLECTION
+using System.Collections.Generic;
+using System.Diagnostics;
+#endif // NANOCLR_REFLECTION
namespace System
{
@@ -343,6 +347,25 @@ public static int IndexOf(Array array, Object value, int startIndex, int count)
return -1;
}
+#if NANOCLR_REFLECTION
+ ///
+ /// Creates and returns an empty array of the specified type.
+ ///
+ ///
+ ///
+ public static T[] Empty()
+ {
+ return EmptyArray.Value;
+ }
+
+ private static class EmptyArray
+ {
+#pragma warning disable CA1825, IDE0300 // this is the implementation of Array.Empty()
+ internal static readonly T[] Value = new T[0];
+#pragma warning restore CA1825, IDE0300
+ }
+#endif
+
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern bool TrySzIndexOf(Array sourceArray, int sourceIndex, int count, Object value, out int retVal);
@@ -410,5 +433,153 @@ public void Reset()
_index = _startIndex - 1;
}
}
+
+#if NANOCLR_REFLECTION
+#pragma warning disable CA1822 // Mark members as static
+ //----------------------------------------------------------------------------------------
+ // ! READ THIS BEFORE YOU WORK ON THIS CLASS.
+ //
+ // The methods on this class must be written VERY carefully to avoid introducing security holes.
+ // That's because they are invoked with special "this"! The "this" object
+ // for all of these methods are not SZArrayHelper objects. Rather, they are of type U[]
+ // where U[] is castable to T[]. No actual SZArrayHelper object is ever instantiated. Thus, you will
+ // see a lot of expressions that cast "this" "T[]".
+ //
+ // This class is needed to allow an SZ array of type T[] to expose IList,
+ // IList, etc., etc. all the way up to IList