Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 24 additions & 10 deletions idealPDS/src/main/java/typestate/TransitionFunctionImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import com.google.common.collect.Multimap;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
Expand All @@ -35,15 +36,16 @@
public class TransitionFunctionImpl implements TransitionFunction {

@NonNull private final Multimap<Transition, StatementSequence> stateChangeSequences;
@NonNull private final Statement stateChangeStatement;
@NonNull private final LinkedHashSet<Statement> stateChangeStatements;

public TransitionFunctionImpl(
@NonNull Transition transition, @NonNull Statement stateChangeStatement) {
this.stateChangeSequences =
ImmutableMultimap.of(
transition,
new StatementSequence(new StatementSequence.Entry(stateChangeStatement, transition)));
this.stateChangeStatement = stateChangeStatement;
this.stateChangeStatements = new LinkedHashSet<>();
stateChangeStatements.add(stateChangeStatement);
}

public TransitionFunctionImpl(
Expand All @@ -56,14 +58,23 @@ public TransitionFunctionImpl(
}

this.stateChangeSequences = ImmutableMultimap.copyOf(sequencesMap);
this.stateChangeStatement = stateChangeStatement;
this.stateChangeStatements = new LinkedHashSet<>();
stateChangeStatements.add(stateChangeStatement);
}

public TransitionFunctionImpl(
@NonNull Multimap<Transition, StatementSequence> transitionStatementSequences,
@NonNull Statement stateChangeStatement) {
this.stateChangeSequences = ImmutableMultimap.copyOf(transitionStatementSequences);
this.stateChangeStatement = stateChangeStatement;
this.stateChangeStatements = new LinkedHashSet<>();
stateChangeStatements.add(stateChangeStatement);
}

public TransitionFunctionImpl(
@NonNull Multimap<Transition, StatementSequence> transitionStatementSequences,
@NonNull LinkedHashSet<Statement> stateChangeStatements) {
this.stateChangeSequences = ImmutableMultimap.copyOf(transitionStatementSequences);
this.stateChangeStatements = new LinkedHashSet<>(stateChangeStatements);
}
Comment thread
swissiety marked this conversation as resolved.
Outdated

@NonNull
Expand All @@ -73,7 +84,7 @@ public Multimap<Transition, StatementSequence> getStateChangeSequences() {
}

public Statement getStateChangeStatement() {
return stateChangeStatement;
return stateChangeStatements.iterator().next();
}

@NonNull
Expand Down Expand Up @@ -122,7 +133,7 @@ public Weight extendWith(@NonNull Weight other) {
}
}
}
return new TransitionFunctionImpl(result, func.stateChangeStatement);
return new TransitionFunctionImpl(result, func.getStateChangeStatement());
}

@NonNull
Expand All @@ -146,16 +157,19 @@ public Weight combineWith(@NonNull Weight other) {
transitions.putAll(idTransition, statements);
}

return new TransitionFunctionImpl(transitions, this.stateChangeStatement);
return new TransitionFunctionImpl(transitions, this.getStateChangeStatement());
}

TransitionFunctionImpl func = (TransitionFunctionImpl) other;

Multimap<Transition, StatementSequence> sequences = HashMultimap.create();
sequences.putAll(stateChangeSequences);
sequences.putAll(func.stateChangeSequences);
LinkedHashSet<Statement> mergedStateChangeStatements = new LinkedHashSet<>();
mergedStateChangeStatements.addAll(func.stateChangeStatements);
mergedStateChangeStatements.addAll(stateChangeStatements);

return new TransitionFunctionImpl(sequences, func.stateChangeStatement);
return new TransitionFunctionImpl(sequences, mergedStateChangeStatements);
}

@Override
Expand All @@ -169,11 +183,11 @@ public boolean equals(Object o) {
if (o == null || getClass() != o.getClass()) return false;
TransitionFunctionImpl that = (TransitionFunctionImpl) o;
return Objects.equals(stateChangeSequences, that.stateChangeSequences)
&& Objects.equals(stateChangeStatement, that.stateChangeStatement);
&& Objects.equals(stateChangeStatements, that.stateChangeStatements);
}

@Override
public int hashCode() {
return Objects.hash(stateChangeSequences, stateChangeStatement);
return Objects.hash(stateChangeSequences, stateChangeStatements);
}
}
57 changes: 57 additions & 0 deletions idealPDS/src/test/java/typestate/TransitionFunctionImplTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/**
* *****************************************************************************
* Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany
* <p>
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
* <p>
* SPDX-License-Identifier: EPL-2.0
* <p>
* Contributors:
* Johannes Spaeth - initial API and implementation
* *****************************************************************************
*/
package typestate;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals;

import boomerang.scope.Method;
import boomerang.scope.Statement;
import boomerang.utils.MethodWrapper;
import java.util.Collections;
import org.junit.jupiter.api.Test;
import test.TestingFramework;
import wpds.impl.Weight;

public class TransitionFunctionImplTest {

@Test
public void testCombineWithCommutative() {
TestingFramework testingFramework = new TestingFramework();
testingFramework.getFrameworkScope(
new MethodWrapper(getClass().getName(), "testCombineWithCommutative"));
Method method = testingFramework.getTestMethod();
Statement first = method.getStatements().get(0);
Statement second = method.getStatements().get(1);
assertNotEquals(first, second);
TransitionFunctionImpl firstTransitionFunction =
new TransitionFunctionImpl(Collections.emptySet(), first);
TransitionFunctionImpl secondTransitionFunction =
new TransitionFunctionImpl(Collections.emptySet(), second);
assertNotEquals(firstTransitionFunction, secondTransitionFunction);
Weight firstSecondResult = firstTransitionFunction.combineWith(secondTransitionFunction);
Weight secondFirstResult = secondTransitionFunction.combineWith(firstTransitionFunction);
assertEquals(firstSecondResult, secondFirstResult);
// ensure that the behavior of getChangeStatement() is as in the
// non-commutative implementation (whether this behavior is "meaningful" is
// debatable, though)
assertEquals(
secondTransitionFunction.getStateChangeStatement(),
((TransitionFunctionImpl) firstSecondResult).getStateChangeStatement());
assertEquals(
firstTransitionFunction.getStateChangeStatement(),
((TransitionFunctionImpl) secondFirstResult).getStateChangeStatement());
}
}
22 changes: 22 additions & 0 deletions idealPDS/src/test/java/typestate/VectorTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -119,4 +119,26 @@ public void staticAccessTest() {
v.firstElement();
Assertions.mustBeInErrorState(v);
}

public void doSth(Vector<Object> x, Object element) {
if (staticallyUnknown()) {
x.add(element);
} else {
element = x.elementAt(0);
}
}

@Test
@TestParameters(expectedSeedCount = 1, expectedAssertionCount = 1)
public void testNoStackOverflowDueToNonCommutativeCombineWith() {
Vector<Object> x = new Vector<>();
Object element = new Object();
x.add(element);
while (staticallyUnknown()) {
// the method call seems to be crucial for triggering the StackOverflowError
// (inlining the code from doSth does not trigger the error)
doSth(x, element);
}
Assertions.mustBeInAcceptingState(x);
}
}
Loading