using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.IO; using System.Linq; using System.Text; using NUnit.Framework; namespace OpenTap.Engine.UnitTests { [TestFixture] public class ListSerialization { public class StringTemp { public string Test { get; set; } } public class StringTempListStep : TestStep { public List TestProp { get; set; } public System.Collections.ObjectModel.ReadOnlyCollection NullList { get; set; } public StringTempListStep() { TestProp = new List(); } public override void Run() { } } public enum TestEnum { A, B, C } public class StringListStep : TestStep { public List TestProp { get; set; } public IList List { get; set; } public HashSet Set { get; set; } public HashSet EnumSet { get; set; } public Dictionary Dict { get; set; } public StringListStep() { TestProp = new List(); List = new List { 1, 2, 3 }; Set = new HashSet(); EnumSet = new HashSet(); Dict = new Dictionary(); } public override void Run() { } } [Test] public void StringTempListSerialization() { TestPlan target = new TestPlan(); var targetStep = new StringTempListStep { TestProp = new List { new StringTemp { Test = "123" }, new StringTemp { Test = "abc" } } }; target.Steps.Add(targetStep); using (var ms = new MemoryStream()) { target.Save(ms); ms.Seek(0, SeekOrigin.Begin); TestPlan deserialized = TestPlan.Load(ms, target.Path); var step = deserialized.ChildTestSteps.First() as StringTempListStep; Assert.IsNotNull(step.TestProp); Assert.AreEqual(targetStep.TestProp.Count, step.TestProp.Count); for (int i = 0; i < targetStep.TestProp.Count; i++) Assert.AreEqual(targetStep.TestProp[i].Test, step.TestProp[i].Test); } } [Test] public void StringListSerialization() { TestPlan target = new TestPlan(); var specList = new List { 5, 6, 7 }; var hashSet = new HashSet(new TestEnum[] { TestEnum.C }); var targetStep = new StringListStep { TestProp = new List { "123", "abc" }, List = specList, EnumSet = hashSet, Set = new HashSet(Enumerable.Range(100, 10)), Dict = new Dictionary() { } }; targetStep.Dict["asd"] = 5; targetStep.Dict[""] = 15; target.Steps.Add(targetStep); TestPlan deserialized; using (var ms = new MemoryStream()) { target.Save(ms); ms.Seek(0, SeekOrigin.Begin); deserialized = TestPlan.Load(ms, target.Path); } var step = deserialized.ChildTestSteps.First() as StringListStep; Assert.IsNotNull(step.TestProp); Assert.AreEqual(targetStep.TestProp.Count, step.TestProp.Count); for (int i = 0; i < targetStep.TestProp.Count; i++) Assert.AreEqual(targetStep.TestProp[i], step.TestProp[i]); Assert.IsTrue(specList.SequenceEqual(step.List.Cast())); Assert.IsTrue(step.EnumSet.Except(hashSet).Count() == 0); Assert.IsTrue(step.Set.OrderBy(x => x).SequenceEqual(targetStep.Set.OrderBy(x => x))); Assert.AreEqual(5, step.Dict["asd"]); Assert.AreEqual(15, step.Dict[""]); } public class InstStep : TestStep { public List Instrs { get; set; } public override void Run() { } } public class SomeotherInstrument : Instrument { } void loadDummyInstruments(int count) { for (int i = 0; i < count; i++) { InstrumentSettings.Current.Add(new ScpiDummyInstrument() { Tag = (i + 1).ToString() }); InstrumentSettings.Current.Add(new SomeotherInstrument()); } } void unloadDummyInstruments() { InstrumentSettings.Current.RemoveIf(instr => instr is ScpiDummyInstrument && ((ScpiDummyInstrument)instr).Tag != null); InstrumentSettings.Current.RemoveIf(instr => instr is SomeotherInstrument); } /// /// Tests deserialization/serialzation of a list of instruments. /// [Test] public void ListInstrumentSerialization() { try { loadDummyInstruments(10); TestPlan target = new TestPlan(); Random rnd = new Random(0); var targetStep = new InstStep { Instrs = InstrumentSettings.Current.OrderBy(item => rnd.Next()).ToList() }; target.Steps.Add(targetStep); using (var ms = new MemoryStream()) { target.Save(ms); ms.Seek(0, SeekOrigin.Begin); TestPlan deserialized = TestPlan.Load(ms, target.Path); var step = deserialized.ChildTestSteps.First() as InstStep; Assert.IsNotNull(step.Instrs); Assert.AreEqual(targetStep.Instrs.Count, step.Instrs.Count); for (int i = 0; i < targetStep.Instrs.Count; i++) Assert.AreEqual(targetStep.Instrs[i], step.Instrs[i]); } } finally { unloadDummyInstruments(); } } public class NestedInstStep : TestStep { public List> Instrs { get; set; } public NestedInstStep() { Instrs = new List>(); } public override void Run() { } } /// /// This test step tests serializing/deserializing a list of lists of instruments. /// Since Instruments are from ComponentSettingsLists, they should all convert to indexes. /// [Test] public void ListListInstrumentSerialization() { loadDummyInstruments(10); try { TestPlan target = new TestPlan(); Random rnd = new Random(0); var randomSeq = InstrumentSettings.Current.OrderBy(item => rnd.Next()); var targetStep = new NestedInstStep { Instrs = new List> { randomSeq.ToList(), randomSeq.ToList(), randomSeq.ToList() } }; target.Steps.Add(targetStep); using (var ms = new MemoryStream()) { target.Save(ms); ms.Seek(0, SeekOrigin.Begin); TestPlan deserialized = TestPlan.Load(ms, target.Path); var step = deserialized.ChildTestSteps.First() as NestedInstStep; Assert.IsNotNull(step.Instrs); Assert.AreEqual(targetStep.Instrs.Count, step.Instrs.Count); for (int i = 0; i < targetStep.Instrs.Count; i++) { Assert.AreEqual(targetStep.Instrs[i].Count, step.Instrs[i].Count); for (int i2 = 0; i2 < targetStep.Instrs[i].Count; i2++) { Assert.AreEqual(targetStep.Instrs[i][i2], step.Instrs[i][i2]); } } } } finally { unloadDummyInstruments(); } } public class DualNestedInstStep : TestStep { public List>> Instrs { get; set; } public DualNestedInstStep() { Instrs = new List>>(); } public override void Run() { } } /// /// This test tests serializing / deserializing of lists of lists of lists of instrments. /// [Test] public void ListListListInstrumentSerialization() { loadDummyInstruments(10); try { TestPlan target = new TestPlan(); Random rnd = new Random(0); var randomSeq = InstrumentSettings.Current.OrderBy(item => rnd.Next()); var targetStep = new DualNestedInstStep { Instrs = new List>> { new List> { randomSeq.ToList(), randomSeq.ToList() }, new List> { randomSeq.ToList(), randomSeq.ToList(), randomSeq.ToList(), randomSeq.ToList() } } }; target.Steps.Add(targetStep); using (var ms = new MemoryStream()) { target.Save(ms); ms.Seek(0, SeekOrigin.Begin); TestPlan deserialized = TestPlan.Load(ms, target.Path); var step = deserialized.ChildTestSteps.First() as DualNestedInstStep; Assert.IsNotNull(step.Instrs); Assert.AreEqual(targetStep.Instrs.Count, step.Instrs.Count); for (int i = 0; i < targetStep.Instrs.Count; i++) { Assert.AreEqual(targetStep.Instrs[i].Count, step.Instrs[i].Count); for (int i2 = 0; i2 < targetStep.Instrs[i].Count; i2++) { Assert.AreEqual(targetStep.Instrs[i][i2].Count, step.Instrs[i][i2].Count); for (int i3 = 0; i3 < targetStep.Instrs[i][i2].Count; i3++) { Assert.AreEqual(targetStep.Instrs[i][i2][i3], step.Instrs[i][i2][i3]); } } } } } finally { unloadDummyInstruments(); } } public class DeserializedCallbackTestStep : TestStep, IDeserializedCallback { public bool WasDeserialized = false; public void OnDeserialized() { WasDeserialized = true; } public override void Run() { } } public class DeserializedCallbackInstrument : Instrument, IDeserializedCallback { public bool WasDeserialized = false; public void OnDeserialized() { WasDeserialized = true; } } [Browsable(false)] public class DeserializedCallbackSettings : ComponentSettings, IDeserializedCallback { public bool WasDeserialized = false; public void OnDeserialized() { WasDeserialized = true; } } [Test] public void TestIDeserializedCallback() { {// test deserializing plan TestPlan plan = new TestPlan(); DeserializedCallbackTestStep step = new DeserializedCallbackTestStep(); plan.ChildTestSteps.Add(step); using (var tmpFile = new MemoryStream()) { plan.Save(tmpFile); tmpFile.Position = 0; plan = TestPlan.Load(tmpFile, plan.Path); } Assert.IsFalse(step.WasDeserialized); step = (DeserializedCallbackTestStep)plan.ChildTestSteps[0]; Assert.IsTrue(step.WasDeserialized); } bool testSerializeStandaloneInstrument = false; if (testSerializeStandaloneInstrument) { // This cannot work, because there is no ComponentSettings referencing inst. // Previously this worked because of an error. // test deserializing instrument DeserializedCallbackInstrument inst = new DeserializedCallbackInstrument(); string xml = new TapSerializer().SerializeToString(inst); var inst2 = (DeserializedCallbackInstrument)new TapSerializer().DeserializeFromString(xml, TypeData.GetTypeData(inst)); Assert.IsTrue(inst2.WasDeserialized); Assert.IsFalse(inst.WasDeserialized); } { // test deserializing settings DeserializedCallbackSettings settings = new DeserializedCallbackSettings(); string xml = new TapSerializer().SerializeToString(settings); var settings2 = (DeserializedCallbackSettings)new TapSerializer().DeserializeFromString(xml, TypeData.GetTypeData(settings)); Assert.IsTrue(settings2.WasDeserialized); Assert.IsFalse(settings.WasDeserialized); } } class PrivateComponentSettingsList : ComponentSettingsList { } [Test] public void SerializeDeserializePrivateType() { var settings = new PrivateComponentSettingsList(); settings.Add(new ScpiDummyInstrument() { VisaAddress = "test" }); var xml = new TapSerializer().SerializeToString(settings); var settings2 = (PrivateComponentSettingsList)(new TapSerializer().DeserializeFromString(xml, TypeData.FromType(typeof(PrivateComponentSettingsList)))); var inst = (ScpiDummyInstrument)settings2[0]; Assert.AreEqual("test", inst.VisaAddress); } [Test] public void SerializeDeserializeNullResource() { IInstrument instr = new ScpiDummyInstrument(); InstrumentSettings.Current.Add(instr); try { ScpiTestStep step = new ScpiTestStep(); step.Instrument = null; var xml = new TapSerializer().SerializeToString(step); Assert.IsTrue(xml.Contains($"")); var deserializedStep = new TapSerializer().DeserializeFromString(xml) as ScpiTestStep; Assert.AreEqual(step.Instrument, deserializedStep.Instrument); } finally { InstrumentSettings.Current.Remove(instr); } } public class StringObject { public string TheString { get; set; } } [Test] public void SerializeDeserializeProblematicString() { { StringBuilder sb = new StringBuilder("test:"); var ser = new TapSerializer(); for (int i = 0; i < 512; i++) sb.Append((char) i); var st = new StringObject() {TheString = sb.ToString()}; var stt = ser.SerializeToString(st); var rev = (StringObject) ser.DeserializeFromString(stt); Assert.IsTrue(string.Compare(st.TheString, rev.TheString) == 0); } { StringBuilder sb = new StringBuilder("test::::"); var ser = new TapSerializer(); for (int i = 0; i < 512; i++) sb.Append((char) i); var st = new StringObject() { TheString = sb.ToString() }; var stt = ser.SerializeToString(st); var rev = (StringObject)ser.DeserializeFromString(stt); Assert.IsTrue(string.Compare(st.TheString, rev.TheString) == 0); } } public class SimpleClass { public SimpleClass(object obj) { } } public class UnbalancedListStep : TestStep { [Display("Tx Command Sequences", "A predefined list of TX command sequences to control the DUT.", Order: 10.2)] public IReadOnlyList ReadOnlyList { get; set; } = new List {new SimpleClass(default), new SimpleClass(default)}.AsReadOnly(); public override void Run() { throw new NotImplementedException(); } } [Test] public void DeserializeUnbalancedList() { using (Session.Create()) { var trace = new EngineUnitTestUtils.TestTraceListener(); Log.AddListener(trace); var plan = new TestPlan(); plan.ChildTestSteps.Add(new UnbalancedListStep()); var ser = new TapSerializer(); var planXml = ser.SerializeToString(plan); CollectionAssert.IsEmpty(ser.Errors); var currentLength = planXml.Length; var itemElem = $"<{nameof(SimpleClass)}>"; // Remove one of the two items from the xml planXml = planXml.Remove(planXml.IndexOf(itemElem, StringComparison.Ordinal), itemElem.Length); // Ensure an element was actually removed Assert.AreEqual(currentLength - itemElem.Length, planXml.Length); var deserializedPlan = ser.DeserializeFromString(planXml) as TestPlan; CollectionAssert.IsEmpty(ser.Errors); // Deserialization should succeed even though we expect an element which was missing Assert.IsTrue( deserializedPlan.ChildTestSteps.First() is UnbalancedListStep s && s.ReadOnlyList.Count == 2, "Expected list to contain 2 element."); Assert.AreEqual(1, trace.WarningMessage.Count); CollectionAssert.Contains(trace.WarningMessage, "Deserialized unbalanced list."); } } } }