/// <summary> /// Creates a new <see cref="AdGroupCriterion"/> configured for an /// <code>ADD</code> operation. /// </summary> /// <param name="node">The node whose criterion should be added.</param> /// <param name="adGroupId">The ad group ID of the criterion.</param> /// <param name="idGenerator">The temporary ID generator for new nodes.</param> /// <returns>An <see cref="AdGroupCriterion"/> object for <code>ADD</code> /// operation.</returns> internal static AdGroupCriterion CreateCriterionForAdd(ProductPartitionNode node, long adGroupId, TemporaryIdGenerator idGenerator) { PreconditionUtilities.CheckNotNull(node, ShoppingMessages.NodeCannotBeNull); AdGroupCriterion adGroupCriterion; if (node.IsExcludedUnit) { adGroupCriterion = new NegativeAdGroupCriterion(); } else { adGroupCriterion = new BiddableAdGroupCriterion() { biddingStrategyConfiguration = node.GetBiddingConfig() }; } adGroupCriterion.adGroupId = adGroupId; adGroupCriterion.criterion = node.GetCriterion(); adGroupCriterion.criterion.id = node.ProductPartitionId; if (node.Parent != null) { (adGroupCriterion.criterion as ProductPartition).parentCriterionId = node.Parent.ProductPartitionId; } return adGroupCriterion; }
public void TestDoesNotGeneratePositiveId() { int startId = -1; TemporaryIdGenerator generator = new TemporaryIdGenerator(startId); Assert.Throws<ApplicationException>(delegate() { long next = generator.Next; }); }
public void TestNextWithStartId() { int startId = -20; TemporaryIdGenerator generator = new TemporaryIdGenerator(startId); Assert.That(generator.Next == startId); Assert.That(generator.Next == startId + 1); }
public void TestThrowsExceptionWithPositiveStartId() { int startId = 20; Assert.Throws<ArgumentException>(delegate() { TemporaryIdGenerator generator = new TemporaryIdGenerator(startId); }); startId = 0; Assert.Throws<ArgumentException>(delegate() { TemporaryIdGenerator generator = new TemporaryIdGenerator(startId); }); }
/// <summary> /// Creates ADD operations for the node and ALL of its children. /// </summary> /// <param name="node">The node.</param> /// <param name="idGenerator">The temporary ID generator for new nodes.</param> /// <returns>A list of operation pair for the specified operation and nodes. /// </returns> private List<OperationPair> CreateAddOperations(ProductPartitionNode node, TemporaryIdGenerator idGenerator) { AdGroupCriterionOperation addOp = new AdGroupCriterionOperation(); addOp.@operator = Operator.ADD; // Overwrite the ID set by the user when doing ADD operations. This // minimizes the chances of a malformed tree. node.ProductPartitionId = idGenerator.Next; addOp.operand = ProductPartitionNodeAdapter.CreateCriterionForAdd(node, adGroupId, idGenerator); List<OperationPair> operationsList = new List<OperationPair>(); operationsList.Add(new OperationPair(node, addOp)); // Recursively add all of this node's children to the operations list. foreach (ProductPartitionNode child in node.Children) { operationsList.AddRange(CreateAddOperations(child, idGenerator)); } return operationsList; }
/// <summary> /// Adds to the operations list all operations required to mutate /// <paramref name="originalNode"/> to the state* of /// <paramref name="newNode"/>. /// </summary> /// <param name="originalNode">The original node.</param> /// <param name="newNode">The new node.</param> /// <param name="ops">The operations list to add to.</param> /// <param name="idGenerator">The temporary ID generator for ADD operations.</param> /// <returns>The set of child product dimensions that require further /// processing.</returns> private void AddMutateOperations(ProductPartitionNode originalNode, ProductPartitionNode newNode, List<OperationPair> ops, TemporaryIdGenerator idGenerator) { NodeDifference nodeDifference = Diff(originalNode, newNode, dimensionComparator); bool isProcessChildren; switch (nodeDifference) { case NodeDifference.NEW_NODE: ops.AddRange(CreateAddOperations(newNode, idGenerator)); // No need to further process children. The ADD operations above will include operations // for all children of newNode. isProcessChildren = false; break; case NodeDifference.REMOVED_NODE: ops.Add(CreateRemoveOperation(originalNode)); // No need to further process children. The REMOVE operation above will perform a // cascading delete of all children of newNode. isProcessChildren = false; break; case NodeDifference.PARTITION_TYPE_CHANGE: case NodeDifference.EXCLUDED_UNIT_CHANGE: ops.Add(CreateRemoveOperation(originalNode)); ops.AddRange(CreateAddOperations(newNode, idGenerator)); // No need to further process children. The ADD operations above will include operations // for all children of newNode. isProcessChildren = false; break; case NodeDifference.BID_CHANGE: // Ensure that the new node has the proper ID (this may have been lost if the node // was removed and then re-added). newNode.ProductPartitionId = originalNode.ProductPartitionId; ops.Add(CreateSetBidOperation(newNode)); // Process the children of newNode. The SET operation above will only handle changes // made to newNode, not its children. isProcessChildren = true; break; case NodeDifference.NONE: // Ensure that the new node has the proper ID (this may have been lost if the node // was removed and then re-added). newNode.ProductPartitionId = originalNode.ProductPartitionId; // This node does not have changes, but its children may. isProcessChildren = true; break; default: throw new InvalidOperationException("Unrecognized difference: " + nodeDifference); } if (isProcessChildren) { // Try to match the children in new and original trees to identify the // matching dimensions. foreach (ProductPartitionNode newChild in newNode.Children) { if (originalNode.HasChild(newChild.Dimension)) { // this is probably an edit. AddMutateOperations(originalNode.GetChild(newChild.Dimension), newChild, ops, idGenerator); } else { // this is a new node. AddMutateOperations(null, newChild, ops, idGenerator); } } foreach (ProductPartitionNode originalChild in originalNode.Children) { if (newNode.HasChild(originalChild.Dimension)) { // this is probably an edit. We dealt with it before continue; } else { // this is a removed node. AddMutateOperations(originalChild, null, ops, idGenerator); } } } }
/// <summary> /// Creates and returns the pairs of node/operation that will apply the /// changes made to this tree. /// </summary> /// <returns>The list of operation pairs.</returns> internal List<OperationPair> CreateMutateOperationPairs() { TemporaryIdGenerator idGenerator = new TemporaryIdGenerator(); List<OperationPair> ops = new List<OperationPair>(); AddMutateOperations(this.originalRoot, this.root, ops, idGenerator); return ops; }
public void TestNextWithDefaultValues() { TemporaryIdGenerator generator = new TemporaryIdGenerator(); Assert.That(generator.Next == Int32.MinValue); Assert.That(generator.Next == Int32.MinValue + 1); }