diff --git a/extra/recorder_enumerator/src/Config.cs b/extra/recorder_enumerator/src/Config.cs index 12646448..e4937351 100644 --- a/extra/recorder_enumerator/src/Config.cs +++ b/extra/recorder_enumerator/src/Config.cs @@ -15,11 +15,14 @@ public static class Config private static HashSet<(string, string)> InternalRegexSupportOverride = new HashSet<(string, string)> { + ("System.Linq.Enumerable", "CastIterator"), ("System.Linq.Enumerable", "DistinctByIterator"), ("System.Linq.Enumerable", "ExceptIterator"), ("System.Linq.Enumerable", "ExceptByIterator"), ("System.Linq.Enumerable", "IntersectIterator"), ("System.Linq.Enumerable", "IntersectByIterator"), + ("System.Linq.Enumerable", "OfTypeIterator"), + ("System.Linq.Lookup", "GetEnumerator"), ("System.Linq.OrderedEnumerable`1", "GetEnumerator"), }; @@ -30,6 +33,11 @@ public static Converter ConverterFactory(Type type) return new SystemLinqEnumerable_RangeIterator_Converter(); } + if (type == System_ArrayEnumerator_Converter.RelevantType) + { + return new System_ArrayEnumerator_Converter(); + } + if (typeof(MethodInfo).IsAssignableFrom(type)) { return new MethodInfo_Converter(); diff --git a/extra/recorder_enumerator/src/System.cs b/extra/recorder_enumerator/src/System.cs new file mode 100644 index 00000000..f3b86a2a --- /dev/null +++ b/extra/recorder_enumerator/src/System.cs @@ -0,0 +1,41 @@ +namespace Dec.RecorderEnumerator +{ + using System; + using System.Reflection; + + public class System_ArrayEnumerator_Converter : ConverterFactoryDynamic + { + internal static Type RelevantType = typeof(System.Array).Assembly.GetType("System.ArrayEnumerator"); + + internal FieldInfo field_Array = RelevantType.GetPrivateFieldInHierarchy("_array"); + internal FieldInfo field_Index = RelevantType.GetPrivateFieldInHierarchy("_index"); + + public override void Write(object input, Recorder recorder) + { + recorder.Shared().RecordPrivate(input, field_Array, "array"); + + // I assume this is an IntPtr just to avoid taking up more space on 32-bit systems + // but, seriously guys, wat + IntPtr intPtr = (IntPtr)field_Index.GetValue(input); + long intPtrValue = intPtr.ToInt64(); + recorder.Record(ref intPtrValue, "index"); + } + + public override object Create(Recorder recorder) + { + // I am frankly bewildered as to why Activator.CreateInstance() doesn't work here. + var cs = RelevantType.GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic); + return cs[0].Invoke(new object[] { null }); + } + + public override void Read(ref object input, Recorder recorder) + { + recorder.Shared().RecordPrivate(input, field_Array, "array"); + + long intPtrValue = 0; + recorder.Record(ref intPtrValue, "index"); + IntPtr intPtr = new IntPtr(intPtrValue); + field_Index.SetValue(input, intPtr); + } + } +} diff --git a/extra/recorder_enumerator/test/Linq.cs b/extra/recorder_enumerator/test/Linq.cs index 123e26a5..4f7376ef 100644 --- a/extra/recorder_enumerator/test/Linq.cs +++ b/extra/recorder_enumerator/test/Linq.cs @@ -515,5 +515,45 @@ public void ReverseEnumeratorTest([ValuesExcept(RecorderMode.Validation)] Record var result = DoRecorderRoundTrip(source, recorderMode); Assert.IsTrue(Util.AreEquivalentEnumerators(source, result)); } + + [Test] + [Ignore("This is hard to support due to Grouping.")] + [Dec.RecorderEnumerator.RecordableClosures] + public void GroupByEnumeratorTest([ValuesExcept(RecorderMode.Validation)] RecorderMode recorderMode) + { + var source = Enumerable.Range(0, 20).GroupBy(i => i % 3).GetEnumerator(); + source.MoveNext(); + source.MoveNext(); + source.MoveNext(); + var result = DoRecorderRoundTrip(source, recorderMode); + Assert.IsTrue(Util.AreEquivalentEnumerators(source, result)); + } + + [Test] + [Dec.RecorderEnumerator.RecordableClosures] + public void OfTypeEnumeratorTest([ValuesExcept(RecorderMode.Validation)] RecorderMode recorderMode) + { + var mixedSource = new object[] { 0, 1, "two", 3, "four", 5 }; + var source = mixedSource.OfType().GetEnumerator(); + source.MoveNext(); + source.MoveNext(); + source.MoveNext(); + var result = DoRecorderRoundTrip(source, recorderMode); + Assert.IsTrue(Util.AreEquivalentEnumerators(source, result)); + } + + [Test] + [Dec.RecorderEnumerator.RecordableClosures] + public void CastEnumeratorTest([ValuesExcept(RecorderMode.Validation)] RecorderMode recorderMode) + { + var objectSource = new object[] { 0, 1, 2, 3, 4, 5 }; + var source = objectSource.Cast().GetEnumerator(); + source.MoveNext(); + source.MoveNext(); + source.MoveNext(); + var result = DoRecorderRoundTrip(source, recorderMode); + Assert.IsTrue(Util.AreEquivalentEnumerators(source, result)); + } + } }