public void TestConstructorWithAlreadyEndedTransaction() { WeightedTransaction <Transaction> testTransaction = new WeightedTransaction <Transaction>( Transaction.EndedDummy ); IObservationSubscriber subscriber = this.mockery.NewMock <IObservationSubscriber>(); Expect.AtLeast(0).On(subscriber).Method("ProgressUpdated"); // This should no be called because otherwise, the 'Ended' event would be raised // to the transaction group before all transactions have been added into // the internal list, leading to an early ending or even multiple endings. Expect.Never.On(subscriber).Method("Ended"); using ( ObservedWeightedTransaction <Transaction> test = new ObservedWeightedTransaction <Transaction>( testTransaction, new ObservedWeightedTransaction <Transaction> .ReportDelegate( subscriber.ProgressUpdated ), new ObservedWeightedTransaction <Transaction> .ReportDelegate( subscriber.Ended ) ) ) { this.mockery.VerifyAllExpectationsHaveBeenMet(); } }
public void TestConstructorWithEndingTransaction() { WeightedTransaction <Transaction> testTransaction = new WeightedTransaction <Transaction>( new FunkyTransaction() ); IObservationSubscriber subscriber = this.mockery.NewMock <IObservationSubscriber>(); Expect.AtLeast(0).On(subscriber).Method("ProgressUpdated"); Expect.Once.On(subscriber).Method("Ended"); using ( ObservedWeightedTransaction <Transaction> test = new ObservedWeightedTransaction <Transaction>( testTransaction, new ObservedWeightedTransaction <Transaction> .ReportDelegate( subscriber.ProgressUpdated ), new ObservedWeightedTransaction <Transaction> .ReportDelegate( subscriber.Ended ) ) ) { this.mockery.VerifyAllExpectationsHaveBeenMet(); } }
public void TestConstructorWithEndingTransaction() { WeightedTransaction <Transaction> testTransaction = new WeightedTransaction <Transaction>( new FunkyTransaction() ); Mock <IObservationSubscriber> subscriber = this.mockery.CreateMock <IObservationSubscriber>(); subscriber.Expects.AtLeast(0).Method(m => m.ProgressUpdated()); subscriber.Expects.One.Method(m => m.Ended()); using ( ObservedWeightedTransaction <Transaction> test = new ObservedWeightedTransaction <Transaction>( testTransaction, new ObservedWeightedTransaction <Transaction> .ReportDelegate( subscriber.MockObject.ProgressUpdated ), new ObservedWeightedTransaction <Transaction> .ReportDelegate( subscriber.MockObject.Ended ) ) ) { this.mockery.VerifyAllExpectationsHaveBeenMet(); } }
/// <summary>Stops tracking the specified background transaction</summary> /// <param name="transaction">Background transaction to stop tracking of</param> public void Untrack(Transaction transaction) { lock (this.trackedTransactions) { // Locate the object to be untracked in our collection int index; for (index = 0; index < this.trackedTransactions.Count; ++index) { bool same = ReferenceEquals( transaction, this.trackedTransactions[index].WeightedTransaction.Transaction ); if (same) { break; } } if (index == this.trackedTransactions.Count) { throw new ArgumentException("Specified transaction is not being tracked"); } // Remove and dispose the transaction the user wants to untrack { ObservedWeightedTransaction <Transaction> wrappedTransaction = this.trackedTransactions[index]; this.trackedTransactions.RemoveAt(index); wrappedTransaction.Dispose(); } // If the list is empty, then we're back in the idle state if (this.trackedTransactions.Count == 0) { this.totalWeight = 0.0f; // If we entered the idle state with this call, report the state change! setIdle(true); } else { // Rebuild the total weight from scratch. Subtracting the removed transaction's // weight would work, too, but we might accumulate rounding errors making the sum // drift slowly away from the actual value. float newTotalWeight = 0.0f; for (index = 0; index < this.trackedTransactions.Count; ++index) { newTotalWeight += this.trackedTransactions[index].WeightedTransaction.Weight; } this.totalWeight = newTotalWeight; recalculateProgress(); } } // lock }
public void TestWrapperCollection() { WeightedTransaction <Transaction> transaction = new WeightedTransaction <Transaction>( Transaction.EndedDummy ); ObservedWeightedTransaction <Transaction> observed = new ObservedWeightedTransaction <Transaction>( transaction, endedCallback, progressUpdatedCallback ); WeightedTransactionWrapperCollection <Transaction> wrapper = new WeightedTransactionWrapperCollection <Transaction>( new ObservedWeightedTransaction <Transaction>[] { observed } ); Assert.AreSame(transaction, wrapper[0]); }
/// <summary> /// Checks whether the provided transaction matches the comparison /// transaction of the instance /// </summary> /// <param name="other">Transaction to match to the comparison transaction</param> public bool Matches(ObservedWeightedTransaction <Transaction> other) { return(ReferenceEquals(other.WeightedTransaction.Transaction, this.toMatch)); }
/// <summary>Begins tracking the specified background transaction</summary> /// <param name="transaction">Background transaction to be tracked</param> /// <param name="weight">Weight to assign to this background transaction</param> public void Track(Transaction transaction, float weight) { // Add the new transaction into the tracking list. This has to be done // inside a lock to prevent issues with the progressUpdate callback, which could // access the totalWeight field before it has been updated to reflect the // new transaction added to the collection. lock (this.trackedTransactions) { bool wasEmpty = (this.trackedTransactions.Count == 0); if (transaction.Ended) { // If the ended transaction would become the only transaction in the list, // there's no sense in doing anything at all because it would have to be // thrown right out again. Only add the transaction when there are other // running transactions to properly sum total progress for consistency. if (!wasEmpty) { // Construct a new observation wrapper. This is done inside the lock // because as soon as we are subscribed to the events, we can potentially // receive them. The lock eliminates the risk of processing a progress update // before the transaction has been added to the tracked transactions list. this.trackedTransactions.Add( new ObservedWeightedTransaction <Transaction>( new WeightedTransaction <Transaction>(transaction, weight), this.asyncProgressUpdatedDelegate, this.asyncEndedDelegate ) ); } } else // Not ended -- Transaction is still running // Construct a new transation observer and add the transaction to our // list of tracked transactions. { ObservedWeightedTransaction <Transaction> observedTransaction = new ObservedWeightedTransaction <Transaction>( new WeightedTransaction <Transaction>(transaction, weight), this.asyncProgressUpdatedDelegate, this.asyncEndedDelegate ); this.trackedTransactions.Add(observedTransaction); // If this is the first transaction to be added to the list, tell our // owner that we're idle no longer! if (wasEmpty) { setIdle(false); } } // if transaction ended // This can be done after we registered the wrapper to our delegates because // any incoming progress updates will be stopped from the danger of a // division-by-zero from the potentially still zeroed totalWeight by the lock. this.totalWeight += weight; // All done, the total progress is different now, so force a recalculation and // send out the AsyncProgressUpdated event. recalculateProgress(); } // lock }
/// <summary>Transforms an item into the exposed type</summary> /// <param name="item">Item to be transformed</param> /// <returns>The transformed item</returns> /// <remarks> /// This method is used to transform an item in the wrapped collection into /// the exposed item type whenever the user accesses an item. Expect it to /// be called frequently, because the TransformingReadOnlyCollection does /// not cache otherwise store the transformed items. /// </remarks> protected override WeightedTransaction <TransactionType> Transform( ObservedWeightedTransaction <TransactionType> item ) { return(item.WeightedTransaction); }