Skip to content

Commit 00bcabb

Browse files
committed
[GR-43097] Add regression test.
1 parent 2609acd commit 00bcabb

File tree

2 files changed

+202
-4
lines changed

2 files changed

+202
-4
lines changed

graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/TestHelper.java

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161

6262
import com.oracle.truffle.api.CompilerDirectives;
6363
import com.oracle.truffle.api.RootCallTarget;
64+
import com.oracle.truffle.api.frame.VirtualFrame;
6465
import com.oracle.truffle.api.interop.ExceptionType;
6566
import com.oracle.truffle.api.interop.InteropLibrary;
6667
import com.oracle.truffle.api.interop.UnsupportedMessageException;
@@ -180,18 +181,20 @@ public void runExpectSyntaxError(String sourceCode) {
180181
}
181182

182183
public Object runNoPolyglot(String source) {
184+
return runNoPolyglot(com.oracle.truffle.api.source.Source.newBuilder(JavaScriptLanguage.ID, source, "<unknown>").build());
185+
}
186+
187+
public Object runNoPolyglot(com.oracle.truffle.api.source.Source source) {
183188
enterContext();
184-
Object result = null;
185189
try {
186190
ScriptNode program = getParser().parseScript(getJSContext(), source);
187-
result = runNoPolyglot(program);
191+
return runNoPolyglot(program);
188192
} finally {
189193
leaveContext();
190194
}
191-
return result;
192195
}
193196

194-
public Object runNoPolyglot(ScriptNode scriptNode) {
197+
private Object runNoPolyglot(ScriptNode scriptNode) {
195198
return scriptNode.run(getRealm());
196199
}
197200

@@ -336,4 +339,19 @@ public void assumeES6OrLater() {
336339
Assume.assumeTrue(getJSContext().getEcmaScriptVersion() >= 6);
337340
leaveContext();
338341
}
342+
343+
public static <T extends Node> T adopt(T node) {
344+
RootNode root = new RootNode(null) {
345+
{
346+
insert(node);
347+
}
348+
349+
@Override
350+
public Object execute(VirtualFrame frame) {
351+
return null;
352+
}
353+
};
354+
root.getCallTarget();
355+
return node;
356+
}
339357
}
Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
/*
2+
* Copyright (c) 2022, 2022, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* The Universal Permissive License (UPL), Version 1.0
6+
*
7+
* Subject to the condition set forth below, permission is hereby granted to any
8+
* person obtaining a copy of this software, associated documentation and/or
9+
* data (collectively the "Software"), free of charge and under any and all
10+
* copyright rights in the Software, and any and all patent rights owned or
11+
* freely licensable by each licensor hereunder covering either (i) the
12+
* unmodified Software as contributed to or provided by such licensor, or (ii)
13+
* the Larger Works (as defined below), to deal in both
14+
*
15+
* (a) the Software, and
16+
*
17+
* (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
18+
* one is included with the Software each a "Larger Work" to which the Software
19+
* is contributed by such licensors),
20+
*
21+
* without restriction, including without limitation the rights to copy, create
22+
* derivative works of, display, perform, and distribute the Software and make,
23+
* use, sell, offer for sale, import, export, have made, and have sold the
24+
* Software and the Larger Work(s), and to sublicense the foregoing rights on
25+
* either these or other terms.
26+
*
27+
* This license is subject to the following condition:
28+
*
29+
* The above copyright notice and either this complete permission notice or at a
30+
* minimum a reference to the UPL must be included in all copies or substantial
31+
* portions of the Software.
32+
*
33+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39+
* SOFTWARE.
40+
*/
41+
package com.oracle.truffle.js.test.interop;
42+
43+
import static org.hamcrest.CoreMatchers.startsWith;
44+
import static org.junit.Assert.assertArrayEquals;
45+
import static org.junit.Assert.assertEquals;
46+
import static org.junit.Assert.assertFalse;
47+
import static org.junit.Assert.assertThat;
48+
import static org.junit.Assert.assertTrue;
49+
import static org.junit.Assert.fail;
50+
51+
import org.graalvm.polyglot.Context;
52+
import org.graalvm.polyglot.PolyglotException;
53+
import org.graalvm.polyglot.Source;
54+
import org.graalvm.polyglot.Value;
55+
import org.junit.Test;
56+
57+
import com.oracle.truffle.api.interop.InteropException;
58+
import com.oracle.truffle.api.interop.InteropLibrary;
59+
import com.oracle.truffle.js.lang.JavaScriptLanguage;
60+
import com.oracle.truffle.js.runtime.JSContextOptions;
61+
import com.oracle.truffle.js.test.JSTest;
62+
import com.oracle.truffle.js.test.TestHelper;
63+
64+
public class GR43097 {
65+
66+
private static final String SIMPLE_MODULE_SOURCE_CODE = "" +
67+
"export function f(a) { return a; };\n" +
68+
"export var a = 41;\n";
69+
70+
@Test
71+
public void testModuleNamespaceObjectPolyglotValue() {
72+
try (Context context = JSTest.newContextBuilder().option(JSContextOptions.ESM_EVAL_RETURNS_EXPORTS_NAME, "true").build();) {
73+
Source moduleSrc = Source.newBuilder(JavaScriptLanguage.ID, SIMPLE_MODULE_SOURCE_CODE, "esm-ns.mjs").buildLiteral();
74+
Value ns = context.eval(moduleSrc);
75+
76+
// Check member 'f'
77+
assertTrue(ns.hasMember("f"));
78+
assertTrue(ns.canInvokeMember("f"));
79+
assertEquals(43, ns.invokeMember("f", 43).asInt());
80+
assertTrue(ns.getMember("f").canExecute());
81+
assertEquals(43, ns.getMember("f").execute(43).asInt());
82+
83+
// Note: Module namespace property names are always sorted.
84+
assertArrayEquals(new String[]{"a", "f"}, ns.getMemberKeys().toArray());
85+
86+
// Properties are writable, but writing throws.
87+
try {
88+
ns.putMember("f", "bla");
89+
fail("should have thrown");
90+
} catch (PolyglotException e) {
91+
assertTrue(e.isGuestException());
92+
assertThat(e.getMessage(), startsWith("TypeError"));
93+
}
94+
assertTrue(ns.getMember("f").canExecute());
95+
assertEquals(43, ns.getMember("f").execute(43).asInt());
96+
97+
try {
98+
ns.removeMember("f");
99+
fail("should have thrown");
100+
} catch (UnsupportedOperationException e) {
101+
// non-removable member key
102+
}
103+
assertTrue(ns.hasMember("f"));
104+
assertTrue(ns.getMember("f").canExecute());
105+
assertEquals(43, ns.getMember("f").execute(43).asInt());
106+
107+
// Check member 'a'
108+
assertTrue(ns.hasMember("a"));
109+
assertFalse(ns.canInvokeMember("a"));
110+
assertEquals(41, ns.getMember("a").asInt());
111+
112+
// Properties are writable, but writing throws.
113+
try {
114+
ns.putMember("a", 42);
115+
fail("should have thrown");
116+
} catch (PolyglotException e) {
117+
assertTrue(e.isGuestException());
118+
assertThat(e.getMessage(), startsWith("TypeError"));
119+
}
120+
assertTrue(ns.hasMember("a"));
121+
assertEquals(41, ns.getMember("a").asInt());
122+
123+
try {
124+
ns.removeMember("a");
125+
fail("should have thrown");
126+
} catch (UnsupportedOperationException e) {
127+
// non-removable member key
128+
}
129+
assertTrue(ns.hasMember("a"));
130+
assertEquals(41, ns.getMember("a").asInt());
131+
}
132+
}
133+
134+
@Test
135+
public void testModuleNamespaceObjectInterop() throws InteropException {
136+
try (TestHelper testHelper = new TestHelper(JSTest.newContextBuilder().option(JSContextOptions.ESM_EVAL_RETURNS_EXPORTS_NAME, "true"))) {
137+
com.oracle.truffle.api.source.Source moduleSrc = com.oracle.truffle.api.source.Source.newBuilder(JavaScriptLanguage.ID, SIMPLE_MODULE_SOURCE_CODE, "esm-ns.mjs").build();
138+
Object ns = testHelper.runNoPolyglot(moduleSrc);
139+
InteropLibrary cached = TestHelper.adopt(InteropLibrary.getFactory().create(ns));
140+
InteropLibrary uncached = InteropLibrary.getUncached();
141+
142+
testHelper.enterContext();
143+
144+
// Check member 'f'
145+
assertTrue(cached.isMemberInvocable(ns, "f"));
146+
assertTrue(cached.isMemberReadable(ns, "f"));
147+
assertEquals(43, cached.invokeMember(ns, "f", 43));
148+
assertTrue(uncached.isExecutable(cached.readMember(ns, "f")));
149+
assertEquals(43, uncached.execute(cached.readMember(ns, "f"), 43));
150+
151+
// Check member 'a'
152+
assertTrue(cached.isMemberReadable(ns, "a"));
153+
assertFalse(cached.isMemberInvocable(ns, "a"));
154+
assertEquals(41, cached.readMember(ns, "a"));
155+
156+
testHelper.leaveContext();
157+
}
158+
}
159+
160+
@Test
161+
public void testModuleNamespaceObjectDefineProperty() {
162+
try (Context context = JSTest.newContextBuilder().option(JSContextOptions.ESM_EVAL_RETURNS_EXPORTS_NAME, "true").build();) {
163+
Source moduleSrc = Source.newBuilder(JavaScriptLanguage.ID, SIMPLE_MODULE_SOURCE_CODE, "esm-ns.mjs").buildLiteral();
164+
Value ns = context.eval(moduleSrc);
165+
166+
Value tester = context.eval(Source.create(JavaScriptLanguage.ID, "(function(ns){ Object.defineProperty(ns, 'f', {writable: false, value: 'boom'}) })"));
167+
try {
168+
tester.executeVoid(ns);
169+
fail("should have thrown");
170+
} catch (PolyglotException e) {
171+
assertTrue(e.isGuestException());
172+
assertThat(e.getMessage(), startsWith("TypeError"));
173+
}
174+
175+
assertTrue(ns.canInvokeMember("f"));
176+
assertEquals(43, ns.invokeMember("f", 43).asInt());
177+
}
178+
}
179+
180+
}

0 commit comments

Comments
 (0)