From 72bf92384d32707ba0b988d7049fa593a80675d8 Mon Sep 17 00:00:00 2001 From: Tamino Dauth Date: Tue, 16 Apr 2019 16:30:20 +0200 Subject: [PATCH] Support directories and add tests #19 - Store Neo4J databases in a directory. - Remove execution counter to simplify code. - Reuse the sutState and action messages when creating identifiers. - Simplify tests and reuse them for Neo4J. --- README.md | 4 +- .../api/ActionIdentifier.scala | 7 +- .../api/ActionTransitions.scala | 4 +- .../guistatemachine/api/GuiStateMachine.scala | 7 +- .../api/GuiStateMachineApi.scala | 10 +- .../api/GuiStateMachineSerializer.scala | 2 +- .../de/retest/guistatemachine/api/State.scala | 3 +- .../api/SutStateIdentifier.scala | 7 +- .../guistatemachine/api/example/Example.scala | 9 +- .../guistatemachine/api/impl/StateImpl.scala | 16 +- .../api/neo4j/ActionTransitionEntity.scala | 7 +- .../api/neo4j/GuiStateMachineApiNeo4J.scala | 61 ++-- .../api/neo4j/GuiStateMachineNeo4J.scala | 2 +- .../api/neo4j/Neo4jSessionFactory.scala | 5 +- .../api/neo4j/StateNeo4J.scala | 19 +- .../api/neo4j/SutStateEntity.scala | 2 +- .../serialization/GraphActionEdge.scala | 3 +- .../serialization/GraphicsProvider.scala | 2 +- .../GuiStateMachinGMLSerializer.scala | 3 +- ...ateMachineJavaObjectStreamSerializer.scala | 2 +- .../api/AbstractGuiStateMachineApiSpec.scala | 273 ++++++++++++++++++ .../api/impl/GuiStateMachineApiImplSpec.scala | 25 +- .../api/impl/GuiStateMachineImplSpec.scala | 108 ------- ...achineJavaObjectStreamSerializerSpec.scala | 4 +- .../GuiStateMachineGMLSerializerSpec.scala | 166 ----------- .../neo4j/GuiStateMachineApiNeo4jSpec.scala | 16 + 26 files changed, 386 insertions(+), 381 deletions(-) rename src/main/scala/de/retest/guistatemachine/api/{impl => }/serialization/GraphActionEdge.scala (80%) rename src/main/scala/de/retest/guistatemachine/api/{impl => }/serialization/GraphicsProvider.scala (94%) rename src/main/scala/de/retest/guistatemachine/api/{impl => }/serialization/GuiStateMachinGMLSerializer.scala (97%) rename src/main/scala/de/retest/guistatemachine/api/{impl => }/serialization/GuiStateMachineJavaObjectStreamSerializer.scala (95%) create mode 100644 src/test/scala/de/retest/guistatemachine/api/AbstractGuiStateMachineApiSpec.scala delete mode 100644 src/test/scala/de/retest/guistatemachine/api/impl/GuiStateMachineImplSpec.scala rename src/test/scala/de/retest/guistatemachine/api/impl/{serialization => }/GuiStateMachineJavaObjectStreamSerializerSpec.scala (93%) delete mode 100644 src/test/scala/de/retest/guistatemachine/api/impl/serialization/GuiStateMachineGMLSerializerSpec.scala create mode 100644 src/test/scala/de/retest/guistatemachine/api/neo4j/GuiStateMachineApiNeo4jSpec.scala diff --git a/README.md b/README.md index 9380a94..aa25618 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,9 @@ Each state machine is represented by a separate graph database stored in a separ The relationship types correspond to actions. Each relation has the property "counter" which contains the execution counter of the action. -We cannot use an embdedded driver if we want to use the corresponding software such as Neo4J Desktop. +The embedded databases are stored into sub directories in the directory `$HOME/.retest/guistatemachines` by default. +Using an embedded database simplifies the usage of the API on a local machine and improves the performance. +However, we cannot use an embdedded driver if we want to use the corresponding software such as Neo4J Desktop. apoc procedures have to be registered manually for an embedded database. Useful software for Neo4J: diff --git a/src/main/scala/de/retest/guistatemachine/api/ActionIdentifier.scala b/src/main/scala/de/retest/guistatemachine/api/ActionIdentifier.scala index 626ef03..24f67a1 100644 --- a/src/main/scala/de/retest/guistatemachine/api/ActionIdentifier.scala +++ b/src/main/scala/de/retest/guistatemachine/api/ActionIdentifier.scala @@ -2,12 +2,11 @@ package de.retest.guistatemachine.api import de.retest.surili.commons.actions.Action -class ActionIdentifier(hash: String) extends HashIdentifier(hash) { - var msg = s"ActionIdentifier[action=Unknown, hash=$hash]" +class ActionIdentifier(hash: String, val actionMsg: String = "Unknown") extends HashIdentifier(hash) { + val msg = s"ActionIdentifier[action=$actionMsg, hash=$hash]" def this(action: Action) = { - this(HashIdentifier.sha256Hash(action)) - msg = s"ActionIdentifier[action=${action.toString}, hash=$hash]" + this(HashIdentifier.sha256Hash(action), action.toString) } override def toString: String = msg } diff --git a/src/main/scala/de/retest/guistatemachine/api/ActionTransitions.scala b/src/main/scala/de/retest/guistatemachine/api/ActionTransitions.scala index 4e06251..5f9fc3f 100644 --- a/src/main/scala/de/retest/guistatemachine/api/ActionTransitions.scala +++ b/src/main/scala/de/retest/guistatemachine/api/ActionTransitions.scala @@ -5,8 +5,6 @@ package de.retest.guistatemachine.api * The corresponding symbol is not stored in this class but in the [[State]] from which the transitions are started or which the transitions lead to. * * @param states The states which the transitions lead to or start from. Since it is a NFA, there can be multiple states for the same symbol. - * @param executionCounter The number of times all transitions for the action have been executed from the corresponding state. - * It does not matter to which state. In the legacy code this was stored as `StateGraph.executionCounter`. */ @SerialVersionUID(1L) -case class ActionTransitions(states: Set[State], executionCounter: Int) extends Serializable +case class ActionTransitions(states: Set[State]) extends Serializable diff --git a/src/main/scala/de/retest/guistatemachine/api/GuiStateMachine.scala b/src/main/scala/de/retest/guistatemachine/api/GuiStateMachine.scala index 514c931..a3b65ba 100644 --- a/src/main/scala/de/retest/guistatemachine/api/GuiStateMachine.scala +++ b/src/main/scala/de/retest/guistatemachine/api/GuiStateMachine.scala @@ -29,11 +29,10 @@ trait GuiStateMachine { * @param from The state the action is executed from * @param a The action which is executed by the user. * @param to The state which the execution leads to. - * @return The number of times the action has been executed. */ - def executeAction(from: State, a: ActionIdentifier, to: State): Int = from.addTransition(a, to) - def executeAction(from: State, a: Action, to: State): Int = executeAction(from, new ActionIdentifier(a), to) - def executeAction(fromSutState: SutState, a: Action, toSutState: SutState): Int = + def executeAction(from: State, a: ActionIdentifier, to: State): Unit = from.addTransition(a, to) + def executeAction(from: State, a: Action, to: State): Unit = executeAction(from, new ActionIdentifier(a), to) + def executeAction(fromSutState: SutState, a: Action, toSutState: SutState): Unit = executeAction(getState(fromSutState), a, getState(toSutState)) def getAllStates: Map[SutStateIdentifier, State] diff --git a/src/main/scala/de/retest/guistatemachine/api/GuiStateMachineApi.scala b/src/main/scala/de/retest/guistatemachine/api/GuiStateMachineApi.scala index b58dfb5..8a5a96c 100644 --- a/src/main/scala/de/retest/guistatemachine/api/GuiStateMachineApi.scala +++ b/src/main/scala/de/retest/guistatemachine/api/GuiStateMachineApi.scala @@ -1,4 +1,6 @@ package de.retest.guistatemachine.api +import java.nio.file.Paths + import de.retest.guistatemachine.api.impl.GuiStateMachineApiImpl import de.retest.guistatemachine.api.neo4j.GuiStateMachineApiNeo4J @@ -38,6 +40,12 @@ trait GuiStateMachineApi { } object GuiStateMachineApi { + + /** + * The default directory where all state machines are stored. + */ + val StorageDirectory = Paths.get(System.getProperty("user.home"), ".retest", "guistatemachines").toAbsolutePath.toString + val default = new GuiStateMachineApiImpl /** @@ -45,5 +53,5 @@ object GuiStateMachineApi { */ def apply(): GuiStateMachineApi = default - val neo4j = new GuiStateMachineApiNeo4J + val neo4j = new GuiStateMachineApiNeo4J(StorageDirectory) } diff --git a/src/main/scala/de/retest/guistatemachine/api/GuiStateMachineSerializer.scala b/src/main/scala/de/retest/guistatemachine/api/GuiStateMachineSerializer.scala index 8eb76ea..64bb707 100644 --- a/src/main/scala/de/retest/guistatemachine/api/GuiStateMachineSerializer.scala +++ b/src/main/scala/de/retest/guistatemachine/api/GuiStateMachineSerializer.scala @@ -1,6 +1,6 @@ package de.retest.guistatemachine.api -import de.retest.guistatemachine.api.impl.serialization.{GuiStateMachinGMLSerializer, GuiStateMachineJavaObjectStreamSerializer} +import de.retest.guistatemachine.api.serialization.{GuiStateMachinGMLSerializer, GuiStateMachineJavaObjectStreamSerializer} trait GuiStateMachineSerializer { def save(filePath: String) diff --git a/src/main/scala/de/retest/guistatemachine/api/State.scala b/src/main/scala/de/retest/guistatemachine/api/State.scala index b199f37..2fd900d 100644 --- a/src/main/scala/de/retest/guistatemachine/api/State.scala +++ b/src/main/scala/de/retest/guistatemachine/api/State.scala @@ -46,7 +46,6 @@ trait State { * * @param a The action which represents the transition's consumed symbol. * @param to The state which the transition leads t o. - * @return The number of times the action has been executed from this state. The target state does not matter for this number. */ - private[api] def addTransition(a: ActionIdentifier, to: State): Int + private[api] def addTransition(a: ActionIdentifier, to: State): Unit } diff --git a/src/main/scala/de/retest/guistatemachine/api/SutStateIdentifier.scala b/src/main/scala/de/retest/guistatemachine/api/SutStateIdentifier.scala index fe5e180..e2675d0 100644 --- a/src/main/scala/de/retest/guistatemachine/api/SutStateIdentifier.scala +++ b/src/main/scala/de/retest/guistatemachine/api/SutStateIdentifier.scala @@ -2,12 +2,11 @@ package de.retest.guistatemachine.api import de.retest.recheck.ui.descriptors.SutState -class SutStateIdentifier(hash: String) extends HashIdentifier(hash) { - var msg = s"SutStateIdentifier[sutState=Unknown, hash=$hash]" +class SutStateIdentifier(hash: String, val sutStateMsg: String = "Unknown") extends HashIdentifier(hash) { + val msg = s"SutStateIdentifier[sutState=$sutStateMsg, hash=$hash]" def this(sutState: SutState) { - this(HashIdentifier.sha256Hash(sutState)) - msg = s"SutStateIdentifier[sutState=${sutState.toString}, hash=$hash]" + this(HashIdentifier.sha256Hash(sutState), sutState.toString) } override def toString: String = msg } diff --git a/src/main/scala/de/retest/guistatemachine/api/example/Example.scala b/src/main/scala/de/retest/guistatemachine/api/example/Example.scala index 5907264..a5963fd 100644 --- a/src/main/scala/de/retest/guistatemachine/api/example/Example.scala +++ b/src/main/scala/de/retest/guistatemachine/api/example/Example.scala @@ -15,7 +15,14 @@ object Example extends App { private val action0 = new NavigateToAction("http://google.com") private val action1 = new NavigateToAction("http://wikipedia.org") - val stateMachine = GuiStateMachineApi.neo4j.createStateMachine("tmp") + val stateMachine = GuiStateMachineApi.neo4j.getStateMachine("tmp") match { + case Some(s) => s + + case None => GuiStateMachineApi.neo4j.createStateMachine("tmp") + } + + println(s"All states before clearing: ${stateMachine.getAllStates.size}") + stateMachine.clear() println(s"All states after clearing: ${stateMachine.getAllStates.size}") 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 91a9f14..6985837 100644 --- a/src/main/scala/de/retest/guistatemachine/api/impl/StateImpl.scala +++ b/src/main/scala/de/retest/guistatemachine/api/impl/StateImpl.scala @@ -22,17 +22,15 @@ case class StateImpl(sutState: SutStateIdentifier) extends State with Serializab override def getOutgoingActionTransitions: Map[ActionIdentifier, ActionTransitions] = this.synchronized { outgoingActionTransitions } override def getIncomingActionTransitions: Map[ActionIdentifier, ActionTransitions] = this.synchronized { incomingActionTransitions } - private[api] override def addTransition(a: ActionIdentifier, to: State): Int = { - val executionCounter = this.synchronized { + private[api] override def addTransition(a: ActionIdentifier, to: State): Unit = { + this.synchronized { outgoingActionTransitions.get(a) match { case Some(oldTransitions) => - val updatedTransitions = ActionTransitions(oldTransitions.states + to, oldTransitions.executionCounter + 1) + val updatedTransitions = ActionTransitions(oldTransitions.states + to) outgoingActionTransitions = outgoingActionTransitions + (a -> updatedTransitions) - updatedTransitions.executionCounter case None => - outgoingActionTransitions += (a -> ActionTransitions(Set(to), 1)) - 1 + outgoingActionTransitions += (a -> ActionTransitions(Set(to))) } } @@ -40,14 +38,12 @@ case class StateImpl(sutState: SutStateIdentifier) extends State with Serializab val other = to.asInstanceOf[StateImpl] other.incomingActionTransitions.get(a) match { case Some(oldTransitions) => - val updatedTransitions = ActionTransitions(oldTransitions.states + this, oldTransitions.executionCounter + 1) + val updatedTransitions = ActionTransitions(oldTransitions.states + this) other.incomingActionTransitions = other.incomingActionTransitions + (a -> updatedTransitions) case None => - other.incomingActionTransitions += (a -> ActionTransitions(Set(this), 1)) + other.incomingActionTransitions += (a -> ActionTransitions(Set(this))) } } - - executionCounter } } diff --git a/src/main/scala/de/retest/guistatemachine/api/neo4j/ActionTransitionEntity.scala b/src/main/scala/de/retest/guistatemachine/api/neo4j/ActionTransitionEntity.scala index 145b745..7f51d1e 100644 --- a/src/main/scala/de/retest/guistatemachine/api/neo4j/ActionTransitionEntity.scala +++ b/src/main/scala/de/retest/guistatemachine/api/neo4j/ActionTransitionEntity.scala @@ -5,7 +5,7 @@ import org.neo4j.ogm.annotation._ @RelationshipEntity(`type` = "ACTIONS") class ActionTransitionEntity(s: SutStateEntity, e: SutStateEntity, a: String, msg: String) { - def this(s: SutStateEntity, e: SutStateEntity, a: ActionIdentifier) = this(s, e, a.hash, a.msg) + def this(s: SutStateEntity, e: SutStateEntity, a: ActionIdentifier) = this(s, e, a.hash, a.actionMsg) def this() = this(null, null, null, null) @Id @@ -26,10 +26,6 @@ class ActionTransitionEntity(s: SutStateEntity, e: SutStateEntity, a: String, ms @Property(name = ActionTransitionEntity.PropertyMessage) var message: String = msg - - /// The number of times this action has been executed. - @Property(name = ActionTransitionEntity.PropertyNameCounter) - var counter: Int = 1 } object ActionTransitionEntity { @@ -37,5 +33,4 @@ object ActionTransitionEntity { final val PropertyNameEnd = "end" final val PropertyNameAction = "action" final val PropertyMessage = "message" - final val PropertyNameCounter = "counter" } diff --git a/src/main/scala/de/retest/guistatemachine/api/neo4j/GuiStateMachineApiNeo4J.scala b/src/main/scala/de/retest/guistatemachine/api/neo4j/GuiStateMachineApiNeo4J.scala index 402decc..f8b1dcb 100644 --- a/src/main/scala/de/retest/guistatemachine/api/neo4j/GuiStateMachineApiNeo4J.scala +++ b/src/main/scala/de/retest/guistatemachine/api/neo4j/GuiStateMachineApiNeo4J.scala @@ -1,42 +1,51 @@ package de.retest.guistatemachine.api.neo4j import java.io.File +import java.nio.file.Paths import com.typesafe.scalalogging.Logger import de.retest.guistatemachine.api.{GuiStateMachine, GuiStateMachineApi} +import org.apache.commons.io.FileUtils -import scala.collection.concurrent.TrieMap - -class GuiStateMachineApiNeo4J extends GuiStateMachineApi { +class GuiStateMachineApiNeo4J(directory: String) extends GuiStateMachineApi { private val logger = Logger[GuiStateMachineApiNeo4J] - private val stateMachines = TrieMap[String, GuiStateMachineNeo4J]() - // TODO #19 Load existing state machines based on Neo4J graph databases. - override def createStateMachine(name: String): GuiStateMachine = { - val uri = getUri(name) - Neo4jSessionFactory.getSessionFactoryEmbedded(uri) - logger.info("Created new graph DB in {}.", uri) + override def createStateMachine(name: String): GuiStateMachine = + if (isDirectory(name)) { + throw new RuntimeException(s"State machine $name does already exist.") + } else { + val uri = getUri(name) + Neo4jSessionFactory.getSessionFactoryEmbedded(uri) + logger.info("Created new graph DB in {}.", uri) - val guiStateMachine = new GuiStateMachineNeo4J(uri) - stateMachines += (name -> guiStateMachine) - guiStateMachine - } + new GuiStateMachineNeo4J(uri) + } - override def removeStateMachine(name: String): Boolean = stateMachines.remove(name) match { - case Some(stateMachine) => - // TODO #19 Should we remove the state machine from the disk? - stateMachine.clear() - val uri = getUri(name) - Neo4jSessionFactory.getSessionFactoryEmbedded(uri).close() + override def removeStateMachine(name: String): Boolean = + if (isDirectory(name)) { + val file = getFile(name) + logger.info("Deleting state machine in {}.", file) + FileUtils.deleteDirectory(file) true - case None => false - } - - override def getStateMachine(name: String): Option[GuiStateMachine] = stateMachines.get(name) + } else { + false + } - override def clear(): Unit = stateMachines.keySet foreach { name => // TODO #19 keys can be modified concurrently. So we might not remove all state machines? - removeStateMachine(name) + override def getStateMachine(name: String): Option[GuiStateMachine] = + if (isDirectory(name)) { + val uri = getUri(name) + Some(new GuiStateMachineNeo4J(uri)) + } else { + None + } + + override def clear(): Unit = { + logger.info("Deleting all state machines in {}.", directory) + FileUtils.deleteDirectory(getStorageDirectory()) } - private def getUri(name: String): String = new File(name).toURI.toString + private def getStorageDirectory(): File = new File(directory) + private def isDirectory(name: String): Boolean = getFile(name).isDirectory + private def getFile(name: String): File = new File(Paths.get(directory, name).toAbsolutePath.toString) + private def getUri(name: String): String = getFile(name).toURI.toString } diff --git a/src/main/scala/de/retest/guistatemachine/api/neo4j/GuiStateMachineNeo4J.scala b/src/main/scala/de/retest/guistatemachine/api/neo4j/GuiStateMachineNeo4J.scala index 0eda518..5c0f7de 100644 --- a/src/main/scala/de/retest/guistatemachine/api/neo4j/GuiStateMachineNeo4J.scala +++ b/src/main/scala/de/retest/guistatemachine/api/neo4j/GuiStateMachineNeo4J.scala @@ -39,7 +39,7 @@ class GuiStateMachineNeo4J(var uri: String) extends GuiStateMachine { while (iterator.hasNext) { val node = iterator.next() - val sutState = new SutStateIdentifier(node.hash) + val sutState = new SutStateIdentifier(node.hash, node.message) result = result + (sutState -> StateNeo4J(sutState, this)) } result diff --git a/src/main/scala/de/retest/guistatemachine/api/neo4j/Neo4jSessionFactory.scala b/src/main/scala/de/retest/guistatemachine/api/neo4j/Neo4jSessionFactory.scala index d77a305..468c953 100644 --- a/src/main/scala/de/retest/guistatemachine/api/neo4j/Neo4jSessionFactory.scala +++ b/src/main/scala/de/retest/guistatemachine/api/neo4j/Neo4jSessionFactory.scala @@ -11,7 +11,8 @@ object Neo4jSessionFactory { def getSessionFactoryEmbedded(uri: String): SessionFactory = sessionFactories.get(uri) match { case Some(sessionFactory) => sessionFactory - case None => + case None => + // TODO #19 This must not overwrite an existing database! Actually, one should use one shared session factory but we distinguish between directories. val conf = new Configuration.Builder().uri(uri).build val sessionFactory = new SessionFactory(conf, this.getClass.getPackage.getName) sessionFactories += (uri -> sessionFactory) @@ -33,7 +34,7 @@ object Neo4jSessionFactory { def transaction[A](f: Session => A)(implicit uri: String): A = { // We have to create a session for every transaction since sessions are not thread-safe. - val session = sessionFactories(uri).openSession() + val session = getSessionFactoryEmbedded(uri).openSession() var txn: Option[Transaction] = None try { val transaction = session.beginTransaction() diff --git a/src/main/scala/de/retest/guistatemachine/api/neo4j/StateNeo4J.scala b/src/main/scala/de/retest/guistatemachine/api/neo4j/StateNeo4J.scala index 32f5b68..b5f16d0 100644 --- a/src/main/scala/de/retest/guistatemachine/api/neo4j/StateNeo4J.scala +++ b/src/main/scala/de/retest/guistatemachine/api/neo4j/StateNeo4J.scala @@ -15,14 +15,13 @@ case class StateNeo4J(sutStateIdentifier: SutStateIdentifier, guiStateMachine: G val iterator = sutStateEntity.outgoingActionTransitions.iterator() while (iterator.hasNext) { val relationship = iterator.next() - val action = new ActionIdentifier(relationship.action) + val action = new ActionIdentifier(relationship.action, relationship.message) val targetSutState = new SutStateIdentifier(relationship.end.hash) - val counter = relationship.counter val actionTransitions = if (result.contains(action)) { val existing = result(action) - ActionTransitions(existing.states ++ Set(StateNeo4J(targetSutState, guiStateMachine)), existing.executionCounter + counter) + ActionTransitions(existing.states ++ Set(StateNeo4J(targetSutState, guiStateMachine))) } else { - ActionTransitions(Set(StateNeo4J(targetSutState, guiStateMachine)), counter) + ActionTransitions(Set(StateNeo4J(targetSutState, guiStateMachine))) } result = result + (action -> actionTransitions) } @@ -36,21 +35,20 @@ case class StateNeo4J(sutStateIdentifier: SutStateIdentifier, guiStateMachine: G val iterator = sutStateEntity.incomingActionTransitions.iterator() while (iterator.hasNext) { val relationship = iterator.next() - val action = new ActionIdentifier(relationship.action) + val action = new ActionIdentifier(relationship.action, relationship.message) val sourceSutState = new SutStateIdentifier(relationship.start.hash) - val counter = relationship.counter val actionTransitions = if (result.contains(action)) { val existing = result(action) - ActionTransitions(existing.states ++ Set(StateNeo4J(sourceSutState, guiStateMachine)), existing.executionCounter + counter) + ActionTransitions(existing.states ++ Set(StateNeo4J(sourceSutState, guiStateMachine))) } else { - ActionTransitions(Set(StateNeo4J(sourceSutState, guiStateMachine)), counter) + ActionTransitions(Set(StateNeo4J(sourceSutState, guiStateMachine))) } result = result + (action -> actionTransitions) } result }(guiStateMachine.uri) - private[api] override def addTransition(a: ActionIdentifier, to: State): Int = + private[api] override def addTransition(a: ActionIdentifier, to: State): Unit = Neo4jSessionFactory.transaction { session => val sourceState = getSutStateEntity(session) val targetSutStateIdentifier = to.asInstanceOf[StateNeo4J].sutStateIdentifier @@ -60,13 +58,10 @@ case class StateNeo4J(sutStateIdentifier: SutStateIdentifier, guiStateMachine: G if (matchingTransitions.nonEmpty) { val first = matchingTransitions.head - first.counter = first.counter + 1 session.save(first) - first.counter } else { val transition = new ActionTransitionEntity(sourceState, targetState, a) session.save(transition) - 1 } }(guiStateMachine.uri) diff --git a/src/main/scala/de/retest/guistatemachine/api/neo4j/SutStateEntity.scala b/src/main/scala/de/retest/guistatemachine/api/neo4j/SutStateEntity.scala index cf91d03..bd8e4f8 100644 --- a/src/main/scala/de/retest/guistatemachine/api/neo4j/SutStateEntity.scala +++ b/src/main/scala/de/retest/guistatemachine/api/neo4j/SutStateEntity.scala @@ -9,7 +9,7 @@ class SutStateEntity(@Property(name = SutStateEntity.PropertyNameHash) var hash: java.lang.String, msg: String) { - def this(sutStateIdentifier: SutStateIdentifier) = this(sutStateIdentifier.hash, sutStateIdentifier.msg) + def this(sutStateIdentifier: SutStateIdentifier) = this(sutStateIdentifier.hash, sutStateIdentifier.sutStateMsg) def this() = this(null, null) @Id diff --git a/src/main/scala/de/retest/guistatemachine/api/impl/serialization/GraphActionEdge.scala b/src/main/scala/de/retest/guistatemachine/api/serialization/GraphActionEdge.scala similarity index 80% rename from src/main/scala/de/retest/guistatemachine/api/impl/serialization/GraphActionEdge.scala rename to src/main/scala/de/retest/guistatemachine/api/serialization/GraphActionEdge.scala index ec8debc..7c4ba4f 100644 --- a/src/main/scala/de/retest/guistatemachine/api/impl/serialization/GraphActionEdge.scala +++ b/src/main/scala/de/retest/guistatemachine/api/serialization/GraphActionEdge.scala @@ -1,4 +1,5 @@ -package de.retest.guistatemachine.api.impl.serialization +package de.retest.guistatemachine.api.serialization + import de.retest.guistatemachine.api.{ActionIdentifier, SutStateIdentifier} case class GraphActionEdge(from: SutStateIdentifier, to: SutStateIdentifier, action: ActionIdentifier) { diff --git a/src/main/scala/de/retest/guistatemachine/api/impl/serialization/GraphicsProvider.scala b/src/main/scala/de/retest/guistatemachine/api/serialization/GraphicsProvider.scala similarity index 94% rename from src/main/scala/de/retest/guistatemachine/api/impl/serialization/GraphicsProvider.scala rename to src/main/scala/de/retest/guistatemachine/api/serialization/GraphicsProvider.scala index 77c1011..58d64f8 100644 --- a/src/main/scala/de/retest/guistatemachine/api/impl/serialization/GraphicsProvider.scala +++ b/src/main/scala/de/retest/guistatemachine/api/serialization/GraphicsProvider.scala @@ -1,4 +1,4 @@ -package de.retest.guistatemachine.api.impl.serialization +package de.retest.guistatemachine.api.serialization import java.awt.Color diff --git a/src/main/scala/de/retest/guistatemachine/api/impl/serialization/GuiStateMachinGMLSerializer.scala b/src/main/scala/de/retest/guistatemachine/api/serialization/GuiStateMachinGMLSerializer.scala similarity index 97% rename from src/main/scala/de/retest/guistatemachine/api/impl/serialization/GuiStateMachinGMLSerializer.scala rename to src/main/scala/de/retest/guistatemachine/api/serialization/GuiStateMachinGMLSerializer.scala index a9daab4..450bbf6 100644 --- a/src/main/scala/de/retest/guistatemachine/api/impl/serialization/GuiStateMachinGMLSerializer.scala +++ b/src/main/scala/de/retest/guistatemachine/api/serialization/GuiStateMachinGMLSerializer.scala @@ -1,4 +1,5 @@ -package de.retest.guistatemachine.api.impl.serialization +package de.retest.guistatemachine.api.serialization + import java.io.{BufferedWriter, File, FileOutputStream, OutputStreamWriter} import com.github.systemdir.gml.YedGmlWriter diff --git a/src/main/scala/de/retest/guistatemachine/api/impl/serialization/GuiStateMachineJavaObjectStreamSerializer.scala b/src/main/scala/de/retest/guistatemachine/api/serialization/GuiStateMachineJavaObjectStreamSerializer.scala similarity index 95% rename from src/main/scala/de/retest/guistatemachine/api/impl/serialization/GuiStateMachineJavaObjectStreamSerializer.scala rename to src/main/scala/de/retest/guistatemachine/api/serialization/GuiStateMachineJavaObjectStreamSerializer.scala index dc27536..76c2ca9 100644 --- a/src/main/scala/de/retest/guistatemachine/api/impl/serialization/GuiStateMachineJavaObjectStreamSerializer.scala +++ b/src/main/scala/de/retest/guistatemachine/api/serialization/GuiStateMachineJavaObjectStreamSerializer.scala @@ -1,4 +1,4 @@ -package de.retest.guistatemachine.api.impl.serialization +package de.retest.guistatemachine.api.serialization import java.io.{FileInputStream, FileOutputStream, ObjectInputStream, ObjectOutputStream} diff --git a/src/test/scala/de/retest/guistatemachine/api/AbstractGuiStateMachineApiSpec.scala b/src/test/scala/de/retest/guistatemachine/api/AbstractGuiStateMachineApiSpec.scala new file mode 100644 index 0000000..f5127dd --- /dev/null +++ b/src/test/scala/de/retest/guistatemachine/api/AbstractGuiStateMachineApiSpec.scala @@ -0,0 +1,273 @@ +package de.retest.guistatemachine.api + +import java.io.File + +import de.retest.surili.commons.actions.NavigateToAction +import org.scalatest.BeforeAndAfterEach + +abstract class AbstractGuiStateMachineApiSpec extends AbstractApiSpec with BeforeAndAfterEach { + def getName: String + def getCut: GuiStateMachineApi + private var cut: GuiStateMachineApi = null + + private val rootElementA = getRootElement("a", 0) + private val rootElementB = getRootElement("b", 0) + private val rootElementC = getRootElement("c", 0) + private val action0 = new NavigateToAction("http://google.com") + private val action0Identifier = new ActionIdentifier(action0) + private val action1 = new NavigateToAction("http://wikipedia.org") + private val action1Identifier = new ActionIdentifier(action1) + + override def beforeEach() { + cut = getCut + cut.clear() + } + + getName should { + "create, get and remove a new state machine" in { + cut.createStateMachine("tmp") + val stateMachine = cut.getStateMachine("tmp") + stateMachine.isDefined shouldBe true + cut.removeStateMachine("tmp") shouldBe true + cut.getStateMachine("tmp").isDefined shouldBe false + } + + "clear all state machines" in { + cut.createStateMachine("tmpX") + cut.createStateMachine("tmpY") + cut.createStateMachine("tmpZ") + cut.clear() + cut.getStateMachine("tmpX").isEmpty shouldEqual true + cut.getStateMachine("tmpY").isEmpty shouldEqual true + cut.getStateMachine("tmpZ").isEmpty shouldEqual true + } + + "not create a new state when using the same root elements" in { + 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 + differentState.hashCode() should not equal s0.hashCode() + val stateMachine = cut.createStateMachine("tmp") + stateMachine.getAllStates.size shouldEqual 0 + stateMachine.getState(s0) + stateMachine.getAllStates.size shouldEqual 1 + stateMachine.getState(s0Equal) + stateMachine.getAllStates.size shouldEqual 1 + stateMachine.getState(differentState) + stateMachine.getAllStates.size shouldEqual 2 + } + + "add two transitions to two new states for the same action and two transitions for the same action to another state" in { + val stateMachine = cut.createStateMachine("tmp") + val initialSutState = createSutState(rootElementA, rootElementB, rootElementC) + val initial = stateMachine.getState(initialSutState) + + // execute action0 for the first time + val s0SutState = createSutState(rootElementA) + val s0 = stateMachine.getState(s0SutState) + stateMachine.executeAction(initialSutState, action0, s0SutState) + initial.getOutgoingActionTransitions.size shouldEqual 1 + initial.getOutgoingActionTransitions(action0Identifier).states.size shouldEqual 1 + initial.getIncomingActionTransitions.size shouldEqual 0 + s0.getOutgoingActionTransitions.size shouldEqual 0 + s0.getIncomingActionTransitions.size shouldEqual 1 + s0.getIncomingActionTransitions(action0Identifier).states.size shouldEqual 1 + + // execute action0 for the second time + val s1SutState = createSutState(rootElementB) + val s1 = stateMachine.getState(s1SutState) + stateMachine.executeAction(initialSutState, action0, s1SutState) + initial.getOutgoingActionTransitions.size shouldEqual 1 + initial.getOutgoingActionTransitions(action0Identifier).states.size shouldEqual 2 + initial.getIncomingActionTransitions.size shouldEqual 0 + s1.getOutgoingActionTransitions.size shouldEqual 0 + s1.getIncomingActionTransitions.size shouldEqual 1 + s1.getIncomingActionTransitions(action0Identifier).states.size shouldEqual 1 + + // execute action1 for the first time + val s2SutState = createSutState(rootElementC) + val s2 = stateMachine.getState(s2SutState) + stateMachine.executeAction(initialSutState, action1, s2SutState) + initial.getOutgoingActionTransitions.size shouldEqual 2 + initial.getOutgoingActionTransitions(action1Identifier).states.size shouldEqual 1 + initial.getIncomingActionTransitions.size shouldEqual 0 + s2.getOutgoingActionTransitions.size shouldEqual 0 + s2.getIncomingActionTransitions.size shouldEqual 1 + s2.getIncomingActionTransitions(action1Identifier).states.size shouldEqual 1 + + // execute action1 for the second time but from s1SutState to create one incoming action from two different states + stateMachine.executeAction(s1SutState, action1, s2SutState) + s1.getOutgoingActionTransitions.size shouldEqual 1 + s1.getOutgoingActionTransitions(action1Identifier).states.size shouldEqual 1 + s1.getIncomingActionTransitions.size shouldEqual 1 + s1.getIncomingActionTransitions(action0Identifier).states.size shouldEqual 1 + s2.getOutgoingActionTransitions.size shouldEqual 0 + s2.getIncomingActionTransitions.size shouldEqual 1 + s2.getIncomingActionTransitions(action1Identifier).states shouldEqual Set(initial, s1) + + stateMachine.clear() + stateMachine.getAllStates.isEmpty shouldEqual true + } + + "store a state for the second access" in { + val stateMachine = cut.createStateMachine("tmp") + val initialSutState = createSutState(rootElementA, rootElementB, rootElementC) + val initialFromAccess0 = stateMachine.getState(initialSutState) + val initialFromAccess1 = stateMachine.getState(initialSutState) + initialFromAccess0 shouldEqual initialFromAccess1 + } + + "save GML " in { + val rootElementA = getRootElement("a", 0) + val rootElementB = getRootElement("b", 0) + val rootElementC = getRootElement("c", 0) + val action0 = new NavigateToAction("http://google.com") + val action1 = new NavigateToAction("http://wikipedia.org") + + val initialSutState = createSutState(rootElementA, rootElementB, rootElementC) + val finalSutState = createSutState(rootElementC) + + // Create the whole state machine: + val guiStateMachine = cut.createStateMachine("tmp") + guiStateMachine.executeAction(initialSutState, action0, finalSutState) + guiStateMachine.executeAction(initialSutState, action1, finalSutState) + guiStateMachine.executeAction(finalSutState, action0, initialSutState) + guiStateMachine.executeAction(finalSutState, action1, initialSutState) + + val filePath = "./target/test_state_machine.gml" + val oldFile = new File(filePath) + + if (oldFile.exists()) { oldFile.delete() } shouldEqual true + + GuiStateMachineSerializer.gml(guiStateMachine).save(filePath) + + val f = new File(filePath) + f.exists() shouldEqual true + f.isDirectory shouldEqual false + + val source = scala.io.Source.fromFile(filePath) + val lines = source.mkString + lines shouldEqual + """Creator "JGraphT GML Exporter - modified by Hayato Hess, Andreas Hofstadler" + |Version 1 + |graph + |[ + | label "" + | directed 1 + | node + | [ + | id 1 + | label "SutStateIdentifier[sutState=State[descriptor=[]], hash=acd05dfba59670825451169c470d430727226dd0dec48c64961305a0c5ab1ecb]" + | graphics + | [ + | type "rectangle" + | fill "#c0c0c0ff" + | line "#000000ff" + | ] + | LabelGraphics + | [ + | fontStyle "ITALIC" + | ] + | ] + | node + | [ + | id 2 + | label "SutStateIdentifier[sutState=State[descriptor=[, , ]], hash=c44472d3d18e4f62b073a232e3119de9d94d3c6242b65125f454d62aced7f84e]" + | graphics + | [ + | type "rectangle" + | fill "#c0c0c0ff" + | line "#000000ff" + | ] + | LabelGraphics + | [ + | fontStyle "ITALIC" + | ] + | ] + | edge + | [ + | id 3 + | source 1 + | target 2 + | label "ActionIdentifier[action=NavigateToAction(url=http://wikipedia.org), hash=240d08498736de4d893c146fd64b58b1ae1eda8c36a565919b035d86c6ee2084]" + | LabelGraphics + | [ + | model "centered" + | position "center" + | ] + | graphics + | [ + | fill "#000000ff" + | style "DASHED" + | targetArrow "short" + | ] + | ] + | edge + | [ + | id 4 + | source 1 + | target 2 + | label "ActionIdentifier[action=NavigateToAction(url=http://google.com), hash=fd00ea22cb50efd96c3ff59d8900685d0d64f2cee1e77873133e7e186afd2e7f]" + | LabelGraphics + | [ + | model "centered" + | position "center" + | ] + | graphics + | [ + | fill "#000000ff" + | style "DASHED" + | targetArrow "short" + | ] + | ] + | edge + | [ + | id 5 + | source 2 + | target 1 + | label "ActionIdentifier[action=NavigateToAction(url=http://wikipedia.org), hash=240d08498736de4d893c146fd64b58b1ae1eda8c36a565919b035d86c6ee2084]" + | LabelGraphics + | [ + | model "centered" + | position "center" + | ] + | graphics + | [ + | fill "#000000ff" + | style "DASHED" + | targetArrow "short" + | ] + | ] + | edge + | [ + | id 6 + | source 2 + | target 1 + | label "ActionIdentifier[action=NavigateToAction(url=http://google.com), hash=fd00ea22cb50efd96c3ff59d8900685d0d64f2cee1e77873133e7e186afd2e7f]" + | LabelGraphics + | [ + | model "centered" + | position "center" + | ] + | graphics + | [ + | fill "#000000ff" + | style "DASHED" + | targetArrow "short" + | ] + | ] + |] + |""".stripMargin + + source.close() + } + + "load GML " in { + val guiStateMachine = cut.createStateMachine("tmp") + the[UnsupportedOperationException] thrownBy GuiStateMachineSerializer.gml(guiStateMachine).load("bla") should have message "Loading GML is not supported." + } + } +} 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 f77db6e..7472a05 100644 --- a/src/test/scala/de/retest/guistatemachine/api/impl/GuiStateMachineApiImplSpec.scala +++ b/src/test/scala/de/retest/guistatemachine/api/impl/GuiStateMachineApiImplSpec.scala @@ -1,25 +1,8 @@ package de.retest.guistatemachine.api.impl -import de.retest.guistatemachine.api.{AbstractApiSpec, GuiStateMachineApi} +import de.retest.guistatemachine.api.{AbstractGuiStateMachineApiSpec, GuiStateMachineApi} -class GuiStateMachineApiImplSpec extends AbstractApiSpec { - "GuiStateMachineApi" should { - "create, get and remove a new state machine" in { - GuiStateMachineApi().createStateMachine("tmp") - val stateMachine = GuiStateMachineApi().getStateMachine("tmp") - stateMachine.isDefined shouldBe true - GuiStateMachineApi().removeStateMachine("tmp") shouldBe true - GuiStateMachineApi().getStateMachine("tmp").isDefined shouldBe false - } - - "clear all state machines" in { - GuiStateMachineApi().createStateMachine("tmp0") - GuiStateMachineApi().createStateMachine("tmp1") - GuiStateMachineApi().createStateMachine("tmp2") - GuiStateMachineApi().clear() - GuiStateMachineApi().getStateMachine("tmp0").isEmpty shouldEqual true - GuiStateMachineApi().getStateMachine("tmp1").isEmpty shouldEqual true - GuiStateMachineApi().getStateMachine("tmp2").isEmpty shouldEqual true - } - } +class GuiStateMachineApiImplSpec extends AbstractGuiStateMachineApiSpec { + override def getName: String = "GuiStateMachineApiImpl" + override def getCut: GuiStateMachineApi = new GuiStateMachineApiImpl } diff --git a/src/test/scala/de/retest/guistatemachine/api/impl/GuiStateMachineImplSpec.scala b/src/test/scala/de/retest/guistatemachine/api/impl/GuiStateMachineImplSpec.scala deleted file mode 100644 index c91ad90..0000000 --- a/src/test/scala/de/retest/guistatemachine/api/impl/GuiStateMachineImplSpec.scala +++ /dev/null @@ -1,108 +0,0 @@ -package de.retest.guistatemachine.api.impl - -import de.retest.guistatemachine.api.{AbstractApiSpec, ActionIdentifier} -import de.retest.surili.commons.actions.NavigateToAction -import org.scalatest.BeforeAndAfterEach - -class GuiStateMachineImplSpec extends AbstractApiSpec with BeforeAndAfterEach { - private val sut = new GuiStateMachineImpl - private val rootElementA = getRootElement("a", 0) - private val rootElementB = getRootElement("b", 0) - private val rootElementC = getRootElement("c", 0) - private val action0 = new NavigateToAction("http://google.com") - private val action0Identifier = new ActionIdentifier(action0) - private val action1 = new NavigateToAction("http://wikipedia.org") - private val action1Identifier = new ActionIdentifier(action1) - - override def beforeEach() { - sut.clear() - } - - "GuiStateMachine" should { - "not create a new state when using the same root elements" in { - 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 - differentState.hashCode() should not equal s0.hashCode() - sut.getAllStates.size shouldEqual 0 - sut.getState(s0) - sut.getAllStates.size shouldEqual 1 - sut.getState(s0Equal) - sut.getAllStates.size shouldEqual 1 - sut.getState(differentState) - sut.getAllStates.size shouldEqual 2 - } - - "add two transitions to two new states for the same action and two transitions for the same action to another state" in { - val initialSutState = createSutState(rootElementA, rootElementB, rootElementC) - val initial = sut.getState(initialSutState) - - // execute action0 for the first time - val s0SutState = createSutState(rootElementA) - val s0 = sut.getState(s0SutState) - sut.executeAction(initialSutState, action0, s0SutState) shouldEqual 1 - initial.getOutgoingActionTransitions.size shouldEqual 1 - initial.getOutgoingActionTransitions(action0Identifier).states.size shouldEqual 1 - initial.getOutgoingActionTransitions(action0Identifier).executionCounter shouldEqual 1 - initial.getIncomingActionTransitions.size shouldEqual 0 - s0.getOutgoingActionTransitions.size shouldEqual 0 - s0.getIncomingActionTransitions.size shouldEqual 1 - s0.getIncomingActionTransitions(action0Identifier).states.size shouldEqual 1 - s0.getIncomingActionTransitions(action0Identifier).executionCounter shouldEqual 1 - - // execute action0 for the second time - val s1SutState = createSutState(rootElementB) - val s1 = sut.getState(s1SutState) - sut.executeAction(initialSutState, action0, s1SutState) shouldEqual 2 - initial.getOutgoingActionTransitions.size shouldEqual 1 - initial.getOutgoingActionTransitions(action0Identifier).states.size shouldEqual 2 - initial.getOutgoingActionTransitions(action0Identifier).executionCounter shouldEqual 2 - initial.getIncomingActionTransitions.size shouldEqual 0 - s1.getOutgoingActionTransitions.size shouldEqual 0 - s1.getIncomingActionTransitions.size shouldEqual 1 - s1.getIncomingActionTransitions(action0Identifier).states.size shouldEqual 1 - s1.getIncomingActionTransitions(action0Identifier).executionCounter shouldEqual 1 - - // execute action1 for the first time - val s2SutState = createSutState(rootElementC) - val s2 = sut.getState(s2SutState) - sut.executeAction(initialSutState, action1, s2SutState) shouldEqual 1 - initial.getOutgoingActionTransitions.size shouldEqual 2 - initial.getOutgoingActionTransitions(action1Identifier).states.size shouldEqual 1 - initial.getOutgoingActionTransitions(action1Identifier).executionCounter shouldEqual 1 - initial.getIncomingActionTransitions.size shouldEqual 0 - s2.getOutgoingActionTransitions.size shouldEqual 0 - s2.getIncomingActionTransitions.size shouldEqual 1 - s2.getIncomingActionTransitions(action1Identifier).states.size shouldEqual 1 - s2.getIncomingActionTransitions(action1Identifier).executionCounter shouldEqual 1 - - // execute action1 for the second time but from s1SutState to create one incoming action from two different states - sut.executeAction(s1SutState, action1, s2SutState) shouldEqual 1 - s1.getOutgoingActionTransitions.size shouldEqual 1 - s1.getOutgoingActionTransitions(action1Identifier).states.size shouldEqual 1 - s1.getOutgoingActionTransitions(action1Identifier).executionCounter shouldEqual 1 - s1.getIncomingActionTransitions.size shouldEqual 1 - s1.getIncomingActionTransitions(action0Identifier).states.size shouldEqual 1 - s1.getIncomingActionTransitions(action0Identifier).executionCounter shouldEqual 1 - s2.getOutgoingActionTransitions.size shouldEqual 0 - s2.getIncomingActionTransitions.size shouldEqual 1 - s2.getIncomingActionTransitions(action1Identifier).states shouldEqual Set(initial, s1) - s2.getIncomingActionTransitions(action1Identifier).executionCounter shouldEqual 2 - } - - "store a state for the second access" in { - val initialSutState = createSutState(rootElementA, rootElementB, rootElementC) - val initialFromAccess0 = sut.getState(initialSutState) - val initialFromAccess1 = sut.getState(initialSutState) - initialFromAccess0 shouldEqual initialFromAccess1 - } - - "clear the state machine" in { - sut.clear() - sut.getAllStates.isEmpty shouldEqual true - } - } -} diff --git a/src/test/scala/de/retest/guistatemachine/api/impl/serialization/GuiStateMachineJavaObjectStreamSerializerSpec.scala b/src/test/scala/de/retest/guistatemachine/api/impl/GuiStateMachineJavaObjectStreamSerializerSpec.scala similarity index 93% rename from src/test/scala/de/retest/guistatemachine/api/impl/serialization/GuiStateMachineJavaObjectStreamSerializerSpec.scala rename to src/test/scala/de/retest/guistatemachine/api/impl/GuiStateMachineJavaObjectStreamSerializerSpec.scala index d9c5f1e..d06d6e9 100644 --- a/src/test/scala/de/retest/guistatemachine/api/impl/serialization/GuiStateMachineJavaObjectStreamSerializerSpec.scala +++ b/src/test/scala/de/retest/guistatemachine/api/impl/GuiStateMachineJavaObjectStreamSerializerSpec.scala @@ -1,8 +1,7 @@ -package de.retest.guistatemachine.api.impl.serialization +package de.retest.guistatemachine.api.impl import java.io.File -import de.retest.guistatemachine.api.impl.GuiStateMachineImpl import de.retest.guistatemachine.api.{AbstractApiSpec, ActionIdentifier, GuiStateMachineSerializer, SutStateIdentifier} import de.retest.surili.commons.actions.NavigateToAction import org.scalatest.BeforeAndAfterEach @@ -53,7 +52,6 @@ class GuiStateMachineJavaObjectStreamSerializerSpec extends AbstractApiSpec with loadedInitialState.getOutgoingActionTransitions.size shouldEqual 1 loadedInitialState.getOutgoingActionTransitions.contains(action0Identifier) shouldEqual true val loadedTransition = loadedInitialState.getOutgoingActionTransitions(action0Identifier) - loadedTransition.executionCounter shouldEqual 1 loadedTransition.states.size shouldEqual 1 loadedTransition.states.head shouldEqual loadedFinalState loadedFinalState.getSutStateIdentifier shouldEqual finalSutStateIdentifier 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 deleted file mode 100644 index 4eb9e18..0000000 --- a/src/test/scala/de/retest/guistatemachine/api/impl/serialization/GuiStateMachineGMLSerializerSpec.scala +++ /dev/null @@ -1,166 +0,0 @@ -package de.retest.guistatemachine.api.impl.serialization - -import java.io.File - -import de.retest.guistatemachine.api.impl.GuiStateMachineImpl -import de.retest.guistatemachine.api.{AbstractApiSpec, GuiStateMachineSerializer} -import de.retest.surili.commons.actions.NavigateToAction -import org.scalatest.BeforeAndAfterEach - -class GuiStateMachineGMLSerializerSpec extends AbstractApiSpec with BeforeAndAfterEach { - private val guiStateMachine = new GuiStateMachineImpl - - override def beforeEach() { - guiStateMachine.clear() - } - - "GuiStateMachineGMLSerializer" should { - "save GML " in { - val rootElementA = getRootElement("a", 0) - val rootElementB = getRootElement("b", 0) - val rootElementC = getRootElement("c", 0) - val action0 = new NavigateToAction("http://google.com") - val action1 = new NavigateToAction("http://wikipedia.org") - - val initialSutState = createSutState(rootElementA, rootElementB, rootElementC) - val finalSutState = createSutState(rootElementC) - - // Create the whole state machine: - guiStateMachine.executeAction(initialSutState, action0, finalSutState) - guiStateMachine.executeAction(initialSutState, action1, finalSutState) - guiStateMachine.executeAction(finalSutState, action0, initialSutState) - guiStateMachine.executeAction(finalSutState, action1, initialSutState) - - val filePath = "./target/test_state_machine.gml" - val oldFile = new File(filePath) - - if (oldFile.exists()) { oldFile.delete() } shouldEqual true - - GuiStateMachineSerializer.gml(guiStateMachine).save(filePath) - - val f = new File(filePath) - f.exists() shouldEqual true - f.isDirectory shouldEqual false - - val source = scala.io.Source.fromFile(filePath) - val lines = source.mkString - lines shouldEqual - """Creator "JGraphT GML Exporter - modified by Hayato Hess, Andreas Hofstadler" - |Version 1 - |graph - |[ - | label "" - | directed 1 - | node - | [ - | id 1 - | label "SutStateIdentifier[sutState=State[descriptor=[]], hash=acd05dfba59670825451169c470d430727226dd0dec48c64961305a0c5ab1ecb]" - | graphics - | [ - | type "rectangle" - | fill "#c0c0c0ff" - | line "#000000ff" - | ] - | LabelGraphics - | [ - | fontStyle "ITALIC" - | ] - | ] - | node - | [ - | id 2 - | label "SutStateIdentifier[sutState=State[descriptor=[, , ]], hash=c44472d3d18e4f62b073a232e3119de9d94d3c6242b65125f454d62aced7f84e]" - | graphics - | [ - | type "rectangle" - | fill "#c0c0c0ff" - | line "#000000ff" - | ] - | LabelGraphics - | [ - | fontStyle "ITALIC" - | ] - | ] - | edge - | [ - | id 3 - | source 1 - | target 2 - | label "ActionIdentifier[action=NavigateToAction(url=http://wikipedia.org), hash=240d08498736de4d893c146fd64b58b1ae1eda8c36a565919b035d86c6ee2084]" - | LabelGraphics - | [ - | model "centered" - | position "center" - | ] - | graphics - | [ - | fill "#000000ff" - | style "DASHED" - | targetArrow "short" - | ] - | ] - | edge - | [ - | id 4 - | source 1 - | target 2 - | label "ActionIdentifier[action=NavigateToAction(url=http://google.com), hash=fd00ea22cb50efd96c3ff59d8900685d0d64f2cee1e77873133e7e186afd2e7f]" - | LabelGraphics - | [ - | model "centered" - | position "center" - | ] - | graphics - | [ - | fill "#000000ff" - | style "DASHED" - | targetArrow "short" - | ] - | ] - | edge - | [ - | id 5 - | source 2 - | target 1 - | label "ActionIdentifier[action=NavigateToAction(url=http://wikipedia.org), hash=240d08498736de4d893c146fd64b58b1ae1eda8c36a565919b035d86c6ee2084]" - | LabelGraphics - | [ - | model "centered" - | position "center" - | ] - | graphics - | [ - | fill "#000000ff" - | style "DASHED" - | targetArrow "short" - | ] - | ] - | edge - | [ - | id 6 - | source 2 - | target 1 - | label "ActionIdentifier[action=NavigateToAction(url=http://google.com), hash=fd00ea22cb50efd96c3ff59d8900685d0d64f2cee1e77873133e7e186afd2e7f]" - | LabelGraphics - | [ - | model "centered" - | position "center" - | ] - | graphics - | [ - | fill "#000000ff" - | style "DASHED" - | targetArrow "short" - | ] - | ] - |] - |""".stripMargin - - source.close() - } - - "load GML " in { - the[UnsupportedOperationException] thrownBy GuiStateMachineSerializer.gml(guiStateMachine).load("bla") should have message "Loading GML is not supported." - } - } -} diff --git a/src/test/scala/de/retest/guistatemachine/api/neo4j/GuiStateMachineApiNeo4jSpec.scala b/src/test/scala/de/retest/guistatemachine/api/neo4j/GuiStateMachineApiNeo4jSpec.scala new file mode 100644 index 0000000..216d5f2 --- /dev/null +++ b/src/test/scala/de/retest/guistatemachine/api/neo4j/GuiStateMachineApiNeo4jSpec.scala @@ -0,0 +1,16 @@ +package de.retest.guistatemachine.api.neo4j + +import java.nio.file.Files + +import de.retest.guistatemachine.api.{AbstractGuiStateMachineApiSpec, GuiStateMachineApi} +import org.scalatest.BeforeAndAfterAll + +class GuiStateMachineApiNeo4jSpec extends AbstractGuiStateMachineApiSpec with BeforeAndAfterAll { + private val tempDir = Files.createTempDirectory("GuiStateMachineApiNeo4jSpec").toFile + override def getName: String = "GuiStateMachineApiNeo4J" + override def getCut: GuiStateMachineApi = new GuiStateMachineApiNeo4J(tempDir.getAbsolutePath) + + override def afterAll(): Unit = { + tempDir.delete() + } +}