Skip to content

Commit 9df90b1

Browse files
committed
[GR-10520] test_set unittets
PullRequest: graalpython/93
2 parents 1210a26 + 85c0929 commit 9df90b1

File tree

21 files changed

+468
-33
lines changed

21 files changed

+468
-33
lines changed

graalpython/com.oracle.graal.python.test/src/tests/test_bytes.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,3 +448,8 @@ def test_find():
448448
assert b.find(i, 6) == 7
449449
assert b.find(i, 1, 3) == 1
450450
assert b.find(w, 1, 3) == -1
451+
452+
453+
def test_same_id():
454+
empty_ids = set([id(bytes()) for i in range(100)])
455+
assert len(empty_ids) == 1

graalpython/com.oracle.graal.python.test/src/tests/test_generators.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,3 +168,13 @@ def f():
168168

169169
if sys.version_info.minor == 4 and sys.version_info.micro < 3:
170170
del ExceptionTest
171+
172+
173+
def test_generator_starargs():
174+
def func(*args):
175+
return set(args)
176+
177+
lst = [x for x in range(10)]
178+
gen = (x for x in range(10))
179+
assert func(*lst) == set(lst)
180+
assert func(*gen) == set(lst)

graalpython/com.oracle.graal.python.test/src/tests/test_set.py

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,10 @@ def test_difference():
126126
def test_difference_update():
127127
word = 'simsalabim'
128128
otherword = 'madagascar'
129+
letters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
129130
s = set(word)
131+
d = dict.fromkeys(word)
132+
130133

131134
retval = s.difference_update(otherword)
132135
assert retval == None
@@ -176,3 +179,76 @@ def test_sub_and_super():
176179
assert set('abc').issuperset('a')
177180
assert not set('a').issubset('cbs')
178181
assert not set('cbs').issuperset('a')
182+
183+
184+
def test_intersection():
185+
word = 'simsalabim'
186+
otherword = 'madagascar'
187+
letters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
188+
s = set(word)
189+
d = dict.fromkeys(word)
190+
191+
i = s.intersection(otherword)
192+
for c in letters:
193+
assert (c in i) == (c in d and c in otherword)
194+
195+
assert s == set(word)
196+
# assert type(i) == set
197+
assert_raises(PassThru, s.intersection, check_pass_thru())
198+
199+
for C in set, frozenset, dict.fromkeys, str, list, tuple:
200+
assert set('abcba').intersection(C('cdc')) == set('cc')
201+
assert set('abcba').intersection(C('efgfe')) == set('')
202+
assert set('abcba').intersection(C('ccb')) == set('bc')
203+
assert set('abcba').intersection(C('ef')) == set('')
204+
assert set('abcba').intersection(C('cbcf'), C('bag')) == set('b')
205+
206+
# TODO: currently the id function behaves a bit differently than the one in cPython
207+
# s = set('abcba')
208+
# z = s.intersection()
209+
# if set == frozenset():
210+
# assert id(s) == id(z)
211+
# else:
212+
# assert id(s) != id(z)
213+
214+
215+
def test_same_id():
216+
empty_ids = set([id(frozenset()) for i in range(100)])
217+
assert len(empty_ids) == 1
218+
219+
220+
def test_rich_compare():
221+
class TestRichSetCompare:
222+
def __gt__(self, some_set):
223+
self.gt_called = True
224+
return False
225+
def __lt__(self, some_set):
226+
self.lt_called = True
227+
return False
228+
def __ge__(self, some_set):
229+
self.ge_called = True
230+
return False
231+
def __le__(self, some_set):
232+
self.le_called = True
233+
return False
234+
235+
# This first tries the builtin rich set comparison, which doesn't know
236+
# how to handle the custom object. Upon returning NotImplemented, the
237+
# corresponding comparison on the right object is invoked.
238+
myset = {1, 2, 3}
239+
240+
myobj = TestRichSetCompare()
241+
myset < myobj
242+
assert myobj.gt_called
243+
244+
myobj = TestRichSetCompare()
245+
myset > myobj
246+
assert myobj.lt_called
247+
248+
myobj = TestRichSetCompare()
249+
myset <= myobj
250+
assert myobj.ge_called
251+
252+
myobj = TestRichSetCompare()
253+
myset >= myobj
254+
assert myobj.le_called

graalpython/com.oracle.graal.python.test/src/tests/test_tuple.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
#
44
# Licensed under the PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
55
import seq_tests
6-
import unittest
76
#import pickle
87
from compare import CompareTest
98

@@ -374,3 +373,8 @@ def test_slice(self):
374373
t1 = tuple(range (1, 22, 2))
375374
s = slice(2, 6)
376375
self.assertEqual(t1[s], (5, 7, 9, 11))
376+
377+
378+
def test_same_id():
379+
empty_ids = set([id(tuple()) for i in range(100)])
380+
assert len(empty_ids) == 1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
* Copyright (c) 2017, 2018, 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.graal.python.builtins;
42+
43+
public enum PythonImmutableBuiltinType {
44+
PFrozenSet,
45+
PTuple,
46+
PBytes
47+
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/BuiltinConstructors.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ protected List<com.oracle.truffle.api.dsl.NodeFactory<? extends PythonBuiltinBas
171171
@GenerateNodeFactory
172172
public abstract static class BytesNode extends PythonBuiltinNode {
173173

174-
@Specialization
174+
@Specialization(guards = "isNoValue(source)")
175175
public PBytes bytes(PythonClass cls, @SuppressWarnings("unused") PNone source, @SuppressWarnings("unused") PNone encoding, @SuppressWarnings("unused") PNone errors) {
176176
return factory().createBytes(cls, new byte[0]);
177177
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/BuiltinFunctions.java

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
import static com.oracle.graal.python.nodes.BuiltinNames.SETATTR;
5454
import static com.oracle.graal.python.nodes.BuiltinNames.SUM;
5555
import static com.oracle.graal.python.nodes.BuiltinNames.__BREAKPOINT__;
56+
import static com.oracle.graal.python.nodes.HiddenAttributes.ID_KEY;
5657
import static com.oracle.graal.python.nodes.SpecialAttributeNames.__NAME__;
5758
import static com.oracle.graal.python.nodes.SpecialMethodNames.__INSTANCECHECK__;
5859
import static com.oracle.graal.python.nodes.SpecialMethodNames.__LEN__;
@@ -74,6 +75,7 @@
7475
import com.oracle.graal.python.builtins.Builtin;
7576
import com.oracle.graal.python.builtins.CoreFunctions;
7677
import com.oracle.graal.python.builtins.PythonBuiltins;
78+
import com.oracle.graal.python.builtins.PythonImmutableBuiltinType;
7779
import com.oracle.graal.python.builtins.objects.PNone;
7880
import com.oracle.graal.python.builtins.objects.PNotImplemented;
7981
import com.oracle.graal.python.builtins.objects.bytes.PBytes;
@@ -87,6 +89,7 @@
8789
import com.oracle.graal.python.builtins.objects.list.PList;
8890
import com.oracle.graal.python.builtins.objects.module.PythonModule;
8991
import com.oracle.graal.python.builtins.objects.object.PythonObject;
92+
import com.oracle.graal.python.builtins.objects.set.PFrozenSet;
9093
import com.oracle.graal.python.builtins.objects.str.PString;
9194
import com.oracle.graal.python.builtins.objects.tuple.PTuple;
9295
import com.oracle.graal.python.builtins.objects.type.PythonClass;
@@ -144,7 +147,6 @@
144147
import com.oracle.truffle.api.nodes.ExplodeLoop;
145148
import com.oracle.truffle.api.nodes.RootNode;
146149
import com.oracle.truffle.api.nodes.UnexpectedResultException;
147-
import com.oracle.truffle.api.object.HiddenKey;
148150
import com.oracle.truffle.api.profiles.ConditionProfile;
149151
import com.oracle.truffle.api.source.Source;
150152

@@ -637,8 +639,6 @@ public abstract static class IdNode extends PythonBuiltinNode {
637639
* The next available global id. We reserve space for all integers to be their own id +
638640
* offset.
639641
*/
640-
private static long GLOBAL_ID = Integer.MAX_VALUE * 2 + 4L;
641-
private static HiddenKey idKey = new HiddenKey("object_id");
642642

643643
@Child private ReadAttributeFromObjectNode readId = null;
644644
@Child private WriteAttributeToObjectNode writeId = null;
@@ -690,7 +690,28 @@ int doId(double value) {
690690
return Double.hashCode(value);
691691
}
692692

693-
@Specialization(guards = {"!isPInt(obj)", "!isPString(obj)", "!isPFloat(obj)"})
693+
@Specialization(guards = "isEmpty(value)")
694+
Object doEmptyTuple(PTuple value) {
695+
return getId(value, PythonImmutableBuiltinType.PTuple);
696+
}
697+
698+
@Specialization(guards = "isEmpty(value)")
699+
Object doEmptyBytes(PBytes value) {
700+
return getId(value, PythonImmutableBuiltinType.PBytes);
701+
}
702+
703+
@Specialization(guards = "isEmpty(value)")
704+
Object doEmptyFrozenSet(PFrozenSet value) {
705+
return getId(value, PythonImmutableBuiltinType.PFrozenSet);
706+
}
707+
708+
protected boolean isEmptyImmutableBuiltin(Object object) {
709+
return (object instanceof PTuple && PGuards.isEmpty((PTuple) object)) ||
710+
(object instanceof PBytes && PGuards.isEmpty((PBytes) object)) ||
711+
(object instanceof PFrozenSet && PGuards.isEmpty((PFrozenSet) object));
712+
}
713+
714+
@Specialization(guards = {"!isPInt(obj)", "!isPString(obj)", "!isPFloat(obj)", "!isEmptyImmutableBuiltin(obj)"})
694715
Object doId(PythonObject obj) {
695716
return getId(obj);
696717
}
@@ -701,15 +722,23 @@ Object doId(Object obj) {
701722
}
702723

703724
private Object getId(PythonObject obj) {
725+
return getId(obj, null);
726+
}
727+
728+
private Object getId(PythonObject obj, PythonImmutableBuiltinType immutableType) {
704729
if (readId == null) {
705730
CompilerDirectives.transferToInterpreterAndInvalidate();
706731
readId = insert(ReadAttributeFromObjectNode.create());
707732
writeId = insert(WriteAttributeToObjectNode.create());
708733
}
709-
Object id = readId.execute(obj, idKey);
734+
Object id = readId.execute(obj, ID_KEY);
710735
if (id == NO_VALUE) {
711-
id = GLOBAL_ID++;
712-
writeId.execute(obj, idKey, id);
736+
if (immutableType != null) {
737+
id = getContext().getEmptyImmutableObjectGlobalId(immutableType);
738+
} else {
739+
id = getContext().getNextGlobalId();
740+
}
741+
writeId.execute(obj, ID_KEY, id);
713742
}
714743
return id;
715744
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/common/HashingStorage.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,8 +234,25 @@ public void addAll(HashingStorage other, Equivalence eq) {
234234

235235
public abstract Iterable<Object> keys();
236236

237+
private Object[] iteratorAsArray(Iterable<Object> iterable) {
238+
Object[] items = new Object[this.length()];
239+
int i = 0;
240+
for (Object item : iterable) {
241+
items[i++] = item;
242+
}
243+
return items;
244+
}
245+
246+
public Object[] keysAsArray() {
247+
return iteratorAsArray(keys());
248+
}
249+
237250
public abstract Iterable<Object> values();
238251

252+
public Object[] valuesAsArray() {
253+
return iteratorAsArray(values());
254+
}
255+
239256
public abstract Iterable<DictEntry> entries();
240257

241258
public abstract void clear();

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/dict/PJavaIteratorIterator.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
public abstract class PJavaIteratorIterator<T> extends PythonBuiltinObject {
3535

3636
private final Iterator<T> iterator;
37+
private int index;
3738

3839
public PJavaIteratorIterator(PythonClass clazz, Iterator<T> iterator) {
3940
super(clazz);
@@ -47,11 +48,16 @@ public Iterator<T> getIterator() {
4748
@TruffleBoundary
4849
public final Object next() {
4950
assert hasNext();
51+
index++;
5052
return iterator.next();
5153
}
5254

5355
@TruffleBoundary
5456
public final boolean hasNext() {
5557
return iterator.hasNext();
5658
}
59+
60+
public int getIndex() {
61+
return index;
62+
}
5763
}

0 commit comments

Comments
 (0)