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 of
is defined, that method will obtain a newOrdinal
s produced by invoking *next
andnextNewOldPair
on the currentOrdinal
. * ** Instances of this class are thread safe. Multiple threads can invoke
nextOrdinal
* andnextTracker
concurrently. This facilitates multi-threaded tests that send *infoProvided
reports concurrently. When using aDispatcher
to execute * suites in parallel, the intention is that eachTracker
will only be used by one * thread. For example, if the optionalDispatcher
passed toSuite
's implementation * of runNestedSuitesTracker
by invoking *nextTracker
for each nested suite it passes to theDispatcher
. * * * @param firstOrdinal the firstOrdinal
in the series ofOrdinal
s * 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 nextOrdinal
in the series tracked by thisTracker
. * ** This method saves the current
* * @return the nextOrdinal
in a local variable, reassigns the currentOrdinal
* with the value returned by invokingnextOrdinal
on the savedOrdinal
, then * returns the savedOrdinal
. As a result, if this method is invoked immediately after construction, * this method will return theOrdinal
passed asfirstOrdinal
. *Ordinal
in the series */ def nextOrdinal(): Ordinal = { synchronized { val ordinalToReturn = currentOrdinal currentOrdinal = currentOrdinal.next ordinalToReturn } } /** * Returns aTracker
initialized with the first element in the tuple returned by invoking *nextNewOldPair
on the currentOrdinal
, and reassigns the currentOrdinal
* with the second element that was returned by thenextNewOldPair
invocation. * ** The
* * @return the nextOrdinal
series of the returnedTracker
will be placed after all the *Ordinal
s previously returned by invokingnextOrdinal
on thisTracker
and * before all theOrdinal
s subsequently returned by invokingnextOrdinal
on * thisTracker
in the future. This method is intended to be used when executing nested suites * in parallel. Each nested suite passed to theDistributor
will get its ownTracker
* obtained by invokingnextTracker
on the current thread'sTracker
. *Tracker
in 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 }