-
Notifications
You must be signed in to change notification settings - Fork 323
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Testing current behavior of if/then/else (#11395)
Related to #9165 work. Let's make sure the current behavior of `if`/`then`/`else` is properly tested by a unit test. Extracting test created as part of #11365 to verify it really describes the current behavior.
- Loading branch information
1 parent
ca9df70
commit 4898445
Showing
1 changed file
with
299 additions
and
0 deletions.
There are no files selected for viewing
299 changes: 299 additions & 0 deletions
299
engine/runtime-integration-tests/src/test/java/org/enso/compiler/test/IfThenElseTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,299 @@ | ||
package org.enso.compiler.test; | ||
|
||
import static org.hamcrest.MatcherAssert.assertThat; | ||
import static org.junit.Assert.assertEquals; | ||
import static org.junit.Assert.assertNotNull; | ||
import static org.junit.Assert.assertTrue; | ||
import static org.junit.Assert.fail; | ||
|
||
import com.oracle.truffle.api.interop.InteropLibrary; | ||
import com.oracle.truffle.api.interop.TruffleObject; | ||
import com.oracle.truffle.api.library.ExportLibrary; | ||
import com.oracle.truffle.api.library.ExportMessage; | ||
import java.io.ByteArrayOutputStream; | ||
import org.enso.test.utils.ContextUtils; | ||
import org.graalvm.polyglot.Context; | ||
import org.graalvm.polyglot.PolyglotException; | ||
import org.graalvm.polyglot.Value; | ||
import org.hamcrest.Matchers; | ||
import org.hamcrest.core.AllOf; | ||
import org.junit.After; | ||
import org.junit.AfterClass; | ||
import org.junit.BeforeClass; | ||
import org.junit.Ignore; | ||
import org.junit.Test; | ||
|
||
public class IfThenElseTest { | ||
private static Context ctx; | ||
private static final ByteArrayOutputStream MESSAGES = new ByteArrayOutputStream(); | ||
|
||
@BeforeClass | ||
public static void initEnsoContext() { | ||
ctx = ContextUtils.defaultContextBuilder().out(MESSAGES).err(MESSAGES).build(); | ||
assertNotNull("Enso language is supported", ctx.getEngine().getLanguages().get("enso")); | ||
} | ||
|
||
@After | ||
public void cleanMessages() { | ||
MESSAGES.reset(); | ||
} | ||
|
||
@AfterClass | ||
public static void closeEnsoContext() { | ||
ctx.close(); | ||
ctx = null; | ||
} | ||
|
||
@Test | ||
public void simpleIfThenElse() throws Exception { | ||
var code = """ | ||
check x = if x then "Yes" else "No" | ||
"""; | ||
|
||
var check = ContextUtils.getMethodFromModule(ctx, code, "check"); | ||
|
||
assertEquals("Yes", check.execute(true).asString()); | ||
assertEquals("No", check.execute(false).asString()); | ||
} | ||
|
||
@Test | ||
public void simpleIfThen() throws Exception { | ||
var code = """ | ||
check x = if x then "Yes" | ||
"""; | ||
|
||
var check = ContextUtils.getMethodFromModule(ctx, code, "check"); | ||
|
||
assertEquals("Yes", check.execute(true).asString()); | ||
assertTrue("Expect Nothing", check.execute(false).isNull()); | ||
} | ||
|
||
@Test | ||
public void variableDefinedInThen() throws Exception { | ||
var code = """ | ||
check x = if x then | ||
xt = x.to_text | ||
"Good:"+xt | ||
"""; | ||
|
||
var check = ContextUtils.getMethodFromModule(ctx, code, "check"); | ||
|
||
assertEquals("Good:True", check.execute(true).asString()); | ||
assertTrue("Expect Nothing", check.execute(false).isNull()); | ||
} | ||
|
||
@Test | ||
public void variableDefinedInElse() throws Exception { | ||
var code = | ||
""" | ||
check x = if x then "OKeyish:"+x.to_text else | ||
xt = x.to_text | ||
"Bad:"+xt | ||
"""; | ||
var check = ContextUtils.getMethodFromModule(ctx, code, "check"); | ||
|
||
assertEquals("OKeyish:True", check.execute(true).asString()); | ||
assertEquals("Bad:False", check.execute(false).asString()); | ||
} | ||
|
||
@Test | ||
public void variableUsedAfterTheBranch() throws Exception { | ||
try { | ||
var code = | ||
""" | ||
check x = | ||
res = if x then "OKeyish:"+x.to_text else | ||
xt = x.to_text | ||
"Bad:"+xt | ||
xt | ||
"""; | ||
|
||
var check = ContextUtils.getMethodFromModule(ctx, code, "check"); | ||
fail("Expecting error, but got: " + check); | ||
} catch (PolyglotException ex) { | ||
assertThat( | ||
ex.getMessage(), | ||
AllOf.allOf( | ||
Matchers.containsString("The name `xt` could not be found"), | ||
Matchers.containsString("6:5: error"))); | ||
} | ||
} | ||
|
||
@Test | ||
public void conditionMustBeBoolean() throws Exception { | ||
var code = """ | ||
check x = if x then "Yes" else "No" | ||
"""; | ||
|
||
var check = ContextUtils.getMethodFromModule(ctx, code, "check"); | ||
|
||
try { | ||
var res = check.execute("Yes").asString(); | ||
fail("Expecting error, not: " + res); | ||
} catch (PolyglotException ex) { | ||
assertThat(ex.getMessage(), Matchers.containsString(".Error")); | ||
} | ||
try { | ||
var res = check.execute((Object) null).asString(); | ||
fail("Expecting error, not: " + res); | ||
} catch (PolyglotException ex) { | ||
assertThat(ex.getMessage(), Matchers.containsString(".Error")); | ||
} | ||
} | ||
|
||
@Test | ||
public void javaScriptBooleanIsSupported() throws Exception { | ||
var code = | ||
""" | ||
foreign js toBool txt = ''' | ||
if (txt == "Ano") return true; | ||
if (txt == "Ne") return false; | ||
throw "What do you mean by: " + txt; | ||
check x = if toBool x then "Yes" else "No" | ||
"""; | ||
|
||
var check = ContextUtils.getMethodFromModule(ctx, code, "check"); | ||
|
||
assertEquals("Yes", check.execute("Ano").asString()); | ||
assertEquals("No", check.execute("Ne").asString()); | ||
} | ||
|
||
@Ignore | ||
@Test | ||
public void truffleObjectConvertibleToBooleanIsSupported() throws Exception { | ||
var code = | ||
""" | ||
from Standard.Base import all | ||
check x = if x then "Yes" else "No" | ||
"""; | ||
|
||
var check = ContextUtils.getMethodFromModule(ctx, code, "check"); | ||
|
||
var t = new BoolObject(true); | ||
var f = new BoolObject(false); | ||
|
||
assertEquals("Yes", check.execute(t).asString()); | ||
assertEquals("No", check.execute(f).asString()); | ||
} | ||
|
||
@ExportLibrary(InteropLibrary.class) | ||
static final class BoolObject implements TruffleObject { | ||
private final boolean value; | ||
|
||
public BoolObject(boolean value) { | ||
this.value = value; | ||
} | ||
|
||
@ExportMessage | ||
boolean isBoolean() { | ||
return true; | ||
} | ||
|
||
@ExportMessage | ||
boolean asBoolean() { | ||
return value; | ||
} | ||
} | ||
|
||
@Test | ||
public void warningsAndIfThenElse() throws Exception { | ||
var code = | ||
""" | ||
from Standard.Base import all | ||
check x = if x then "Yes" else "No" | ||
"""; | ||
|
||
var check = ContextUtils.getMethodFromModule(ctx, code, "check"); | ||
|
||
var warnCode = """ | ||
from Standard.Base import all | ||
warn w v = Warning.attach w v | ||
"""; | ||
var warn = ContextUtils.getMethodFromModule(ctx, warnCode, "warn"); | ||
|
||
var t = warn.execute("Maybe", true); | ||
var f = warn.execute("Maybe not", false); | ||
|
||
var yes = check.execute(t); | ||
var no = check.execute(f); | ||
|
||
assertEquals("Yes", yes.asString()); | ||
assertWarning("Maybe", yes); | ||
assertEquals("No", no.asString()); | ||
assertWarning("Maybe not", no); | ||
} | ||
|
||
@Test | ||
public void warningsInThenOrElse() throws Exception { | ||
var code = """ | ||
from Standard.Base import all | ||
check x y n = if x then y else n | ||
"""; | ||
|
||
var check = ContextUtils.getMethodFromModule(ctx, code, "check"); | ||
|
||
var warnCode = """ | ||
from Standard.Base import all | ||
warn w v = Warning.attach w v | ||
"""; | ||
var warn = ContextUtils.getMethodFromModule(ctx, warnCode, "warn"); | ||
|
||
var y = warn.execute("Good", "Yes"); | ||
var n = warn.execute("Bad", "No"); | ||
|
||
var yes = check.execute(true, y, n); | ||
var no = check.execute(false, y, n); | ||
|
||
assertEquals("Yes", yes.asString()); | ||
assertWarning("Good", yes); | ||
assertEquals("No", no.asString()); | ||
assertWarning("Bad", no); | ||
} | ||
|
||
@Test | ||
public void warningsInCondAndThenOrElse() throws Exception { | ||
var code = """ | ||
from Standard.Base import all | ||
check x y n = if x then y else n | ||
"""; | ||
|
||
var check = ContextUtils.getMethodFromModule(ctx, code, "check"); | ||
|
||
var warnCode = """ | ||
from Standard.Base import all | ||
warn w v = Warning.attach w v | ||
"""; | ||
var warn = ContextUtils.getMethodFromModule(ctx, warnCode, "warn"); | ||
|
||
var y = warn.execute("Good", "Yes"); | ||
var n = warn.execute("Bad", "No"); | ||
var t = warn.execute("Maybe", true); | ||
var f = warn.execute("Maybe not", false); | ||
|
||
var yes = check.execute(t, y, n); | ||
var no = check.execute(f, y, n); | ||
|
||
assertEquals("Yes", yes.asString()); | ||
assertWarning("GoodMaybe", yes); | ||
assertEquals("No", no.asString()); | ||
assertWarning("BadMaybe not", no); | ||
} | ||
|
||
private static void assertWarning(String txt, Value v) { | ||
assertTrue("Value " + v + " should be an exceptional", v.isException()); | ||
try { | ||
throw v.throwException(); | ||
} catch (PolyglotException ex) { | ||
assertEquals(txt, ex.getMessage()); | ||
} | ||
} | ||
} |