1 /*
   2  * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  * 
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  * 
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  * 
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  * 
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /**
  25  * JDK-8193371: Use Dynalink REMOVE operation in Nashorn
  26  *
  27  * @test
  28  * @run
  29  */
  30 
  31 // This test exercises new functionality enabled by the issue, namely removal of elements from Java lists and maps.
  32 
  33 var ArrayList = java.util.ArrayList;
  34 var HashMap = java.util.HashMap;
  35 var listOf = java.util.List.of;
  36 var mapOf = java.util.Map.of;
  37 
  38 // Remove from a list
  39 (function() { 
  40     var a = new ArrayList(listOf("foo", "bar", "baz"));
  41     Assert.assertFalse(delete a.add);
  42 
  43     // Delete actual element
  44     Assert.assertTrue(delete a[1]);
  45     Assert.assertEquals(a, listOf("foo", "baz"));
  46 
  47     // Gracefully ignore silly indices
  48     Assert.assertTrue(delete a[5]);
  49     Assert.assertTrue(delete a[-1]);
  50     Assert.assertTrue(delete a["whatever"]);
  51     Assert.assertTrue(delete a.whatever);
  52 
  53     // Gracefully ignore attempts at deleting methods and properties
  54     Assert.assertFalse(delete a.add);
  55     Assert.assertFalse(delete a.class);
  56 
  57     Assert.assertEquals(a, listOf("foo", "baz"));
  58 
  59     print("List passed.")
  60 })();
  61 
  62 // Remove from a list, strict
  63 (function() { 
  64     "use strict";
  65         
  66     var a = new ArrayList(listOf("foo", "bar", "baz"));
  67 
  68     // Delete actual element
  69     Assert.assertTrue(delete a[1]);
  70     Assert.assertEquals(a, listOf("foo", "baz"));
  71 
  72     // Gracefully ignore silly indices
  73     Assert.assertTrue(delete a[5]);
  74     Assert.assertTrue(delete a[-1]);
  75     Assert.assertTrue(delete a["whatever"]);
  76     Assert.assertTrue(delete a.whatever);
  77 
  78     // Fail deleting methods and properties
  79     try { delete a.add; Assert.fail(); } catch (e) { Assert.assertTrue(e instanceof TypeError) }
  80     try { delete a.class; Assert.fail(); } catch (e) { Assert.assertTrue(e instanceof TypeError) }
  81 
  82     Assert.assertEquals(a, listOf("foo", "baz"));
  83 
  84     print("Strict list passed.")
  85 })();
  86 
  87 // Remove from a map
  88 (function() { 
  89     var m = new HashMap(mapOf("a", 1, "b", 2, "c", 3));
  90 
  91     // Delete actual elements
  92     Assert.assertTrue(delete m.a);
  93     Assert.assertEquals(m, mapOf("b", 2, "c", 3));
  94     var key = "b"
  95     Assert.assertTrue(delete m[key]);
  96     Assert.assertEquals(m, mapOf("c", 3));
  97 
  98     // Gracefully ignore silly indices
  99     Assert.assertTrue(delete m.x);
 100     Assert.assertTrue(delete m[5]);
 101     Assert.assertTrue(delete m[-1]);
 102     Assert.assertTrue(delete m["whatever"]);
 103 
 104     // Gracefully ignore attempts at deleting methods and properties
 105     Assert.assertFalse(delete m.put);
 106     Assert.assertFalse(delete m.class);
 107 
 108     Assert.assertEquals(m, mapOf("c", 3));
 109     print("Map passed.")
 110 })();
 111 
 112 // Remove from a map, strict
 113 (function() { 
 114     "use strict";
 115 
 116     var m = new HashMap(mapOf("a", 1, "b", 2, "c", 3));
 117 
 118     // Delete actual elements
 119     Assert.assertTrue(delete m.a);
 120     Assert.assertEquals(m, mapOf("b", 2, "c", 3));
 121     var key = "b"
 122     Assert.assertTrue(delete m[key]);
 123     Assert.assertEquals(m, mapOf("c", 3));
 124 
 125     // Gracefully ignore silly indices
 126     Assert.assertTrue(delete m.x);
 127     Assert.assertTrue(delete m[5]);
 128     Assert.assertTrue(delete m[-1]);
 129     Assert.assertTrue(delete m["whatever"]);
 130 
 131     // Fail deleting methods and properties
 132     try { delete m.size; Assert.fail(); } catch (e) { Assert.assertTrue(e instanceof TypeError) }
 133     try { delete m.class; Assert.fail(); } catch (e) { Assert.assertTrue(e instanceof TypeError) }
 134 
 135     // Somewhat counterintuitive, but if we define an element of a map, we can 
 136     // delete it, however then the method surfaces, and we can't delete that.
 137     m.size = 4
 138     Assert.assertTrue(delete m.size)
 139     try { delete m.size; Assert.fail(); } catch (e) { Assert.assertTrue(e instanceof TypeError) }
 140     
 141     Assert.assertEquals(m, mapOf("c", 3));
 142 
 143     print("Strict map passed.")
 144 })();
 145 
 146 // Remove from arrays and beans
 147 (function() { 
 148     var a = new (Java.type("int[]"))(2)
 149     a[0] = 42
 150     a[1] = 13
 151     
 152     // Huh, Dynalink doesn't expose .clone() on Java arrays?
 153     var c = new (Java.type("int[]"))(2)
 154     c[0] = 42
 155     c[1] = 13
 156 
 157     // passes vacuously, but does nothing
 158     Assert.assertTrue(delete a[0])
 159     Assert.assertEquals(a, c);
 160     
 161     var b = new java.util.BitSet()
 162     b.set(2)
 163     // does nothing
 164     Assert.assertFalse(delete b.get)
 165     // Method is still there and operational
 166     Assert.assertTrue(b.get(2))
 167 
 168     // passes vacuously for non-existant property
 169     Assert.assertTrue(delete b.foo)
 170 
 171     // statics
 172     var Calendar = java.util.Calendar
 173     Assert.assertFalse(delete Calendar.UNDECIMBER) // field
 174     Assert.assertFalse(delete Calendar.availableLocales) // property
 175     Assert.assertFalse(delete Calendar.getInstance) // method
 176     Assert.assertTrue(delete Calendar.BLAH) // no such thing
 177   
 178     print("Beans passed.")
 179 })();
 180 
 181 // Remove from arrays and beans, strict
 182 (function() { 
 183     "use strict";
 184     
 185     var a = new (Java.type("int[]"))(2)
 186     a[0] = 42
 187     a[1] = 13
 188 
 189     var c = new (Java.type("int[]"))(2)
 190     c[0] = 42
 191     c[1] = 13
 192 
 193     // passes vacuously, but does nothing
 194     Assert.assertTrue(delete a[0])
 195     Assert.assertEquals(a, c);
 196     
 197     var b = new java.util.BitSet()
 198     b.set(2)
 199     // fails to delete a method
 200     try { delete b.get; Assert.fail(); } catch (e) { Assert.assertTrue(e instanceof TypeError) }
 201     // Method is still there and operational
 202     Assert.assertTrue(b.get(2))
 203 
 204     // passes vacuously for non-existant property
 205     Assert.assertTrue(delete b.foo)
 206     
 207     // statics
 208     var Calendar = java.util.Calendar
 209     try { delete Calendar.UNDECIMBER; Assert.fail(); } catch (e) { Assert.assertTrue(e instanceof TypeError) }
 210     try { delete Calendar.availableLocales; Assert.fail(); } catch (e) { Assert.assertTrue(e instanceof TypeError) }
 211     try { delete Calendar.getInstance; Assert.fail(); } catch (e) { Assert.assertTrue(e instanceof TypeError) }
 212     Assert.assertTrue(delete Calendar.BLAH) // no such thing
 213   
 214     print("Strict beans passed.")
 215 })();