using System;
using System.Collections.Generic;
using System.Device.Gpio;
using System.Device.I2c;
using System.Text;
using System.Threading;
using ArduinoCsCompiler;
using ArduinoCsCompiler.Runtime;
using Iot.Device.Arduino;
using Iot.Device.CharacterLcd;
using Xunit;
namespace Iot.Device.Arduino.Tests
{
[Collection("SingleClientOnly")]
[Trait("feature", "firmata")]
[Trait("requires", "hardware")]
public class ArduinoNativeLibraryTest : ArduinoTestBase, IClassFixture<FirmataTestFixture>
{
private const int MaxTestMemoryUsage = 400000;
public ArduinoNativeLibraryTest(FirmataTestFixture fixture)
: base(fixture)
{
Compiler.ClearAllData(true, true);
CompilerSettings = new CompilerSettings()
{
CreateKernelForFlashing = false,
LaunchProgramFromFlash = false,
UseFlashForKernel = false,
};
}
public class SimpleLedBinding
{
private readonly GpioController _controller;
private int _ledPin;
private int _delay;
public SimpleLedBinding(GpioController controller, int pin, int delay)
{
_controller = controller;
_controller.OpenPin(pin);
_controller.SetPinMode(pin, PinMode.Output);
_ledPin = pin;
_delay = delay;
}
public static int RunBlink(int pin, int delay)
{
var gpioController = new GpioController(new ArduinoNativeGpioDriver());
SimpleLedBinding blink = new SimpleLedBinding(gpioController, pin, delay);
blink.Loop();
return 1;
}
public void Loop()
{
for (int i = 0; i < 2; i++)
{
_controller.Write(_ledPin, 1);
Thread.Sleep(_delay);
_controller.Write(_ledPin, 0);
Thread.Sleep(_delay);
}
}
}
[Fact]
public void RunBlinkWithGpioController()
{
ExecuteComplexProgramSuccess<Func<int, int, int>>(SimpleLedBinding.RunBlink, nameof(RunBlinkWithGpioController), false, 6, 1000);
}
[Fact]
public void ExpectArrayIndexOutOfBounds()
{
ExecuteComplexProgramCausesException<Func<int, int>, IndexOutOfRangeException>(typeof(ArduinoNativeLibraryTest), OutOfBoundsCheck, 10);
}
[Fact]
public void ExpectCustomException()
{
ExecuteComplexProgramCausesException<Func<int, int>, NotImplementedException>(typeof(ArduinoNativeLibraryTest), NotImplemented, 10);
}
[Fact]
public void ExpectDivideByZero()
{
ExecuteComplexProgramCausesException<Func<int, int>, DivideByZeroException>(typeof(ArduinoNativeLibraryTest), DivideByZero, 0);
}
[Fact]
public void ExpectOutOfMemory()
{
ExecuteComplexProgramCausesException<Func<int, int>, OutOfMemoryException>(typeof(ArduinoNativeLibraryTest), OutOfMemory, (1 << 31) + (1 << 30));
}
private static int OutOfBoundsCheck(int index)
{
int[] array = new int[2];
return array[index];
}
private static int NotImplemented(int index)
{
throw new NotImplementedException("This method is not implemented on purpose");
}
private static int DivideByZero(int zero)
{
return 10 / zero;
}
private static int OutOfMemory(int sizeToAllocate)
{
int[] array = new int[sizeToAllocate];
return array.Length;
}
[Fact]
public void GetDataFromStaticByteField()
{
ExecuteComplexProgramSuccess<Func<int, int, int>>(ClassWithStaticByteField.GetFirstByte, nameof(GetDataFromStaticByteField), true, 0, 0);
}
[Fact]
public void CpuIsLittleEndian()
{
ExecuteComplexProgramSuccess<Func<int>>(IsLittleEndianTest, nameof(CpuIsLittleEndian), true);
}
private static int IsLittleEndianTest()
{
return BitConverter.IsLittleEndian ? 1 : 0;
}
public static int MethodCallOnGenericTest()
{
var obj1 = new ClassWithGenericParameter<int>(2);
MiniAssert.That(obj1.CompareTo(2) == 0);
MiniAssert.That(obj1.CompareTo(3) == -1);
var obj2 = new ClassWithGenericParameter<string>("Test");
MiniAssert.That(obj2.CompareTo("Test") == 0);
return 1;
}
public static int MethodCallOnValueType()
{
int i = 32;
if (i.CompareTo(11) == 0)
{
return 0;
}
int hash = i.GetHashCode();
if (hash == 0)
{
return 0;
}
IComparable<int> i2 = i;
if (i2.CompareTo(12) == 0)
{
return 0;
}
DateTime dt = new DateTime(2020, 01, 20);
dt = dt.AddDays(1.0f);
if (dt.DayOfYear != 21)
{
return dt.DayOfYear;
}
return 1;
}
[Fact]
public void ClassWith64BitFieldTest()
{
ExecuteComplexProgramSuccess<Func<int>>(ClassWith64BitField.ClassMain, nameof(ClassWith64BitFieldTest), true);
}
[Fact]
public void MethodCallOnValueTypeTest()
{
ExecuteComplexProgramSuccess<Func<int>>(MethodCallOnValueType, nameof(MethodCallOnValueTypeTest), true);
}
[Fact]
public void MethodCallOnGenericClass()
{
ExecuteComplexProgramSuccess<Func<int>>(MethodCallOnGenericTest, nameof(MethodCallOnGenericClass), true);
}
public class ClassWith64BitField
{
private int _field1;
private long _field2;
public ClassWith64BitField()
{
_field1 = -1;
_field2 = 2;
}
public static int ClassMain()
{
var instance = new ClassWith64BitField();
return instance.GetResult();
}
public int GetResult()
{
return (int)(_field1 + _field2);
}
}
public class ClassWithStaticByteField
{
private static byte[] _byteData =
{
1, 2, 3, 4, 5, 6
};
public ClassWithStaticByteField()
{
}
public byte[] ByteData
{
get
{
return _byteData;
}
}
public static int GetFirstByte(int index, int extraIndex)
{
return _byteData[index + extraIndex];
}
}
[Fact]
public void GetDataFromClassWithStaticField2()
{
ExecuteComplexProgramSuccess<Func<int, int, int>>(ClassWithStaticField2.GetFirstByte, nameof(GetDataFromClassWithStaticField2), true, 0, 0);
}
public class ClassWithStaticField2
{
private static object?[] _byteData = new object?[]
{
new object(), new HashSet<int>(), null,
};
public ClassWithStaticField2()
{
}
public static int GetFirstByte(int index, int extraIndex)
{
if (_byteData[index + extraIndex] != null)
{
return 1;
}
return 0;
}
}
[Fact]
public void GetDataFromStaticIntField()
{
ExecuteComplexProgramSuccess<Func<int, int, int>>(ClassWithStaticIntField.GetFirst, nameof(GetDataFromStaticIntField), true, 2, 5);
}
[Fact]
public void SimpleDelegateTest()
{
ExecuteComplexProgramSuccess<Func<int>>(ClassWithAnEvent.Test1, nameof(SimpleDelegateTest), true);
}
[Fact]
public void NonStaticDelegateTest()
{
ExecuteComplexProgramSuccess<Func<int>>(ClassWithAnEvent.Test2, nameof(NonStaticDelegateTest), true);
}
[Fact]
public void EventHandlerTest()
{
ExecuteComplexProgramSuccess<Func<int>>(ClassWithAnEvent.Test3, nameof(EventHandlerTest), true);
}
[Fact]
public void OverridingObjectEqualsWorksTest()
{
ExecuteComplexProgramSuccess<Func<int>>(ClassThatOverridesObjectEquals.Test1, nameof(OverridingObjectEqualsWorksTest), true);
}
[Fact]
public void OverridingObjectEqualsInderivedClassWorksTest()
{
ExecuteComplexProgramSuccess<Func<int>>(ClassThatDoesNotOverrideObjectEquals.Test2, nameof(OverridingObjectEqualsInderivedClassWorksTest), true);
}
[Fact]
public void EqualityDoesNotReturnTrueIfTypeIsNotSame()
{
ExecuteComplexProgramSuccess<Func<int>>(ClassThatDoesNotOverrideObjectEquals.Test3, nameof(EqualityDoesNotReturnTrueIfTypeIsNotSame), true);
}
[Fact]
public void HashSetTest()
{
ExecuteComplexProgramSuccess<Func<int>>(CollectionsTest.TestHashSet, nameof(HashSetTest), true);
}
[Fact]
public void DictionaryTest()
{
ExecuteComplexProgramSuccess<Func<int>>(CollectionsTest.DictionaryTest, nameof(DictionaryTest), true);
}
[Fact]
public void ReflectionTest()
{
ExecuteComplexProgramSuccess<Func<int>>(CollectionsTest.ReflectionTest, nameof(ReflectionTest), true);
}
[Fact]
public void CreateInstanceTest()
{
CompilerSettings s = new CompilerSettings()
{
CreateKernelForFlashing = false,
LaunchProgramFromFlash = false,
UseFlashForProgram = false,
AutoRestartProgram = false,
MaxMemoryUsage = 100_000,
};
ExecuteComplexProgramSuccess<Func<int>>(CollectionsTest.CreateInstanceTest, nameof(CreateInstanceTest), true, s);
}
public class ClassThatOverridesObjectEquals : IEquatable<ClassThatOverridesObjectEquals>
{
private readonly int _a;
public ClassThatOverridesObjectEquals(int a)
{
_a = a;
}
public static int Test1()
{
var c1 = new ClassThatOverridesObjectEquals(42);
var c2 = new ClassThatOverridesObjectEquals(42);
MiniAssert.False(ReferenceEquals(c1, c2));
MiniAssert.That(c1.Equals(c2));
MiniAssert.That(c1.GetHashCode() == 42);
object o1 = c1;
object o2 = c2;
MiniAssert.That(o2.Equals(o1));
return 1;
}
public bool Equals(ClassThatOverridesObjectEquals? other)
{
if (ReferenceEquals(null, other))
{
return false;
}
if (ReferenceEquals(this, other))
{
return true;
}
return _a == other._a;
}
public override bool Equals(object? obj)
{
if (ReferenceEquals(null, obj))
{
return false;
}
if (ReferenceEquals(this, obj))
{
return true;
}
if (obj.GetType() != GetType())
{
return false;
}
return Equals((ClassThatOverridesObjectEquals)obj);
}
public override int GetHashCode()
{
return _a;
}
}
public class ClassThatDoesNotOverrideObjectEquals : ClassThatOverridesObjectEquals
{
public ClassThatDoesNotOverrideObjectEquals(int a)
: base(a)
{
}
public static int Test2()
{
var c1 = new ClassThatDoesNotOverrideObjectEquals(42);
var c2 = new ClassThatDoesNotOverrideObjectEquals(42);
MiniAssert.False(ReferenceEquals(c1, c2));
MiniAssert.That(c1.Equals(c2));
MiniAssert.That(c1.GetHashCode() == 42);
object o1 = c1;
object o2 = c2;
MiniAssert.That(o2.Equals(o1));
return 1;
}
public static int Test3()
{
var c1 = new ClassThatDoesNotOverrideObjectEquals(42);
var c2 = new ClassThatOverridesObjectEquals(42);
MiniAssert.False(ReferenceEquals(c1, c2));
MiniAssert.That(c1.Equals(c2));
MiniAssert.False(((object)c1).Equals(c2));
object o1 = c1;
object o2 = c2;
MiniAssert.False(o2.Equals(o1));
return 1;
}
}
public class ClassWithAnEvent
{
public Func<int>? SimpleDelegate;
public event Action<int>? SimpleEvent;
private int _myValue;
public ClassWithAnEvent()
{
SimpleEvent = null;
}
public static int Test1()
{
ClassWithAnEvent ev = new ClassWithAnEvent();
ev.SimpleDelegate = StaticNonVoidMethod;
int result = ev.FireDelegate();
MiniAssert.That(result == 1);
return result;
}
public static int Test2()
{
ClassWithAnEvent ev = new ClassWithAnEvent();
ev._myValue = 2;
ev.SimpleDelegate = ev.NonVoidMethod;
int result = ev.FireDelegate();
MiniAssert.That(result == 2);
return result - 1;
}
public static int Test3()
{
ClassWithAnEvent ev = new ClassWithAnEvent();
ev._myValue = 3;
ev.SimpleEvent += ev.EventHandler;
ev.FireEvent(1);
ev.SimpleEvent -= ev.EventHandler;
ev.FireEvent(27);
return ev._myValue;
}
public static int StaticNonVoidMethod()
{
return 1;
}
public int NonVoidMethod()
{
return _myValue;
}
public void EventHandler(int data)
{
_myValue = data;
}
public int FireDelegate()
{
if (SimpleDelegate != null)
{
return SimpleDelegate.Invoke();
}
return -1;
}
public void FireEvent(int data)
{
if (SimpleEvent != null)
{
SimpleEvent.Invoke(data);
}
}
}
public class ClassWithStaticIntField
{
private static int[] _intData =
{
7, 2, 3, 4, 5, 6, 4711, 1, 80000,
};
public ClassWithStaticIntField()
{
}
public int[] IntData
{
get
{
return _intData;
}
}
public static int GetFirst(int index, int extraIndex)
{
return _intData[index + extraIndex];
}
}
public class ClassWithGenericParameter<T>
where T : IComparable<T>
{
private T _a;
public ClassWithGenericParameter(T a)
{
_a = a;
}
public int CompareTo(T other)
{
return _a.CompareTo(other);
}
}
public class CollectionsTest
{
public static int TestHashSet()
{
HashSet<int> mySet = new HashSet<int>();
mySet.Add(1);
mySet.Add(2);
mySet.Add(1);
MiniAssert.That(mySet.Count == 2);
MiniAssert.That(mySet.Contains(2));
mySet.Remove(1);
MiniAssert.That(mySet.Count == 1);
return 1;
}
public static int DictionaryTest()
{
Dictionary<int, PinValue?> dict = new Dictionary<int, PinValue?>();
dict.Add(2, null);
MiniAssert.That(dict[2] == null);
dict.Add(5, null);
MiniAssert.That(dict.TryGetValue(5, out var value) && value.HasValue == false);
dict[5] = PinValue.Low;
MiniAssert.That(dict.TryGetValue(5, out value));
if (value.HasValue)
{
MiniAssert.That(value.Value == PinValue.Low);
}
else
{
MiniAssert.That(false, "Value cannot be retrieved");
}
dict.Remove(5);
MiniAssert.That(dict.ContainsKey(2));
MiniAssert.False(dict.ContainsKey(5));
return 1;
}
public static int ReflectionTest()
{
List<bool> list = new List<bool>();
var type = list.GetType();
MiniAssert.That(type.IsGenericType);
var args = list.GetType().GetGenericArguments();
MiniAssert.That(args.Length == 1);
MiniAssert.That(args[0] == typeof(bool));
var main = type.GetGenericTypeDefinition();
MiniAssert.That(main == typeof(List<>));
Type listTypeReconstructed = typeof(List<>).MakeGenericType(typeof(bool));
MiniAssert.That(listTypeReconstructed == type);
var test = main.GetGenericTypeDefinition();
MiniAssert.That(test == typeof(List<>));
var test2 = main.GetGenericArguments();
MiniAssert.That(test2[0] != null);
Dictionary<int, string> dictionary = new Dictionary<int, string>();
var args2 = dictionary.GetType().GetGenericArguments();
MiniAssert.That(args2.Length == 2);
MiniAssert.That(args2[0] == typeof(int));
MiniAssert.That(args2[1] == typeof(string));
var main2 = dictionary.GetType().GetGenericTypeDefinition();
MiniAssert.That(main2 == typeof(Dictionary<,>));
var dictionaryReconstructed = typeof(Dictionary<,>).MakeGenericType(typeof(int), typeof(string));
MiniAssert.That(dictionaryReconstructed == dictionary.GetType());
return 1;
}
public static int CreateInstanceTest()
{
List<int> aList = new List<int>(2);
GC.KeepAlive(aList);
Type t = typeof(List<>).MakeGenericType(typeof(int));
var instance = (List<int>?)Activator.CreateInstance(t, 5);
MiniAssert.That(instance != null);
MiniAssert.That(instance!.Capacity >= 5);
return 1;
}
}
}
}