diff --git a/.runsettings b/.runsettings
index 3d17b679..536c73fb 100644
--- a/.runsettings
+++ b/.runsettings
@@ -1,4 +1,4 @@
-
+
@@ -12,5 +12,6 @@
VerboseFalse --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 @@
trueUnitTestv1.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..93b37f48 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();
}
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/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..d00acd5a
--- /dev/null
+++ b/azure-pipelines-templates/check-nf-interpreter-to-test.yml
@@ -0,0 +1,80 @@
+# 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: >-
+ and(
+ eq(variables['DownloadNanoClrPreview'], true),
+ 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: >-
+ and(
+ succeeded(),
+ eq(variables['DownloadNanoClrPreview'], true),
+ 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.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/CoreLibraryimages\nf-logo.png
- Copyright (c) .NET Foundation and Contributors
+ Copyright (c) .NET Foundation and ContributorsThis 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);.pdbtruetrue
- default
+ 13.0true
@@ -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