// 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 System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
namespace OpenTap.Plugins
{
/// Serializer implementation for TestStep.
public class TestStepSerializer : TapSerializerPlugin
{
/// The order of this serializer.
public override double Order { get { return 1; } }
readonly Dictionary stepLookup = new Dictionary();
/// Tries to find a step based on ID.
internal ITestStep FindStep(Guid id)
{
stepLookup.TryGetValue(id, out var step);
return step;
}
///
/// Guids where duplicate guids should be ignored. Useful when pasting to test plan.
///
readonly HashSet ignoredGuids = new HashSet();
///
/// Adds known steps to the list of tests used for finding references in deserialization.
///
///
public void AddKnownStepHeirarchy(ITestStepParent stepParent)
{
var step = stepParent as ITestStep; // could also be TestPlan.
if (step != null)
{
stepLookup[step.Id] = step;
ignoredGuids.Add(step.Id);
}
foreach (var step2 in stepParent.ChildTestSteps)
AddKnownStepHeirarchy(step2);
}
///
/// Ensures that duplicate step IDs are not present in the test plan and updates an ID->step mapping.
///
/// the step to fix.
/// true if child steps should also be 'fixed'.
public void FixupStep(ITestStep step, bool recurse)
{
if (stepLookup.TryGetValue(step.Id, out ITestStep currentStep) && currentStep != step && !ignoredGuids.Contains(step.Id))
{
bool anyParentReadonly(ITestStep s) => s.GetParents().Any(p => p.ChildTestSteps.IsReadOnly);
step.Id = Guid.NewGuid();
// If any parent of the step's child steps are readonly, this step was likely generated from some other source.
// This could happen e.g. when loading a TestPlanReference to the same test plan twice. In this case,
// we don't want to emit any warnings about duplicate IDs. Just assign the step a new ID and continue.
if (anyParentReadonly(step) == false)
{
if (step is IDynamicStep)
{
// if newStep is an IDynamicStep, we just print in debug.
Log.Debug(
"Duplicate test step ID found in dynamic step. The duplicate ID has been changed for step '{0}'.",
step.Name);
}
else
{
Log.Warning("Duplicate test step ID found. The duplicate ID has been changed for step '{0}'.",
step.Name);
}
}
}
stepLookup[step.Id] = step;
if (recurse == false) return;
foreach(var step2 in step.ChildTestSteps)
{
FixupStep(step2, true);
}
}
/// Deserialization implementation.
public override bool Deserialize( XElement elem, ITypeData t, Action