org.scalatest.Tracker.scala Maven / Gradle / Ivy
/* * Copyright 2001-2013 Artima, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.scalatest import org.scalatest.events.Ordinal // Note: The reason Tracker is mutable is that methods would have to pass back, and that's hard because exceptions can // also be thrown. So this mutable object is how methods invoked "returns" updates to the current ordinal whether those // methods return normally or complete abruptly with an exception. Also, sometimes with closures capturing free variables, // those free variables may want to grab an ordinal in the context of a callee even after the callee has already called // some other method. So in other words the calling method may need to know the "current ordinal" even before the method // it calls has completed in any manner, i.e., while it is running. (The example is the info stuff in FunSuite, which sets // up an info that's useful during a run, then calls super.run(...). /** * Class that tracks the progress of a series ofis defined, that method will obtain a newOrdinals produced by invoking *nextandnextNewOldPairon the currentOrdinal. * ** Instances of this class are thread safe. Multiple threads can invoke
nextOrdinal* andnextTrackerconcurrently. This facilitates multi-threaded tests that send *infoProvidedreports concurrently. When using aDispatcherto execute * suites in parallel, the intention is that eachTrackerwill only be used by one * thread. For example, if the optionalDispatcherpassed toSuite's implementation * of runNestedSuitesTrackerby invoking *nextTrackerfor each nested suite it passes to theDispatcher. * * * @param firstOrdinal the firstOrdinalin the series ofOrdinals * tracked by thisTracker, which will be used to initialize thisTracker's * currentOrdinal. * * @author Bill Venners */ final class Tracker(firstOrdinal: Ordinal = new Ordinal(0)) { private var currentOrdinal = firstOrdinal /** * Returns the nextOrdinalin the series tracked by thisTracker. * ** This method saves the current
* * @return the nextOrdinalin a local variable, reassigns the currentOrdinal* with the value returned by invokingnextOrdinalon the savedOrdinal, then * returns the savedOrdinal. As a result, if this method is invoked immediately after construction, * this method will return theOrdinalpassed asfirstOrdinal. *Ordinalin the series */ def nextOrdinal(): Ordinal = { synchronized { val ordinalToReturn = currentOrdinal currentOrdinal = currentOrdinal.next ordinalToReturn } } /** * Returns aTrackerinitialized with the first element in the tuple returned by invoking *nextNewOldPairon the currentOrdinal, and reassigns the currentOrdinal* with the second element that was returned by thenextNewOldPairinvocation. * ** The
* * @return the nextOrdinalseries of the returnedTrackerwill be placed after all the *Ordinals previously returned by invokingnextOrdinalon thisTrackerand * before all theOrdinals subsequently returned by invokingnextOrdinalon * thisTrackerin the future. This method is intended to be used when executing nested suites * in parallel. Each nested suite passed to theDistributorwill get its ownTracker* obtained by invokingnextTrackeron the current thread'sTracker. *Trackerin this series */ def nextTracker(): Tracker = { synchronized { val (nextForNewThread, nextForThisThread) = currentOrdinal.nextNewOldPair currentOrdinal = nextForThisThread new Tracker(nextForNewThread) } } } object Tracker { private val defaultTracker = new Tracker() def default: Tracker = defaultTracker }