diff --git a/README.md b/README.md index f4d1e94..f61efff 100644 --- a/README.md +++ b/README.md @@ -10,8 +10,7 @@ import de.retest.guistatemachine.api.GuiStateMachineSerializer import de.retest.recheck.ui.descriptors.SutState import de.retest.surili.commons.actions.NavigateToAction -val stateMachineId = GuiStateMachineApi().createStateMachine() -val stateMachine = GuiStateMachineApi().getStateMachine(stateMachineId).get +val stateMachine = GuiStateMachineApi().createStateMachine("test") val currentState = new SutState(currentDescriptors) val action = new NavigateToAction("http://google.com") val nextState = new SutState(nextDescriptors) diff --git a/src/main/scala/de/retest/guistatemachine/api/ActionTransitions.scala b/src/main/scala/de/retest/guistatemachine/api/ActionTransitions.scala index 14a4fe4..b1c9d5f 100644 --- a/src/main/scala/de/retest/guistatemachine/api/ActionTransitions.scala +++ b/src/main/scala/de/retest/guistatemachine/api/ActionTransitions.scala @@ -1,7 +1,7 @@ package de.retest.guistatemachine.api /** - * Represents transitions for one single symbol which is represented by an `de.retest.surili.model.Action` to a number of states. + * Represents transitions for one single symbol which is represented by an `de.retest.surili.commons.actions.Action` to a number of states. * The corresponding symbol is not stored in this class but in the [[State]] from which the transitions are started. * * @param to The states which the transitions lead to. Since it is a NFA, there can be multiple states for the same symbol. diff --git a/src/main/scala/de/retest/guistatemachine/api/GuiStateMachineApi.scala b/src/main/scala/de/retest/guistatemachine/api/GuiStateMachineApi.scala index 65f57d0..5c7e1ec 100644 --- a/src/main/scala/de/retest/guistatemachine/api/GuiStateMachineApi.scala +++ b/src/main/scala/de/retest/guistatemachine/api/GuiStateMachineApi.scala @@ -12,23 +12,23 @@ trait GuiStateMachineApi { * * @return The new GUI state machine. */ - def createStateMachine(): Id + def createStateMachine(name: String): GuiStateMachine /** * Removes an existing [[GuiStateMachine]]. * - * @param id The ID of the GUI state machine. + * @param name The name of the GUI state machine. * @return True if it existed and was removed by this call. Otherwise, false. */ - def removeStateMachine(id: Id): Boolean + def removeStateMachine(name: String): Boolean /** * Gets an existing [[GuiStateMachine]]. * - * @param id The ID of the GUI state machine. + * @param name The name of the GUI state machine. * @return The existing GUI state machine or nothing. */ - def getStateMachine(id: Id): Option[GuiStateMachine] + def getStateMachine(name: String): Option[GuiStateMachine] /** * Clears all state machines. diff --git a/src/main/scala/de/retest/guistatemachine/api/Id.scala b/src/main/scala/de/retest/guistatemachine/api/Id.scala deleted file mode 100644 index 91e1ed7..0000000 --- a/src/main/scala/de/retest/guistatemachine/api/Id.scala +++ /dev/null @@ -1,7 +0,0 @@ -package de.retest.guistatemachine.api - -@SerialVersionUID(1L) -case class Id(id: Long) extends Ordered[Id] with Serializable { - - override def compare(that: Id): Int = this.id compare that.id -} diff --git a/src/main/scala/de/retest/guistatemachine/api/impl/GuiStateMachineApiImpl.scala b/src/main/scala/de/retest/guistatemachine/api/impl/GuiStateMachineApiImpl.scala index 74466d8..13d193d 100644 --- a/src/main/scala/de/retest/guistatemachine/api/impl/GuiStateMachineApiImpl.scala +++ b/src/main/scala/de/retest/guistatemachine/api/impl/GuiStateMachineApiImpl.scala @@ -1,18 +1,24 @@ package de.retest.guistatemachine.api.impl -import de.retest.guistatemachine.api.{GuiStateMachine, GuiStateMachineApi, Id} +import de.retest.guistatemachine.api.{GuiStateMachine, GuiStateMachineApi} + +import scala.collection.concurrent.TrieMap /** - * Thread-safe implementation of the API. It is thread-safe because it uses `IdMap`. + * Thread-safe implementation of the API. */ class GuiStateMachineApiImpl extends GuiStateMachineApi { - private val stateMachines = IdMap[GuiStateMachine]() + private val stateMachines = TrieMap[String, GuiStateMachine]() - override def createStateMachine(): Id = stateMachines.addNewElement(new GuiStateMachineImpl) + override def createStateMachine(name: String): GuiStateMachine = { + val guiStateMachine = new GuiStateMachineImpl + stateMachines += (name -> guiStateMachine) + guiStateMachine + } - override def removeStateMachine(id: Id): Boolean = stateMachines.removeElement(id) + override def removeStateMachine(name: String): Boolean = stateMachines.remove(name).isDefined - override def getStateMachine(id: Id): Option[GuiStateMachine] = stateMachines.getElement(id) + override def getStateMachine(name: String): Option[GuiStateMachine] = stateMachines.get(name) override def clear(): Unit = stateMachines.clear() } diff --git a/src/main/scala/de/retest/guistatemachine/api/impl/IdMap.scala b/src/main/scala/de/retest/guistatemachine/api/impl/IdMap.scala deleted file mode 100644 index deb969c..0000000 --- a/src/main/scala/de/retest/guistatemachine/api/impl/IdMap.scala +++ /dev/null @@ -1,63 +0,0 @@ -package de.retest.guistatemachine.api.impl - -import de.retest.guistatemachine.api.Id - -import scala.collection.mutable.HashMap - -/** - * This custom type allows storing values using [[Id]] as key. We cannot extend immutable maps in Scala, so we have to - * keep it as field. The implementation is thread-safe. - */ -@SerialVersionUID(1L) -case class IdMap[T]() extends Serializable { - private type HashMapType = HashMap[Id, T] - - private val values = new HashMapType - - def addNewElement(v: T): Id = this.synchronized { - val generatedId = generateId() - values += (generatedId -> v) - generatedId - } - - def removeElement(id: Id): Boolean = this.synchronized { - if (values.contains(id)) { - values -= id - true - } else { - false - } - } - - def getElement(id: Id): Option[T] = this.synchronized { values.get(id) } - - def hasElement(id: Id): Boolean = this.synchronized { values.contains(id) } - - def clear(): Unit = this.synchronized { values.clear() } - - def size: Int = this.synchronized { values.size } - - /** - * Generates a new ID based on the existing entries. - */ - private def generateId(): Id = { - var id = Id(0L) - while (values.keySet.contains(id)) { id = Id(id.id + 1) } - id - } -} - -object IdMap { - - /** - * Creates a new `IdMap` by a number of values. - * @param v The initial values of the `IdMap`. - * @tparam T The type of the values of the `IdMap`. - * @return A newly created `IdMap`. - */ - def apply[T](v: T*): IdMap[T] = { - val r = new IdMap[T]() - for (e <- v) { r.addNewElement(e) } - r - } -} diff --git a/src/main/scala/de/retest/guistatemachine/api/impl/StateImpl.scala b/src/main/scala/de/retest/guistatemachine/api/impl/StateImpl.scala index 2d226cf..83ccaa3 100644 --- a/src/main/scala/de/retest/guistatemachine/api/impl/StateImpl.scala +++ b/src/main/scala/de/retest/guistatemachine/api/impl/StateImpl.scala @@ -13,7 +13,7 @@ case class StateImpl(sutState: SutState) extends State with Serializable { * Currently, there is no MultiMap trait for immutable maps in the Scala standard library. * The legacy code used `AmbigueState` here which was more complicated than just a multi map. */ - var transitions = new HashMap[Action, ActionTransitions] + var transitions = HashMap[Action, ActionTransitions]() override def getSutState: SutState = this.synchronized { sutState } override def getTransitions: Map[Action, ActionTransitions] = this.synchronized { transitions } diff --git a/src/test/scala/de/retest/guistatemachine/api/AbstractApiSpec.scala b/src/test/scala/de/retest/guistatemachine/api/AbstractApiSpec.scala index e30f911..04a9bd1 100644 --- a/src/test/scala/de/retest/guistatemachine/api/AbstractApiSpec.scala +++ b/src/test/scala/de/retest/guistatemachine/api/AbstractApiSpec.scala @@ -8,6 +8,8 @@ import org.scalatest.{Matchers, WordSpec} abstract trait AbstractApiSpec extends WordSpec with Matchers { + def createSutState(rootElements: RootElement*) : SutState = new SutState(Arrays.asList(rootElements: _*)) + /** * Creates a new identifying attributes collection which should only match other identifying attributes with the same ID. * diff --git a/src/test/scala/de/retest/guistatemachine/api/IdSpec.scala b/src/test/scala/de/retest/guistatemachine/api/IdSpec.scala deleted file mode 100644 index d49cb86..0000000 --- a/src/test/scala/de/retest/guistatemachine/api/IdSpec.scala +++ /dev/null @@ -1,16 +0,0 @@ -package de.retest.guistatemachine.api - -import org.scalatest.{Matchers, WordSpec} - -class IdSpec extends WordSpec with Matchers { - - "Id" should { - "compare" in { - val id0 = Id(0) - val id1 = Id(1) - id0.compare(id0) shouldEqual 0 - id0.compare(id1) shouldEqual -1 - id1.compare(id0) shouldEqual 1 - } - } -} diff --git a/src/test/scala/de/retest/guistatemachine/api/impl/GuiStateMachineApiImplSpec.scala b/src/test/scala/de/retest/guistatemachine/api/impl/GuiStateMachineApiImplSpec.scala index 31f1457..7f51e64 100644 --- a/src/test/scala/de/retest/guistatemachine/api/impl/GuiStateMachineApiImplSpec.scala +++ b/src/test/scala/de/retest/guistatemachine/api/impl/GuiStateMachineApiImplSpec.scala @@ -1,28 +1,29 @@ package de.retest.guistatemachine.api.impl -import de.retest.guistatemachine.api.{AbstractApiSpec, GuiStateMachineApi, Id} +import de.retest.guistatemachine.api.{AbstractApiSpec, GuiStateMachineApi} class GuiStateMachineApiImplSpec extends AbstractApiSpec { "GuiStateMachineApi" should { "create, get and remove a new state machine" in { - val stateMachineId = GuiStateMachineApi().createStateMachine() - stateMachineId shouldEqual Id(0) - - val stateMachine = GuiStateMachineApi().getStateMachine(stateMachineId) + GuiStateMachineApi().createStateMachine("tmp") + val stateMachine = GuiStateMachineApi().getStateMachine("tmp") stateMachine.isDefined shouldBe true val fsm = stateMachine.get fsm.getActionExecutionTimes.size shouldEqual 0 fsm.getAllExploredActions.size shouldEqual 0 - GuiStateMachineApi().removeStateMachine(stateMachineId) shouldBe true + GuiStateMachineApi().removeStateMachine("tmp") shouldBe true + GuiStateMachineApi().getStateMachine("tmp").isDefined shouldBe false } "clear all state machines" in { - GuiStateMachineApi().createStateMachine shouldEqual Id(0) - GuiStateMachineApi().createStateMachine shouldEqual Id(1) - GuiStateMachineApi().createStateMachine shouldEqual Id(2) + GuiStateMachineApi().createStateMachine("tmp0") + GuiStateMachineApi().createStateMachine("tmp1") + GuiStateMachineApi().createStateMachine("tmp2") GuiStateMachineApi().clear() - GuiStateMachineApi().getStateMachine(Id(2)).isEmpty shouldEqual true + GuiStateMachineApi().getStateMachine("tmp0").isEmpty shouldEqual true + GuiStateMachineApi().getStateMachine("tmp1").isEmpty shouldEqual true + GuiStateMachineApi().getStateMachine("tmp2").isEmpty shouldEqual true } } } diff --git a/src/test/scala/de/retest/guistatemachine/api/impl/GuiStateMachineImplSpec.scala b/src/test/scala/de/retest/guistatemachine/api/impl/GuiStateMachineImplSpec.scala index d620158..ba65245 100644 --- a/src/test/scala/de/retest/guistatemachine/api/impl/GuiStateMachineImplSpec.scala +++ b/src/test/scala/de/retest/guistatemachine/api/impl/GuiStateMachineImplSpec.scala @@ -1,9 +1,6 @@ package de.retest.guistatemachine.api.impl -import java.util.Arrays - import de.retest.guistatemachine.api.AbstractApiSpec -import de.retest.recheck.ui.descriptors.SutState import de.retest.surili.commons.actions.NavigateToAction import org.scalatest.BeforeAndAfterEach @@ -21,9 +18,9 @@ class GuiStateMachineImplSpec extends AbstractApiSpec with BeforeAndAfterEach { "GuiStateMachine" should { "not create a new state when using the same root elements" in { - val s0 = new SutState(Arrays.asList(getRootElement("a", 1))) - val s0Equal = new SutState(Arrays.asList(getRootElement("a", 1))) - val differentState = new SutState(Arrays.asList(getRootElement("a", 2))) + val s0 = createSutState(getRootElement("a", 1)) + val s0Equal = createSutState(getRootElement("a", 1)) + val differentState = createSutState(getRootElement("a", 2)) s0.equals(s0Equal) shouldBe true s0.hashCode() shouldEqual s0Equal.hashCode() differentState.equals(s0) shouldBe false @@ -38,13 +35,13 @@ class GuiStateMachineImplSpec extends AbstractApiSpec with BeforeAndAfterEach { } "add two transitions to two new states for the same action and one transition to another state for another action" in { - val initialSutState = getSutState + val initialSutState = createSutState(rootElementA, rootElementB, rootElementC) val initial = sut.getState(initialSutState) sut.getAllExploredActions.size shouldEqual 0 sut.getActionExecutionTimes.size shouldEqual 0 // execute action0 for the first time - val s0SutState = new SutState(Arrays.asList(rootElementA)) + val s0SutState = createSutState(rootElementA) val s0 = sut.getState(s0SutState) sut.executeAction(initialSutState, action0, s0SutState) initial.getTransitions.size shouldEqual 1 @@ -56,7 +53,7 @@ class GuiStateMachineImplSpec extends AbstractApiSpec with BeforeAndAfterEach { sut.getActionExecutionTimes(action0) shouldEqual 1 // execute action0 for the second time - val s1SutState = new SutState(Arrays.asList(rootElementB)) + val s1SutState = createSutState(rootElementB) val s1 = sut.getState(s1SutState) sut.executeAction(initialSutState, action0, s1SutState) initial.getTransitions.size shouldEqual 1 @@ -68,7 +65,7 @@ class GuiStateMachineImplSpec extends AbstractApiSpec with BeforeAndAfterEach { sut.getActionExecutionTimes(action0) shouldEqual 2 // execute action1 for the first time - val s2SutState = new SutState(Arrays.asList(rootElementC)) + val s2SutState = createSutState(rootElementC) val s2 = sut.getState(s2SutState) sut.executeAction(initialSutState, action1, s2SutState) initial.getTransitions.size shouldEqual 2 @@ -81,7 +78,7 @@ class GuiStateMachineImplSpec extends AbstractApiSpec with BeforeAndAfterEach { } "store a state for the second access" in { - val initialSutState = getSutState + val initialSutState = createSutState(rootElementA, rootElementB, rootElementC) val initialFromAccess0 = sut.getState(initialSutState) val initialFromAccess1 = sut.getState(initialSutState) initialFromAccess0 shouldEqual initialFromAccess1 @@ -94,6 +91,4 @@ class GuiStateMachineImplSpec extends AbstractApiSpec with BeforeAndAfterEach { sut.getAllStates.isEmpty shouldEqual true } } - - private def getSutState: SutState = new SutState(Arrays.asList(rootElementA, rootElementB, rootElementC)) } diff --git a/src/test/scala/de/retest/guistatemachine/api/impl/IdMapSpec.scala b/src/test/scala/de/retest/guistatemachine/api/impl/IdMapSpec.scala deleted file mode 100644 index e5f1187..0000000 --- a/src/test/scala/de/retest/guistatemachine/api/impl/IdMapSpec.scala +++ /dev/null @@ -1,24 +0,0 @@ -package de.retest.guistatemachine.api.impl - -import de.retest.guistatemachine.api.Id -import org.scalatest.{Matchers, WordSpec} - -class IdMapSpec extends WordSpec with Matchers { - - "IdMapSpec" should { - "create a new ID Map" in { - val map = IdMap[Int](1, 2, 3) - map.size shouldEqual 3 - map.hasElement(Id(0)) shouldEqual true - map.getElement(Id(0)).get shouldEqual 1 - map.removeElement(Id(0)) shouldEqual true - map.removeElement(Id(0)) shouldEqual false - map.hasElement(Id(0)) shouldEqual false - map.size shouldEqual 2 - map.addNewElement(4) shouldEqual Id(0) - map.size shouldEqual 3 - map.clear() - map.size shouldEqual 0 - } - } -} diff --git a/src/test/scala/de/retest/guistatemachine/api/impl/StateImplSpec.scala b/src/test/scala/de/retest/guistatemachine/api/impl/StateImplSpec.scala index 3f25de6..902021c 100644 --- a/src/test/scala/de/retest/guistatemachine/api/impl/StateImplSpec.scala +++ b/src/test/scala/de/retest/guistatemachine/api/impl/StateImplSpec.scala @@ -1,15 +1,12 @@ package de.retest.guistatemachine.api.impl -import java.util.Arrays - import de.retest.guistatemachine.api.AbstractApiSpec -import de.retest.recheck.ui.descriptors.SutState class StateImplSpec extends AbstractApiSpec { private val rootElementA = getRootElement("a", 0) private val rootElementB = getRootElement("b", 0) - private val sutStateA = new SutState(Arrays.asList(rootElementA)) - private val sutStateB = new SutState(Arrays.asList(rootElementB)) + private val sutStateA = createSutState(rootElementA) + private val sutStateB = createSutState(rootElementB) "StateImpl" should { "not equal" in { diff --git a/src/test/scala/de/retest/guistatemachine/api/impl/serialization/GuiStateMachineGMLSerializerSpec.scala b/src/test/scala/de/retest/guistatemachine/api/impl/serialization/GuiStateMachineGMLSerializerSpec.scala index 770d770..029c658 100644 --- a/src/test/scala/de/retest/guistatemachine/api/impl/serialization/GuiStateMachineGMLSerializerSpec.scala +++ b/src/test/scala/de/retest/guistatemachine/api/impl/serialization/GuiStateMachineGMLSerializerSpec.scala @@ -1,11 +1,9 @@ package de.retest.guistatemachine.api.impl.serialization import java.io.File -import java.util.Arrays import de.retest.guistatemachine.api.impl.GuiStateMachineImpl import de.retest.guistatemachine.api.{AbstractApiSpec, GuiStateMachineSerializer} -import de.retest.recheck.ui.descriptors.SutState import de.retest.surili.commons.actions.NavigateToAction import org.scalatest.BeforeAndAfterEach @@ -24,8 +22,8 @@ class GuiStateMachineGMLSerializerSpec extends AbstractApiSpec with BeforeAndAft val action0 = new NavigateToAction("http://google.com") val action1 = new NavigateToAction("http://wikipedia.org") - val initialSutState = new SutState(Arrays.asList(rootElementA, rootElementB, rootElementC)) - val finalSutState = new SutState(Arrays.asList(rootElementC)) + val initialSutState = createSutState(rootElementA, rootElementB, rootElementC) + val finalSutState = createSutState(rootElementC) // Create the whole state machine: val initialState = guiStateMachine.getState(initialSutState) diff --git a/src/test/scala/de/retest/guistatemachine/api/impl/serialization/GuiStateMachineJavaObjectStreamSerializerSpec.scala b/src/test/scala/de/retest/guistatemachine/api/impl/serialization/GuiStateMachineJavaObjectStreamSerializerSpec.scala index 0853c21..ac3a24c 100644 --- a/src/test/scala/de/retest/guistatemachine/api/impl/serialization/GuiStateMachineJavaObjectStreamSerializerSpec.scala +++ b/src/test/scala/de/retest/guistatemachine/api/impl/serialization/GuiStateMachineJavaObjectStreamSerializerSpec.scala @@ -1,11 +1,9 @@ package de.retest.guistatemachine.api.impl.serialization import java.io.File -import java.util.Arrays import de.retest.guistatemachine.api.impl.GuiStateMachineImpl import de.retest.guistatemachine.api.{AbstractApiSpec, GuiStateMachineSerializer} -import de.retest.recheck.ui.descriptors.SutState import de.retest.surili.commons.actions.NavigateToAction import org.scalatest.BeforeAndAfterEach @@ -29,8 +27,8 @@ class GuiStateMachineJavaObjectStreamSerializerSpec extends AbstractApiSpec with val action0 = new NavigateToAction("http://google.com") val action1 = new NavigateToAction("http://wikipedia.org") - val initialSutState = new SutState(Arrays.asList(rootElementA, rootElementB, rootElementC)) - val finalSutState = new SutState(Arrays.asList(rootElementC)) + val initialSutState = createSutState(rootElementA, rootElementB, rootElementC) + val finalSutState = createSutState(rootElementC) // Create the whole state machine: guiStateMachine.executeAction(initialSutState, action0, finalSutState)