1 /*
  2  * Copyright (c) 2015, 2026, 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  * @test
 26  * @bug 8072726
 27  * @summary Tests for Enumeration-to-Iterator conversion.
 28  * @library /test/lib
 29  * @run testng EnumerationAsIterator
 30  */
 31 
 32 import jdk.test.lib.valueclass.VClass;
 33 import org.testng.annotations.DataProvider;
 34 import org.testng.annotations.Test;
 35 
 36 import java.util.ArrayList;
 37 import java.util.Arrays;
 38 import java.util.Collection;
 39 import java.util.Collections;
 40 import java.util.Enumeration;
 41 import java.util.Iterator;
 42 import java.util.List;
 43 import java.util.NoSuchElementException;
 44 import java.util.concurrent.atomic.AtomicInteger;
 45 import java.util.function.Supplier;
 46 
 47 import static org.testng.Assert.*;
 48 
 49 @Test
 50 public class EnumerationAsIterator {
 51 
 52     static Object[] of(String description, Supplier<Enumeration<?>> s, Collection<?> exp) {
 53         return new Object[]{description, s, exp};
 54     }
 55 
 56     static Object[] of(String description, Collection<?> c, Collection<?> exp) {
 57         return of(description, () -> Collections.enumeration(c), exp);
 58     }
 59 
 60     /**
 61      * A wrapper Enumeration that doesn't override the
 62      * default method on Enumeration.
 63      */
 64     static <T> Enumeration<T> wrapInDefault(Enumeration<T> e) {
 65         return new Enumeration<>() {
 66             @Override
 67             public boolean hasMoreElements() {
 68                 return e.hasMoreElements();
 69             }
 70 
 71             @Override
 72             public T nextElement() {
 73                 return e.nextElement();
 74             }
 75         };
 76     }
 77 
 78     @DataProvider
 79     public static Iterator<Object[]> unmodifiable() {
 80         return Arrays.asList(
 81             of("Default-wrapped ArrayList",
 82                () -> wrapInDefault(
 83                    Collections.enumeration(new ArrayList<>(Arrays.asList("a")))),
 84                Arrays.asList("a")),
 85 
 86             of("Unmodifiable ArrayList",
 87                Collections.unmodifiableList(new ArrayList<>(Arrays.asList("a"))),
 88                Arrays.asList("a")),
 89 
 90             of("Modifiable ArrayList",
 91                new ArrayList<>(Arrays.asList("a")),
 92                Arrays.asList("a"))
 93         ).iterator();
 94     }
 95 
 96     @DataProvider
 97     public static Iterator<Object[]> others() {
 98         return Arrays.asList(
 99             of("Default Collections.emptyEnumeration()",
100                () -> wrapInDefault(Collections.emptyEnumeration()),
101                Collections.emptyList()),
102 
103             of("Collections.emptyEnumeration()",
104                Collections::emptyEnumeration,
105                Collections.emptyList()),
106 
107             of("Collections.emptyList()",
108                Collections.emptyList(),
109                Collections.emptyList()),
110 
111             of("Collections.singletonList()",
112                Collections.singletonList("a"),
113                Collections.singletonList("a")),
114 
115             of("Arrays.asList(...)",
116                Arrays.asList("a", "b", "c"),
117                Arrays.asList("a", "b", "c")),
118 
119             of("Value Collections.enumeration()",
120                () -> Collections.enumeration(Arrays.asList(new VClass(1, new int[] { 1 }), new VClass(2, new int[] { 2 }))),
121                Arrays.asList(new VClass(1, new int[] { 1 }), new VClass(2, new int[] { 2 })))
122         ).iterator();
123     }
124 
125     @DataProvider
126     public static Iterator<Object[]> all() {
127         List<Object[]> all = new ArrayList<>();
128         unmodifiable().forEachRemaining(all::add);
129         others().forEachRemaining(all::add);
130         return all.iterator();
131     }
132 
133     @Test(dataProvider = "all")
134     public void consumeByNext(String description, Supplier<Enumeration<?>> s, Collection<?> exp) {
135         Iterator<?> i = s.get().asIterator();
136         int count = 0;
137         while (i.hasNext()) {
138             assertTrue(i.hasNext());
139 
140             i.next();
141             count++;
142         }
143         assertEquals(count, exp.size());
144 
145         assertFalse(i.hasNext());
146 
147         try {
148             i.next();
149             fail();
150         } catch (NoSuchElementException e) {
151         }
152     }
153 
154     @Test(dataProvider = "all")
155     public void consumeByForEachRemaining(String description,
156                                           Supplier<Enumeration<?>> s,
157                                           Collection<?> exp) {
158         Iterator<?> i = s.get().asIterator();
159         AtomicInteger ai = new AtomicInteger();
160         i.forEachRemaining(e -> ai.getAndIncrement());
161         assertEquals(ai.get(), exp.size());
162         i.forEachRemaining(e -> ai.getAndIncrement());
163         assertEquals(ai.get(), exp.size());
164 
165         assertFalse(i.hasNext());
166 
167         try {
168             i.next();
169             fail();
170         } catch (NoSuchElementException e) {
171         }
172     }
173 
174     @Test(dataProvider = "all")
175     public void consumeByNextThenForEachRemaining(String description,
176                                                   Supplier<Enumeration<?>> s,
177                                                   Collection<?> exp) {
178         Iterator<?> i = s.get().asIterator();
179         AtomicInteger ai = new AtomicInteger();
180         if (i.hasNext()) {
181             i.next();
182             ai.getAndIncrement();
183         }
184         i.forEachRemaining(e -> ai.getAndIncrement());
185         assertEquals(ai.get(), exp.size());
186         i.forEachRemaining(e -> ai.getAndIncrement());
187         assertEquals(ai.get(), exp.size());
188 
189         assertFalse(i.hasNext());
190 
191         try {
192             i.next();
193             fail();
194         } catch (NoSuchElementException e) {
195         }
196     }
197 
198     @Test(dataProvider = "all")
199     public void contents(String description, Supplier<Enumeration<?>> s, Collection<?> exp) {
200         assertEquals(copy(s.get()), exp);
201     }
202 
203     private List<?> copy(Enumeration<?> input) {
204         List<Object> output = new ArrayList<>();
205         input.asIterator().forEachRemaining(output::add);
206         return output;
207     }
208 
209     @Test(dataProvider = "unmodifiable",
210           expectedExceptions=UnsupportedOperationException.class)
211     public void removeThrowsAfterAdvancingE(String description,
212                                             Supplier<Enumeration<?>> s,
213                                             Collection<?> exp) {
214         Enumeration<?> e = s.get();
215         e.nextElement();
216         e.asIterator().remove();
217     }
218 
219     @Test(dataProvider = "unmodifiable",
220           expectedExceptions=UnsupportedOperationException.class)
221     public void removeThrowsAfterAdvancingI(String description,
222                                             Supplier<Enumeration<?>> s,
223                                             Collection<?> exp) {
224         Iterator<?> i = s.get().asIterator();
225         i.next();
226         i.remove();
227     }
228 }