Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix displaying of host values in chrome devtools #11468

Merged
merged 28 commits into from
Nov 27, 2024
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
845e030
Remove leftover typo from tests
Akirathan Nov 1, 2024
b80e0b0
Add tests
Akirathan Nov 1, 2024
1f68c9a
Discard warnings from the compiler in the test.
Akirathan Nov 1, 2024
4289d6c
Remove the test for non-null properties
Akirathan Nov 1, 2024
b354f80
Update test to reflect that atom with builtin type has null properties
Akirathan Nov 1, 2024
ae14326
Try to convert HostObject in DebugLocalScope.readMember
Akirathan Nov 5, 2024
a7c110c
Fix testests
Akirathan Nov 8, 2024
c038f55
Implement getPolyglotConversionType
Akirathan Nov 8, 2024
d2cd44a
DebugLocalScope uses getPolyglotConversionType
Akirathan Nov 8, 2024
08c066f
Add tests
Akirathan Nov 8, 2024
c18ad2c
Remove unused method
Akirathan Nov 8, 2024
2c46980
Testing also js and py foreign languages
Akirathan Nov 11, 2024
9134e52
Polyglot conversion logic is in EnsoLanguage.getLanguageView
Akirathan Nov 11, 2024
19e3798
Use only PolyglotCallType
Akirathan Nov 11, 2024
e283355
long is wrapped in LanguageViewWrapper
Akirathan Nov 11, 2024
b95d4bb
ArrayBuilder exports hasLanguage and getLanguage messages
Akirathan Nov 11, 2024
61e363a
Call Value.asString instead of Value.toString
Akirathan Nov 11, 2024
5fab1da
Test that WithWarnings has meta object
Akirathan Nov 11, 2024
293811e
Implement hasLanguage and getLanguage messages for EnsoBigInt and Text
Akirathan Nov 11, 2024
f4b199b
EnsoLanguage.getLanguageView returns null by default
Akirathan Nov 11, 2024
95b8d09
Merge branch 'develop' into wip/akirathan/7890-java-values-devtools
Akirathan Nov 26, 2024
cdc0ba3
Classes that extend EnsoObject do not export getLanguage and hasLangu…
Akirathan Nov 26, 2024
b743106
Build fixes after merge
Akirathan Nov 26, 2024
368415f
Update WithWarning test - do not use primitive value.
Akirathan Nov 26, 2024
19328ac
Add test for polyglot semantics of Enso numbers
Akirathan Nov 26, 2024
1826dde
Add comments to BigNumberTest
Akirathan Nov 27, 2024
1d01221
A value that fits in double is double, not converted to BigInt
Akirathan Nov 27, 2024
65553f3
EnsoObject is returned from getLanguageView without any conversions
Akirathan Nov 27, 2024
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
Original file line number Diff line number Diff line change
Expand Up @@ -567,7 +567,7 @@ public void resultOfConversionIsTypeChecked() throws Exception {
ex.getMessage().toLowerCase(),
AllOf.allOf(containsString("type"), containsString("error")));
var typeError = ex.getGuestObject();
assertEquals("Expected type", "First_Type", typeError.getMember("expected").toString());
assertEquals("Expected type", "First_Type", typeError.getMember("expected").asString());
assertEquals("Got wrong value", 42, typeError.getMember("actual").asInt());
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package org.enso.interpreter.test;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
Expand Down Expand Up @@ -177,4 +179,39 @@ public void doubleBigInteger() throws Exception {
var fourtyTwo = assertMul(6.0, new BigInteger("7"));
assertEquals(42, fourtyTwo.asInt());
}

@Test
public void everyValueSmallerThanIntegerMaxVal_IsPrimitiveInt() {
var almostMaxInt = Integer.toString(Integer.MAX_VALUE - 1);
var intVal = ContextUtils.evalModule(ctx, "main = " + almostMaxInt);
assertThat("Is a number", intVal.isNumber(), is(true));
assertThat("Fits in int", intVal.fitsInInt(), is(true));
assertThat("Fits in long", intVal.fitsInLong(), is(true));
assertThat("Fits in double", intVal.fitsInDouble(), is(true));
assertThat("Fits in big int", intVal.fitsInBigInteger(), is(true));
}

@Test
public void everyValueSmallerThanLongMaxVal_IsPrimitiveLong() {
var almostMaxLong = Long.toString(Long.MAX_VALUE - 1);
var longVal = ContextUtils.evalModule(ctx, "main = " + almostMaxLong);
assertThat("Is a number", longVal.isNumber(), is(true));
assertThat("Does not fit in int", longVal.fitsInInt(), is(false));
assertThat("Fits in long", longVal.fitsInLong(), is(true));
assertThat("Does not fit in double (but could)", longVal.fitsInDouble(), is(false));
Akirathan marked this conversation as resolved.
Show resolved Hide resolved
assertThat("Fits in big int", longVal.fitsInBigInteger(), is(true));
}

@Test
public void everyValueBiggerThanLongMaxVal_IsEnsoBigInt() {
// This number is bigger than Long.MAX_VALUE, but smaller than Double.MAX_VALUE
// so it could technically fit in double, but in Enso, it is automatically converted
// to EnsoBigInteger
var bigIntVal = ContextUtils.evalModule(ctx, "main = 9223372036854775808");
assertThat("Is a number", bigIntVal.isNumber(), is(true));
assertThat("Does not fit in int", bigIntVal.fitsInInt(), is(false));
assertThat("Does not fit in long", bigIntVal.fitsInLong(), is(false));
assertThat("Does not fit in double (but could)", bigIntVal.fitsInDouble(), is(false));
assertThat("Fits in big int", bigIntVal.fitsInBigInteger(), is(true));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,13 @@
import com.oracle.truffle.api.debug.SuspendedCallback;
import com.oracle.truffle.api.debug.SuspendedEvent;
import com.oracle.truffle.api.nodes.LanguageInfo;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.URI;
import java.nio.file.Paths;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
Expand All @@ -42,23 +45,30 @@
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestWatcher;
import org.junit.runner.Description;

public class DebuggingEnsoTest {
private Context context;
private Engine engine;
private Debugger debugger;
private final ByteArrayOutputStream out = new ByteArrayOutputStream();

@Before
public void initContext() {
out.reset();
engine =
Engine.newBuilder()
.allowExperimentalOptions(true)
.option(
RuntimeOptions.LANGUAGE_HOME_OVERRIDE,
Paths.get("../../distribution/component").toFile().getAbsolutePath())
.option(RuntimeOptions.LOG_LEVEL, Level.WARNING.getName())
.logHandler(System.err)
.logHandler(out)
.err(out)
.out(out)
.build();

context =
Expand All @@ -76,13 +86,26 @@ public void initContext() {
}

@After
public void disposeContext() {
public void disposeContext() throws IOException {
context.close();
context = null;
engine.close();
engine = null;
}

/** Only print warnings from the compiler if a test fails. */
@Rule
public TestWatcher testWatcher =
new TestWatcher() {
@Override
protected void failed(Throwable e, Description description) {
JaroslavTulach marked this conversation as resolved.
Show resolved Hide resolved
System.err.println("Test failed: " + description.getMethodName());
System.err.println("Error: " + e.getMessage());
System.err.println("Logs from the compiler and the engine: ");
System.err.println(out);
}
};

private static void expectStackFrame(
DebugStackFrame actualFrame, Map<String, String> expectedValues) {
Map<String, String> actualValues = new HashMap<>();
Expand Down Expand Up @@ -246,6 +269,125 @@ public void testHostValues() {
}
}

/**
* Both {@code Date.new 2024 12 15} and {@code Date.parse "2024-12-15"} should be seen by the
* debugger as the exact same objects. Internally, the value from {@code Date.parse} is a host
* value.
*/
@Test
public void hostValueIsTreatedAsItsEnsoCounterpart() {
Value fooFunc =
createEnsoMethod(
"""
from Standard.Base import Date, Date_Time, Dictionary
polyglot java import java.lang.String
polyglot java import java.util.List as JList
polyglot java import java.util.Map as JMap

foreign js js_date = '''
return new Date();

foreign js js_str = '''
return "Hello_World";

foreign js js_list = '''
return [1, 2, 3];

foreign js js_map = '''
let m = new Map();
m.set('A', 1);
m.set('B', 2);
return m;

foreign python py_list = '''
return [1, 2, 3]

foreign python py_dict = '''
return {'A': 1, 'B': 2}

foo _ =
d_enso = Date.new 2024 12 15
d_js = js_date
d_java = Date.parse "2024-12-15"
dt_enso = Date_Time.now
dt_java = Date_Time.parse "2020-05-06 04:30:20" "yyyy-MM-dd HH:mm:ss"
str_enso = "Hello_World"
str_js = js_str
str_java = String.new "Hello_World"
list_enso = [1, 2, 3]
list_js = js_list
list_py = py_list
list_java = JList.of 1 2 3
dict_enso = Dictionary.from_vector [["A", 1], ["B", 2]]
dict_js = js_map
dict_py = py_dict
dict_java = JMap.of "A" 1 "B" 2
end = 42
""",
"foo");

try (DebuggerSession session =
debugger.startSession(
(SuspendedEvent event) -> {
switch (event.getSourceSection().getCharacters().toString().strip()) {
case "end = 42" -> {
DebugScope scope = event.getTopStackFrame().getScope();

DebugValue ensoDate = scope.getDeclaredValue("d_enso");
DebugValue javaDate = scope.getDeclaredValue("d_java");
DebugValue jsDate = scope.getDeclaredValue("d_js");
assertSameProperties(ensoDate.getProperties(), javaDate.getProperties());
assertSameProperties(ensoDate.getProperties(), jsDate.getProperties());

DebugValue ensoDateTime = scope.getDeclaredValue("dt_enso");
DebugValue javaDateTime = scope.getDeclaredValue("dt_java");
assertSameProperties(ensoDateTime.getProperties(), javaDateTime.getProperties());

DebugValue ensoString = scope.getDeclaredValue("str_enso");
DebugValue javaString = scope.getDeclaredValue("str_java");
DebugValue jsString = scope.getDeclaredValue("str_js");
assertSameProperties(ensoString.getProperties(), javaString.getProperties());
assertSameProperties(ensoString.getProperties(), jsString.getProperties());

DebugValue ensoList = scope.getDeclaredValue("list_enso");
DebugValue javaList = scope.getDeclaredValue("list_java");
DebugValue jsList = scope.getDeclaredValue("list_js");
DebugValue pyList = scope.getDeclaredValue("list_py");
assertSameProperties(ensoList.getProperties(), javaList.getProperties());
Akirathan marked this conversation as resolved.
Show resolved Hide resolved
assertSameProperties(ensoList.getProperties(), jsList.getProperties());
assertSameProperties(ensoList.getProperties(), pyList.getProperties());

DebugValue ensoDict = scope.getDeclaredValue("dict_enso");
DebugValue javaDict = scope.getDeclaredValue("dict_java");
DebugValue jsDict = scope.getDeclaredValue("dict_js");
DebugValue pyDict = scope.getDeclaredValue("dict_py");
assertSameProperties(ensoDict.getProperties(), javaDict.getProperties());
Akirathan marked this conversation as resolved.
Show resolved Hide resolved
assertSameProperties(ensoDict.getProperties(), jsDict.getProperties());
assertSameProperties(ensoDict.getProperties(), pyDict.getProperties());
}
}
event.getSession().suspendNextExecution();
})) {
session.suspendNextExecution();
fooFunc.execute(0);
}
}

/** Asserts that the given values have same property names. */
private void assertSameProperties(
Collection<DebugValue> expectedProps, Collection<DebugValue> actualProps) {
if (expectedProps == null) {
assertThat(actualProps, anyOf(empty(), nullValue()));
return;
}
assertThat(actualProps.size(), is(expectedProps.size()));
var expectedPropNames =
expectedProps.stream().map(DebugValue::getName).collect(Collectors.toUnmodifiableSet());
var actualPropNames =
actualProps.stream().map(DebugValue::getName).collect(Collectors.toUnmodifiableSet());
assertThat(actualPropNames, is(expectedPropNames));
}

@Test
public void testHostValueAsAtomField() {
Value fooFunc =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.sameInstance;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
Expand Down Expand Up @@ -102,6 +103,17 @@ public void wrapAndUnwrap() {
fail("One shall not be created WithWarnings without any warnings " + without);
}

@Test
public void withWarningsDelegatesToMetaObject() {
var warning42 = wrap.execute("warn:1", "Text");
var meta = warning42.getMetaObject();
assertThat(
"Value (" + warning42 + ") wrapped in warning must have a meta object",
meta,
is(notNullValue()));
assertThat(meta.toString(), containsString("Text"));
}

@Test
public void warningIsAnException() {
var warning42 = wrap.execute("warn:1", 42);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ class TypeSignaturesTest
)
}

"XX resolve imported names" in {
"resolve imported names" in {
val code =
"""
|from project.Util import all
Expand Down
Loading
Loading