chr
2026-04-05 fe750b791d5b517cc4e9bc8e99a9a75139a0cfba
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
//            Copyright Keysight Technologies 2012-2019
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, you can obtain one at http://mozilla.org/MPL/2.0/.
using NUnit.Framework;
using System.IO;
using System.Text;
using OpenTap.Plugins.BasicSteps;
using System;
using System.Linq;
using OpenTap.Plugins;
 
namespace OpenTap.Engine.UnitTests
{
    public class MacroFilePathTestStep : TestStep
    {
        public MacroString PathToThing { get; set; }
 
        public string ExpandedString { get; set; }
 
        public MacroFilePathTestStep()
        {
            PathToThing = new MacroString(this);
            ExpandedString = "";
        }
 
        public override void Run()
        {
            ExpandedString = PathToThing.Expand();
        }
    }
 
    [TestFixture]
    public class ExternalTestPlanParameterTest
    {
        [Test]
        public void SetValuesTest()
        {
            var delayStep1 = new DelayStep();
            var delayStep2 = new DelayStep();
            var logStep = new LogStep();
            var logStep2 = new LogStep();
            var fileStep = new MacroFilePathTestStep();
            var fileStep2 = new MacroFilePathTestStep();
            var ifstep = new IfStep();
            
            fileStep.PathToThing.Text = "<TESTPLANDIR>\\asdasd";
            TestPlan plan = new TestPlan();
            plan.ChildTestSteps.Add(delayStep1);
            plan.ChildTestSteps.Add(delayStep2);
            plan.ChildTestSteps.Add(logStep);
            plan.ChildTestSteps.Add(logStep2);
            plan.ChildTestSteps.Add(fileStep);
            plan.ChildTestSteps.Add(fileStep2);
            plan.ChildTestSteps.Add(ifstep);
            ifstep.InputVerdict.Step = delayStep2;
            ifstep.InputVerdict.Property = TypeData.GetTypeData(delayStep1).GetMember("Verdict");
            var delayInfo = TypeData.GetTypeData(delayStep1);
            var logInfo = TypeData.GetTypeData(logStep);
            var fileStepInfo = TypeData.GetTypeData(fileStep);
            plan.ExternalParameters.Add(delayStep1, delayInfo.GetMember("DelaySecs"));
            plan.ExternalParameters.Add(delayStep2, delayInfo.GetMember("DelaySecs"), "Time Delay");
            plan.ExternalParameters.Add(logStep, logInfo.GetMember("Severity"), Name: "Severity");
            plan.ExternalParameters.Add(logStep2, logInfo.GetMember("Severity"), Name: "Severity");
            plan.ExternalParameters.Add(fileStep, fileStepInfo.GetMember("PathToThing"), Name: "Path1");
            plan.ExternalParameters.Add(fileStep2, fileStepInfo.GetMember("PathToThing"), Name: "Path1");
            plan.ExternalParameters.Add(ifstep, TypeData.GetTypeData(ifstep).GetMember(nameof(IfStep.InputVerdict)), Name: "InputVerdict");
            for (int j = 0; j < 5; j++)
            {
                for (double x = 0.01; x < 10; x += 3.14)
                {
                    plan.ExternalParameters.Get("Time Delay").Value = x;
                    Assert.AreEqual(x, delayStep1.DelaySecs);
                    Assert.AreEqual(x, delayStep2.DelaySecs);
                }
 
                plan.ExternalParameters.Get("Severity").Value = LogSeverity.Error;
                Assert.AreEqual(LogSeverity.Error, logStep.Severity);
                Assert.AreEqual(LogSeverity.Error, logStep2.Severity);
                
                plan.ExternalParameters.Get("Path1").Value = plan.ExternalParameters.Get("Path1").Value;
 
                string planstr = null;
                using (var memstream = new MemoryStream())
                {
                    plan.Save(memstream);
                    planstr = Encoding.UTF8.GetString(memstream.ToArray());
                }
                Assert.IsTrue(planstr.Contains(@"Parameter=""Time Delay"""));
                Assert.IsTrue(planstr.Contains(@"Parameter=""Severity"""));
                Assert.IsTrue(planstr.Contains(@"Parameter=""Path1"""));
 
                using (var memstream = new MemoryStream(Encoding.UTF8.GetBytes(planstr)))
                    plan = TestPlan.Load(memstream, planstr);
 
                delayStep1 = (DelayStep)plan.ChildTestSteps[0];
                delayStep2 = (DelayStep)plan.ChildTestSteps[1];
                logStep = (LogStep)plan.ChildTestSteps[2];
                logStep2 = (LogStep)plan.ChildTestSteps[3];
                fileStep = (MacroFilePathTestStep)plan.ChildTestSteps[4];
                fileStep2 = (MacroFilePathTestStep)plan.ChildTestSteps[5];
                ifstep = (IfStep)plan.ChildTestSteps[6];
                Assert.IsTrue(fileStep2.PathToThing.Context == fileStep2);
                Assert.AreEqual(fileStep2.PathToThing.Text, fileStep.PathToThing.Text);
                Assert.AreEqual(delayStep2, ifstep.InputVerdict.Step);
            }
        }
 
        [Test]
        public void SerializeDeserializeWithDutExternalParameter()
        {
            var plan = new TestPlan();
            var step = new TestPlanTest.DutStep();
            var dut1 = new DummyDut {Name = "DUT1"};
            var dut2 = new DummyDut {Name = "DUT2"};
            
            DutSettings.Current.Add(dut1);
            DutSettings.Current.Add(dut2);
            try
            {
                step.Dut = dut1;
                plan.ChildTestSteps.Add(step);
                plan.ExternalParameters.Add(step,
                    TypeData.GetTypeData(step).GetMember(nameof(TestPlanTest.DutStep.Dut)), "dut");
 
                using (var memstr = new MemoryStream())
                {
                    plan.Save(memstr);
                    
                    var serializer = new TapSerializer();
                    var ext = serializer.GetSerializer<ExternalParameterSerializer>();
                    ext.PreloadedValues["dut"] = "DUT2";
 
                    memstr.Seek(0, SeekOrigin.Begin);
                    plan = (TestPlan)serializer.Deserialize(memstr);
                }
 
                step = (TestPlanTest.DutStep) plan.ChildTestSteps[0];
                Assert.AreEqual(step.Dut, dut2);
            }
            finally
            {
                DutSettings.Current.Remove(dut1);
                DutSettings.Current.Remove(dut2);
            }
 
        }
 
 
        [Test]
        public void TestParameterizedVerdictOf()
        {
            // Create the test plan
            var plan = new TestPlan();
            var seq = new SequenceStep();
            var repeat = new RepeatStep();
            plan.ChildTestSteps.Add(seq);
            seq.ChildTestSteps.Add(repeat);
 
            var a = AnnotationCollection.Annotate(repeat);
 
            void VerifyAvailable(AnnotationCollection mem)
            {
                // Verify the expected available values for the member
                var avail = mem.Get<IAvailableValuesAnnotation>().AvailableValues.Cast<object>().ToArray();
                Assert.AreEqual(2, avail.Length);
                Assert.IsTrue(avail.Contains(seq));
                Assert.IsTrue(avail.Contains(repeat));
            }
            
            var mem = a.GetMember(nameof(repeat.TargetStep));
            VerifyAvailable(mem);
 
            { // Parameterize the member on the parent step
                var parameterize = mem.Get<MenuAnnotation>().MenuItems.FirstOrDefault(x =>
                    x.Get<IconAnnotationAttribute>()?.IconName == IconNames.ParameterizeOnParent);
                parameterize.Get<IMethodAnnotation>().Invoke();
 
                mem = AnnotationCollection.Annotate(seq).GetMember(@"Parameters \ Verdict Of");
                VerifyAvailable(mem);
                
                var unparameterize = mem.Get<MenuAnnotation>().MenuItems.FirstOrDefault(x =>
                    x.Get<IconAnnotationAttribute>()?.IconName == IconNames.Unparameterize);
                unparameterize.Get<IMethodAnnotation>().Invoke();
            }
 
            { // Parameterize the member on the test plan
                var parameterize = mem.Get<MenuAnnotation>().MenuItems.FirstOrDefault(x =>
                    x.Get<IconAnnotationAttribute>()?.IconName == IconNames.ParameterizeOnTestPlan);
                parameterize.Get<IMethodAnnotation>().Invoke();
 
                mem = AnnotationCollection.Annotate(plan).GetMember(@"Parameters \ Verdict Of");
                VerifyAvailable(mem);
            }
        }
 
        private void GenerateTestPlanWithNDelaySteps(int stepsCount, string filePath, double defaultValue, string externalParameterName)
        {
            Assert.IsTrue(stepsCount > 0);
 
            // Create a test plan with two DelaySteps.
            // Each of the DelaySteps will expose a it's delay property as an external parameter.
            TestPlan plan = new TestPlan();
 
            for (int i = 0; i < stepsCount; i++)
            {
                var delayStep = new DelayStep { DelaySecs = defaultValue };
                plan.ChildTestSteps.Add(delayStep);
                var delayInfo = TypeData.GetTypeData(delayStep);
                plan.ExternalParameters.Add(delayStep, delayInfo.GetMember("DelaySecs"), externalParameterName);
            }
 
            // Write the test plan to a file
            plan.Save(filePath);
        }
 
        [Test]
        public void SettingOfExternalParametersOnTestReferencePlan()
        {
            double defaultValue = 0.7; //seconds
            double newValue = 7.0; //seconds            
            //double tolerance = Math.Abs(newValue * .0000001); // The tolerance for variation in their delay double values
            int stepsCount = 20; // how many delay steps should be generated and tested
            string externalParameterName = "External Delay";
            string filePath = System.IO.Path.GetTempPath() + Guid.NewGuid().ToString() + ".TapPlan";
            
            GenerateTestPlanWithNDelaySteps(stepsCount, filePath, defaultValue, externalParameterName);
 
            try
            {
                // Create a test plan
                TestPlan testPlan = new TestPlan();
 
                // Create a ReferencePlanStep and add it to the test plan
                TestPlanReference tpr = new TestPlanReference();
                MacroString ms = new MacroString(tpr) { Text = filePath };
                tpr.Filepath = ms; // automatically calls LoadTesPlan
                testPlan.ChildTestSteps.Add(tpr);
 
                Assert.AreEqual(1, testPlan.ChildTestSteps.Count);
                Assert.AreEqual(stepsCount, tpr.ChildTestSteps.Count);
 
                // ----------------------------------------------------------------------------------------------------
                // This is how to get access to a TestPlanReference loaded test plan's children's external paramters:
                ITypeData ti = TypeData.GetTypeData(tpr);
                // IMemberInfo mi = ti.GetMember(externalParameterName); <- not possible to get property by its name in case the property name contains characters not valid of a C# property name
                IMemberData mi = ti.GetMembers().FirstOrDefault(m => m.Attributes.Any(xa => (xa as IDisplayAnnotation)?.Name == externalParameterName)); // <- the right approach              
                // ----------------------------------------------------------------------------------------------------
 
                Assert.IsNotNull(mi);
                Assert.AreEqual(defaultValue, mi.GetValue(tpr));
                mi.SetValue(tpr, newValue);
 
                // Test that the new value has been set on all the inner delay steps
                for (int i = 0; i < stepsCount; i++)
                {
                    DelayStep delayStep = tpr.ChildTestSteps[i] as DelayStep;
                    Assert.IsNotNull(delayStep);
                    //Assert.IsTrue(Math.Abs(newValue - delayStep.DelaySecs) <= tolerance);
                    Assert.AreEqual(newValue, delayStep.DelaySecs);
                }
            }
            finally
            {
                // delete the temporary file in the end
                if(File.Exists(filePath))
                {
                    File.Delete(filePath);
                }
            }
        }
 
        [Test]
        public void SaveAndLoadTestPlanReference()
        {
            double defaultValue = 0.7; //seconds   
            //double tolerance = Math.Abs(newValue * .0000001); // The tolerance for variation in their delay double values
            int stepsCount = 1; // how many delay steps should be generated and tested
            string externalParameterName = "External Delay";
            string externalParamaterNameEncoded = "External_x0020_Delay";
            string externalParamaterNameLegacy = "prop0";
            string filePath1 = System.IO.Path.GetTempPath() + Guid.NewGuid().ToString() + ".TapPlan";
            string filePath2 = System.IO.Path.GetTempPath() + Guid.NewGuid().ToString() + ".TapPlan";
            string filePath3 = System.IO.Path.GetTempPath() + Guid.NewGuid().ToString() + ".TapPlan";
 
            try
            {
                // Save the test plan to be referenced
                GenerateTestPlanWithNDelaySteps(stepsCount, filePath1, defaultValue, externalParameterName);
 
                // Scope for separating the test Serialization (Save) from Deserialization (Load)
                {
                    // Create a test plan
                    TestPlan testPlan = new TestPlan();
 
                    // Create a ReferencePlanStep and add it to the test plan
                    TestPlanReference tpr = new TestPlanReference();
                    MacroString ms = new MacroString(tpr) { Text = filePath1 };
                    tpr.Filepath = ms; // automatically calls LoadTesPlan
                    testPlan.ChildTestSteps.Add(tpr);
 
                    // Save the new test plan
                    testPlan.Save(filePath2);
 
                    // The output should be something like this, remark the "External Delay" has been encoded as "External_x0020_Delay"
                    //<?xml version=\"1.0\" encoding=\"utf-8\"?>
                    //<TestPlan type=\"OpenTap.TestPlan\" Locked=\"false\">
                    //  <Steps>
                    //    <TestStep type=\"ref@OpenTap.Plugins.BasicSteps.TestPlanReference\" Version=\"9.0.0-Development\" Id=\"ae56d9d6-e077-4524-bd14-cb0c9f2d4ced\">
                    //      <External_x0020_Delay>0.7</External_x0020_Delay>
                    //      <Filepath>%TEMP%\\e7563ab3-d5e2-4e27-bc77-1f9b76feb37c.TapPlan</Filepath>
                    //      <StepMapping />
                    //      <Enabled>true</Enabled>
                    //      <Name>Test Plan Reference</Name>
                    //    </TestStep>
                    //  </Steps>
                    //  <Package.Dependencies>
                    //    <Package Name=\"OpenTAP\" Version=\"9.0.0+15a61e86\" />
                    //  </Package.Dependencies>
                    //</TestPlan>
 
                    // Verify that the saved file contains the encoded elements
                    using (var str = File.Open(filePath2, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
                    {
                        using (var read = new StreamReader(str))
                        {
                            string content = read.ReadToEnd();
                            Assert.IsTrue(content.Contains($"<{externalParamaterNameEncoded}>"));
                            Assert.IsTrue(content.Contains($"</{externalParamaterNameEncoded}>"));
                            Assert.IsFalse(content.Contains($"<{externalParameterName}>"));
                            Assert.IsFalse(content.Contains($"</{externalParameterName}>"));
                            Assert.IsFalse(content.Contains($"<{externalParamaterNameLegacy}>"));
                            Assert.IsFalse(content.Contains($"</{externalParamaterNameLegacy}>"));
                        }
                    }
                }
 
                // Scope for separating the test Deserialization (Load) from Serialization (Save)
                {
                    TestPlan testPlan = TestPlan.Load(filePath2);
                    Assert.AreEqual(1, testPlan.ChildTestSteps.Count);
                    TestPlanReference tpr = testPlan.ChildTestSteps[0] as TestPlanReference;
                    Assert.IsNotNull(tpr);
 
                    ITypeData ti = TypeData.GetTypeData(tpr);
 
                    // ensure there is a property "External Delay"
                    IMemberData mi = ti.GetMembers().FirstOrDefault(m => m.Attributes.Any(xa => (xa as IDisplayAnnotation)?.Name == externalParameterName));
                    Assert.IsNotNull(mi);
                    Assert.AreEqual(defaultValue, mi.GetValue(tpr));
 
                    // ensure there is no property "External_x0020_Delay"
                    Assert.IsNull(ti.GetMembers().FirstOrDefault(m => m.Attributes.Any(xa => (xa as IDisplayAnnotation)?.Name == externalParamaterNameEncoded)));
                    
                    // ensure there is no property "prop0"
                    Assert.IsNull(ti.GetMembers().FirstOrDefault(m => m.Attributes.Any(xa => (xa as IDisplayAnnotation)?.Name == externalParamaterNameLegacy)));
                }
 
                // Scope for separating the test Deserialization legacy (Load) from Serialization (Save)
                {
                    // Replace 
                    string content = "";
                    using (var str = File.Open(filePath2, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
                    {
                        using (var read = new StreamReader(str))
                        {
                            content = read.ReadToEnd();
                        }
                    }
 
                    Assert.IsTrue(content.Contains($"<{externalParamaterNameEncoded}>"));
                    Assert.IsTrue(content.Contains($"</{externalParamaterNameEncoded}>"));
                    Assert.IsFalse(content.Contains($"<{externalParameterName}>"));
                    Assert.IsFalse(content.Contains($"</{externalParameterName}>"));
                    Assert.IsFalse(content.Contains($"<{externalParamaterNameLegacy}>"));
                    Assert.IsFalse(content.Contains($"</{externalParamaterNameLegacy}>"));
 
                    content = content.Replace(externalParamaterNameEncoded, externalParamaterNameLegacy);
                        
                    Assert.IsFalse(content.Contains($"<{externalParamaterNameEncoded}>"));
                    Assert.IsFalse(content.Contains($"</{externalParamaterNameEncoded}>"));
                    Assert.IsFalse(content.Contains($"<{externalParameterName}>"));
                    Assert.IsFalse(content.Contains($"</{externalParameterName}>"));
                    Assert.IsTrue(content.Contains($"<{externalParamaterNameLegacy}>"));
                    Assert.IsTrue(content.Contains($"</{externalParamaterNameLegacy}>"));
 
                    Assert.IsFalse(File.Exists(filePath3));
                    using (var str = File.Open(filePath3, FileMode.Create, FileAccess.Write, FileShare.ReadWrite))
                    {
                        using (var write = new StreamWriter(str))
                        {
                             write.Write(content);
                        }
                    }
                    Assert.IsTrue(File.Exists(filePath3));
 
                    // Load the test case and its test ref
                    TestPlan testPlan = TestPlan.Load(filePath3);
                    Assert.AreEqual(1, testPlan.ChildTestSteps.Count);
                    TestPlanReference tpr = testPlan.ChildTestSteps[0] as TestPlanReference;
                    Assert.IsNotNull(tpr);
 
                    ITypeData ti = TypeData.GetTypeData(tpr);
 
                    // ensure there is a property "External Delay"
                    IMemberData mi = ti.GetMembers().FirstOrDefault(m => m.Attributes.Any(xa => (xa as IDisplayAnnotation)?.Name == externalParameterName));
                    Assert.IsNotNull(mi);
                    Assert.AreEqual(defaultValue, mi.GetValue(tpr));
 
                    // ensure there is no property "External_x0020_Delay"
                    Assert.IsNull(ti.GetMembers().FirstOrDefault(m => m.Attributes.Any(xa => (xa as IDisplayAnnotation)?.Name == externalParamaterNameEncoded)));
 
                    // ensure there is no property "prop0"
                    Assert.IsNull(ti.GetMembers().FirstOrDefault(m => m.Attributes.Any(xa => (xa as IDisplayAnnotation)?.Name == externalParamaterNameLegacy)));
                }
            }
            finally
            {
                if (File.Exists(filePath1))
                {
                    File.Delete(filePath1);
                }
                if (File.Exists(filePath2))
                {
                    File.Delete(filePath2);
                }
                if (File.Exists(filePath3))
                {
                    File.Delete(filePath3);
                }
            }
        }
 
        [Test]
        public void SaveAndLoadExternalScopeParameters()
        {
            var plan = new TestPlan();
            var sequence = new SequenceStep();
            var delay = new DelayStep();
            plan.Steps.Add(sequence);
            sequence.ChildTestSteps.Add(delay);
            var newmember = TypeData.GetTypeData(delay).GetMember(nameof(DelayStep.DelaySecs))
                .Parameterize(sequence, delay, nameof(DelayStep.DelaySecs));
            var fwd = newmember.Parameterize(plan, sequence, nameof(DelayStep.DelaySecs));
            
            Assert.AreEqual(1, plan.ExternalParameters.Entries.Count);
            var xml = plan.SerializeToString();
            var newplan = Utils.DeserializeFromString<TestPlan>(xml);
            
            Assert.AreEqual(1, newplan.ExternalParameters.Entries.Count);
        }
 
        [Test]
        public void MultiSelectEditParametersDisabled()
        {
            var plan = new TestPlan();
 
            var sequence = new SequenceStep();    
            var delay = new DelayStep();
            plan.Steps.Add(sequence);
            sequence.ChildTestSteps.Add(delay);
 
            var p1 = TypeData.GetTypeData(delay).GetMember(nameof(DelayStep.DelaySecs))
                .Parameterize(sequence, delay, nameof(DelayStep.DelaySecs));
 
            var sequence2 = new SequenceStep();    
            var delay2 = new DelayStep();
            plan.Steps.Add(sequence2);
            sequence2.ChildTestSteps.Add(delay2);
            
            var p2 = TypeData.GetTypeData(delay2).GetMember(nameof(DelayStep.DelaySecs))
                .Parameterize(sequence2, delay2, nameof(DelayStep.DelaySecs));
            
            
            Assert.NotNull(p1);
            Assert.NotNull(p2);
 
            var models = new ITestStepParent[][]
            {
                new ITestStepParent[] {sequence, sequence2},
                new ITestStepParent[] {sequence},
                new ITestStepParent[] {sequence2}
            };
 
            foreach (var stepModel in models)
            {
                var stepsModel = AnnotationCollection.Annotate(stepModel);
                var delayAnnotation = stepsModel.GetMember(nameof(DelayStep.DelaySecs));
                var menu = delayAnnotation.Get<MenuAnnotation>();
                var edit = menu.MenuItems.FirstOrDefault(x =>
                    x.Get<IconAnnotationAttribute>()?.IconName == IconNames.EditParameter);
 
                var access = edit.Get<IAccessAnnotation>();
                
                Assert.AreEqual(access.IsVisible, stepModel.Length == 1);
            }            
        }
        
        [Test]
        public void ExternalParametersPlusReloadPlugins()
        {
            var plan = new TestPlan();
            var delay = new DelayStep();
            plan.ChildTestSteps.Add(delay);
            
            var preMember = TypeData.GetTypeData(delay).GetMember(nameof(DelayStep.DelaySecs))
                .Parameterize(plan, delay, nameof(DelayStep.DelaySecs));
            
            var xmlPreSearch = plan.SerializeToString();
            
            // searching for plugins should not affect serialization.
            PluginManager.Search();
            var xmlPostSearch = plan.SerializeToString();
            
            Assert.AreEqual(xmlPreSearch, xmlPostSearch);
        }
    }
}