From 5771d78b24433b9bcda73f0242b08aca5371c81e Mon Sep 17 00:00:00 2001 From: Fedor Isakov Date: Fri, 25 Jan 2019 13:52:10 +0100 Subject: [PATCH] Logical with assigned value has higher rank. Notifications are to be dispatched accordingly. --- .../mps/logic/reactor/core/Logical.kt | 14 ++- reactor/Test/test/AssertHelper.kt | 4 + reactor/Test/test/TestLogical.kt | 110 ++++++++++++++++++ 3 files changed, 125 insertions(+), 3 deletions(-) create mode 100644 reactor/Test/test/TestLogical.kt diff --git a/reactor/Core/src/jetbrains/mps/logic/reactor/core/Logical.kt b/reactor/Core/src/jetbrains/mps/logic/reactor/core/Logical.kt index adaadbc1..3eceec55 100644 --- a/reactor/Core/src/jetbrains/mps/logic/reactor/core/Logical.kt +++ b/reactor/Core/src/jetbrains/mps/logic/reactor/core/Logical.kt @@ -119,16 +119,24 @@ class LogicalImpl : JoinableLogical { val otherRepr = (other as LogicalImpl).find() if (thisRepr === otherRepr) { - throw IllegalStateException("cannnot unite logical with itself") + // nothing to do + return } // invariant: thisRepr.rank > otherRepr.rank if (thisRepr.rank() < otherRepr.rank()) { otherRepr.union(thisRepr, reconciler); - return; + return } else if (thisRepr.rank() == otherRepr.rank()) { - thisRepr.incRank(); + if (thisRepr._value == null && otherRepr._value != null) { + otherRepr.union(thisRepr, reconciler); + return + + } else { + thisRepr.incRank(); + + } } val thisVal = thisRepr.value(); diff --git a/reactor/Test/test/AssertHelper.kt b/reactor/Test/test/AssertHelper.kt index c7155a55..d1312c47 100644 --- a/reactor/Test/test/AssertHelper.kt +++ b/reactor/Test/test/AssertHelper.kt @@ -22,3 +22,7 @@ import org.junit.Assert infix fun A.shouldBe(that: B) = Assert.assertEquals(that, this) +infix fun A.shouldBeSame(that: B) = Assert.assertSame(that, this) + +infix fun A.shouldNotBeSame(that: B) = Assert.assertNotSame(that, this) + diff --git a/reactor/Test/test/TestLogical.kt b/reactor/Test/test/TestLogical.kt new file mode 100644 index 00000000..1c2dbf04 --- /dev/null +++ b/reactor/Test/test/TestLogical.kt @@ -0,0 +1,110 @@ +import jetbrains.mps.logic.reactor.core.LogicalImpl +import jetbrains.mps.logic.reactor.core.LogicalObserver +import jetbrains.mps.logic.reactor.core.addObserver +import jetbrains.mps.logic.reactor.logical.JoinableLogical +import jetbrains.mps.logic.reactor.logical.Logical +import org.junit.Test +import kotlin.math.log + +/* + * 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. + */ + +/** + * @author Fedor Isakov + */ + +class TestLogical { + + inline fun logical(name: String): JoinableLogical = LogicalImpl(name) + + class Observer(logical: Logical<*>): LogicalObserver { + + var parentUpdated: Pair, Logical<*>>? = null + var valueUpdated: Pair, Any>? = null + + init { + logical.addObserver(this) + } + + override fun valueUpdated(logical: Logical<*>) { + if (valueUpdated != null) + throw IllegalStateException("value already assigned") + else + valueUpdated = logical to logical.findRoot().value() + } + + override fun parentUpdated(logical: Logical<*>) { + parentUpdated = logical to logical.findRoot() + } + } + + @Test + fun union_notifies_observers () { + val xLogical = logical("X") + val yLogical = logical("Y") + val zLogical = logical("Z") + + val observerX = Observer(xLogical) + val observerY = Observer(yLogical) + val observerZ = Observer(zLogical) + + // the logical on the left has higher rank + yLogical.union(xLogical) + observerX.parentUpdated shouldBe (xLogical to yLogical) + observerY.parentUpdated shouldBe (null) + + // now logical on the right has higher rank + zLogical.union(xLogical) + observerZ.parentUpdated shouldBe (zLogical to yLogical) + observerY.parentUpdated shouldBe (null) + + // should not fail + yLogical.union(zLogical) + } + + @Test + fun assigned_logical_has_higher_rank() { + val xLogical = logical("X") + val yLogical = logical("Y") + val observerX = Observer(xLogical) + val observerY = Observer(yLogical) + + xLogical.union(yLogical) + observerY.parentUpdated shouldBe (yLogical to xLogical) + observerX.parentUpdated shouldBe (null) + yLogical.findRoot() shouldBeSame xLogical + + yLogical.findRoot().setValue("foobar") + observerX.valueUpdated shouldBe (xLogical to "foobar") + observerY.valueUpdated shouldBe (yLogical to "foobar") + + val zLogical = logical("Z") + val wLogical = logical("W") + val observerZ = Observer(zLogical) + val observerW = Observer(wLogical) + + zLogical.union(wLogical) + observerW.parentUpdated shouldBe (wLogical to zLogical) + observerZ.parentUpdated shouldBe (null) + + zLogical.union(yLogical) + zLogical.findRoot() shouldBeSame xLogical + observerZ.parentUpdated shouldBe (zLogical to xLogical) + observerW.parentUpdated shouldBe (wLogical to xLogical) + observerZ.valueUpdated shouldBe (zLogical to "foobar") + observerW.valueUpdated shouldBe (wLogical to "foobar") + } +} \ No newline at end of file