Fix small issue related to mutable justifications in Occurrence. Upd tests with latest changes.
This commit is contained in:
parent
ef2627cab4
commit
769e7fd2ba
|
|
@ -31,6 +31,7 @@ typealias Justs = TIntSet
|
|||
fun emptyJusts() = TIntHashSet(1)
|
||||
fun justsOf(vararg elements: Int) = TIntHashSet(elements)
|
||||
fun justsFromCollection(collection: Collection<Int>) = TIntHashSet(collection)
|
||||
fun justsCopy(other: Justs) = TIntHashSet(other)
|
||||
|
||||
|
||||
data class OccurrenceObserver(val occurrence: Occurrence, val controller: Controller) : LogicalObserver {
|
||||
|
|
|
|||
|
|
@ -207,7 +207,7 @@ internal class ControllerImpl (
|
|||
val args = supervisor.instantiateArguments(constraint.arguments(), context.logicalContext, context)
|
||||
return context.eval { status ->
|
||||
|
||||
state.processActivated(this, constraint.occurrence(this, args, justs, context.logicalContext), status)
|
||||
state.processActivated(this, constraint.occurrence(this, args, justsCopy(justs), context.logicalContext), status)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -161,7 +161,6 @@ interface MatchJournal : MutableIterable<MatchJournal.Chunk> {
|
|||
}
|
||||
|
||||
class OccChunk(override val id: Int, val occ: Occurrence) : Chunk {
|
||||
|
||||
init { occ.justifications.add(id) }
|
||||
|
||||
override val justifications: Justs
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
package jetbrains.mps.logic.reactor.core.internal
|
||||
|
||||
import jetbrains.mps.logic.reactor.core.ProcessingState
|
||||
import jetbrains.mps.logic.reactor.program.IncrementalProgramSpec
|
||||
import java.lang.IllegalArgumentException
|
||||
|
||||
|
||||
|
|
@ -32,7 +33,10 @@ interface StoreAwareJournal : MatchJournal, ProcessingState {
|
|||
|
||||
// for tests
|
||||
companion object {
|
||||
fun fromView(view: MatchJournal.View? = null): StoreAwareJournal = StoreAwareJournalImpl(MatchJournalImpl(view))
|
||||
fun fromView(
|
||||
ispec: IncrementalProgramSpec = IncrementalProgramSpec.DefaultSpec,
|
||||
view: MatchJournal.View? = null
|
||||
): StoreAwareJournal = StoreAwareJournalImpl(MatchJournalImpl(ispec, view))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright 2014-2019 JetBrains s.r.o.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import jetbrains.mps.logic.reactor.program.Constraint
|
||||
import jetbrains.mps.logic.reactor.program.ConstraintSymbol
|
||||
import jetbrains.mps.logic.reactor.program.IncrementalProgramSpec
|
||||
import jetbrains.mps.logic.reactor.program.Rule
|
||||
|
||||
class MockIncrProgSpec(val principalRuleTags: Set<Any>, val principalCtrSyms: Set<ConstraintSymbol>) : IncrementalProgramSpec {
|
||||
override fun isPrincipal(ctr: Constraint): Boolean = principalCtrSyms.contains(ctr.symbol())
|
||||
override fun isPrincipal(rule: Rule): Boolean = principalRuleTags.contains(rule.uniqueTag())
|
||||
}
|
||||
|
|
@ -7,7 +7,6 @@ import jetbrains.mps.logic.reactor.evaluation.EvaluationResult
|
|||
import jetbrains.mps.logic.reactor.evaluation.EvaluationSession
|
||||
import jetbrains.mps.logic.reactor.program.Constraint
|
||||
import jetbrains.mps.logic.reactor.program.ConstraintSymbol
|
||||
import jetbrains.mps.logic.reactor.program.Rule as CRule
|
||||
import org.junit.*
|
||||
import org.junit.Assert.assertNotEquals
|
||||
import program.MockConstraint
|
||||
|
|
@ -48,11 +47,6 @@ class TestIncrementalProgram {
|
|||
}
|
||||
}
|
||||
|
||||
private class MockIncrProgSpec(val principalRuleTags: Set<Any>, val principalCtrSyms: Set<ConstraintSymbol>) : IncrementalProgramSpec {
|
||||
override fun isPrincipal(ctr: Constraint): Boolean = principalCtrSyms.contains(ctr.symbol())
|
||||
override fun isPrincipal(rule: CRule): Boolean = principalRuleTags.contains(rule.uniqueTag())
|
||||
}
|
||||
|
||||
private fun Builder.launch(name: String, incrSpec: IncrementalProgramSpec, resultHandler: (EvaluationResult) -> Unit)
|
||||
: Pair<Builder, EvaluationResult>
|
||||
{
|
||||
|
|
@ -230,7 +224,7 @@ class TestIncrementalProgram {
|
|||
).launch("addRule", progSpec) { result ->
|
||||
|
||||
result.storeView().constraintSymbols() shouldBe setOf(sym0("foo"), sym0("main"))
|
||||
result.countChunks() shouldBe 2
|
||||
result.countChunks() shouldBe 3
|
||||
result.lastChunkSymbols() shouldBe listOf(sym0("foo"))
|
||||
|
||||
}.also { (builder, evalRes) ->
|
||||
|
|
@ -246,7 +240,7 @@ class TestIncrementalProgram {
|
|||
).relaunch("atStart", progSpec, evalRes.token()) { result ->
|
||||
|
||||
result.storeView().constraintSymbols() shouldBe setOf(sym0("foo"), sym0("main"), sym0("bar"))
|
||||
result.countChunks() shouldBe 3
|
||||
result.countChunks() shouldBe 3+1
|
||||
result.lastChunkSymbols() shouldBe listOf(sym0("bar"))
|
||||
}
|
||||
}
|
||||
|
|
@ -635,7 +629,7 @@ class TestIncrementalProgram {
|
|||
// if "foobar" happens too early, "1st" occ won't be produced
|
||||
result.storeView().constraintSymbols() shouldBe setOf(sym0("foo"), sym0("bar"), sym0("marker"))
|
||||
result.lastChunkSymbols() shouldBe listOf(sym0("marker"))
|
||||
result.countChunks() shouldBe (2 + nPrincipalMatches) // +[.bar, foobar]
|
||||
result.countChunks() shouldBe (2 + 1 + nPrincipalMatches) // +[.bar, foobar] +activation of bar
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -859,7 +853,7 @@ class TestIncrementalProgram {
|
|||
|
||||
result.storeView().constraintSymbols() shouldBe setOf(sym0("lax"))
|
||||
result.lastChunkSymbols() shouldBe listOf(sym0("lax"))
|
||||
result.countChunks() shouldBe (nPrincipalMatches - 2)
|
||||
result.countChunks() shouldBe (nPrincipalMatches - 3)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -910,13 +904,12 @@ class TestIncrementalProgram {
|
|||
}.also { (builder, evalRes) ->
|
||||
val nPrincipalMatches = evalRes.countChunks()
|
||||
|
||||
// "barbaz.qux" rule match is removed as a dependency of "foo.bar" match
|
||||
builder.removeRules(listOf("foo.bar"))
|
||||
.relaunch("removed", progSpec, evalRes.token()) { result ->
|
||||
|
||||
result.storeView().constraintSymbols() shouldBe setOf(sym0("lax"))
|
||||
result.lastChunkSymbols() shouldBe listOf(sym0("lax"))
|
||||
result.countChunks() shouldBe (nPrincipalMatches - 1 + 2)
|
||||
result.countChunks() shouldBe (nPrincipalMatches - 1 + 3)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1026,7 +1019,7 @@ class TestIncrementalProgram {
|
|||
))
|
||||
).relaunch("substituted", progSpec, evalRes.token()) { result ->
|
||||
|
||||
result.countChunks() shouldBe (nPrincipalMatches - 1)
|
||||
result.countChunks() shouldBe (nPrincipalMatches - 3 + 1)
|
||||
result.lastChunkSymbols() shouldBe listOf(sym0("bar"))
|
||||
}
|
||||
}
|
||||
|
|
@ -1097,7 +1090,7 @@ class TestIncrementalProgram {
|
|||
|
||||
// println(result.token().journalView.chunks)
|
||||
|
||||
result.countChunks() shouldBe (nPrincipalMatches)
|
||||
result.countChunks() shouldBe (nPrincipalMatches - 1)
|
||||
result.storeView().constraintSymbols() shouldBe setOf(sym0("bar"))
|
||||
result.lastChunkSymbols() shouldBe listOf(sym0("bar"))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
import jetbrains.mps.logic.reactor.core.*
|
||||
import jetbrains.mps.logic.reactor.core.internal.*
|
||||
import jetbrains.mps.logic.reactor.program.Constraint
|
||||
import jetbrains.mps.logic.reactor.program.ConstraintSymbol
|
||||
import jetbrains.mps.logic.reactor.program.IncrementalProgramSpec
|
||||
import jetbrains.mps.logic.reactor.program.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.Assert.*
|
||||
import org.junit.Ignore
|
||||
|
|
@ -24,8 +27,16 @@ import org.junit.Ignore
|
|||
|
||||
class TestStoreAwareJournal {
|
||||
|
||||
private class JournalDispatcherHelper(dispatcher: Dispatcher, val hist: StoreAwareJournal = StoreAwareJournal.fromView())
|
||||
{
|
||||
private object LegacyMockIncrProgSpec : IncrementalProgramSpec {
|
||||
override fun isPrincipal(ctr: Constraint): Boolean = ctr.isPrincipal
|
||||
override fun isPrincipal(rule: Rule): Boolean = rule.all().any { it is Constraint && it.isPrincipal }
|
||||
}
|
||||
|
||||
private class JournalDispatcherHelper(
|
||||
dispatcher: Dispatcher,
|
||||
ispec: IncrementalProgramSpec = LegacyMockIncrProgSpec,
|
||||
val hist: StoreAwareJournal = StoreAwareJournal.fromView(ispec)
|
||||
) {
|
||||
var d: Dispatcher.DispatchingFront = dispatcher.front()
|
||||
|
||||
fun logExpand(occ: Occurrence) {
|
||||
|
|
@ -37,7 +48,7 @@ class TestStoreAwareJournal {
|
|||
|
||||
// log and expand occurrence while tracking its justifications
|
||||
fun logExpandJustified(id: String, vararg args: Any) =
|
||||
logExpand(justifiedOccurrence(id, hist.justs(), * args))
|
||||
logExpand(justifiedOccurrence(id, justsCopy(hist.justs()), * args))
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -76,7 +87,7 @@ class TestStoreAwareJournal {
|
|||
// log first 'foo' match
|
||||
|
||||
hist.logMatch(fooMatches.first())
|
||||
hist.justs() shouldBe justsOf(1)
|
||||
hist.justs() shouldBe justsOf(1,2)
|
||||
|
||||
logExpandJustified("bar")
|
||||
d.matches().count() shouldBe 0
|
||||
|
|
@ -84,13 +95,13 @@ class TestStoreAwareJournal {
|
|||
// log second 'foo' match
|
||||
|
||||
hist.logMatch(fooMatches.elementAt(1))
|
||||
hist.justs() shouldBe justsOf(1,2)
|
||||
hist.justs() shouldBe justsOf(1,4)
|
||||
|
||||
logExpandJustified("qux")
|
||||
d.matches().count() shouldBe 1
|
||||
|
||||
logFirstMatch()
|
||||
hist.justs() shouldBe justsOf(1,2,3)
|
||||
hist.justs() shouldBe justsOf(1,2,3,4,5,6) // 3 & 5 are ids of OccChunks
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -130,6 +141,8 @@ class TestStoreAwareJournal {
|
|||
|
||||
logExpand(justifiedOccurrence("foo", setOf(1)))
|
||||
|
||||
val fooPos = hist.currentPos()
|
||||
|
||||
logFirstMatch()
|
||||
logExpandJustified("bar")
|
||||
|
||||
|
|
@ -146,7 +159,7 @@ class TestStoreAwareJournal {
|
|||
|
||||
storeView().constraintSymbols() shouldBe setOf(sym0("qux"), sym0("lax"))
|
||||
val nchunks = view().chunks.size
|
||||
nchunks shouldBe 4
|
||||
nchunks shouldBe 4 * 2 // 4 rules, each activates 1 principal occurrence
|
||||
|
||||
// try replay the last chunk
|
||||
replay(mockController, lastPos)
|
||||
|
|
@ -164,8 +177,12 @@ class TestStoreAwareJournal {
|
|||
|
||||
replay(mockController, initPos)
|
||||
|
||||
// storeView replays only the initial chunk, journal remains the same
|
||||
storeView().constraintSymbols() shouldBe setOf<ConstraintSymbol>()
|
||||
|
||||
replay(mockController, fooPos)
|
||||
|
||||
storeView().constraintSymbols() shouldBe setOf(sym0("foo"))
|
||||
// although storeView() results change, journal remains the same
|
||||
view().chunks.size shouldBe nchunks
|
||||
}
|
||||
}
|
||||
|
|
@ -337,7 +354,6 @@ class TestStoreAwareJournal {
|
|||
hist.testPush()
|
||||
// last production from rule2
|
||||
logExpand(quxOcc)
|
||||
// logExpandJustified("qux")
|
||||
|
||||
|
||||
// rule4
|
||||
|
|
@ -352,12 +368,9 @@ class TestStoreAwareJournal {
|
|||
val oldStore = hist.storeView().allOccurrences()
|
||||
val savedPos = hist.currentPos()
|
||||
|
||||
// println("chunks on save: ${oldState.chunks}")
|
||||
hist.testPush()
|
||||
logExpand(occurrence("last"))
|
||||
|
||||
// println("chunks on save: ${oldState.chunks}")
|
||||
// println("chunks on exec: ${hist.view().chunks}")
|
||||
oldState.chunks.size shouldBe 3
|
||||
assertNotEquals(oldState.chunks, hist.view().chunks)
|
||||
assertNotEquals(oldStore, hist.storeView().allOccurrences())
|
||||
|
|
@ -373,6 +386,7 @@ class TestStoreAwareJournal {
|
|||
}
|
||||
|
||||
|
||||
@Ignore("manipulating journal without controller is too fragile. not a good test.")
|
||||
@Test
|
||||
fun testRmAddInMiddle() {
|
||||
val mockController = MockController()
|
||||
|
|
@ -452,9 +466,12 @@ class TestStoreAwareJournal {
|
|||
// continue from the second chunk (match of rule1)
|
||||
val rmIt = iterator()
|
||||
rmIt.next() // skip initial chunk
|
||||
val continueFrom = rmIt.next().toPos()
|
||||
rmIt.next()
|
||||
rmIt.remove()
|
||||
rmIt.next() // 'foo' activation
|
||||
val continueFrom = rmIt.next().toPos() // 'rule1' activation
|
||||
rmIt.next() // 'bar1' activation
|
||||
rmIt.next() // 'bazz' activation
|
||||
rmIt.next() // 'rule2a' match
|
||||
rmIt.remove() // rm rule2a match
|
||||
|
||||
// store is not longer valid after removing chunks from history, so reset it
|
||||
resetStore()
|
||||
|
|
@ -462,14 +479,14 @@ class TestStoreAwareJournal {
|
|||
replay(mockController, continueFrom)
|
||||
|
||||
// according to the history 'qux' wasn't activated at this point & 'bar1' wasn't discarded
|
||||
storeView().constraintSymbols() shouldBe setOf(sym0("bazz"), sym0("bar1"))
|
||||
storeView().constraintSymbols() shouldBe setOf<ConstraintSymbol>()
|
||||
}
|
||||
|
||||
// add another instance of bar (i.e. bar2) and trigger another rule, rule2b
|
||||
// (bar2 plays a role of the reactivation of original bar)
|
||||
logExpandJustified("bar2")
|
||||
// 'bazz' is already expanded from the first execution
|
||||
hist.justs() shouldBe justsOf(1) // dependency is only the first chunk
|
||||
hist.justs() shouldBe justsOf(1,2,7) // dependency is only the first chunk, the first activation + new id
|
||||
|
||||
// we have only a single _new_ match; rule3 has been matched already and remains in the history, in future
|
||||
d.matches().count() shouldBe 1
|
||||
|
|
|
|||
Loading…
Reference in New Issue