undefect. CWE-407 — 63 sites patched across 27 ecosystems

Authors: russell@unturf.com · brackishbert@gmail.com · foxhop.net · TimeHexOn.com

Patches, unit tests, benchmarks, whitepaper, and outreach briefs.
Public domain — no copyright claimed. Use freely.
This commit is contained in:
russell@unturf.com 2026-03-26 17:11:57 -04:00
commit 0a580b313d
70422 changed files with 17213626 additions and 0 deletions

View file

@ -0,0 +1,213 @@
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 7121314
* @summary AbstractCollection.toArray(T[]) doesn't return the given array
* in concurrent modification.
* @author Ulf Zibis, David Holmes
*/
import java.util.AbstractCollection;
import java.util.Arrays;
import java.util.Iterator;
public class ToArrayTest {
static class TestCollection<E> extends AbstractCollection<E> {
private final E[] elements;
private int[] sizes;
private int nextSize;
public TestCollection(E[] elements) {
this.elements = elements;
setSizeSequence(new int[] { elements.length });
}
/*
* Sets the values that size() will return on each use. The next
* call to size will return sizes[0], then sizes[1] etc. This allows us
* to emulate a concurrent change to the contents of the collection
* without having to perform concurrent changes. If sizes[n+1] contains
* a larger value, the collection will appear to have shrunk when
* iterated; if a smaller value then the collection will appear to have
* grown when iterated.
*/
void setSizeSequence(int... sizes) {
this.sizes = sizes;
nextSize = 0;
}
/* can change collection's size after each invocation */
@Override
public int size() {
return sizes[nextSize == sizes.length - 1 ? nextSize : nextSize++];
}
@Override
public Iterator<E> iterator() {
return new Iterator<E>() {
int pos = 0;
public boolean hasNext() {
return pos < sizes[nextSize];
}
public E next() {
return elements[pos++];
}
public void remove() {
throw new UnsupportedOperationException(
"Not supported yet.");
}
};
}
}
static final Object[] OBJECTS = { new Object(), new Object(), new Object() };
static final TestCollection<?> CANDIDATE = new TestCollection<Object>(OBJECTS);
static final int CAP = OBJECTS.length; // capacity of the CANDIDATE
static final int LAST = CAP - 1; // last possible array index
Object[] a;
Object[] res;
int last() {
return a.length - 1;
}
protected void test() throws Throwable {
// Check array type conversion
res = new TestCollection<>(new Object[] { "1", "2" }).toArray(new String[0]);
check(res instanceof String[]);
check(res.length == 2);
check(res[1] == "2");
// Check incompatible type of target array
try {
res = CANDIDATE.toArray(new String[CAP]);
check(false);
} catch (Throwable t) {
check(t instanceof ArrayStoreException);
}
// Check more elements than a.length
a = new Object[CAP - 1]; // appears too small
res = CANDIDATE.toArray(a);
check(res != a);
check(res[LAST] != null);
// Check equal elements as a.length
a = new Object[CAP]; // appears to match
res = CANDIDATE.toArray(a);
check(res == a);
check(res[last()] != null);
// Check equal elements as a.length
a = new Object[CAP + 1]; // appears too big
res = CANDIDATE.toArray(a);
check(res == a);
check(res[last()] == null);
// Check less elements than expected, but more than a.length
a = new Object[CAP - 2]; // appears too small
CANDIDATE.setSizeSequence(CAP, CAP - 1);
res = CANDIDATE.toArray(a);
check(res != a);
check(res.length == CAP - 1);
check(res[LAST - 1] != null);
// Check less elements than expected, but equal as a.length
a = Arrays.copyOf(OBJECTS, CAP); // appears to match
CANDIDATE.setSizeSequence(CAP, CAP - 1);
res = CANDIDATE.toArray(a);
check(res == a);
check(res[last()] == null);
// Check more elements than expected and more than a.length
a = new Object[CAP - 1]; // appears to match
CANDIDATE.setSizeSequence(CAP - 1, CAP);
res = CANDIDATE.toArray(a);
check(res != a);
check(res[LAST] != null);
// Check more elements than expected, but equal as a.length
a = new Object[CAP - 1]; // appears to match
CANDIDATE.setSizeSequence(CAP - 2, CAP - 1);
res = CANDIDATE.toArray(a);
check(res == a);
check(res[last()] != null);
// Check more elements than expected, but less than a.length
a = Arrays.copyOf(OBJECTS, CAP); // appears to match
CANDIDATE.setSizeSequence(CAP - 2, CAP - 1);
res = CANDIDATE.toArray(a);
check(res == a);
check(res[last()] == null);
test_7121314();
}
/*
* Major target of this testcase, bug 7121314.
*/
protected void test_7121314() throws Throwable {
// Check equal elements as a.length, but less than expected
a = new Object[CAP - 1]; // appears too small
CANDIDATE.setSizeSequence(CAP, CAP - 1);
res = CANDIDATE.toArray(a);
check(res == a);
check(res[last()] != null);
// Check less elements than a.length and less than expected
a = Arrays.copyOf(OBJECTS, CAP - 1); // appears too small
CANDIDATE.setSizeSequence(CAP, CAP - 2);
res = CANDIDATE.toArray(a);
check(res == a);
check(res[last()] == null);
}
public static void main(String[] args) throws Throwable {
ToArrayTest testcase = new ToArrayTest();
try {
testcase.test();
} catch (Throwable t) {
unexpected(t);
}
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
if (failed > 0) throw new Exception("Some tests failed");
}
//--------------------- Infrastructure ---------------------------
static volatile int passed = 0, failed = 0;
static void pass() { passed++; }
static void fail() { failed++; Thread.dumpStack(); }
static void fail(String msg) { System.out.println(msg); fail(); }
static void unexpected(Throwable t) { failed++; t.printStackTrace(); }
static void check(boolean cond) { if (cond) pass(); else fail(); }
static void equal(Object x, Object y) {
if (x == null ? y == null : x.equals(y)) pass();
else {System.out.println(x + " not equal to " + y); fail(); }
}
}

View file

@ -0,0 +1,84 @@
/*
* Copyright (c) 2001, 2005, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 4486049 6282555 6318622
* @summary toString method fails if size changes in between a call to size
* and an attempt to iterate.
* @author Josh Bloch, Martin Buchholz
*/
import java.util.AbstractCollection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Vector;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;
public class ToString {
private static void realMain(String[] args) {
testCollection(new LinkedHashSet<Object>() {
public int size() {
return super.size() + 1; // Lies, lies, all lies!
}});
testCollection(new ArrayList<Object>());
testCollection(new Vector<Object>());
testCollection(new CopyOnWriteArrayList<Object>());
testCollection(new CopyOnWriteArraySet<Object>());
}
private static void testCollection(Collection<Object> c) {
System.out.println(c.getClass());
equal(c.toString(), "[]");
check(c.add("x"));
equal(c.toString(), "[x]");
check(c.add("y"));
equal(c.toString(), "[x, y]");
check(c.add(null));
equal(c.toString(), "[x, y, null]");
if (c instanceof AbstractCollection) {
check(c.add(c));
equal(c.toString(), "[x, y, null, (this Collection)]");
}
}
//--------------------- Infrastructure ---------------------------
static volatile int passed = 0, failed = 0;
static void pass() { passed++; }
static void fail() { failed++; Thread.dumpStack(); }
static void fail(String msg) { System.out.println(msg); fail(); }
static void unexpected(Throwable t) { failed++; t.printStackTrace(); }
static void check(boolean cond) { if (cond) pass(); else fail(); }
static void equal(Object x, Object y) {
if (x == null ? y == null : x.equals(y)) pass();
else {System.out.println(x + " not equal to " + y); fail(); }}
public static void main(String[] args) throws Throwable {
try { realMain(args); } catch (Throwable t) { unexpected(t); }
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
if (failed > 0) throw new Exception("Some tests failed");
}
}

View file

@ -0,0 +1,52 @@
/*
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 4902078
* @summary concurrent modification not detected on 2nd to last iteration
* @author Josh Bloch
*
* @ignore Bug fix temporarily removed as it uncovered other bugs (4992226)
*/
import java.util.ArrayList;
import java.util.ConcurrentModificationException;
import java.util.List;
public class CheckForComodification {
private static final int LENGTH = 10;
public static void main(String[] args) throws Exception {
List<Integer> list = new ArrayList<>();
for (int i = 0; i < LENGTH; i++)
list.add(i);
try {
for (int i : list)
if (i == LENGTH - 2)
list.remove(i);
} catch (ConcurrentModificationException e) {
return;
}
throw new RuntimeException("No ConcurrentModificationException");
}
}

View file

@ -0,0 +1,114 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8161558
* @summary ListIterator should not discard cause on exception
* @run testng CheckForIndexOutOfBoundsException
*/
import java.util.List;
import java.util.AbstractList;
import java.util.Iterator;
import java.util.ListIterator;
import java.util.NoSuchElementException;
import org.testng.annotations.Test;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.fail;
// Fixed size list containing two elements
class MyList extends AbstractList<String> {
private static final int SIZE = 2;
public String get(int i) {
if (i >= 0 && i < SIZE) {
return "x";
} else {
throw new IndexOutOfBoundsException(i);
}
}
public int size() {
return SIZE;
}
}
@Test
public class CheckForIndexOutOfBoundsException {
List<String> list = new MyList();
@Test
public void checkIteratorNext() {
var iterator = list.iterator(); // position at start
try {
for (int i = 0; i <= list.size(); i++) {
iterator.next();
}
fail("Failing checkIteratorNext() - NoSuchElementException should have been thrown");
} catch (NoSuchElementException e) {
checkAssertOnException(e);
}
}
@Test
public void checkListIteratorNext() {
var iterator = list.listIterator(list.size()); // position at end
try {
iterator.next();
fail("Failing checkListIteratorNext() - NoSuchElementException should have been thrown");
} catch (NoSuchElementException e) {
checkAssertOnException(e);
}
}
@Test
public void checkListIteratorPrevious() {
var iterator = list.listIterator(0); // position at start
try {
iterator.previous();
fail("Failing checkListIteratorPrevious() - NoSuchElementException should have been thrown");
} catch (NoSuchElementException e) {
checkAssertOnException(e);
}
}
private void checkAssertOnException(NoSuchElementException e) {
var cause = e.getCause();
assertNotNull(cause, "Exception.getCause()");
assertTrue(cause instanceof IndexOutOfBoundsException, "Exception.getCause() should be an " +
"IndexOutOfBoundsException");
var msg = e.getMessage();
assertNotNull(msg, "Exception.getMessage()");
assertTrue(msg.contains("IndexOutOfBoundsException"), "Exception.getMessage() should " +
"contain the string 'IndexOutOfBoundsException'");
}
}

View file

@ -0,0 +1,78 @@
/*
* Copyright (c) 1999, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 4189896
* @summary AbstractList iterators previously checked for co-modification
* *after* the set/add/remove operations were performed.
*/
import java.util.ArrayList;
import java.util.ConcurrentModificationException;
import java.util.List;
import java.util.ListIterator;
public class FailFastIterator {
public static void main(String[] args) throws Exception {
List orig = new ArrayList(100);
for (int i=0; i<100; i++)
orig.add(new Integer(i));
List copy = new ArrayList(orig);
try {
ListIterator i = copy.listIterator();
i.next();
copy.remove(99);
copy.add(new Integer(99));
i.remove();
throw new Exception("remove: iterator didn't fail fast");
} catch (ConcurrentModificationException e) {
}
if (!copy.equals(orig))
throw new Exception("remove: iterator didn't fail fast enough");
try {
ListIterator i = copy.listIterator();
i.next();
copy.remove(99);
copy.add(new Integer(99));
i.set(new Integer(666));
throw new Exception("set: iterator didn't fail fast");
} catch (ConcurrentModificationException e) {
}
if (!copy.equals(orig))
throw new Exception("set: iterator didn't fail fast enough");
try {
ListIterator i = copy.listIterator();
copy.remove(99);
copy.add(new Integer(99));
i.add(new Integer(666));
throw new Exception("add: iterator didn't fail fast");
} catch (ConcurrentModificationException e) {
}
if (!copy.equals(orig))
throw new Exception("add: iterator didn't fail fast enough");
}
}

View file

@ -0,0 +1,53 @@
/*
* Copyright (c) 2000, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 4375048
* @summary AbstractList's ListIterator.hasNext() returns
* true, after ListIterator.previous() causes
* an exception for an empty list.
* @author Konstantin Kladko
*/
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
import java.util.NoSuchElementException;
public class HasNextAfterException {
public static void main(String[] args) {
List list = new ArrayList();
ListIterator i = list.listIterator();
try {
i.previous();
}
catch (NoSuchElementException e) {
}
if (i.hasNext()) {
throw new RuntimeException(
"ListIterator.hasNext() returns true for an empty "
+ "List after ListIterator.previous().");
}
}
}

View file

@ -0,0 +1,72 @@
/*
* Copyright (c) 2000, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 4328748
* @summary AbstractMap's clone() method is implemented to
* reset AbstractMap's private fields after super.clone()
*
* @author Konstantin Kladko
*/
import java.util.AbstractMap;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class AbstractMapClone extends AbstractMap implements Cloneable {
private Map map = new HashMap();
public Set entrySet() {
return map.entrySet();
}
public Object put(Object key, Object value) {
return map.put(key, value);
}
public Object clone() {
final AbstractMapClone clone;
try {
clone = (AbstractMapClone)super.clone();
} catch (CloneNotSupportedException e) {
throw new AssertionError(e);
}
clone.map = (Map)((HashMap)map).clone();
return clone;
}
public static void main(String[] args) {
AbstractMapClone m1 = new AbstractMapClone();
m1.put("1", "1");
Set k1 = m1.keySet();
AbstractMapClone m2 = (AbstractMapClone)m1.clone();
Set k2 = m2.keySet();
m2.put("2","2");
if (k1.equals(k2)) {
throw new RuntimeException("AbstractMap.clone() failed.");
}
}
}

View file

@ -0,0 +1,61 @@
/*
* Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
/**
* @test
* @bug 4503672
* @summary AbstractMap.equals and AbstractSet.equals are fragile: they
* throw exceptions when they should return false.
* @author Josh Bloch
*/
public class Equals {
public static void main(String[] args) {
Map m = new HashMap();
m.put(null, "");
Map h = new Hashtable();
h.put("", "");
if (m.equals(h))
throw new RuntimeException("1");
Map m1 = new TreeMap();
m1.put(new Integer(42), "The Answer");
Map m2 = new TreeMap();
m2.put("The Answer", new Integer(42));
if (m1.equals(m2))
throw new RuntimeException("3");
Set s1 = new TreeSet();
s1.add(new Integer(666));
Set s2 = new TreeSet();
s2.add("Great googly moogly!");
if (s1.equals(s2))
throw new RuntimeException("2");
}
}

View file

@ -0,0 +1,105 @@
/*
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 4904074 6328220 6330389 8308167
* @modules java.base/jdk.internal.util
* @summary Basic tests for several Map.Entry implementations
* @author Martin Buchholz
*/
import java.util.Map;
import jdk.internal.util.NullableKeyValueHolder;
import static java.util.AbstractMap.SimpleEntry;
import static java.util.AbstractMap.SimpleImmutableEntry;
public class SimpleEntries {
private static String k = "foo";
private static Long v = 1L;
private static Long v2 = 2L;
private static void realMain(String[] args) throws Throwable {
testEntry(new SimpleEntry<String,Long>(k,v));
testEntry(new SimpleImmutableEntry<String,Long>(k,v));
testEntry(Map.entry(k,v));
testEntry(Map.Entry.copyOf(Map.entry(k,v)));
testEntry(new NullableKeyValueHolder(k,v));
testNullEntry(new SimpleEntry<String,Long>(null,null));
testNullEntry(new SimpleImmutableEntry<String,Long>(null,null));
testNullEntry(new NullableKeyValueHolder(null,null));
}
private static void testEntry(Map.Entry<String,Long> e) {
equal(e.getKey(), k);
equal(e.getValue(), v);
equal(e, new SimpleEntry<String,Long>(k,v));
check(! e.equals(new SimpleEntry<String,Long>(k,v2)));
check(! e.equals(null));
equal(e, new SimpleImmutableEntry<String,Long>(k,v));
equal(e.toString(), k+"="+v);
check(e.hashCode() == 101575); // hash("foo") ^ hash(1L)
if (e instanceof SimpleEntry) {
equal(e.setValue(v2), v);
equal(e.getValue(), v2);
equal(e.setValue(null), v2);
equal(e.getValue(), null);
} else {
try { e.setValue(v2); fail(); }
catch (UnsupportedOperationException t) {}
catch (Throwable t) { unexpected(t); }
}
}
private static void testNullEntry(Map.Entry<String,Long> e) {
equal(e.getKey(), null);
equal(e.getValue(), null);
equal(e, new SimpleEntry<String,Long>(null, null));
equal(e, new SimpleImmutableEntry<String,Long>(null, null));
equal(e.toString(), "null=null");
check(e.hashCode() == 0);
if (e instanceof SimpleEntry) {
equal(e.setValue(v), null);
equal(e.getValue(), v);
} else {
try { e.setValue(null); fail(); }
catch (UnsupportedOperationException t) {}
catch (Throwable t) { unexpected(t); }
}
}
//--------------------- Infrastructure ---------------------------
static volatile int passed = 0, failed = 0;
static void pass() {passed++;}
static void fail() {failed++; Thread.dumpStack();}
static void fail(String msg) {System.out.println(msg); fail();}
static void unexpected(Throwable t) {failed++; t.printStackTrace();}
static void check(boolean cond) {if (cond) pass(); else fail();}
static void equal(Object x, Object y) {
if (x == null ? y == null : x.equals(y)) pass();
else fail(x + " not equal to " + y);}
public static void main(String[] args) throws Throwable {
try {realMain(args);} catch (Throwable t) {unexpected(t);}
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
if (failed > 0) throw new AssertionError("Some tests failed");}
}

View file

@ -0,0 +1,55 @@
/*
* Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 4486049
* @summary toString method fails if size changes in between a call to size
* and an attempt to iterate.
* @author Josh Bloch
*/
import java.util.LinkedHashMap;
import java.util.Map;
public class ToString {
public static void main(String[] args) {
Map m = new LyingMap();
if (!m.toString().equals("{}"))
throw new RuntimeException(m.toString() + "!= {}");
m.put("x", "1");
if (!m.toString().equals("{x=1}"))
throw new RuntimeException(m.toString() + "!= {x=1}");
m.put("y", "2");
if (!m.toString().equals("{x=1, y=2}"))
throw new RuntimeException(m.toString() + "!= {x=1, y=2}");
}
}
class LyingMap extends LinkedHashMap {
public int size() {
return super.size() + 1; // Lies, lies, all lies!
}
}

View file

@ -0,0 +1,56 @@
/*
* Copyright (c) 1999, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 4295163
* @summary AddAll(int, Collection) intersperses the Collection with this List.
*/
import java.util.AbstractSequentialList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.ListIterator;
public class AddAll {
public static void main(String[] args) throws Exception {
List t = new FooList();
t.add("b"); t.add("a"); t.add("r");
t.addAll(0, Arrays.asList(new String[] {"f","o","o"}));
if (!t.equals(Arrays.asList(new String[] {"f","o","o","b","a","r"})))
throw new Exception("addAll is broken");
}
}
class FooList extends AbstractSequentialList {
List a = new ArrayList();
public int size() {
return a.size();
}
public ListIterator listIterator(int index) {
return a.listIterator(index);
}
}

View file

@ -0,0 +1,153 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* Written by Martin Buchholz with assistance from members of JCP
* JSR-166 Expert Group and released to the public domain, as
* explained at http://creativecommons.org/publicdomain/zero/1.0/
*/
/*
* @test
* @modules java.base/java.util:open
* @run testng WhiteBox
* @summary White box tests of implementation details
*/
import static org.testng.Assert.*;
import org.testng.annotations.Test;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.util.ArrayDeque;
import java.util.concurrent.ThreadLocalRandom;
@Test
public class WhiteBox {
final ThreadLocalRandom rnd = ThreadLocalRandom.current();
final VarHandle ELEMENTS, HEAD, TAIL;
WhiteBox() throws ReflectiveOperationException {
Class<?> klazz = ArrayDeque.class;
MethodHandles.Lookup lookup
= MethodHandles.privateLookupIn(klazz, MethodHandles.lookup());
ELEMENTS = lookup.findVarHandle(klazz, "elements", Object[].class);
HEAD = lookup.findVarHandle(klazz, "head", int.class);
TAIL = lookup.findVarHandle(klazz, "tail", int.class);
}
Object[] elements(ArrayDeque d) { return (Object[]) ELEMENTS.get(d); }
int head(ArrayDeque d) { return (int) HEAD.get(d); }
int tail(ArrayDeque d) { return (int) TAIL.get(d); }
void checkCapacity(ArrayDeque d, int capacity) {
assertTrue(d.isEmpty());
assertEquals(0, head(d));
assertEquals(0, tail(d));
Object[] initialElements = elements(d);
assertInvariants(d);
for (int i = capacity; i--> 0; ) {
d.add(rnd.nextInt(42));
assertSame(elements(d), initialElements);
assertInvariants(d);
}
d.add(rnd.nextInt(42));
assertNotSame(elements(d), initialElements);
assertInvariants(d);
}
@Test
public void defaultConstructor() {
checkCapacity(new ArrayDeque(), 16);
}
@Test
public void shouldNotResizeWhenInitialCapacityProvided() {
int initialCapacity = rnd.nextInt(20);
checkCapacity(new ArrayDeque(initialCapacity), initialCapacity);
}
byte[] serialBytes(Object o) {
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(o);
oos.flush();
oos.close();
return bos.toByteArray();
} catch (Exception fail) {
throw new AssertionError(fail);
}
}
@SuppressWarnings("unchecked")
<T> T serialClone(T o) {
try {
ObjectInputStream ois = new ObjectInputStream
(new ByteArrayInputStream(serialBytes(o)));
T clone = (T) ois.readObject();
assertNotSame(o, clone);
assertSame(o.getClass(), clone.getClass());
return clone;
} catch (Exception fail) {
throw new AssertionError(fail);
}
}
@Test
public void testSerialization() {
ArrayDeque[] ds = { new ArrayDeque(), new ArrayDeque(rnd.nextInt(20)) };
for (ArrayDeque d : ds) {
if (rnd.nextBoolean()) d.add(99);
ArrayDeque clone = serialClone(d);
assertInvariants(clone);
assertNotSame(elements(d), elements(clone));
assertEquals(d, clone);
}
}
/** Checks conditions which should always be true. */
void assertInvariants(ArrayDeque d) {
final Object[] elements = elements(d);
final int head = head(d);
final int tail = tail(d);
final int capacity = elements.length;
assertTrue(0 <= head && head < capacity);
assertTrue(0 <= tail && tail < capacity);
assertTrue(capacity > 0);
assertTrue(d.size() < capacity);
assertTrue((head == tail) ^ (elements[head] != null));
assertNull(elements[tail]);
assertTrue((head == tail) ^ (elements[Math.floorMod(tail - 1, capacity)] != null));
}
}

View file

@ -0,0 +1,88 @@
/*
* Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 4715206
* @summary Ensure that addAll method can cope with underestimate by size().
* @author Josh Bloch
*/
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import java.util.WeakHashMap;
public class AddAll {
public static void main(String[] args) {
for (int j = 0; j < 1; j++) {
Map m = new WeakHashMap(100000);
for (int i = 0; i < 100000; i++)
m.put(new Object(), Boolean.TRUE);
new ArrayList().addAll(m.keySet());
}
for (int j = 0; j < 1; j++) {
Map m = new WeakHashMap(100000);
for (int i = 0; i < 100000; i++)
m.put(new Object(), Boolean.TRUE);
new LinkedList().addAll(m.keySet());
}
for (int j = 0; j < 1; j++) {
Map m = new WeakHashMap(100000);
for (int i = 0; i < 100000; i++)
m.put(new Object(), Boolean.TRUE);
new Vector().addAll(m.keySet());
}
for (int j = 0; j < 1; j++) {
Map m = new WeakHashMap(100000);
for (int i = 0; i < 100000; i++)
m.put(new Object(), Boolean.TRUE);
List list = new ArrayList();
list.add("inka"); list.add("dinka"); list.add("doo");
list.addAll(1, m.keySet());
}
for (int j = 0; j < 1; j++) {
Map m = new WeakHashMap(100000);
for (int i = 0; i < 100000; i++)
m.put(new Object(), Boolean.TRUE);
List list = new LinkedList();
list.add("inka"); list.add("dinka"); list.add("doo");
list.addAll(1, m.keySet());
}
for (int j = 0; j < 1; j++) {
Map m = new WeakHashMap(100000);
for (int i = 0; i < 100000; i++)
m.put(new Object(), Boolean.TRUE);
List list = new ArrayList();
list.add("inka"); list.add("dinka"); list.add("doo");
list.addAll(1, m.keySet());
}
}
}

View file

@ -0,0 +1,214 @@
/*
* Copyright 2016 Google, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8146568
* @summary brittle white box test of internal array management
* @modules java.base/java.util:open
* @run testng ArrayManagement
*/
import java.lang.reflect.Field;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.SplittableRandom;
import org.testng.annotations.Test;
import static org.testng.Assert.*;
public class ArrayManagement {
static final int DEFAULT_CAPACITY = 10;
static final Field ELEMENT_DATA;
static final Field MODCOUNT;
static final SplittableRandom rnd = new SplittableRandom();
static {
try {
ELEMENT_DATA = ArrayList.class.getDeclaredField("elementData");
ELEMENT_DATA.setAccessible(true);
MODCOUNT = AbstractList.class.getDeclaredField("modCount");
MODCOUNT.setAccessible(true);
} catch (ReflectiveOperationException huh) {
throw new AssertionError(huh);
}
}
static Object[] elementData(ArrayList<?> list) {
try {
return (Object[]) ELEMENT_DATA.get(list);
} catch (ReflectiveOperationException huh) {
throw new AssertionError(huh);
}
}
static int modCount(ArrayList<?> list) {
try {
return MODCOUNT.getInt(list);
} catch (ReflectiveOperationException huh) {
throw new AssertionError(huh);
}
}
static int capacity(ArrayList<?> list) {
return elementData(list).length;
}
static int newCapacity(int oldCapacity) {
return oldCapacity + (oldCapacity >> 1);
}
static void ensureCapacity(ArrayList<Object> list, int capacity) {
int oldCapacity = capacity(list);
int oldModCount = modCount(list);
list.ensureCapacity(capacity);
assertTrue(capacity(list) >= capacity || capacity(list) == 0);
assertEquals(modCount(list),
(capacity(list) == oldCapacity)
? oldModCount
: oldModCount + 1);
}
static List<Object> singletonList() {
return Collections.singletonList(Boolean.TRUE);
}
/** Opportunistically randomly test various add operations. */
static void addOneElement(ArrayList<Object> list) {
int size = list.size();
int modCount = modCount(list);
switch (rnd.nextInt(4)) {
case 0: assertTrue(list.add(Boolean.TRUE)); break;
case 1: list.add(size, Boolean.TRUE); break;
case 2: assertTrue(list.addAll(singletonList())); break;
case 3: assertTrue(list.addAll(size, singletonList())); break;
default: throw new AssertionError();
}
assertEquals(modCount(list), modCount + 1);
assertEquals(list.size(), size + 1);
}
@Test public void defaultCapacity() {
ArrayList<Object> list = new ArrayList<>();
assertEquals(capacity(new ArrayList<Object>()), 0);
for (int i = 0; i < DEFAULT_CAPACITY; i++) {
addOneElement(list);
assertEquals(capacity(list), DEFAULT_CAPACITY);
}
addOneElement(list);
assertEquals(capacity(list), newCapacity(DEFAULT_CAPACITY));
}
@Test public void defaultCapacityEnsureCapacity() {
ArrayList<Object> list = new ArrayList<>();
for (int i = 0; i <= DEFAULT_CAPACITY; i++) {
ensureCapacity(list, i); // no-op!
assertEquals(capacity(list), 0);
}
for (int i = 0; i < DEFAULT_CAPACITY; i++) {
addOneElement(list);
assertEquals(capacity(list), DEFAULT_CAPACITY);
}
addOneElement(list);
assertEquals(capacity(list), newCapacity(DEFAULT_CAPACITY));
{
int capacity = capacity(list);
ensureCapacity(list, capacity + 1);
assertEquals(capacity(list), newCapacity(capacity));
}
{
int capacity = capacity(list);
ensureCapacity(list, 3 * capacity);
assertEquals(capacity(list), 3 * capacity);
}
}
@Test public void ensureCapacityBeyondDefaultCapacity() {
ArrayList<Object> list = new ArrayList<>();
list.ensureCapacity(DEFAULT_CAPACITY + 1);
assertEquals(capacity(list), DEFAULT_CAPACITY + 1);
for (int i = 0; i < DEFAULT_CAPACITY + 1; i++) {
addOneElement(list);
assertEquals(capacity(list), DEFAULT_CAPACITY + 1);
}
addOneElement(list);
assertEquals(capacity(list), newCapacity(DEFAULT_CAPACITY + 1));
}
@Test public void explicitZeroCapacity() {
ArrayList<Object> list = new ArrayList<>(0);
assertEquals(capacity(list), 0);
addOneElement(list);
assertEquals(capacity(list), 1);
addOneElement(list);
assertEquals(capacity(list), 2);
addOneElement(list);
assertEquals(capacity(list), 3);
addOneElement(list);
assertEquals(capacity(list), 4);
addOneElement(list);
assertEquals(capacity(list), 6);
addOneElement(list);
assertEquals(capacity(list), 6);
addOneElement(list);
assertEquals(capacity(list), 9);
list.clear();
assertEquals(capacity(list), 9);
}
@Test public void explicitLargeCapacity() {
int n = DEFAULT_CAPACITY * 3;
ArrayList<Object> list = new ArrayList<>(n);
assertEquals(capacity(list), n);
ensureCapacity(list, 0);
ensureCapacity(list, n);
for (int i = 0; i < n; i++) addOneElement(list);
assertEquals(capacity(list), n);
addOneElement(list);
assertEquals(capacity(list), newCapacity(n));
}
@Test public void emptyArraysAreShared() {
assertSame(elementData(new ArrayList<Object>()),
elementData(new ArrayList<Object>()));
assertSame(elementData(new ArrayList<Object>(0)),
elementData(new ArrayList<Object>(0)));
}
@Test public void emptyArraysDifferBetweenDefaultAndExplicit() {
assertNotSame(elementData(new ArrayList<Object>()),
elementData(new ArrayList<Object>(0)));
}
@Test public void negativeCapacity() {
for (int capacity : new int[] { -1, Integer.MIN_VALUE }) {
try {
new ArrayList<Object>(capacity);
fail("should throw");
} catch (IllegalArgumentException success) {}
}
}
}

View file

@ -0,0 +1,70 @@
/*
* Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 6533203
* @summary AbstractList.ListItr.add might corrupt iterator state if enclosing add throws
*/
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
@SuppressWarnings({"serial","unchecked"})
public class Bug6533203 {
void test(String[] args) throws Throwable {
final List<Integer> superstitious = new ArrayList<>() {
public void add(int index, Integer i) {
if (i == 13) throw new Error("unlucky");
else super.add(index, i); }};
final ListIterator it = superstitious.listIterator(0);
equal(it.nextIndex(), 0);
THROWS(Error.class, new F(){void f(){it.add(13);}});
equal(it.nextIndex(), 0);
}
//--------------------- Infrastructure ---------------------------
volatile int passed = 0, failed = 0;
void pass() {passed++;}
void fail() {failed++; Thread.dumpStack();}
void fail(String msg) {System.out.println(msg); fail();}
void unexpected(Throwable t) {failed++; t.printStackTrace();}
void check(boolean cond) {if (cond) pass(); else fail();}
void equal(Object x, Object y) {
if (x == null ? y == null : x.equals(y)) pass();
else fail(x + " not equal to " + y);}
public static void main(String[] args) throws Throwable {
new Bug6533203().instanceMain(args);}
void instanceMain(String[] args) throws Throwable {
try {test(args);} catch (Throwable t) {unexpected(t);}
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
if (failed > 0) throw new AssertionError("Some tests failed");}
abstract class F {abstract void f() throws Throwable;}
void THROWS(Class<? extends Throwable> k, F... fs) {
for (F f : fs)
try {f.f(); fail("Expected " + k.getName() + " not thrown");}
catch (Throwable t) {
if (k.isAssignableFrom(t.getClass())) pass();
else unexpected(t);}}
}

View file

@ -0,0 +1,43 @@
/*
* Copyright 2016 Google, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8146568
* @summary repro for: NegativeArraySizeException in ArrayList.grow(int)
* @run main/manual/othervm -Xmx17g Bug8146568
* @requires os.maxMemory>17G
*/
public class Bug8146568 {
public static void main(String[] args) {
int size = Integer.MAX_VALUE - 2;
java.util.ArrayList<Object> huge = new java.util.ArrayList<>(size);
for (int i = 0; i < size; i++)
huge.add(null);
try {
huge.addAll(huge);
throw new Error("expected OutOfMemoryError not thrown");
} catch (OutOfMemoryError success) {}
}
}

View file

@ -0,0 +1,64 @@
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @bug 6992121
* @summary Test the ArrayList.ensureCapacity() and Vector.ensureCapacity
* method with negative minimumCapacity input argument.
*/
import java.util.ArrayList;
import java.util.Vector;
public class EnsureCapacity {
public static void main(String[] args) {
testArrayList();
testVector();
}
private static void checkCapacity(int before, int after) {
if (before != after) {
throw new RuntimeException("capacity is expected to be unchanged: " +
"before=" + before + " after=" + after);
}
}
private static void testArrayList() {
ArrayList<String> al = new ArrayList<String>();
al.add("abc");
al.ensureCapacity(Integer.MIN_VALUE);
// there is no method to query the capacity of ArrayList
// so before and after capacity are not checked
}
private static void testVector() {
Vector<String> vector = new Vector<String>();
vector.add("abc");
int cap = vector.capacity();
vector.ensureCapacity(Integer.MIN_VALUE);
checkCapacity(cap, vector.capacity());
}
}

View file

@ -0,0 +1,710 @@
/*
* Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @summary micro-benchmark correctness mode
* @run main IteratorMicroBenchmark iterations=1 size=8 warmup=0
*/
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.stream.Collectors.toList;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Spliterator;
import java.util.Vector;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ThreadLocalRandom;
import java.util.regex.Pattern;
/**
* Usage: [iterations=N] [size=N] [filter=REGEXP] [warmup=SECONDS]
*
* To run this in micro-benchmark mode, simply run as a normal java program.
* Be patient; this program runs for a very long time.
* For faster runs, restrict execution using command line args.
*
* @author Martin Buchholz
*/
public class IteratorMicroBenchmark {
abstract static class Job {
private final String name;
public Job(String name) { this.name = name; }
public String name() { return name; }
public abstract void work() throws Throwable;
}
static double warmupSeconds;
static long warmupNanos;
// --------------- GC finalization infrastructure ---------------
/** No guarantees, but effective in practice. */
static void forceFullGc() {
long timeoutMillis = 1000L;
CountDownLatch finalized = new CountDownLatch(1);
ReferenceQueue<Object> queue = new ReferenceQueue<>();
WeakReference<Object> ref = new WeakReference<>(
new Object() { protected void finalize() { finalized.countDown(); }},
queue);
try {
for (int tries = 3; tries--> 0; ) {
System.gc();
if (finalized.await(timeoutMillis, MILLISECONDS)
&& queue.remove(timeoutMillis) != null
&& ref.get() == null) {
System.runFinalization(); // try to pick up stragglers
return;
}
timeoutMillis *= 4;
}
} catch (InterruptedException unexpected) {
throw new AssertionError("unexpected InterruptedException");
}
throw new AssertionError("failed to do a \"full\" gc");
}
/**
* Runs each job for long enough that all the runtime compilers
* have had plenty of time to warm up, i.e. get around to
* compiling everything worth compiling.
* Returns array of average times per job per run.
*/
private static long[] time0(Job ... jobs) throws Throwable {
long[] nanoss = new long[jobs.length];
for (int i = 0; i < jobs.length; i++) {
if (warmupNanos > 0) forceFullGc();
Job job = jobs[i];
long totalTime;
int runs = 0;
long startTime = System.nanoTime();
do { job.work(); runs++; }
while ((totalTime = System.nanoTime() - startTime) < warmupNanos);
nanoss[i] = totalTime/runs;
}
return nanoss;
}
private static void time(Job ... jobs) throws Throwable {
if (warmupSeconds > 0.0) time0(jobs); // Warm up run
long[] nanoss = time0(jobs); // Real timing run
long[] milliss = new long[jobs.length];
double[] ratios = new double[jobs.length];
final String nameHeader = "Method";
final String millisHeader = "Millis";
final String ratioHeader = "Ratio";
int nameWidth = nameHeader.length();
int millisWidth = millisHeader.length();
int ratioWidth = ratioHeader.length();
for (int i = 0; i < jobs.length; i++) {
nameWidth = Math.max(nameWidth, jobs[i].name().length());
milliss[i] = nanoss[i]/(1000L * 1000L);
millisWidth = Math.max(millisWidth,
String.format("%d", milliss[i]).length());
ratios[i] = (double) nanoss[i] / (double) nanoss[0];
ratioWidth = Math.max(ratioWidth,
String.format("%.3f", ratios[i]).length());
}
String format = String.format("%%-%ds %%%dd %%%d.3f%%n",
nameWidth, millisWidth, ratioWidth);
String headerFormat = String.format("%%-%ds %%%ds %%%ds%%n",
nameWidth, millisWidth, ratioWidth);
System.out.printf(headerFormat, "Method", "Millis", "Ratio");
// Print out absolute and relative times, calibrated against first job
for (int i = 0; i < jobs.length; i++)
System.out.printf(format, jobs[i].name(), milliss[i], ratios[i]);
}
private static String keywordValue(String[] args, String keyword) {
for (String arg : args)
if (arg.startsWith(keyword))
return arg.substring(keyword.length() + 1);
return null;
}
private static int intArg(String[] args, String keyword, int defaultValue) {
String val = keywordValue(args, keyword);
return (val == null) ? defaultValue : Integer.parseInt(val);
}
private static double doubleArg(String[] args, String keyword, double defaultValue) {
String val = keywordValue(args, keyword);
return (val == null) ? defaultValue : Double.parseDouble(val);
}
private static Pattern patternArg(String[] args, String keyword) {
String val = keywordValue(args, keyword);
return (val == null) ? null : Pattern.compile(val);
}
private static Job[] filter(Pattern filter, Job[] jobs) {
return (filter == null) ? jobs
: Arrays.stream(jobs)
.filter(job -> filter.matcher(job.name()).find())
.collect(toList())
.toArray(new Job[0]);
}
private static void deoptimize(int sum) {
if (sum == 42)
System.out.println("the answer");
}
private static <T> List<T> asSubList(List<T> list) {
return list.subList(0, list.size());
}
private static <T> Iterable<T> backwards(final List<T> list) {
return new Iterable<T>() {
public Iterator<T> iterator() {
return new Iterator<T>() {
final ListIterator<T> it = list.listIterator(list.size());
public boolean hasNext() { return it.hasPrevious(); }
public T next() { return it.previous(); }
public void remove() { it.remove(); }};}};
}
public static void main(String[] args) throws Throwable {
final int iterations = intArg(args, "iterations", 100_000);
final int size = intArg(args, "size", 1000);
warmupSeconds = doubleArg(args, "warmup", 7.0);
final Pattern filter = patternArg(args, "filter");
warmupNanos = (long) (warmupSeconds * (1000L * 1000L * 1000L));
// System.out.printf(
// "iterations=%d size=%d, warmup=%1g, filter=\"%s\"%n",
// iterations, size, warmupSeconds, filter);
final ConcurrentSkipListMap<Integer,Integer> m
= new ConcurrentSkipListMap<>();
final ArrayList<Integer> al = new ArrayList<>(size);
// Populate collections with random data
final ThreadLocalRandom rnd = ThreadLocalRandom.current();
for (int i = 0; i < size; i++) {
m.put(rnd.nextInt(size), rnd.nextInt(size));
al.add(rnd.nextInt(size));
}
final Vector<Integer> v = new Vector<>(al);
final ArrayDeque<Integer> ad = new ArrayDeque<>(al);
// shuffle ArrayDeque elements so they wrap
for (int i = 0, n = rnd.nextInt(size); i < n; i++)
ad.addLast(ad.removeFirst());
// Also test "short" collections
final int shortSize = 5;
final Vector<Integer> sv = new Vector<>(v.subList(0, shortSize));
final ArrayList<Integer> sal = new ArrayList<>(sv);
// Checks for correctness *and* prevents loop optimizations
class Check {
private int sum;
public void sum(int sum) {
if (this.sum == 0)
this.sum = sum;
if (this.sum != sum)
throw new AssertionError("Sum mismatch");
}
}
final Check check = new Check();
final Check shortCheck = new Check();
Job[] jobs = {
// new Job("Vector iterate desugared") {
// public void work() throws Throwable {
// for (int i = 0; i < iterations; i++) {
// int sum = 0;
// for (Iterator<Integer> it = v.iterator(); it.hasNext();)
// sum += it.next();
// check.sum(sum);}}},
new Job("array loop") {
public void work() throws Throwable {
Integer[] a = al.toArray(new Integer[0]);
for (int i = 0; i < iterations; i++) {
int sum = 0;
int size = a.length;
for (int j = 0; j < size; ++j)
sum += a[j];
check.sum(sum);}}},
new Job("descending array loop") {
public void work() throws Throwable {
Integer[] a = al.toArray(new Integer[0]);
for (int i = 0; i < iterations; i++) {
int sum = 0;
int size = a.length;
for (int j = size - 1; j >= 0; j--)
sum += a[j];
check.sum(sum);}}},
new Job("Vector get loop") {
public void work() throws Throwable {
for (int i = 0; i < iterations; i++) {
int sum = 0;
int size = v.size();
for (int j = 0; j < size; ++j)
sum += v.get(j);
check.sum(sum);}}},
new Job("Vector iterate for loop") {
public void work() throws Throwable {
for (int i = 0; i < iterations; i++) {
int sum = 0;
for (Integer n : v)
sum += n;
check.sum(sum);}}},
new Job("Vector descending listIterator loop") {
public void work() throws Throwable {
for (int i = 0; i < iterations; i++) {
int sum = 0;
ListIterator<Integer> it = v.listIterator(al.size());
while (it.hasPrevious())
sum += it.previous();
check.sum(sum);}}},
new Job("Vector Enumeration loop") {
public void work() throws Throwable {
for (int i = 0; i < iterations; i++) {
int sum = 0;
Enumeration<Integer> it = v.elements();
while (it.hasMoreElements())
sum += it.nextElement();
check.sum(sum);}}},
new Job("Vector subList iterate for loop") {
public void work() throws Throwable {
for (int i = 0; i < iterations; i++) {
int sum = 0;
for (Integer n : asSubList(v))
sum += n;
check.sum(sum);}}},
new Job("Vector subList subList subList iterate for loop") {
public void work() throws Throwable {
for (int i = 0; i < iterations; i++) {
int sum = 0;
for (Integer n : asSubList(asSubList(asSubList(v))))
sum += n;
check.sum(sum);}}},
new Job("Vector backwards wrapper ListIterator for loop") {
public void work() throws Throwable {
for (int i = 0; i < iterations; i++) {
int sum = 0;
for (Integer n : backwards(v))
sum += n;
check.sum(sum);}}},
new Job("Vector backwards wrapper subList ListIterator for loop") {
public void work() throws Throwable {
for (int i = 0; i < iterations; i++) {
int sum = 0;
for (Integer n : backwards(asSubList(v)))
sum += n;
check.sum(sum);}}},
// new Job("Vector iterate for loop invokeinterface") {
// public void work() throws Throwable {
// final List<Integer> l = v;
// for (int i = 0; i < iterations; i++) {
// int sum = 0;
// for (Integer n : l)
// sum += n;
// check.sum(sum);}}},
// new Job("Vector subList iterate for loop invokeinterface") {
// public void work() throws Throwable {
// final List<Integer> l = v;
// for (int i = 0; i < iterations; i++) {
// int sum = 0;
// for (Integer n : asSubList(l))
// sum += n;
// check.sum(sum);}}},
new Job("Short Vector get loop") {
public void work() throws Throwable {
for (int i = 0; i < (iterations * size / shortSize); i++) {
int sum = 0;
int size = sv.size();
for (int j = 0; j < size; ++j)
sum += sv.get(j);
shortCheck.sum(sum);}}},
new Job("Short Vector iterate for loop") {
public void work() throws Throwable {
for (int i = 0; i < (iterations * size / shortSize); i++) {
int sum = 0;
for (Integer n : sv)
sum += n;
shortCheck.sum(sum);}}},
new Job("Short Vector sublist iterate for loop") {
public void work() throws Throwable {
for (int i = 0; i < (iterations * size / shortSize); i++) {
int sum = 0;
for (Integer n : asSubList(sv))
sum += n;
shortCheck.sum(sum);}}},
new Job("ArrayList get loop") {
public void work() throws Throwable {
for (int i = 0; i < iterations; i++) {
int sum = 0;
int size = al.size();
for (int j = 0; j < size; ++j)
sum += al.get(j);
check.sum(sum);}}},
new Job("ArrayList iterate for loop") {
public void work() throws Throwable {
for (int i = 0; i < iterations; i++) {
int sum = 0;
for (Integer n : al)
sum += n;
check.sum(sum);}}},
new Job("ArrayDeque iterate for loop") {
public void work() throws Throwable {
for (int i = 0; i < iterations; i++) {
int sum = 0;
for (Integer n : ad)
sum += n;
check.sum(sum);}}},
new Job("ArrayList descending listIterator loop") {
public void work() throws Throwable {
for (int i = 0; i < iterations; i++) {
int sum = 0;
ListIterator<Integer> it = al.listIterator(al.size());
while (it.hasPrevious())
sum += it.previous();
check.sum(sum);}}},
new Job("ArrayList listIterator loop") {
public void work() throws Throwable {
for (int i = 0; i < iterations; i++) {
int sum = 0;
ListIterator<Integer> it = al.listIterator();
while (it.hasNext())
sum += it.next();
check.sum(sum);}}},
new Job("ArrayDeque.descendingIterator() loop") {
public void work() throws Throwable {
for (int i = 0; i < iterations; i++) {
int sum = 0;
Iterator<Integer> it = ad.descendingIterator();
while (it.hasNext())
sum += it.next();
check.sum(sum);}}},
new Job("ArrayList.forEach") {
public void work() throws Throwable {
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
al.forEach(n -> sum[0] += n);
check.sum(sum[0]);}}},
new Job("ArrayDeque.forEach") {
public void work() throws Throwable {
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
ad.forEach(n -> sum[0] += n);
check.sum(sum[0]);}}},
new Job("Vector.forEach") {
public void work() throws Throwable {
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
v.forEach(n -> sum[0] += n);
check.sum(sum[0]);}}},
new Job("ArrayList.iterator().forEachRemaining()") {
public void work() throws Throwable {
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
al.iterator().forEachRemaining(n -> sum[0] += n);
check.sum(sum[0]);}}},
new Job("ArrayDeque.descendingIterator().forEachRemaining()") {
public void work() throws Throwable {
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
ad.descendingIterator().forEachRemaining(n -> sum[0] += n);
check.sum(sum[0]);}}},
new Job("ArrayDeque.iterator().forEachRemaining()") {
public void work() throws Throwable {
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
ad.iterator().forEachRemaining(n -> sum[0] += n);
check.sum(sum[0]);}}},
new Job("Vector.iterator().forEachRemaining()") {
public void work() throws Throwable {
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
v.iterator().forEachRemaining(n -> sum[0] += n);
check.sum(sum[0]);}}},
new Job("ArrayList.spliterator().forEachRemaining()") {
public void work() throws Throwable {
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
al.spliterator().forEachRemaining(n -> sum[0] += n);
check.sum(sum[0]);}}},
new Job("ArrayDeque.spliterator().forEachRemaining()") {
public void work() throws Throwable {
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
ad.spliterator().forEachRemaining(n -> sum[0] += n);
check.sum(sum[0]);}}},
new Job("Vector.spliterator().forEachRemaining()") {
public void work() throws Throwable {
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
v.spliterator().forEachRemaining(n -> sum[0] += n);
check.sum(sum[0]);}}},
new Job("ArrayList.spliterator().tryAdvance()") {
public void work() throws Throwable {
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
Spliterator<Integer> spliterator = al.spliterator();
do {} while (spliterator.tryAdvance(n -> sum[0] += n));
check.sum(sum[0]);}}},
new Job("ArrayDeque.spliterator().tryAdvance()") {
public void work() throws Throwable {
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
Spliterator<Integer> spliterator = ad.spliterator();
do {} while (spliterator.tryAdvance(n -> sum[0] += n));
check.sum(sum[0]);}}},
new Job("Vector.spliterator().tryAdvance()") {
public void work() throws Throwable {
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
Spliterator<Integer> spliterator = v.spliterator();
do {} while (spliterator.tryAdvance(n -> sum[0] += n));
check.sum(sum[0]);}}},
new Job("ArrayList.removeIf") {
public void work() throws Throwable {
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
al.removeIf(n -> { sum[0] += n; return false; });
check.sum(sum[0]);}}},
new Job("ArrayDeque.removeIf") {
public void work() throws Throwable {
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
ad.removeIf(n -> { sum[0] += n; return false; });
check.sum(sum[0]);}}},
new Job("Vector.removeIf") {
public void work() throws Throwable {
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
v.removeIf(n -> { sum[0] += n; return false; });
check.sum(sum[0]);}}},
new Job("ArrayList subList .removeIf") {
public void work() throws Throwable {
int[] sum = new int[1];
List<Integer> sl = asSubList(al);
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
sl.removeIf(n -> { sum[0] += n; return false; });
check.sum(sum[0]);}}},
new Job("ArrayList subList get loop") {
public void work() throws Throwable {
List<Integer> sl = asSubList(al);
for (int i = 0; i < iterations; i++) {
int sum = 0;
int size = sl.size();
for (int j = 0; j < size; ++j)
sum += sl.get(j);
check.sum(sum);}}},
new Job("ArrayList subList iterate for loop") {
public void work() throws Throwable {
for (int i = 0; i < iterations; i++) {
int sum = 0;
for (Integer n : asSubList(al))
sum += n;
check.sum(sum);}}},
new Job("ArrayList subList subList subList iterate for loop") {
public void work() throws Throwable {
for (int i = 0; i < iterations; i++) {
int sum = 0;
for (Integer n : asSubList(asSubList(asSubList(al))))
sum += n;
check.sum(sum);}}},
new Job("ArrayList backwards wrapper ListIterator for loop") {
public void work() throws Throwable {
for (int i = 0; i < iterations; i++) {
int sum = 0;
for (Integer n : backwards(al))
sum += n;
check.sum(sum);}}},
new Job("ArrayList backwards wrapper subList ListIterator for loop") {
public void work() throws Throwable {
for (int i = 0; i < iterations; i++) {
int sum = 0;
for (Integer n : backwards(asSubList(al)))
sum += n;
check.sum(sum);}}},
// new Job("ArrayList iterate desugared") {
// public void work() throws Throwable {
// for (int i = 0; i < iterations; i++) {
// int sum = 0;
// for (Iterator<Integer> it = al.iterator(); it.hasNext();)
// sum += it.next();
// check.sum(sum);}}},
new Job("Short ArrayList get loop") {
public void work() throws Throwable {
for (int i = 0; i < (iterations * size / shortSize); i++) {
int sum = 0;
int size = sal.size();
for (int j = 0; j < size; ++j)
sum += sal.get(j);
shortCheck.sum(sum);}}},
new Job("Short ArrayList iterate for loop") {
public void work() throws Throwable {
for (int i = 0; i < (iterations * size / shortSize); i++) {
int sum = 0;
for (Integer n : sal)
sum += n;
shortCheck.sum(sum);}}},
new Job("Short ArrayList sublist iterate for loop") {
public void work() throws Throwable {
for (int i = 0; i < (iterations * size / shortSize); i++) {
int sum = 0;
for (Integer n : asSubList(sal))
sum += n;
shortCheck.sum(sum);}}},
new Job("Vector ArrayList alternating iteration") {
public void work() throws Throwable {
for (int i = 0; i < iterations; i++) {
int sum = 0;
Iterator<Integer> it1 = v.iterator();
Iterator<Integer> it2 = al.iterator();
while (it1.hasNext())
sum += it1.next() + it2.next();
check.sum(sum/2);}}},
new Job("Vector ArrayList alternating invokeVirtual iteration") {
public void work() throws Throwable {
for (int i = 0; i < iterations; i++) {
int sum = 0;
List<Iterator<Integer>> its = new ArrayList<>(2);
its.add(v.iterator());
its.add(al.iterator());
for (int k = 0; its.get(k).hasNext(); k = (k == 0) ? 1 : 0)
sum += its.get(k).next();
check.sum(sum/2);}}},
new Job("ConcurrentSkipListMap entrySet iterate") {
public void work() throws Throwable {
for (int i = 0; i < iterations; i++) {
int sum = 0;
for (Map.Entry<Integer,Integer> e : m.entrySet())
sum += e.getKey();
deoptimize(sum);}}},
new Job("ArrayList.toArray()") {
public void work() throws Throwable {
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
for (Object o : al.toArray())
sum[0] += (Integer) o;
check.sum(sum[0]);}}},
new Job("ArrayList.toArray(a)") {
public void work() throws Throwable {
Integer[] a = new Integer[size];
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
al.toArray(a);
for (Object o : a)
sum[0] += (Integer) o;
check.sum(sum[0]);}}},
new Job("ArrayList subList .toArray()") {
public void work() throws Throwable {
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
for (Object o : asSubList(al).toArray())
sum[0] += (Integer) o;
check.sum(sum[0]);}}},
new Job("ArrayList subList .toArray(a)") {
public void work() throws Throwable {
Integer[] a = new Integer[size];
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
asSubList(al).toArray(a);
for (Object o : a)
sum[0] += (Integer) o;
check.sum(sum[0]);}}},
new Job("ArrayDeque.toArray()") {
public void work() throws Throwable {
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
for (Object o : ad.toArray())
sum[0] += (Integer) o;
check.sum(sum[0]);}}},
new Job("ArrayDeque.toArray(a)") {
public void work() throws Throwable {
Integer[] a = new Integer[size];
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
ad.toArray(a);
for (Object o : a)
sum[0] += (Integer) o;
check.sum(sum[0]);}}},
new Job("Vector.toArray()") {
public void work() throws Throwable {
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
for (Object o : v.toArray())
sum[0] += (Integer) o;
check.sum(sum[0]);}}},
new Job("Vector.toArray(a)") {
public void work() throws Throwable {
Integer[] a = new Integer[size];
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
v.toArray(a);
for (Object o : a)
sum[0] += (Integer) o;
check.sum(sum[0]);}}},
};
time(filter(filter, jobs));
}
}

View file

@ -0,0 +1,234 @@
/*
* Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* This is not a regression test, but a micro-benchmark.
*
* I have run this as follows:
*
* repeat 5 for f in -client -server; do mergeBench dolphin . jr -dsa -da $f RangeCheckMicroBenchmark.java; done
*
*
* @author Martin Buchholz
*/
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.regex.Pattern;
import static java.util.stream.Collectors.toList;
public class RangeCheckMicroBenchmark {
abstract static class Job {
private final String name;
Job(String name) { this.name = name; }
String name() { return name; }
abstract void work() throws Throwable;
}
private static void collectAllGarbage() {
final CountDownLatch drained = new CountDownLatch(1);
try {
System.gc(); // enqueue finalizable objects
new Object() { protected void finalize() {
drained.countDown(); }};
System.gc(); // enqueue detector
drained.await(); // wait for finalizer queue to drain
System.gc(); // cleanup finalized objects
} catch (InterruptedException e) { throw new Error(e); }
}
/**
* Runs each job for long enough that all the runtime compilers
* have had plenty of time to warm up, i.e. get around to
* compiling everything worth compiling.
* Returns array of average times per job per run.
*/
private static long[] time0(Job ... jobs) throws Throwable {
final long warmupNanos = 10L * 1000L * 1000L * 1000L;
long[] nanoss = new long[jobs.length];
for (int i = 0; i < jobs.length; i++) {
collectAllGarbage();
long t0 = System.nanoTime();
long t;
int j = 0;
do { jobs[i].work(); j++; }
while ((t = System.nanoTime() - t0) < warmupNanos);
nanoss[i] = t/j;
}
return nanoss;
}
private static void time(Job ... jobs) throws Throwable {
long[] warmup = time0(jobs); // Warm up run
long[] nanoss = time0(jobs); // Real timing run
long[] milliss = new long[jobs.length];
double[] ratios = new double[jobs.length];
final String nameHeader = "Method";
final String millisHeader = "Millis";
final String ratioHeader = "Ratio";
int nameWidth = nameHeader.length();
int millisWidth = millisHeader.length();
int ratioWidth = ratioHeader.length();
for (int i = 0; i < jobs.length; i++) {
nameWidth = Math.max(nameWidth, jobs[i].name().length());
milliss[i] = nanoss[i]/(1000L * 1000L);
millisWidth = Math.max(millisWidth,
String.format("%d", milliss[i]).length());
ratios[i] = (double) nanoss[i] / (double) nanoss[0];
ratioWidth = Math.max(ratioWidth,
String.format("%.3f", ratios[i]).length());
}
String format = String.format("%%-%ds %%%dd %%%d.3f%%n",
nameWidth, millisWidth, ratioWidth);
String headerFormat = String.format("%%-%ds %%%ds %%%ds%%n",
nameWidth, millisWidth, ratioWidth);
System.out.printf(headerFormat, "Method", "Millis", "Ratio");
// Print out absolute and relative times, calibrated against first job
for (int i = 0; i < jobs.length; i++)
System.out.printf(format, jobs[i].name(), milliss[i], ratios[i]);
}
private static String keywordValue(String[] args, String keyword) {
for (String arg : args)
if (arg.startsWith(keyword))
return arg.substring(keyword.length() + 1);
return null;
}
private static int intArg(String[] args, String keyword, int defaultValue) {
String val = keywordValue(args, keyword);
return val == null ? defaultValue : Integer.parseInt(val);
}
private static Pattern patternArg(String[] args, String keyword) {
String val = keywordValue(args, keyword);
return val == null ? null : Pattern.compile(val);
}
private static Job[] filter(Pattern filter, Job[] jobs) {
return (filter == null) ? jobs
: Arrays.stream(jobs)
.filter(job -> filter.matcher(job.name()).find())
.collect(toList())
.toArray(new Job[0]);
}
private static void deoptimize(ArrayList<Integer> list) {
for (Integer x : list)
if (x == null)
throw new Error();
}
/**
* Usage: [iterations=N] [size=N] [filter=REGEXP]
*/
public static void main(String[] args) throws Throwable {
final int iterations = intArg(args, "iterations", 30000);
final int size = intArg(args, "size", 1000);
final Pattern filter = patternArg(args, "filter");
final ArrayList<Integer> list = new ArrayList<>();
final Random rnd = new Random();
for (int i = 0; i < size; i++)
list.add(rnd.nextInt());
final Job[] jobs = {
new Job("get") { void work() {
for (int i = 0; i < iterations; i++) {
for (int k = 0; k < size; k++)
if (list.get(k) == 42)
throw new Error();
}
deoptimize(list);}},
new Job("set") { void work() {
Integer[] xs = list.toArray(new Integer[size]);
for (int i = 0; i < iterations; i++) {
for (int k = 0; k < size; k++)
list.set(k, xs[k]);
}
deoptimize(list);}},
new Job("get/set") { void work() {
for (int i = 0; i < iterations; i++) {
for (int k = 0; k < size; k++)
list.set(k, list.get(size - k - 1));
}
deoptimize(list);}},
new Job("add/remove at end") { void work() {
Integer x = rnd.nextInt();
for (int i = 0; i < iterations; i++) {
for (int k = 0; k < size - 1; k++) {
list.add(size, x);
list.remove(size);
}
}
deoptimize(list);}},
new Job("subList get") { void work() {
List<Integer> sublist = list.subList(0, list.size());
for (int i = 0; i < iterations; i++) {
for (int k = 0; k < size; k++)
if (sublist.get(k) == 42)
throw new Error();
}
deoptimize(list);}},
new Job("subList set") { void work() {
List<Integer> sublist = list.subList(0, list.size());
Integer[] xs = sublist.toArray(new Integer[size]);
for (int i = 0; i < iterations; i++) {
for (int k = 0; k < size; k++)
sublist.set(k, xs[k]);
}
deoptimize(list);}},
new Job("subList get/set") { void work() {
List<Integer> sublist = list.subList(0, list.size());
for (int i = 0; i < iterations; i++) {
for (int k = 0; k < size; k++)
sublist.set(k, sublist.get(size - k - 1));
}
deoptimize(list);}},
new Job("subList add/remove at end") { void work() {
List<Integer> sublist = list.subList(0, list.size());
Integer x = rnd.nextInt();
for (int i = 0; i < iterations; i++) {
for (int k = 0; k < size - 1; k++) {
sublist.add(size, x);
sublist.remove(size);
}
}
deoptimize(list);}}
};
time(filter(filter, jobs));
}
}

View file

@ -0,0 +1,59 @@
/*
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.util.ArrayList;
import java.util.Collections;
import java.util.ConcurrentModificationException;
import java.util.List;
/**
* @test
* @bug 8340572
* @summary ConcurrentModificationException when sorting ArrayList sublists
*/
public class SortingModCount {
public static void main(String[] args) {
testSortingSubListsDoesNotIncrementModCount();
testSortingListDoesIncrementModCount();
}
private static void testSortingSubListsDoesNotIncrementModCount() {
List<Integer> l = new ArrayList<>(List.of(1, 2, 3, 4));
var a = l.subList(0, 2);
var b = l.subList(2, 4);
Collections.sort(a);
Collections.sort(b);
}
private static void testSortingListDoesIncrementModCount() {
List<Integer> l = new ArrayList<>(List.of(1, 2, 3, 4));
var b = l.subList(2, 4);
Collections.sort(l);
try {
Collections.sort(b);
throw new Error("expected ConcurrentModificationException not thrown");
} catch (ConcurrentModificationException expected) {
}
}
}

View file

@ -0,0 +1,68 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @bug 8234423
* @summary Modifying ArrayList.subList().subList() resets modCount of subList
*/
import java.util.ArrayList;
import java.util.ConcurrentModificationException;
public class SubListModCount {
public static void main(String[] args) {
int failures = 0;
var root = new ArrayList<Integer>();
var subList = root.subList(0, 0);
root.add(42);
try {
subList.size();
failures++;
System.out.println("Accessing subList");
} catch (ConcurrentModificationException expected) {
}
var subSubList = subList.subList(0, 0);
try {
subSubList.size();
failures++;
System.out.println("Accessing subList.subList");
} catch (ConcurrentModificationException expected) {
}
try {
subSubList.add(42);
failures++;
System.out.println("Modifying subList.subList");
} catch (ConcurrentModificationException expected) {
}
try {
subList.size();
failures++;
System.out.println("Accessing subList again");
} catch (ConcurrentModificationException expected) {
}
if (failures > 0) {
throw new AssertionError(failures + " tests failed");
}
}
}

View file

@ -0,0 +1,506 @@
/*
* Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 4906359 6239296
* @summary Basic test for content-based array object methods
* @author Josh Bloch, Martin Buchholz
* @key randomness
*/
import java.util.*;
import java.io.*;
public class ArrayObjectMethods {
int[] sizes = {0, 10, 100, 200, 1000};
void test(String[] args) throws Throwable {
equal(Arrays.deepToString(null), "null");
equal(Arrays.deepToString(new Object[]{}), "[]");
equal(Arrays.deepToString(new Object[]{null}), "[null]");
equal(Arrays.deepToString(new Object[]{null, 1}), "[null, 1]");
equal(Arrays.deepToString(new Object[]{1, null}), "[1, null]");
equal(Arrays.deepToString(new Object[]{new Object[]{}, null}), "[[], null]");
{
Object[] a = {1, null};
a[1] = a;
equal(Arrays.deepToString(a), "[1, [...]]");
a[0] = a;
equal(Arrays.deepToString(a), "[[...], [...]]");
a[0] = a[1] = new Object[]{1, null, a};
equal(Arrays.deepToString(a), "[[1, null, [...]], [1, null, [...]]]");
}
for (int size : sizes) {
{
long[] a = Rnd.longArray(size);
equal(Arrays.toString(a), PrimitiveArrays.asList(a).toString());
equal(Arrays.hashCode(a), PrimitiveArrays.asList(a).hashCode());
}
{
int[] a = Rnd.intArray(size);
equal(Arrays.toString(a), PrimitiveArrays.asList(a).toString());
equal(Arrays.hashCode(a), PrimitiveArrays.asList(a).hashCode());
}
{
short[] a = Rnd.shortArray(size);
equal(Arrays.toString(a), PrimitiveArrays.asList(a).toString());
equal(Arrays.hashCode(a), PrimitiveArrays.asList(a).hashCode());
}
{
char[] a = Rnd.charArray(size);
equal(Arrays.toString(a), PrimitiveArrays.asList(a).toString());
equal(Arrays.hashCode(a), PrimitiveArrays.asList(a).hashCode());
}
{
byte[] a = Rnd.byteArray(size);
equal(Arrays.toString(a), PrimitiveArrays.asList(a).toString());
equal(Arrays.hashCode(a), PrimitiveArrays.asList(a).hashCode());
}
{
boolean[] a = Rnd.booleanArray(size);
equal(Arrays.toString(a), PrimitiveArrays.asList(a).toString());
equal(Arrays.hashCode(a), PrimitiveArrays.asList(a).hashCode());
}
{
double[] a = Rnd.doubleArray(size);
equal(Arrays.toString(a), PrimitiveArrays.asList(a).toString());
equal(Arrays.hashCode(a), PrimitiveArrays.asList(a).hashCode());
}
{
float[] a = Rnd.floatArray(size);
equal(Arrays.toString(a), PrimitiveArrays.asList(a).toString());
equal(Arrays.hashCode(a), PrimitiveArrays.asList(a).hashCode());
}
{
Object[] a = Rnd.flatObjectArray(size);
equal(Arrays.toString(a), Arrays.asList(a).toString());
equal(Arrays.deepToString(a), Arrays.asList(a).toString());
equal(Arrays.hashCode(a), Arrays.asList(a).hashCode());
}
if (size <= 200) {
Object[] a = Rnd.nestedObjectArray(size);
List aList = deepToList(a);
equal(Arrays.toString(a), Arrays.asList(a).toString());
equal(Arrays.deepToString(a), aList.toString());
equal(Arrays.deepHashCode(a), aList.hashCode());
equal(Arrays.hashCode(a), Arrays.asList(a).hashCode());
Object[] deepCopy = (Object[]) deepCopy(a);
check(Arrays.deepEquals(a, deepCopy));
check(Arrays.deepEquals(deepCopy, a));
// Make deepCopy != a
if (size == 0)
deepCopy = new Object[] {"foo"};
else if (deepCopy[deepCopy.length - 1] == null)
deepCopy[deepCopy.length - 1] = "baz";
else
deepCopy[deepCopy.length - 1] = null;
check(! Arrays.deepEquals(a, deepCopy));
check(! Arrays.deepEquals(deepCopy, a));
}
}
}
// Utility method to turn an array into a list "deeply," turning
// all primitives into objects
List<Object> deepToList(Object[] a) {
List<Object> result = new ArrayList<Object>();
for (Object e : a) {
if (e instanceof byte[])
result.add(PrimitiveArrays.asList((byte[])e));
else if (e instanceof short[])
result.add(PrimitiveArrays.asList((short[])e));
else if (e instanceof int[])
result.add(PrimitiveArrays.asList((int[])e));
else if (e instanceof long[])
result.add(PrimitiveArrays.asList((long[])e));
else if (e instanceof char[])
result.add(PrimitiveArrays.asList((char[])e));
else if (e instanceof double[])
result.add(PrimitiveArrays.asList((double[])e));
else if (e instanceof float[])
result.add(PrimitiveArrays.asList((float[])e));
else if (e instanceof boolean[])
result.add(PrimitiveArrays.asList((boolean[])e));
else if (e instanceof Object[])
result.add(deepToList((Object[])e));
else
result.add(e);
}
return result;
}
// Utility method to do a deep copy of an object *very slowly* using
// serialization/deserialization
Object deepCopy(Object oldObj) {
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(oldObj);
oos.flush();
ByteArrayInputStream bin = new ByteArrayInputStream(
bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bin);
return ois.readObject();
} catch(Exception e) {
throw new IllegalArgumentException(e);
}
}
//--------------------- Infrastructure ---------------------------
volatile int passed = 0, failed = 0;
void pass() {passed++;}
void fail() {failed++; Thread.dumpStack();}
void fail(String msg) {System.err.println(msg); fail();}
void unexpected(Throwable t) {failed++; t.printStackTrace();}
void check(boolean cond) {if (cond) pass(); else fail();}
void equal(Object x, Object y) {
if (x == null ? y == null : x.equals(y)) pass();
else fail(x + " not equal to " + y);}
public static void main(String[] args) throws Throwable {
new ArrayObjectMethods().instanceMain(args);}
void instanceMain(String[] args) throws Throwable {
try {test(args);} catch (Throwable t) {unexpected(t);}
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
if (failed > 0) throw new AssertionError("Some tests failed");}
}
/**
* Methods to generate "interesting" random primitives and primitive
* arrays. Unlike Random.nextXxx, these methods return small values
* and boundary values (e.g., 0, -1, NaN) with greater than normal
* likelihood.
*/
class Rnd {
private static Random rnd = new Random();
public static long nextLong() {
switch(rnd.nextInt(10)) {
case 0: return 0;
case 1: return Long.MIN_VALUE;
case 2: return Long.MAX_VALUE;
case 3: case 4: case 5:
return (long) (rnd.nextInt(20) - 10);
default: return rnd.nextLong();
}
}
public static int nextInt() {
switch(rnd.nextInt(10)) {
case 0: return 0;
case 1: return Integer.MIN_VALUE;
case 2: return Integer.MAX_VALUE;
case 3: case 4: case 5:
return rnd.nextInt(20) - 10;
default: return rnd.nextInt();
}
}
public static short nextShort() {
switch(rnd.nextInt(10)) {
case 0: return 0;
case 1: return Short.MIN_VALUE;
case 2: return Short.MAX_VALUE;
case 3: case 4: case 5:
return (short) (rnd.nextInt(20) - 10);
default: return (short) rnd.nextInt();
}
}
public static char nextChar() {
switch(rnd.nextInt(10)) {
case 0: return 0;
case 1: return Character.MIN_VALUE;
case 2: return Character.MAX_VALUE;
case 3: case 4: case 5:
return (char) (rnd.nextInt(20) - 10);
default: return (char) rnd.nextInt();
}
}
public static byte nextByte() {
switch(rnd.nextInt(10)) {
case 0: return 0;
case 1: return Byte.MIN_VALUE;
case 2: return Byte.MAX_VALUE;
case 3: case 4: case 5:
return (byte) (rnd.nextInt(20) - 10);
default: return (byte) rnd.nextInt();
}
}
public static boolean nextBoolean() {
return rnd.nextBoolean();
}
public static double nextDouble() {
switch(rnd.nextInt(20)) {
case 0: return 0;
case 1: return -0.0;
case 2: return Double.MIN_VALUE;
case 3: return Double.MAX_VALUE;
case 4: return Double.NaN;
case 5: return Double.NEGATIVE_INFINITY;
case 6: return Double.POSITIVE_INFINITY;
case 7: case 8: case 9:
return (rnd.nextInt(20) - 10);
default: return rnd.nextDouble();
}
}
public static float nextFloat() {
switch(rnd.nextInt(20)) {
case 0: return 0;
case 1: return -0.0f;
case 2: return Float.MIN_VALUE;
case 3: return Float.MAX_VALUE;
case 4: return Float.NaN;
case 5: return Float.NEGATIVE_INFINITY;
case 6: return Float.POSITIVE_INFINITY;
case 7: case 8: case 9:
return (rnd.nextInt(20) - 10);
default: return rnd.nextFloat();
}
}
public static Object nextObject() {
switch(rnd.nextInt(10)) {
case 0: return null;
case 1: return "foo";
case 2: case 3: case 4:
return Double.valueOf(nextDouble());
default: return Integer.valueOf(nextInt());
}
}
public static long[] longArray(int length) {
long[] result = new long[length];
for (int i = 0; i < length; i++)
result[i] = Rnd.nextLong();
return result;
}
public static int[] intArray(int length) {
int[] result = new int[length];
for (int i = 0; i < length; i++)
result[i] = Rnd.nextInt();
return result;
}
public static short[] shortArray(int length) {
short[] result = new short[length];
for (int i = 0; i < length; i++)
result[i] = Rnd.nextShort();
return result;
}
public static char[] charArray(int length) {
char[] result = new char[length];
for (int i = 0; i < length; i++)
result[i] = Rnd.nextChar();
return result;
}
public static byte[] byteArray(int length) {
byte[] result = new byte[length];
for (int i = 0; i < length; i++)
result[i] = Rnd.nextByte();
return result;
}
public static boolean[] booleanArray(int length) {
boolean[] result = new boolean[length];
for (int i = 0; i < length; i++)
result[i] = Rnd.nextBoolean();
return result;
}
public static double[] doubleArray(int length) {
double[] result = new double[length];
for (int i = 0; i < length; i++)
result[i] = Rnd.nextDouble();
return result;
}
public static float[] floatArray(int length) {
float[] result = new float[length];
for (int i = 0; i < length; i++)
result[i] = Rnd.nextFloat();
return result;
}
public static Object[] flatObjectArray(int length) {
Object[] result = new Object[length];
for (int i = 0; i < length; i++)
result[i] = Rnd.nextObject();
return result;
}
// Calling this for length >> 100 is likely to run out of memory! It
// should be perhaps be tuned to allow for longer arrays
public static Object[] nestedObjectArray(int length) {
Object[] result = new Object[length];
for (int i = 0; i < length; i++) {
switch(rnd.nextInt(16)) {
case 0: result[i] = nestedObjectArray(length/2);
break;
case 1: result[i] = longArray(length/2);
break;
case 2: result[i] = intArray(length/2);
break;
case 3: result[i] = shortArray(length/2);
break;
case 4: result[i] = charArray(length/2);
break;
case 5: result[i] = byteArray(length/2);
break;
case 6: result[i] = floatArray(length/2);
break;
case 7: result[i] = doubleArray(length/2);
break;
case 8: result[i] = longArray(length/2);
break;
default: result[i] = Rnd.nextObject();
}
}
return result;
}
}
/**
* Primitive arrays viewed as lists. Inefficient but cool.
* This utility should be generally useful in writing regression/unit/basic
* tests.
*/
class PrimitiveArrays {
public static List<Long> asList(final long[] a) {
return new AbstractList<Long>() {
public Long get(int i) { return a[i]; }
public int size() { return a.length; }
public Long set(int i, Long e) {
long oldVal = a[i];
a[i] = e;
return oldVal;
}
};
}
public static List<Integer> asList(final int[] a) {
return new AbstractList<Integer>() {
public Integer get(int i) { return a[i]; }
public int size() { return a.length; }
public Integer set(int i, Integer e) {
int oldVal = a[i];
a[i] = e;
return oldVal;
}
};
}
public static List<Short> asList(final short[] a) {
return new AbstractList<Short>() {
public Short get(int i) { return a[i]; }
public int size() { return a.length; }
public Short set(int i, Short e) {
short oldVal = a[i];
a[i] = e;
return oldVal;
}
};
}
public static List<Character> asList(final char[] a) {
return new AbstractList<Character>() {
public Character get(int i) { return a[i]; }
public int size() { return a.length; }
public Character set(int i, Character e) {
Character oldVal = a[i];
a[i] = e;
return oldVal;
}
};
}
public static List<Byte> asList(final byte[] a) {
return new AbstractList<Byte>() {
public Byte get(int i) { return a[i]; }
public int size() { return a.length; }
public Byte set(int i, Byte e) {
Byte oldVal = a[i];
a[i] = e;
return oldVal;
}
};
}
public static List<Boolean> asList(final boolean[] a) {
return new AbstractList<Boolean>() {
public Boolean get(int i) { return a[i]; }
public int size() { return a.length; }
public Boolean set(int i, Boolean e) {
Boolean oldVal = a[i];
a[i] = e;
return oldVal;
}
};
}
public static List<Double> asList(final double[] a) {
return new AbstractList<Double>() {
public Double get(int i) { return a[i]; }
public int size() { return a.length; }
public Double set(int i, Double e) {
Double oldVal = a[i];
a[i] = e;
return oldVal;
}
};
}
public static List<Float> asList(final float[] a) {
return new AbstractList<Float>() {
public Float get(int i) { return a[i]; }
public int size() { return a.length; }
public Float set(int i, Float e) {
Float oldVal = a[i];
a[i] = e;
return oldVal;
}
};
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,80 @@
/*
* Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8155600
* @summary Tests for Arrays.asList()
* @run junit AsList
*/
import java.util.Arrays;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.stream.IntStream;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import static org.junit.jupiter.api.Assertions.*;
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class AsList {
/*
* Iterator contract test
*/
@ParameterizedTest
@MethodSource("arrays")
public void testIterator(Object[] array) {
Iterator<Object> itr = Arrays.asList(array).iterator();
for (Object o : array) {
assertTrue(itr.hasNext());
assertTrue(itr.hasNext()); // must be idempotent
assertSame(o, itr.next());
assertThrows(UnsupportedOperationException.class, itr::remove);
}
for (int i = 0; i < 3; i++) {
assertFalse(itr.hasNext());
assertThrows(NoSuchElementException.class, itr::next);
}
}
public static Object[][] arrays() {
return new Object[][] {
{ new Object[] { } },
{ new Object[] { 1 } },
{ new Object[] { null } },
{ new Object[] { null, 1 } },
{ new Object[] { 1, null } },
{ new Object[] { null, null } },
{ new Object[] { null, 1, 2 } },
{ new Object[] { 1, null, 2 } },
{ new Object[] { 1, 2, null } },
{ new Object[] { null, null, null } },
{ new Object[] { 1, 2, 3, null, 4 } },
{ new Object[] { "a", "a", "a", "a" } },
{ IntStream.range(0, 100).boxed().toArray() }
};
}
}

View file

@ -0,0 +1,115 @@
/*
* Copyright (c) 2006, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 5045582
* @summary arrays larger than 1<<30
* @author Martin Buchholz
*/
// A proper regression test for 5045582 requires too much memory.
// If you have a really big machine, run like this:
// java -Xms25g -Xmx25g Big 30
import java.util.*;
public class Big {
private static void realMain(String[] args) throws Throwable {
final int shift = intArg(args, 0, 10); // "30" is real test
final int tasks = intArg(args, 1, ~0); // all tasks
final int n = (1<<shift) + 47;
// To test byte arrays larger than 1<<30, you need 1600MB. Run like:
// java -Xms1600m -Xmx1600m Big 30 1
if ((tasks & 0x1) != 0) {
System.out.println("byte[]");
System.gc();
byte[] a = new byte[n];
a[0] = (byte) -44;
a[1] = (byte) -43;
a[n-2] = (byte) +43;
a[n-1] = (byte) +44;
for (int i : new int[] { 0, 1, n-2, n-1 })
try { equal(i, Arrays.binarySearch(a, a[i])); }
catch (Throwable t) { unexpected(t); }
for (int i : new int[] { n-2, n-1 })
try { equal(i, Arrays.binarySearch(a, n-5, n, a[i])); }
catch (Throwable t) { unexpected(t); }
a[n-19] = (byte) 45;
try { Arrays.sort(a, n-29, n); }
catch (Throwable t) { unexpected(t); }
equal(a[n-1], (byte) 45);
equal(a[n-2], (byte) 44);
equal(a[n-3], (byte) 43);
equal(a[n-4], (byte) 0);
}
// To test Object arrays larger than 1<<30, you need 13GB. Run like:
// java -Xms13g -Xmx13g Big 30 2
if ((tasks & 0x2) != 0) {
System.out.println("Integer[]");
System.gc();
Integer[] a = new Integer[n];
Integer ZERO = 0;
Arrays.fill(a, ZERO);
a[0] = -44;
a[1] = -43;
a[n-2] = +43;
a[n-1] = +44;
for (int i : new int[] { 0, 1, n-2, n-1 })
try { equal(i, Arrays.binarySearch(a, a[i])); }
catch (Throwable t) { unexpected(t); }
for (int i : new int[] { n-2, n-1 })
try { equal(i, Arrays.binarySearch(a, n-5, n, a[i])); }
catch (Throwable t) { unexpected(t); }
a[n-19] = 45;
try { Arrays.sort(a, n-29, n); }
catch (Throwable t) { unexpected(t); }
equal(a[n-1], 45);
equal(a[n-2], 44);
equal(a[n-3], 43);
equal(a[n-4], 0);
}
}
//--------------------- Infrastructure ---------------------------
static volatile int passed = 0, failed = 0;
static void pass() {passed++;}
static void fail() {failed++; Thread.dumpStack();}
static void fail(String msg) {System.out.println(msg); fail();}
static void unexpected(Throwable t) {failed++; t.printStackTrace();}
static void check(boolean cond) {if (cond) pass(); else fail();}
static void equal(Object x, Object y) {
if (x == null ? y == null : x.equals(y)) pass();
else fail(x + " not equal to " + y);}
public static void main(String[] args) throws Throwable {
try {realMain(args);} catch (Throwable t) {unexpected(t);}
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
if (failed > 0) throw new AssertionError("Some tests failed");}
static int intArg(String[] args, int i, int defaultValue) {
return args.length > i ? Integer.parseInt(args[i]) : defaultValue;}
}

View file

@ -0,0 +1,425 @@
/*
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 4655503
* @summary Test for array cloning and slicing methods.
* @author John Rose
* @key randomness
*/
import java.util.*;
import java.lang.reflect.*;
public class CopyMethods {
static int muzzle; // if !=0, suppresses ("muzzles") messages
static int maxLen = 40; // maximum length of test arrays
static int shortStepsNear = 4; // interesting span near critical values
static int downShift = 3;
static int testCasesRun = 0;
static long consing = 0;
// very simple tests, mainly to test the framework itself
static void simpleTests() {
int[] a = (int[]) makeArray(3, int.class);
if (muzzle == 0)
System.out.println("int[] a = "+Arrays.toString(a));
check(a.length == 3);
check(a[0] == testValues[0]);
check(a[1] == testValues[1]);
check(a[2] == testValues[2]);
checkArray(a, int.class, 3, 0, 3);
// negative test of testing framework:
for (int bad = -2; bad < a.length; bad++) {
try {
int[] aa = a.clone();
if (bad < 0) aa = new int[4];
else aa[bad] = 0;
++muzzle;
// the following check should fail!
if (bad == -2)
checkArray(new String[3], int.class, 0, 0, a.length);
else
checkArray(aa, int.class, 0, 0, a.length);
throw new Error("Should Not Reach Here");
} catch (RuntimeException ee) {
--muzzle;
if (muzzle == 0)
System.out.println("Expected: "+ee);
}
}
checkArray(Arrays.copyOf(a, 0), int.class, 0, 0, 3);
checkArray(Arrays.copyOf(a, 1), int.class, 1, 0, 3);
checkArray(Arrays.copyOf(a, 2), int.class, 2, 0, 3);
checkArray(Arrays.copyOf(a, 3), int.class, 3, 0, 3);
checkArray(Arrays.copyOf(a, 4), int.class, 4, 0, 3);
// quick test of copyOfRange
int[] ar = Arrays.copyOfRange(a, 1, 3);
check(ar.length == 2);
check(ar[0] == a[1]);
check(ar[1] == a[2]);
checkArray(ar, int.class, 2, 1, 2);
ar = Arrays.copyOfRange(a, 2, 4);
check(ar.length == 2);
check(ar[0] == a[2]);
check(ar[1] == 0);
checkArray(ar, int.class, 2, 2, 1);
ar = Arrays.copyOfRange(a, 3, 5);
check(ar.length == 2);
check(ar[0] == 0);
check(ar[1] == 0);
checkArray(ar, int.class, 2, 3, 0);
byte[] ba = (byte[]) makeArray(3, byte.class);
if (muzzle == 0)
System.out.println("byte[] ba = "+Arrays.toString(ba));
for (int j = 0; j <= ba.length+2; j++) {
byte[] bb = Arrays.copyOf(ba, j);
if (muzzle == 0)
System.out.println("copyOf(ba,"+j+") = "+
Arrays.toString(bb));
checkArray(bb, byte.class, j, 0, ba.length);
byte[] bbr = Arrays.copyOfRange(ba, 0, j);
check(Arrays.equals(bb, bbr));
}
for (int i = 0; i <= a.length; i++) {
for (int j = i; j <= a.length+2; j++) {
byte[] br = Arrays.copyOfRange(ba, i, j);
if (muzzle == 0)
System.out.println("copyOfRange(ba,"+i+","+j+") = "+
Arrays.toString(br));
checkArray(br, byte.class, j-i, i, ba.length-i);
}
}
String[] sa = (String[]) makeArray(3, String.class);
if (muzzle == 0)
System.out.println("String[] sa = "+Arrays.toString(sa));
check(sa[0].equals(Integer.toHexString(testValues[0])));
check(sa[1].equals(Integer.toHexString(testValues[1])));
check(sa[2].equals(Integer.toHexString(testValues[2])));
checkArray(sa, String.class, sa.length, 0, sa.length);
String[] sa4 = Arrays.copyOf(sa, sa.length+1);
check(sa4[0] == sa[0]);
check(sa4[1] == sa[1]);
check(sa4[2] == sa[2]);
check(sa4[sa.length] == null);
checkArray(sa4, String.class, sa4.length, 0, sa.length);
String[] sr4 = Arrays.copyOfRange(sa, 1, 5);
check(sr4[0] == sa[1]);
check(sr4[1] == sa[2]);
check(sr4[2] == null);
check(sr4[3] == null);
checkArray(sr4, String.class, 4, 1, sa.length-1);
if (muzzle == 0)
System.out.println("simpleTests done");
}
// the framework: a fixed series of test values
static final int[] testValues;
static {
testValues = new int[1000];
Random r = new Random();
for (int i = 0; i < testValues.length; i++) {
testValues[i] = r.nextInt();
}
}
/** Return a canonical test value of a desired index and type.
* The original test values are random ints. Derive other test
* values as follows:
* <pre>
* int tv = testValues[i]
* (C)tv C is byte, short, char, long, float, double
* (tv&1)!=0 C is boolean
* (Integer)tv C is Object and tv%16 != 0
* null C is Object and tv%16 == 0
* Integer.toHexString(tv) C is String and tv != 0
* null C is String and tv == 0
* </pre>
* are derived by ordinary Java coercions, except that boolean
* samples the LSB of the int value, and String is the hex numeral.
*
* (Also, the 0th String is null, and the 0th Object mod 16 is null,
* regardless of the original int test value.)
*/
static Object testValue(int i, Class<?> c) {
int tv = testValues[i % testValues.length];
if (i >= testValues.length) tv ^= i;
// Turn the canonical int to a float, boolean, String, whatever:
return invoke(coercers.get(c), tv);
}
/** Build a test array of the given length,
* packed with a subsequence of the test values.
* The first element of the array is always testValue(0).
*/
static Object makeArray(int len, Class<?> c) {
Object a = Array.newInstance(c, len);
for (int i = 0; i < len; i++) {
Array.set(a, i, testValue(i, c));
}
return a;
}
/** Check that the given array has the required length.
* Check also that it is packed, up to firstNull, with
* a particular subsequence of the canonical test values.
* The subsequence must begin with a[0] == testValue(offset).
* At a[firstNull] and beyond, the array must contain null values.
*/
static void checkArray(Object a, Class<?> c, int requiredLen, int offset, int firstNull) {
check(c == a.getClass().getComponentType());
Object nullValue = nullValues.get(c);
// Note: asserts in here are not part of the test program.
// They verify the integrity of the test method itself.
assert(nullValues.containsKey(c));
int misses = 0;
int firstMiss = -1;
// Check required length first.
int length = Array.getLength(a);
if (length != requiredLen && requiredLen != -1) {
if (muzzle == 0)
System.out.println("*** a.length = "+length+" != "+requiredLen);
++misses;
}
for (int i = 0; i < length; i++) {
Object tv = (i >= firstNull) ? nullValue : testValue(i+offset, c);
Object ai = Array.get(a, i);
if (!eq(ai, tv)) {
if (muzzle == 0)
System.out.println("*** a["+i+"] = "+ai+" != "+tv);
if (misses == 0) firstMiss = i;
if (++misses > 10) break;
}
}
if (misses != 0) {
Method toString = toStrings.get(c);
if (toString == null) toString = toStrings.get(Object.class);
throw new RuntimeException("checkArray failed at "+firstMiss
+" "+c+"[]"
+" : "+invoke(toString, a));
}
}
// Typical comparison helper. Why isn't this a method somewhere.
static boolean eq(Object x, Object y) {
return x == null? y == null: x.equals(y);
}
// Exception-ignoring invoke function.
static Object invoke(Method m, Object... args) {
Exception ex;
try {
return m.invoke(null, args);
} catch (InvocationTargetException ee) {
ex = ee;
} catch (IllegalAccessException ee) {
ex = ee;
} catch (IllegalArgumentException ee) {
ex = ee;
}
ArrayList<Object> call = new ArrayList<Object>();
call.add(m); Collections.addAll(call, args);
throw new RuntimeException(call+" : "+ex);
}
// version of assert() that runs unconditionally
static void check(boolean z) {
if (!z) throw new RuntimeException("check failed");
}
/** Run about 10**5 distinct parameter combinations
* on copyOf and copyOfRange. Use all primitive types,
* and String and Object.
* Try to all critical values, looking for fencepost errors.
*/
static void fullTests(int maxLen, Class<?> c) {
Method cloner = cloners.get(c);
assert(cloner != null) : c;
Method cloneRanger = cloneRangers.get(c);
// Note: asserts in here are not part of the test program.
// They verify the integrity of the test method itself.
assert(cloneRanger != null) : c;
for (int src = 0; src <= maxLen; src = inc(src, 0, maxLen)) {
Object a = makeArray(src, c);
for (int x : new ArrayList<Integer>()) {}
for (int j = 0; j <= maxLen; j = inc(j, src, maxLen)) {
// b = Arrays.copyOf(a, j);
Object b = invoke(cloner, a, j);
checkArray(b, c, j, 0, src);
testCasesRun++;
consing += j;
int maxI = Math.min(src, j);
for (int i = 0; i <= maxI; i = inc(i, src, maxI)) {
// r = Arrays.copyOfRange(a, i, j);
Object r = invoke(cloneRanger, a, i, j);
checkArray(r, c, j-i, i, src-i);
//System.out.println("case c="+c+" src="+src+" i="+i+" j="+j);
testCasesRun++;
consing += j-i;
}
}
}
}
// Increment x by at least one. Increment by a little more unless
// it is near a critical value, either zero, crit1, or crit2.
static int inc(int x, int crit1, int crit2) {
int D = shortStepsNear;
if (crit1 > crit2) { int t = crit1; crit1 = crit2; crit2 = t; }
assert(crit1 <= crit2);
assert(x <= crit2); // next1 or next2 must be the limit value
x += 1;
if (x > D) {
if (x < crit1-D) {
x += (x << 1) >> downShift; // giant step toward crit1-D
if (x > crit1-D) x = crit1-D;
} else if (x >= crit1+D && x < crit2-D) {
x += (x << 1) >> downShift; // giant step toward crit2-D
if (x > crit2-D) x = crit2-D;
}
}
return x;
}
public static void main(String[] av) {
boolean verbose = (av.length != 0);
muzzle = (verbose? 0: 1);
if (muzzle == 0)
System.out.println("test values: "+Arrays.toString(Arrays.copyOf(testValues, 5))+"...");
simpleTests();
muzzle = 0; // turn on print statements (affects failures only)
fullTests();
if (verbose)
System.out.println("ran "+testCasesRun+" tests, avg len="
+(float)consing/testCasesRun);
// test much larger arrays, more sparsely
maxLen = 500;
shortStepsNear = 2;
downShift = 0;
testCasesRun = 0;
consing = 0;
fullTests();
if (verbose)
System.out.println("ran "+testCasesRun+" tests, avg len="
+(float)consing/testCasesRun);
}
static void fullTests() {
for (Class<?> c : allTypes) {
fullTests(maxLen, c);
}
}
// We must run all the our tests on each of 8 distinct primitive types,
// and two reference types (Object, String) for good measure.
// This would be a pain to write out by hand, statically typed.
// So, use reflection. Following are the tables of methods we use.
// (The initial simple tests exercise enough of the static typing
// features of the API to ensure that they compile as advertised.)
static Object coerceToObject(int x) { return (x & 0xF) == 0? null: new Integer(x); }
static String coerceToString(int x) { return (x == 0)? null: Integer.toHexString(x); }
static Integer coerceToInteger(int x) { return (x == 0)? null: x; }
static byte coerceToByte(int x) { return (byte)x; }
static short coerceToShort(int x) { return (short)x; }
static int coerceToInt(int x) { return x; }
static long coerceToLong(int x) { return x; }
static char coerceToChar(int x) { return (char)x; }
static float coerceToFloat(int x) { return x; }
static double coerceToDouble(int x) { return x; }
static boolean coerceToBoolean(int x) { return (x&1) != 0; }
static Integer[] copyOfIntegerArray(Object[] a, int len) {
// This guy exercises the API based on a type-token.
// Note the static typing.
return Arrays.copyOf(a, len, Integer[].class);
}
static Integer[] copyOfIntegerArrayRange(Object[] a, int m, int n) {
// This guy exercises the API based on a type-token.
// Note the static typing.
return Arrays.copyOfRange(a, m, n, Integer[].class);
}
static final List<Class<?>> allTypes
= Arrays.asList(new Class<?>[]
{ Object.class, String.class, Integer.class,
byte.class, short.class, int.class, long.class,
char.class, float.class, double.class,
boolean.class
});
static final HashMap<Class<?>,Method> coercers;
static final HashMap<Class<?>,Method> cloners;
static final HashMap<Class<?>,Method> cloneRangers;
static final HashMap<Class<?>,Method> toStrings;
static final HashMap<Class<?>,Object> nullValues;
static {
coercers = new HashMap<Class<?>,Method>();
Method[] testMethods = CopyMethods.class.getDeclaredMethods();
Method cia = null, ciar = null;
for (int i = 0; i < testMethods.length; i++) {
Method m = testMethods[i];
if (!Modifier.isStatic(m.getModifiers())) continue;
Class<?> rt = m.getReturnType();
if (m.getName().startsWith("coerceTo") && allTypes.contains(rt))
coercers.put(m.getReturnType(), m);
if (m.getName().equals("copyOfIntegerArray"))
cia = m;
if (m.getName().equals("copyOfIntegerArrayRange"))
ciar = m;
}
Method[] arrayMethods = Arrays.class.getDeclaredMethods();
cloners = new HashMap<Class<?>,Method>();
cloneRangers = new HashMap<Class<?>,Method>();
toStrings = new HashMap<Class<?>,Method>();
for (int i = 0; i < arrayMethods.length; i++) {
Method m = arrayMethods[i];
if (!Modifier.isStatic(m.getModifiers())) continue;
Class<?> rt = m.getReturnType();
if (m.getName().equals("copyOf")
&& m.getParameterTypes().length == 2)
cloners.put(rt.getComponentType(), m);
if (m.getName().equals("copyOfRange")
&& m.getParameterTypes().length == 3)
cloneRangers.put(rt.getComponentType(), m);
if (m.getName().equals("toString")) {
Class<?> pt = m.getParameterTypes()[0];
toStrings.put(pt.getComponentType(), m);
}
}
cloners.put(String.class, cloners.get(Object.class));
cloneRangers.put(String.class, cloneRangers.get(Object.class));
assert(cia != null);
cloners.put(Integer.class, cia);
assert(ciar != null);
cloneRangers.put(Integer.class, ciar);
nullValues = new HashMap<Class<?>,Object>();
for (Class<?> c : allTypes) {
nullValues.put(c, invoke(coercers.get(c), 0));
}
}
}

View file

@ -0,0 +1,149 @@
/*
* Copyright (c) 2002, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 4726380 8037097
* @summary Check that different sorts give equivalent results.
* @key randomness
* @run junit Correct
*/
import java.util.*;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class Correct {
static final Random rnd = new Random();
static final int ITERATIONS = 1000;
static final int TEST_SIZE = 1000;
@Test
public void testDefaultSort() {
for (int i=0; i<ITERATIONS; i++) {
int size = rnd.nextInt(TEST_SIZE) + 1;
Integer[] array1 = getIntegerArray(size);
Integer[] array2 = Arrays.copyOf(array1, array1.length);
Arrays.sort(array1, array1.length/3, array1.length/2);
stupidSort(array2, array2.length/3, array2.length/2);
Assertions.assertArrayEquals(array2, array1, "Arrays did not match. size=" + size);
}
}
@ParameterizedTest
@MethodSource("comparators")
public void testComparatorSort(Comparator<Integer> comparator) {
for (int i=0; i<ITERATIONS; i++) {
int size = rnd.nextInt(TEST_SIZE) + 1;
Integer[] array1 = getIntegerArray(size);
Integer[] array2 = Arrays.copyOf(array1, array1.length);
Arrays.sort(array1, array1.length/3, array1.length/2, comparator);
stupidSort(array2, array2.length/3, array2.length/2, comparator);
Assertions.assertArrayEquals(array2, array1, "Arrays did not match. size=" + size);
}
}
static Integer[] getIntegerArray(int size) {
Integer[] blah = new Integer[size];
for (int x=0; x<size; x++) {
blah[x] = new Integer(rnd.nextInt());
}
return blah;
}
static void stupidSort(Integer[] a1, int from, int to) {
if (from > to - 1 )
return;
for (int x=from; x<to; x++) {
Integer lowest = a1[x];
int lowestIndex = x;
for (int y=x + 1; y<to; y++) {
if (((Comparable)a1[y]).compareTo((Comparable)lowest) < 0) {
lowest = a1[y];
lowestIndex = y;
}
}
if (lowestIndex != x) {
swap(a1, x, lowestIndex);
}
}
}
static void stupidSort(Integer[] a1, int from, int to, Comparator<Integer> comparator) {
if (from > to - 1 )
return;
for (int x=from; x<to; x++) {
Integer lowest = a1[x];
int lowestIndex = x;
for (int y=x + 1; y<to; y++) {
if (comparator.compare(a1[y], lowest) < 0) {
lowest = a1[y];
lowestIndex = y;
}
}
if (lowestIndex != x) {
swap(a1, x, lowestIndex);
}
}
}
static <T> void swap(T[] x, int a, int b) {
T t = x[a];
x[a] = x[b];
x[b] = t;
}
public static Iterator<Object[]> comparators() {
Object[][] comparators = new Object[][] {
new Object[] { Comparator.naturalOrder() },
new Object[] { Comparator.<Integer>naturalOrder().reversed() },
new Object[] { STANDARD_ORDER },
new Object[] { STANDARD_ORDER.reversed() },
new Object[] { REVERSE_ORDER },
new Object[] { REVERSE_ORDER.reversed() },
new Object[] { Comparator.comparingInt(Integer::intValue) }
};
return Arrays.asList(comparators).iterator();
}
private static final Comparator<Integer> STANDARD_ORDER = new Comparator<Integer>() {
public int compare(Integer o1, Integer o2) {
return o1.compareTo(o2);
}
};
private static final Comparator<Integer> REVERSE_ORDER = new Comparator<Integer>() {
public int compare(Integer o1, Integer o2) {
return - o1.compareTo(o2);
}
};
}

View file

@ -0,0 +1,74 @@
/*
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 4229892
* @summary Arrays.fill(Object[], ...) should throw ArrayStoreException
* @author Martin Buchholz
*/
import java.io.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
public class Fill {
private static void realMain(String[] args) throws Throwable {
try {
Arrays.fill(new Integer[3], "foo");
fail("Expected ArrayStoreException");
}
catch (ArrayStoreException e) { pass(); }
catch (Throwable t) { unexpected(t); }
try {
Arrays.fill(new Integer[3], 0, 2, "foo");
fail("Expected ArrayStoreException");
}
catch (ArrayStoreException e) { pass(); }
catch (Throwable t) { unexpected(t); }
try {
Arrays.fill(new Integer[3], 0, 4, "foo");
fail("Expected ArrayIndexOutOfBoundsException");
}
catch (ArrayIndexOutOfBoundsException e) { pass(); }
catch (Throwable t) { unexpected(t); }
}
//--------------------- Infrastructure ---------------------------
static volatile int passed = 0, failed = 0;
static void pass() {passed++;}
static void fail() {failed++; Thread.dumpStack();}
static void fail(String msg) {System.out.println(msg); fail();}
static void unexpected(Throwable t) {failed++; t.printStackTrace();}
static void check(boolean cond) {if (cond) pass(); else fail();}
static void equal(Object x, Object y) {
if (x == null ? y == null : x.equals(y)) pass();
else fail(x + " not equal to " + y);}
public static void main(String[] args) throws Throwable {
try {realMain(args);} catch (Throwable t) {unexpected(t);}
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
if (failed > 0) throw new AssertionError("Some tests failed");}
}

View file

@ -0,0 +1,123 @@
/*
* Copyright (c) 1998, 2007, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @bug 4143272 6548425
* @summary The natural ordering on Float and Double was not even a partial
* order (i.e., it violated the contract of Comparable.compareTo).
* Now it's a total ordering. Arrays.sort(double[])
* and Arrays.sort(double[]) reflect the new ordering. Also,
* Arrays.equals(double[], double[]) and
* Arrays.equals(float[], float[]) reflect the definition of
* equality used by Float and Double.
*/
import java.util.*;
@SuppressWarnings("unchecked")
public class FloatDoubleOrder {
void test(String[] args) throws Throwable {
double[] unsortedDbl = new double[] {1.0d, 3.7d, Double.NaN, -2.0d,
Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY, 0.0d, -0.0d};
double[] sortedDbl = new double[] {Double.NEGATIVE_INFINITY, -2.0d,
-0.0d, 0.0d, 1.0d, 3.7d, Double.POSITIVE_INFINITY, Double.NaN};
List list = new ArrayList();
for (int i=0; i<unsortedDbl.length; i++)
list.add(new Double(unsortedDbl[i]));
Collections.sort(list);
List sortedList = new ArrayList();
for (int i=0; i<sortedDbl.length; i++)
sortedList.add(new Double(sortedDbl[i]));
check(list.equals(sortedList));
Arrays.sort(unsortedDbl);
check(Arrays.equals(unsortedDbl, sortedDbl));
double negNan = Double.longBitsToDouble(0xfff8000000000000L);
for (int i = 0; i < sortedDbl.length; i++) {
equal(Arrays.binarySearch(sortedDbl, sortedDbl[i]), i);
if (Double.isNaN(sortedDbl[i]))
equal(Arrays.binarySearch(sortedDbl, negNan), i);
}
float[] unsortedFlt = new float[] {1.0f, 3.7f, Float.NaN, -2.0f,
Float.POSITIVE_INFINITY, Float.NEGATIVE_INFINITY, 0.0f, -0.0f};
float[] sortedFlt = new float[] {Float.NEGATIVE_INFINITY, -2.0f,
-0.0f, 0.0f, 1.0f, 3.7f, Float.POSITIVE_INFINITY, Float.NaN};
list.clear();
for (int i=0; i<unsortedFlt.length; i++)
list.add(new Float(unsortedFlt[i]));
Collections.sort(list);
sortedList.clear();
for (int i=0; i<sortedFlt.length; i++)
sortedList.add(new Float(sortedFlt[i]));
check(list.equals(sortedList));
Arrays.sort(unsortedFlt);
check(Arrays.equals(unsortedFlt, sortedFlt));
float negNaN = Float.intBitsToFloat(0xFfc00000);
for (int i = 0; i < sortedDbl.length; i++) {
equal(Arrays.binarySearch(sortedFlt, sortedFlt[i]), i);
if (Float.isNaN(sortedFlt[i]))
equal(Arrays.binarySearch(sortedFlt, negNaN), i);
}
// 6548425: Arrays.sort incorrectly sorts a double array
// containing negative zeros
double[] da = {-0.0d, -0.0d, 0.0d, -0.0d};
Arrays.sort(da, 1, 4);
check(Arrays.equals(da, new double[] {-0.0d, -0.0d, -0.0d, 0.0d}));
float[] fa = {-0.0f, -0.0f, 0.0f, -0.0f};
Arrays.sort(fa, 1, 4);
check(Arrays.equals(fa, new float[] {-0.0f, -0.0f, -0.0f, 0.0f}));
}
//--------------------- Infrastructure ---------------------------
volatile int passed = 0, failed = 0;
void pass() {passed++;}
void fail() {failed++; Thread.dumpStack();}
void fail(String msg) {System.err.println(msg); fail();}
void unexpected(Throwable t) {failed++; t.printStackTrace();}
void check(boolean cond) {if (cond) pass(); else fail();}
void equal(Object x, Object y) {
if (x == null ? y == null : x.equals(y)) pass();
else fail(x + " not equal to " + y);}
public static void main(String[] args) throws Throwable {
new FloatDoubleOrder().instanceMain(args);}
void instanceMain(String[] args) throws Throwable {
try {test(args);} catch (Throwable t) {unexpected(t);}
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
if (failed > 0) throw new AssertionError("Some tests failed");}
}

View file

@ -0,0 +1,174 @@
/*
* Copyright (c) 2022, 2024, Oracle, Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @summary Basic array hashCode functionality
* @run main/othervm --add-exports java.base/jdk.internal.util=ALL-UNNAMED
* --add-opens java.base/jdk.internal.util=ALL-UNNAMED -Xcomp -Xbatch HashCode
*/
import java.lang.reflect.Method;
import java.util.Arrays;
public class HashCode {
private static String[] tests = { "", " ", "a", "abcdefg",
"It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only. -- Charles Dickens, Tale of Two Cities",
"C'était le meilleur des temps, c'était le pire des temps, c'était l'âge de la sagesse, c'était l'âge de la folie, c'était l'époque de la croyance, c'était l'époque de l'incrédulité, c'était la saison de la Lumière, c'était C'était la saison des Ténèbres, c'était le printemps de l'espoir, c'était l'hiver du désespoir, nous avions tout devant nous, nous n'avions rien devant nous, nous allions tous directement au Ciel, nous allions tous directement dans l'autre sens bref, la période ressemblait tellement à la période actuelle, que certaines de ses autorités les plus bruyantes ont insisté pour qu'elle soit reçue, pour le bien ou pour le mal, au degré superlatif de la comparaison seulement. -- Charles Dickens, Tale of Two Cities (in French)",
"禅道修行を志した雲水は、一般に参禅のしきたりを踏んだうえで一人の師につき、各地にある専門道場と呼ばれる養成寺院に入門し、与えられた公案に取り組むことになる。公案は、師家(老師)から雲水が悟りの境地へと進んで行くために手助けとして課す問題であり、悟りの境地に達していない人には容易に理解し難い難問だが、屁理屈や詭弁が述べられているわけではなく、頓知や謎かけとも異なる。"
};
byte[][] zeroes = new byte[64][];
private static byte[][] testBytes = new byte[tests.length][];
private static short[][] testShorts = new short[tests.length][];
private static char[][] testChars = new char[tests.length][];
private static int[][] testInts = new int[tests.length][];
private static int[] expected = { 1, 63, 128, 536518979, -1174896354, -1357593156, 428276276};
private static int[] expectedUnsigned = { 1, 63, 128, 536518979, -1174896354, 584369596, -2025326028};
public static void main(String[] args) throws Exception {
// Deep introspection into range-based hash functions
Class<?> arraysSupport = Class.forName("jdk.internal.util.ArraysSupport");
Method vectorizedHashCode = arraysSupport.getDeclaredMethod("vectorizedHashCode", Object.class, int.class, int.class, int.class, int.class);
vectorizedHashCode.setAccessible(true);
for (int i = 0; i < tests.length; i++) {
testBytes[i] = tests[i].getBytes("UTF-8");
int len = testBytes[i].length;
testChars[i] = new char[len];
testShorts[i] = new short[len];
testInts[i] = new int[len];
for (int j = 0; j < len; j++) {
testChars[i][j] = (char) testBytes[i][j];
testShorts[i][j] = testBytes[i][j];
testInts[i][j] = testBytes[i][j];
}
}
boolean failed = false;
try {
int zeroResult = 1;
for (int i = 0; i < 64; i++) {
byte[] zeroes = new byte[i];
byte[] extraZeroes = new byte[i + 47];
for (int j = 0; j < 10_000; j++) {
int hashCode = Arrays.hashCode(zeroes);
if (hashCode != zeroResult) {
throw new RuntimeException("byte[] \"" + Arrays.toString(zeroes) + "\": "
+ " e = " + zeroResult
+ ", hashCode = " + hashCode
+ ", repetition = " + j);
}
hashCode = (int) vectorizedHashCode.invoke(null, extraZeroes, 17, i, 1, /* ArraysSupport.T_BYTE */ 8);
if (hashCode != zeroResult) {
throw new RuntimeException("byte[] subrange \"" + Arrays.toString(extraZeroes)
+ "\" at offset 17, limit " + i + ": "
+ " e = " + zeroResult
+ ", hashCode = " + hashCode
+ ", repetition = " + j);
}
}
zeroResult *= 31;
}
for (int i = 0; i < tests.length; i++) {
for (int j = 0; j < 64; j++) {
int e = expected[i];
int hashCode = Arrays.hashCode(testBytes[i]);
if (hashCode != e) {
throw new RuntimeException("byte[] \"" + Arrays.toString(testBytes[i]) + "\": "
+ " e = " + e
+ ", hashCode = " + hashCode
+ ", repetition = " + j);
}
}
}
System.out.println("byte[] tests passed");
} catch (RuntimeException e) {
System.out.println(e.getMessage());
failed = true;
}
try {
for (int i = 0; i < tests.length; i++) {
for (int j = 0; j < 64; j++) {
int e = expected[i];
int hashCode = Arrays.hashCode(testShorts[i]);
if (hashCode != e) {
throw new RuntimeException("short[] \"" + Arrays.toString(testShorts[i]) + "\": "
+ " e = " + e
+ ", hashCode = " + hashCode
+ ", repetition = " + j);
}
}
}
System.out.println("short[] tests passed");
} catch (RuntimeException e) {
System.out.println(e.getMessage());
failed = true;
}
try {
for (int i = 0; i < tests.length; i++) {
for (int j = 0; j < 64; j++) {
int e = expected[i];
int hashCode = Arrays.hashCode(testInts[i]);
if (hashCode != e) {
throw new RuntimeException("int[] \"" + Arrays.toString(testInts[i]) + "\": "
+ " e = " + e
+ ", hashCode = " + hashCode
+ ", repetition = " + j);
}
}
}
System.out.println("int[] tests passed");
} catch (RuntimeException e) {
System.out.println(e.getMessage());
failed = true;
}
try {
for (int i = 0; i < tests.length; i++) {
for (int j = 0; j < 64; j++) {
int e = expectedUnsigned[i];
int hashCode = Arrays.hashCode(testChars[i]);
if (hashCode != e) {
throw new RuntimeException("char[] \"" + Arrays.toString(testChars[i]) + "\": "
+ " e = " + e
+ ", hashCode = " + hashCode
+ ", repetition = " + j);
}
}
}
System.out.println("char[] tests passed");
} catch (RuntimeException e) {
System.out.println(e.getMessage());
failed = true;
}
if (failed) {
throw new RuntimeException("Some tests failed");
}
}
}

View file

@ -0,0 +1,282 @@
/*
* Copyright (c) 2013, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8012650
* @summary Unit test for setAll, parallelSetAll variants
* @run junit SetAllTest
*/
import java.util.Arrays;
import java.util.function.IntFunction;
import java.util.function.IntToDoubleFunction;
import java.util.function.IntToLongFunction;
import java.util.function.IntUnaryOperator;
import org.junit.jupiter.api.Assertions;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.fail;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class SetAllTest {
private static final IntFunction<String> toString = i -> "N" + Integer.valueOf(i);
private static final IntFunction<String> fillString = i -> "X";
private static final String[] r0 = {};
private static final String[] r1 = { "N0" };
private static final String[] r10 = { "N0", "N1", "N2", "N3", "N4", "N5", "N6", "N7", "N8", "N9" };
private Object[][] stringData = new Object[][] {
{ "empty", 0, toString, r0 },
{ "one", 1, toString, r1 },
{ "ten", 10, toString, r10 },
{ "fill", 3, fillString, new String[] { "X", "X", "X" }}
};
private static final IntUnaryOperator toInt = i -> i << 1;
private static final IntUnaryOperator fillInt = i -> 99;
private static final int[] ir0 = {};
private static final int[] ir1 = { 0 };
private static final int[] ir10 = { 0, 2, 4, 6, 8, 10, 12, 14, 16, 18 };
private Object[][] intData = new Object[][] {
{ "empty", 0, toInt, ir0 },
{ "one", 1, toInt, ir1 },
{ "ten", 10, toInt, ir10 },
{ "fill", 3, fillInt, new int[] { 99, 99, 99 }}
};
private static final IntToLongFunction toLong = i -> i << 1;
private static final IntToLongFunction fillLong = i -> 9999L;
private static final long[] lr0 = {};
private static final long[] lr1 = { 0L };
private static final long[] lr10 = { 0L, 2L, 4L, 6L, 8L, 10L, 12L, 14L, 16L, 18L };
private Object[][] longData = new Object[][] {
{ "empty", 0, toLong, lr0 },
{ "one", 1, toLong, lr1 },
{ "ten", 10, toLong, lr10 },
{ "fill", 3, fillLong, new long[] { 9999L, 9999L, 9999L }}
};
private static final IntToDoubleFunction toDouble = i -> i * 1.1;
private static final IntToDoubleFunction fillDouble = i -> 3.14;
private static final double[] dr0 = {};
private static final double[] dr1 = { 0.0 };
private static final double[] dr10 = { 0.0, 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9 };
private Object[][] doubleData = new Object[][] {
{ "empty", 0, toDouble, dr0 },
{ "one", 1, toDouble, dr1 },
{ "ten", 10, toDouble, dr10 },
{ "fill", 3, fillDouble, new double[] { 3.14, 3.14, 3.14 }}
};
public Object[][] stringTests() { return stringData; }
public Object[][] intTests() { return intData; }
public Object[][] longTests() { return longData; }
public Object[][] doubleTests() { return doubleData; }
@ParameterizedTest
@MethodSource("stringTests")
public void testSetAllString(String name, int size, IntFunction<String> generator, String[] expected) {
String[] result = new String[size];
Arrays.setAll(result, generator);
Assertions.assertArrayEquals(expected, result, "setAll(String[], IntFunction<String>) case " + name + " failed.");
// ensure fresh array
result = new String[size];
Arrays.parallelSetAll(result, generator);
Assertions.assertArrayEquals(expected, result, "parallelSetAll(String[], IntFunction<String>) case " + name + " failed.");
}
@ParameterizedTest
@MethodSource("intTests")
public void testSetAllInt(String name, int size, IntUnaryOperator generator, int[] expected) {
int[] result = new int[size];
Arrays.setAll(result, generator);
Assertions.assertArrayEquals(expected, result, "setAll(int[], IntUnaryOperator) case " + name + " failed.");
// ensure fresh array
result = new int[size];
Arrays.parallelSetAll(result, generator);
Assertions.assertArrayEquals(expected, result, "parallelSetAll(int[], IntUnaryOperator) case " + name + " failed.");
}
@ParameterizedTest
@MethodSource("longTests")
public void testSetAllLong(String name, int size, IntToLongFunction generator, long[] expected) {
long[] result = new long[size];
Arrays.setAll(result, generator);
Assertions.assertArrayEquals(expected, result, "setAll(long[], IntToLongFunction) case " + name + " failed.");
// ensure fresh array
result = new long[size];
Arrays.parallelSetAll(result, generator);
Assertions.assertArrayEquals(expected, result, "parallelSetAll(long[], IntToLongFunction) case " + name + " failed.");
}
private void assertDoubleArrayEquals(double[] actual, double[] expected, double delta, String msg) {
if (actual.length != expected.length) {
fail(msg + ": length mismatch, expected " + expected.length + ", got " + actual.length);
}
for (int i = 0; i < actual.length; i++) {
assertEquals(actual[i], expected[i], delta, msg + "(mismatch at index " + i + ")");
}
}
@ParameterizedTest
@MethodSource("doubleTests")
public void testSetAllDouble(String name, int size, IntToDoubleFunction generator, double[] expected) {
double[] result = new double[size];
Arrays.setAll(result, generator);
assertDoubleArrayEquals(result, expected, 0.05, "setAll(double[], IntToDoubleFunction) case " + name + " failed.");
// ensure fresh array
result = new double[size];
Arrays.parallelSetAll(result, generator);
assertDoubleArrayEquals(result, expected, 0.05, "setAll(double[], IntToDoubleFunction) case " + name + " failed.");
}
@Test
public void testStringSetNulls() {
String[] ar = new String[2];
try {
Arrays.setAll(null, (IntFunction<String>) i -> "X");
fail("Arrays.setAll(null, foo) should throw NPE");
} catch (NullPointerException npe) {
// expected
}
try {
Arrays.parallelSetAll(null, (IntFunction<String>) i -> "X");
fail("Arrays.parallelSetAll(null, foo) should throw NPE");
} catch (NullPointerException npe) {
// expected
}
try {
Arrays.setAll(ar, null);
fail("Arrays.setAll(array, null) should throw NPE");
} catch (NullPointerException npe) {
// expected
}
try {
Arrays.parallelSetAll(ar, null);
fail("Arrays.parallelSetAll(array, null) should throw NPE");
} catch (NullPointerException npe) {
// expected
}
}
@Test
public void testIntSetNulls() {
int[] ar = new int[2];
try {
Arrays.setAll(null, (IntUnaryOperator) i -> i);
fail("Arrays.setAll(null, foo) should throw NPE");
} catch (NullPointerException npe) {
// expected
}
try {
Arrays.parallelSetAll(null, (IntUnaryOperator) i -> i);
fail("Arrays.parallelSetAll(null, foo) should throw NPE");
} catch (NullPointerException npe) {
// expected
}
try {
Arrays.setAll(ar, null);
fail("Arrays.setAll(array, null) should throw NPE");
} catch (NullPointerException npe) {
// expected
}
try {
Arrays.parallelSetAll(ar, null);
fail("Arrays.parallelSetAll(array, null) should throw NPE");
} catch (NullPointerException npe) {
// expected
}
}
@Test
public void testLongSetNulls() {
long[] ar = new long[2];
try {
Arrays.setAll(null, (IntToLongFunction) i -> Long.MAX_VALUE);
fail("Arrays.setAll(null, foo) should throw NPE");
} catch (NullPointerException npe) {
// expected
}
try {
Arrays.parallelSetAll(null, (IntToLongFunction) i -> Long.MAX_VALUE);
fail("Arrays.parallelSetAll(null, foo) should throw NPE");
} catch (NullPointerException npe) {
// expected
}
try {
Arrays.setAll(ar, null);
fail("Arrays.setAll(array, null) should throw NPE");
} catch (NullPointerException npe) {
// expected
}
try {
Arrays.parallelSetAll(ar, null);
fail("Arrays.parallelSetAll(array, null) should throw NPE");
} catch (NullPointerException npe) {
// expected
}
}
@Test
public void testDoubleSetNulls() {
double[] ar = new double[2];
try {
Arrays.setAll(null, (IntToDoubleFunction) i -> Math.E);
fail("Arrays.setAll(null, foo) should throw NPE");
} catch (NullPointerException npe) {
// expected
}
try {
Arrays.parallelSetAll(null, (IntToDoubleFunction) i -> Math.E);
fail("Arrays.parallelSetAll(null, foo) should throw NPE");
} catch (NullPointerException npe) {
// expected
}
try {
Arrays.setAll(ar, null);
fail("Arrays.setAll(array, null) should throw NPE");
} catch (NullPointerException npe) {
// expected
}
try {
Arrays.parallelSetAll(ar, null);
fail("Arrays.parallelSetAll(array, null) should throw NPE");
} catch (NullPointerException npe) {
// expected
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,708 @@
/*
* Copyright 2015 Goldman Sachs.
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Param;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.Warmup;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.TimeUnit;
@State(Scope.Thread)
@BenchmarkMode(Mode.Throughput)
@OutputTimeUnit(TimeUnit.SECONDS)
public class SortingIntBenchmarkTestJMH {
private static final int QUICKSORT_THRESHOLD = 286;
private static final int MAX_RUN_COUNT = 67;
private static final int INSERTION_SORT_THRESHOLD = 47;
public static final int MAX_VALUE = 1_000_000;
@Param({"pairFlipZeroPairFlip", "pairFlipOneHundredPairFlip"
, "zeroHi", "hiZeroLow", "hiFlatLow", "identical",
"randomDups", "randomNoDups", "sortedReversedSorted", "pairFlip", "endLessThan"})
public String listType;
private int[] array;
private static final int LIST_SIZE = 10_000_000;
public static final int NUMBER_OF_ITERATIONS = 10;
@Setup
public void setUp() {
Random random = new Random(123456789012345L);
this.array = new int[LIST_SIZE];
int threeQuarters = (int) (LIST_SIZE * 0.75);
if ("zeroHi".equals(this.listType)) {
for (int i = 0; i < threeQuarters; i++) {
this.array[i] = 0;
}
int k = 1;
for (int i = threeQuarters; i < LIST_SIZE; i++) {
this.array[i] = k;
k++;
}
}
else if ("hiFlatLow".equals(this.listType)) {
int oneThird = LIST_SIZE / 3;
for (int i = 0; i < oneThird; i++) {
this.array[i] = i;
}
int twoThirds = oneThird * 2;
int constant = oneThird - 1;
for (int i = oneThird; i < twoThirds; i++) {
this.array[i] = constant;
}
for (int i = twoThirds; i < LIST_SIZE; i++) {
this.array[i] = constant - i + twoThirds;
}
}
else if ("hiZeroLow".equals(this.listType)) {
int oneThird = LIST_SIZE / 3;
for (int i = 0; i < oneThird; i++) {
this.array[i] = i;
}
int twoThirds = oneThird * 2;
for (int i = oneThird; i < twoThirds; i++) {
this.array[i] = 0;
}
for (int i = twoThirds; i < LIST_SIZE; i++) {
this.array[i] = oneThird - i + twoThirds;
}
}
else if ("identical".equals(this.listType)) {
for (int i = 0; i < LIST_SIZE; i++) {
this.array[i] = 0;
}
}
else if ("randomDups".equals(this.listType)) {
for (int i = 0; i < LIST_SIZE; i++) {
this.array[i] = random.nextInt(1000);
}
}
else if ("randomNoDups".equals(this.listType)) {
Set<Integer> set = new HashSet();
while (set.size() < LIST_SIZE + 1) {
set.add(random.nextInt());
}
List<Integer> list = new ArrayList<>(LIST_SIZE);
list.addAll(set);
for (int i = 0; i < LIST_SIZE; i++) {
this.array[i] = list.get(i);
}
}
else if ("sortedReversedSorted".equals(this.listType)) {
for (int i = 0; i < LIST_SIZE / 2; i++) {
this.array[i] = i;
}
int num = 0;
for (int i = LIST_SIZE / 2; i < LIST_SIZE; i++) {
this.array[i] = LIST_SIZE - num;
num++;
}
}
else if ("pairFlip".equals(this.listType)) {
for (int i = 0; i < LIST_SIZE; i++) {
this.array[i] = i;
}
for (int i = 0; i < LIST_SIZE; i += 2) {
int temp = this.array[i];
this.array[i] = this.array[i + 1];
this.array[i + 1] = temp;
}
}
else if ("endLessThan".equals(this.listType)) {
for (int i = 0; i < LIST_SIZE - 1; i++) {
this.array[i] = 3;
}
this.array[LIST_SIZE - 1] = 1;
}
else if ("pairFlipZeroPairFlip".equals(this.listType)) {
//pairflip
for (int i = 0; i < 64; i++) {
this.array[i] = i;
}
for (int i = 0; i < 64; i += 2) {
int temp = this.array[i];
this.array[i] = this.array[i + 1];
this.array[i + 1] = temp;
}
//zero
for (int i = 64; i < this.array.length - 64; i++) {
this.array[i] = 0;
}
//pairflip
for (int i = this.array.length - 64; i < this.array.length; i++) {
this.array[i] = i;
}
for (int i = this.array.length - 64; i < this.array.length; i += 2) {
int temp = this.array[i];
this.array[i] = this.array[i + 1];
this.array[i + 1] = temp;
}
}
else if ("pairFlipOneHundredPairFlip".equals(this.listType)) {
//10, 5
for (int i = 0; i < 64; i++) {
if (i % 2 == 0) {
this.array[i] = 10;
}
else {
this.array[i] = 5;
}
}
//100
for (int i = 64; i < this.array.length - 64; i++) {
this.array[i] = 100;
}
//10, 5
for (int i = this.array.length - 64; i < this.array.length; i++) {
if (i % 2 == 0) {
this.array[i] = 10;
}
else {
this.array[i] = 5;
}
}
}
}
@Warmup(iterations = 20)
@Measurement(iterations = 10)
@Benchmark
public void sortNewWay() {
for (int i = 0; i < NUMBER_OF_ITERATIONS; i++) {
SortingIntTestJMH.sort(this.array, 0, this.array.length - 1, null, 0, 0);
}
}
@Warmup(iterations = 20)
@Measurement(iterations = 10)
@Benchmark
public void sortCurrentWay() {
for (int i = 0; i < NUMBER_OF_ITERATIONS; i++) {
Arrays.sort(this.array);
}
}
static void sort(int[] a, int left, int right,
int[] work, int workBase, int workLen) {
// Use Quicksort on small arrays
if (right - left < QUICKSORT_THRESHOLD) {
SortingIntTestJMH.sort(a, left, right, true);
return;
}
/*
* Index run[i] is the start of i-th run
* (ascending or descending sequence).
*/
int[] run = new int[MAX_RUN_COUNT + 1];
int count = 0;
run[0] = left;
// Check if the array is nearly sorted
for (int k = left; k < right; run[count] = k) {
while (k < right && a[k] == a[k + 1])
k++;
if (k == right) break;
if (a[k] < a[k + 1]) { // ascending
while (++k <= right && a[k - 1] <= a[k]) ;
}
else if (a[k] > a[k + 1]) { // descending
while (++k <= right && a[k - 1] >= a[k]) ;
for (int lo = run[count] - 1, hi = k; ++lo < --hi; ) {
int t = a[lo];
a[lo] = a[hi];
a[hi] = t;
}
}
if (run[count] > left && a[run[count]] >= a[run[count] - 1]) {
count--;
}
/*
* The array is not highly structured,
* use Quicksort instead of merge sort.
*/
if (++count == MAX_RUN_COUNT) {
sort(a, left, right, true);
return;
}
}
// Check special cases
// Implementation note: variable "right" is increased by 1.
if (run[count] == right++) {
run[++count] = right;
}
if (count <= 1) { // The array is already sorted
return;
}
// Determine alternation base for merge
byte odd = 0;
for (int n = 1; (n <<= 1) < count; odd ^= 1) {
}
// Use or create temporary array b for merging
int[] b; // temp array; alternates with a
int ao, bo; // array offsets from 'left'
int blen = right - left; // space needed for b
if (work == null || workLen < blen || workBase + blen > work.length) {
work = new int[blen];
workBase = 0;
}
if (odd == 0) {
System.arraycopy(a, left, work, workBase, blen);
b = a;
bo = 0;
a = work;
ao = workBase - left;
}
else {
b = work;
ao = 0;
bo = workBase - left;
}
// Merging
for (int last; count > 1; count = last) {
for (int k = (last = 0) + 2; k <= count; k += 2) {
int hi = run[k], mi = run[k - 1];
for (int i = run[k - 2], p = i, q = mi; i < hi; ++i) {
if (q >= hi || p < mi && a[p + ao] <= a[q + ao]) {
b[i + bo] = a[p++ + ao];
}
else {
b[i + bo] = a[q++ + ao];
}
}
run[++last] = hi;
}
if ((count & 1) != 0) {
for (int i = right, lo = run[count - 1]; --i >= lo;
b[i + bo] = a[i + ao]
) {
}
run[++last] = right;
}
int[] t = a;
a = b;
b = t;
int o = ao;
ao = bo;
bo = o;
}
}
private static void sort(int[] a, int left, int right, boolean leftmost) {
int length = right - left + 1;
// Use insertion sort on tiny arrays
if (length < INSERTION_SORT_THRESHOLD) {
if (leftmost) {
/*
* Traditional (without sentinel) insertion sort,
* optimized for server VM, is used in case of
* the leftmost part.
*/
for (int i = left, j = i; i < right; j = ++i) {
int ai = a[i + 1];
while (ai < a[j]) {
a[j + 1] = a[j];
if (j-- == left) {
break;
}
}
a[j + 1] = ai;
}
}
else {
/*
* Skip the longest ascending sequence.
*/
do {
if (left >= right) {
return;
}
}
while (a[++left] >= a[left - 1]);
/*
* Every element from adjoining part plays the role
* of sentinel, therefore this allows us to avoid the
* left range check on each iteration. Moreover, we use
* the more optimized algorithm, so called pair insertion
* sort, which is faster (in the context of Quicksort)
* than traditional implementation of insertion sort.
*/
for (int k = left; ++left <= right; k = ++left) {
int a1 = a[k], a2 = a[left];
if (a1 < a2) {
a2 = a1;
a1 = a[left];
}
while (a1 < a[--k]) {
a[k + 2] = a[k];
}
a[++k + 1] = a1;
while (a2 < a[--k]) {
a[k + 1] = a[k];
}
a[k + 1] = a2;
}
int last = a[right];
while (last < a[--right]) {
a[right + 1] = a[right];
}
a[right + 1] = last;
}
return;
}
// Inexpensive approximation of length / 7
int seventh = (length >> 3) + (length >> 6) + 1;
/*
* Sort five evenly spaced elements around (and including) the
* center element in the range. These elements will be used for
* pivot selection as described below. The choice for spacing
* these elements was empirically determined to work well on
* a wide variety of inputs.
*/
int e3 = (left + right) >>> 1; // The midpoint
int e2 = e3 - seventh;
int e1 = e2 - seventh;
int e4 = e3 + seventh;
int e5 = e4 + seventh;
// Sort these elements using insertion sort
if (a[e2] < a[e1]) {
int t = a[e2];
a[e2] = a[e1];
a[e1] = t;
}
if (a[e3] < a[e2]) {
int t = a[e3];
a[e3] = a[e2];
a[e2] = t;
if (t < a[e1]) {
a[e2] = a[e1];
a[e1] = t;
}
}
if (a[e4] < a[e3]) {
int t = a[e4];
a[e4] = a[e3];
a[e3] = t;
if (t < a[e2]) {
a[e3] = a[e2];
a[e2] = t;
if (t < a[e1]) {
a[e2] = a[e1];
a[e1] = t;
}
}
}
if (a[e5] < a[e4]) {
int t = a[e5];
a[e5] = a[e4];
a[e4] = t;
if (t < a[e3]) {
a[e4] = a[e3];
a[e3] = t;
if (t < a[e2]) {
a[e3] = a[e2];
a[e2] = t;
if (t < a[e1]) {
a[e2] = a[e1];
a[e1] = t;
}
}
}
}
// Pointers
int less = left; // The index of the first element of center part
int great = right; // The index before the first element of right part
if (a[e1] != a[e2] && a[e2] != a[e3] && a[e3] != a[e4] && a[e4] != a[e5]) {
/*
* Use the second and fourth of the five sorted elements as pivots.
* These values are inexpensive approximations of the first and
* second terciles of the array. Note that pivot1 <= pivot2.
*/
int pivot1 = a[e2];
int pivot2 = a[e4];
/*
* The first and the last elements to be sorted are moved to the
* locations formerly occupied by the pivots. When partitioning
* is complete, the pivots are swapped back into their final
* positions, and excluded from subsequent sorting.
*/
a[e2] = a[left];
a[e4] = a[right];
/*
* Skip elements, which are less or greater than pivot values.
*/
while (a[++less] < pivot1) {
}
while (a[--great] > pivot2) {
}
/*
* Partitioning:
*
* left part center part right part
* +--------------------------------------------------------------+
* | < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 |
* +--------------------------------------------------------------+
* ^ ^ ^
* | | |
* less k great
*
* Invariants:
*
* all in (left, less) < pivot1
* pivot1 <= all in [less, k) <= pivot2
* all in (great, right) > pivot2
*
* Pointer k is the first index of ?-part.
*/
outer:
for (int k = less - 1; ++k <= great; ) {
int ak = a[k];
if (ak < pivot1) { // Move a[k] to left part
a[k] = a[less];
/*
* Here and below we use "a[i] = b; i++;" instead
* of "a[i++] = b;" due to performance issue.
*/
a[less] = ak;
++less;
}
else if (ak > pivot2) { // Move a[k] to right part
while (a[great] > pivot2) {
if (great-- == k) {
break outer;
}
}
if (a[great] < pivot1) { // a[great] <= pivot2
a[k] = a[less];
a[less] = a[great];
++less;
}
else { // pivot1 <= a[great] <= pivot2
a[k] = a[great];
}
/*
* Here and below we use "a[i] = b; i--;" instead
* of "a[i--] = b;" due to performance issue.
*/
a[great] = ak;
--great;
}
}
// Swap pivots into their final positions
a[left] = a[less - 1];
a[less - 1] = pivot1;
a[right] = a[great + 1];
a[great + 1] = pivot2;
// Sort left and right parts recursively, excluding known pivots
SortingIntTestJMH.sort(a, left, less - 2, leftmost);
SortingIntTestJMH.sort(a, great + 2, right, false);
/*
* If center part is too large (comprises > 4/7 of the array),
* swap internal pivot values to ends.
*/
if (less < e1 && e5 < great) {
/*
* Skip elements, which are equal to pivot values.
*/
while (a[less] == pivot1) {
++less;
}
while (a[great] == pivot2) {
--great;
}
/*
* Partitioning:
*
* left part center part right part
* +----------------------------------------------------------+
* | == pivot1 | pivot1 < && < pivot2 | ? | == pivot2 |
* +----------------------------------------------------------+
* ^ ^ ^
* | | |
* less k great
*
* Invariants:
*
* all in (*, less) == pivot1
* pivot1 < all in [less, k) < pivot2
* all in (great, *) == pivot2
*
* Pointer k is the first index of ?-part.
*/
outer:
for (int k = less - 1; ++k <= great; ) {
int ak = a[k];
if (ak == pivot1) { // Move a[k] to left part
a[k] = a[less];
a[less] = ak;
++less;
}
else if (ak == pivot2) { // Move a[k] to right part
while (a[great] == pivot2) {
if (great-- == k) {
break outer;
}
}
if (a[great] == pivot1) { // a[great] < pivot2
a[k] = a[less];
/*
* Even though a[great] equals to pivot1, the
* assignment a[less] = pivot1 may be incorrect,
* if a[great] and pivot1 are floating-point zeros
* of different signs. Therefore in float and
* double sorting methods we have to use more
* accurate assignment a[less] = a[great].
*/
a[less] = pivot1;
++less;
}
else { // pivot1 < a[great] < pivot2
a[k] = a[great];
}
a[great] = ak;
--great;
}
}
}
// Sort center part recursively
SortingIntTestJMH.sort(a, less, great, false);
}
else { // Partitioning with one pivot
/*
* Use the third of the five sorted elements as pivot.
* This value is inexpensive approximation of the median.
*/
int pivot = a[e3];
/*
* Partitioning degenerates to the traditional 3-way
* (or "Dutch National Flag") schema:
*
* left part center part right part
* +-------------------------------------------------+
* | < pivot | == pivot | ? | > pivot |
* +-------------------------------------------------+
* ^ ^ ^
* | | |
* less k great
*
* Invariants:
*
* all in (left, less) < pivot
* all in [less, k) == pivot
* all in (great, right) > pivot
*
* Pointer k is the first index of ?-part.
*/
for (int k = less; k <= great; ++k) {
if (a[k] == pivot) {
continue;
}
int ak = a[k];
if (ak < pivot) { // Move a[k] to left part
a[k] = a[less];
a[less] = ak;
++less;
}
else { // a[k] > pivot - Move a[k] to right part
while (a[great] > pivot) {
--great;
}
if (a[great] < pivot) { // a[great] <= pivot
a[k] = a[less];
a[less] = a[great];
++less;
}
else { // a[great] == pivot
/*
* Even though a[great] equals to pivot, the
* assignment a[k] = pivot may be incorrect,
* if a[great] and pivot are floating-point
* zeros of different signs. Therefore in float
* and double sorting methods we have to use
* more accurate assignment a[k] = a[great].
*/
a[k] = pivot;
}
a[great] = ak;
--great;
}
}
/*
* Sort left and right parts recursively.
* All elements from center part are equal
* and, therefore, already sorted.
*/
SortingIntTestJMH.sort(a, left, less - 1, leftmost);
SortingIntTestJMH.sort(a, great + 1, right, false);
}
}
private static void swap(int[] arr, int i, int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}

View file

@ -0,0 +1,725 @@
/*
* Copyright 2015 Goldman Sachs.
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Param;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.Warmup;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.TimeUnit;
@State(Scope.Thread)
@BenchmarkMode(Mode.Throughput)
@OutputTimeUnit(TimeUnit.SECONDS)
public class SortingLongBenchmarkTestJMH {
private static final int QUICKSORT_THRESHOLD = 286;
private static final int MAX_RUN_COUNT = 67;
private static final int INSERTION_SORT_THRESHOLD = 47;
public static final int MAX_VALUE = 1_000_000;
@Param({"pairFlipZeroPairFlip", "descendingAscending", "zeroHi", "hiZeroLow", "hiFlatLow", "identical",
"randomDups", "randomNoDups", "sortedReversedSorted", "pairFlip", "endLessThan"})
public String listType;
private long[] array;
private static final int LIST_SIZE = 10_000_000;
public static final int NUMBER_OF_ITERATIONS = 10;
@Setup
public void setUp() {
Random random = new Random(123456789012345L);
this.array = new long[LIST_SIZE];
int threeQuarters = (int) (LIST_SIZE * 0.75);
if ("zeroHi".equals(this.listType)) {
for (int i = 0; i < threeQuarters; i++) {
this.array[i] = 0;
}
int k = 1;
for (int i = threeQuarters; i < LIST_SIZE; i++) {
this.array[i] = k;
k++;
}
}
else if ("hiFlatLow".equals(this.listType)) {
int oneThird = LIST_SIZE / 3;
for (int i = 0; i < oneThird; i++) {
this.array[i] = i;
}
int twoThirds = oneThird * 2;
int constant = oneThird - 1;
for (int i = oneThird; i < twoThirds; i++) {
this.array[i] = constant;
}
for (int i = twoThirds; i < LIST_SIZE; i++) {
this.array[i] = constant - i + twoThirds;
}
}
else if ("hiZeroLow".equals(this.listType)) {
int oneThird = LIST_SIZE / 3;
for (int i = 0; i < oneThird; i++) {
this.array[i] = i;
}
int twoThirds = oneThird * 2;
for (int i = oneThird; i < twoThirds; i++) {
this.array[i] = 0;
}
for (int i = twoThirds; i < LIST_SIZE; i++) {
this.array[i] = oneThird - i + twoThirds;
}
}
else if ("identical".equals(this.listType)) {
for (int i = 0; i < LIST_SIZE; i++) {
this.array[i] = 0;
}
}
else if ("randomDups".equals(this.listType)) {
for (int i = 0; i < LIST_SIZE; i++) {
this.array[i] = random.nextInt(1000);
}
}
else if ("randomNoDups".equals(this.listType)) {
Set<Integer> set = new HashSet<>();
while (set.size() < LIST_SIZE + 1) {
set.add(random.nextInt());
}
List<Integer> list = new ArrayList<>(LIST_SIZE);
list.addAll(set);
for (int i = 0; i < LIST_SIZE; i++) {
this.array[i] = list.get(i);
}
}
else if ("sortedReversedSorted".equals(this.listType)) {
for (int i = 0; i < LIST_SIZE / 2; i++) {
this.array[i] = i;
}
int num = 0;
for (int i = LIST_SIZE / 2; i < LIST_SIZE; i++) {
this.array[i] = LIST_SIZE - num;
num++;
}
}
else if ("pairFlip".equals(this.listType)) {
for (int i = 0; i < LIST_SIZE; i++) {
this.array[i] = i;
}
for (int i = 0; i < LIST_SIZE; i += 2) {
long temp = this.array[i];
this.array[i] = this.array[i + 1];
this.array[i + 1] = temp;
}
}
else if ("endLessThan".equals(this.listType)) {
for (int i = 0; i < LIST_SIZE - 1; i++) {
this.array[i] = 3;
}
this.array[LIST_SIZE - 1] = 1;
}
else if ("pairFlipZeroPairFlip".equals(this.listType)) {
//pairflip
for (int i = 0; i < 64; i++) {
this.array[i] = i;
}
for (int i = 0; i < 64; i += 2) {
long temp = this.array[i];
this.array[i] = this.array[i + 1];
this.array[i + 1] = temp;
}
//zero
for (int i = 64; i < this.array.length - 64; i++) {
this.array[i] = 0;
}
//pairflip
for (int i = this.array.length - 64; i < this.array.length; i++) {
this.array[i] = i;
}
for (int i = this.array.length - 64; i < this.array.length; i += 2) {
long temp = this.array[i];
this.array[i] = this.array[i + 1];
this.array[i + 1] = temp;
}
}
else if ("pairFlipOneHundredPairFlip".equals(this.listType)) {
//10, 5
for (int i = 0; i < 64; i++) {
if (i % 2 == 0) {
this.array[i] = 10;
}
else {
this.array[i] = 5;
}
}
//100
for (int i = 64; i < this.array.length - 64; i++) {
this.array[i] = 100;
}
//10, 5
for (int i = this.array.length - 64; i < this.array.length; i++) {
if (i % 2 == 0) {
this.array[i] = 10;
}
else {
this.array[i] = 5;
}
}
}
}
@Warmup(iterations = 20)
@Measurement(iterations = 10)
@Benchmark
public void sortNewWay() {
for (int i = 0; i < NUMBER_OF_ITERATIONS; i++) {
SortingLongTestJMH.sort(this.array, 0, this.array.length - 1, null, 0, 0);
}
}
@Warmup(iterations = 20)
@Measurement(iterations = 10)
@Benchmark
public void sortOldWay() {
for (int i = 0; i < NUMBER_OF_ITERATIONS; i++) {
Arrays.sort(this.array);
}
}
/**
* Sorts the specified range of the array using the given
* workspace array slice if possible for merging
*
* @param a the array to be sorted
* @param left the index of the first element, inclusive, to be sorted
* @param right the index of the last element, inclusive, to be sorted
* @param work a workspace array (slice)
* @param workBase origin of usable space in work array
* @param workLen usable size of work array
*/
static void sort(long[] a, int left, int right,
long[] work, int workBase, int workLen) {
// Use Quicksort on small arrays
if (right - left < QUICKSORT_THRESHOLD) {
SortingLongTestJMH.sort(a, left, right, true);
return;
}
/*
* Index run[i] is the start of i-th run
* (ascending or descending sequence).
*/
int[] run = new int[MAX_RUN_COUNT + 1];
int count = 0;
run[0] = left;
// Check if the array is nearly sorted
for (int k = left; k < right; run[count] = k) {
while (k < right && a[k] == a[k + 1])
k++;
if (k == right) break;
if (a[k] < a[k + 1]) { // ascending
while (++k <= right && a[k - 1] <= a[k]) ;
}
else if (a[k] > a[k + 1]) { // descending
while (++k <= right && a[k - 1] >= a[k]) ;
for (int lo = run[count] - 1, hi = k; ++lo < --hi; ) {
long t = a[lo];
a[lo] = a[hi];
a[hi] = t;
}
}
if (run[count] > left && a[run[count]] >= a[run[count] - 1]) {
count--;
}
/*
* The array is not highly structured,
* use Quicksort instead of merge sort.
*/
if (++count == MAX_RUN_COUNT) {
sort(a, left, right, true);
return;
}
}
// Check special cases
// Implementation note: variable "right" is increased by 1.
if (run[count] == right++) {
run[++count] = right;
}
if (count <= 1) { // The array is already sorted
return;
}
// Determine alternation base for merge
byte odd = 0;
for (int n = 1; (n <<= 1) < count; odd ^= 1) {
}
// Use or create temporary array b for merging
long[] b; // temp array; alternates with a
int ao, bo; // array offsets from 'left'
int blen = right - left; // space needed for b
if (work == null || workLen < blen || workBase + blen > work.length) {
work = new long[blen];
workBase = 0;
}
if (odd == 0) {
System.arraycopy(a, left, work, workBase, blen);
b = a;
bo = 0;
a = work;
ao = workBase - left;
}
else {
b = work;
ao = 0;
bo = workBase - left;
}
// Merging
for (int last; count > 1; count = last) {
for (int k = (last = 0) + 2; k <= count; k += 2) {
int hi = run[k], mi = run[k - 1];
for (int i = run[k - 2], p = i, q = mi; i < hi; ++i) {
if (q >= hi || p < mi && a[p + ao] <= a[q + ao]) {
b[i + bo] = a[p++ + ao];
}
else {
b[i + bo] = a[q++ + ao];
}
}
run[++last] = hi;
}
if ((count & 1) != 0) {
for (int i = right, lo = run[count - 1]; --i >= lo;
b[i + bo] = a[i + ao]
) {
}
run[++last] = right;
}
long[] t = a;
a = b;
b = t;
int o = ao;
ao = bo;
bo = o;
}
}
/**
* Sorts the specified range of the array by Dual-Pivot Quicksort.
*
* @param a the array to be sorted
* @param left the index of the first element, inclusive, to be sorted
* @param right the index of the last element, inclusive, to be sorted
* @param leftmost indicates if this part is the leftmost in the range
*/
private static void sort(long[] a, int left, int right, boolean leftmost) {
int length = right - left + 1;
// Use insertion sort on tiny arrays
if (length < INSERTION_SORT_THRESHOLD) {
if (leftmost) {
/*
* Traditional (without sentinel) insertion sort,
* optimized for server VM, is used in case of
* the leftmost part.
*/
for (int i = left, j = i; i < right; j = ++i) {
long ai = a[i + 1];
while (ai < a[j]) {
a[j + 1] = a[j];
if (j-- == left) {
break;
}
}
a[j + 1] = ai;
}
}
else {
/*
* Skip the longest ascending sequence.
*/
do {
if (left >= right) {
return;
}
}
while (a[++left] >= a[left - 1]);
/*
* Every element from adjoining part plays the role
* of sentinel, therefore this allows us to avoid the
* left range check on each iteration. Moreover, we use
* the more optimized algorithm, so called pair insertion
* sort, which is faster (in the context of Quicksort)
* than traditional implementation of insertion sort.
*/
for (int k = left; ++left <= right; k = ++left) {
long a1 = a[k], a2 = a[left];
if (a1 < a2) {
a2 = a1;
a1 = a[left];
}
while (a1 < a[--k]) {
a[k + 2] = a[k];
}
a[++k + 1] = a1;
while (a2 < a[--k]) {
a[k + 1] = a[k];
}
a[k + 1] = a2;
}
long last = a[right];
while (last < a[--right]) {
a[right + 1] = a[right];
}
a[right + 1] = last;
}
return;
}
// Inexpensive approximation of length / 7
int seventh = (length >> 3) + (length >> 6) + 1;
/*
* Sort five evenly spaced elements around (and including) the
* center element in the range. These elements will be used for
* pivot selection as described below. The choice for spacing
* these elements was empirically determined to work well on
* a wide variety of inputs.
*/
int e3 = (left + right) >>> 1; // The midpoint
int e2 = e3 - seventh;
int e1 = e2 - seventh;
int e4 = e3 + seventh;
int e5 = e4 + seventh;
// Sort these elements using insertion sort
if (a[e2] < a[e1]) {
long t = a[e2];
a[e2] = a[e1];
a[e1] = t;
}
if (a[e3] < a[e2]) {
long t = a[e3];
a[e3] = a[e2];
a[e2] = t;
if (t < a[e1]) {
a[e2] = a[e1];
a[e1] = t;
}
}
if (a[e4] < a[e3]) {
long t = a[e4];
a[e4] = a[e3];
a[e3] = t;
if (t < a[e2]) {
a[e3] = a[e2];
a[e2] = t;
if (t < a[e1]) {
a[e2] = a[e1];
a[e1] = t;
}
}
}
if (a[e5] < a[e4]) {
long t = a[e5];
a[e5] = a[e4];
a[e4] = t;
if (t < a[e3]) {
a[e4] = a[e3];
a[e3] = t;
if (t < a[e2]) {
a[e3] = a[e2];
a[e2] = t;
if (t < a[e1]) {
a[e2] = a[e1];
a[e1] = t;
}
}
}
}
// Pointers
int less = left; // The index of the first element of center part
int great = right; // The index before the first element of right part
if (a[e1] != a[e2] && a[e2] != a[e3] && a[e3] != a[e4] && a[e4] != a[e5]) {
/*
* Use the second and fourth of the five sorted elements as pivots.
* These values are inexpensive approximations of the first and
* second terciles of the array. Note that pivot1 <= pivot2.
*/
long pivot1 = a[e2];
long pivot2 = a[e4];
/*
* The first and the last elements to be sorted are moved to the
* locations formerly occupied by the pivots. When partitioning
* is complete, the pivots are swapped back into their final
* positions, and excluded from subsequent sorting.
*/
a[e2] = a[left];
a[e4] = a[right];
/*
* Skip elements, which are less or greater than pivot values.
*/
while (a[++less] < pivot1) {
}
while (a[--great] > pivot2) {
}
/*
* Partitioning:
*
* left part center part right part
* +--------------------------------------------------------------+
* | < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 |
* +--------------------------------------------------------------+
* ^ ^ ^
* | | |
* less k great
*
* Invariants:
*
* all in (left, less) < pivot1
* pivot1 <= all in [less, k) <= pivot2
* all in (great, right) > pivot2
*
* Pointer k is the first index of ?-part.
*/
outer:
for (int k = less - 1; ++k <= great; ) {
long ak = a[k];
if (ak < pivot1) { // Move a[k] to left part
a[k] = a[less];
/*
* Here and below we use "a[i] = b; i++;" instead
* of "a[i++] = b;" due to performance issue.
*/
a[less] = ak;
++less;
}
else if (ak > pivot2) { // Move a[k] to right part
while (a[great] > pivot2) {
if (great-- == k) {
break outer;
}
}
if (a[great] < pivot1) { // a[great] <= pivot2
a[k] = a[less];
a[less] = a[great];
++less;
}
else { // pivot1 <= a[great] <= pivot2
a[k] = a[great];
}
/*
* Here and below we use "a[i] = b; i--;" instead
* of "a[i--] = b;" due to performance issue.
*/
a[great] = ak;
--great;
}
}
// Swap pivots into their final positions
a[left] = a[less - 1];
a[less - 1] = pivot1;
a[right] = a[great + 1];
a[great + 1] = pivot2;
// Sort left and right parts recursively, excluding known pivots
SortingLongTestJMH.sort(a, left, less - 2, leftmost);
SortingLongTestJMH.sort(a, great + 2, right, false);
/*
* If center part is too large (comprises > 4/7 of the array),
* swap internal pivot values to ends.
*/
if (less < e1 && e5 < great) {
/*
* Skip elements, which are equal to pivot values.
*/
while (a[less] == pivot1) {
++less;
}
while (a[great] == pivot2) {
--great;
}
/*
* Partitioning:
*
* left part center part right part
* +----------------------------------------------------------+
* | == pivot1 | pivot1 < && < pivot2 | ? | == pivot2 |
* +----------------------------------------------------------+
* ^ ^ ^
* | | |
* less k great
*
* Invariants:
*
* all in (*, less) == pivot1
* pivot1 < all in [less, k) < pivot2
* all in (great, *) == pivot2
*
* Pointer k is the first index of ?-part.
*/
outer:
for (int k = less - 1; ++k <= great; ) {
long ak = a[k];
if (ak == pivot1) { // Move a[k] to left part
a[k] = a[less];
a[less] = ak;
++less;
}
else if (ak == pivot2) { // Move a[k] to right part
while (a[great] == pivot2) {
if (great-- == k) {
break outer;
}
}
if (a[great] == pivot1) { // a[great] < pivot2
a[k] = a[less];
/*
* Even though a[great] equals to pivot1, the
* assignment a[less] = pivot1 may be incorrect,
* if a[great] and pivot1 are floating-point zeros
* of different signs. Therefore in float and
* double sorting methods we have to use more
* accurate assignment a[less] = a[great].
*/
a[less] = pivot1;
++less;
}
else { // pivot1 < a[great] < pivot2
a[k] = a[great];
}
a[great] = ak;
--great;
}
}
}
// Sort center part recursively
SortingLongTestJMH.sort(a, less, great, false);
}
else { // Partitioning with one pivot
/*
* Use the third of the five sorted elements as pivot.
* This value is inexpensive approximation of the median.
*/
long pivot = a[e3];
/*
* Partitioning degenerates to the traditional 3-way
* (or "Dutch National Flag") schema:
*
* left part center part right part
* +-------------------------------------------------+
* | < pivot | == pivot | ? | > pivot |
* +-------------------------------------------------+
* ^ ^ ^
* | | |
* less k great
*
* Invariants:
*
* all in (left, less) < pivot
* all in [less, k) == pivot
* all in (great, right) > pivot
*
* Pointer k is the first index of ?-part.
*/
for (int k = less; k <= great; ++k) {
if (a[k] == pivot) {
continue;
}
long ak = a[k];
if (ak < pivot) { // Move a[k] to left part
a[k] = a[less];
a[less] = ak;
++less;
}
else { // a[k] > pivot - Move a[k] to right part
while (a[great] > pivot) {
--great;
}
if (a[great] < pivot) { // a[great] <= pivot
a[k] = a[less];
a[less] = a[great];
++less;
}
else { // a[great] == pivot
/*
* Even though a[great] equals to pivot, the
* assignment a[k] = pivot may be incorrect,
* if a[great] and pivot are floating-point
* zeros of different signs. Therefore in float
* and double sorting methods we have to use
* more accurate assignment a[k] = a[great].
*/
a[k] = pivot;
}
a[great] = ak;
--great;
}
}
/*
* Sort left and right parts recursively.
* All elements from center part are equal
* and, therefore, already sorted.
*/
SortingLongTestJMH.sort(a, left, less - 1, leftmost);
SortingLongTestJMH.sort(a, great + 1, right, false);
}
}
private static void swap(long[] arr, int i, int j) {
long tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}

View file

@ -0,0 +1,358 @@
/*
* Copyright 2015 Goldman Sachs.
* Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8154049
* @summary Tests the sorting of a large array of sorted primitive values,
* predominently for cases where the array is nearly sorted. This tests
* code that detects patterns in the array to determine if it is nearly
* sorted and if so employs and optimizes merge sort rather than a
* Dual-Pivot QuickSort.
*
* @run junit SortingNearlySortedPrimitive
*/
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.StringJoiner;
import java.util.function.IntFunction;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class SortingNearlySortedPrimitive {
static final int BASE = 3;
static final int WIDTH = 4;
// Should be > DualPivotQuicksort.QUICKSORT_THRESHOLD
static final int PAD = 300;
Stream<int[]> createCombinations() {
// Create all combinations for the BASE value and double the WIDTH
// elements
// This is create various combinations of ascending, descending and
// equal runs to exercise the nearly sorted code paths
return IntStream.range(0, (int) Math.pow(BASE, 2 * WIDTH)).
mapToObj(this::createArray);
}
// Create an array which at either end is filled with -ve and +ve elements
// according to the base value and padded with zeros in between
int[] createArray(int v) {
int[] a = new int[WIDTH + PAD + WIDTH];
// Fill head of array
for (int j = 0; j < WIDTH; j++) {
a[j] = (v % BASE) - (BASE / 2);
v /= BASE;
}
// Fill tail of array
for (int j = 0; j < WIDTH; j++) {
a[WIDTH + PAD + j] = (v % BASE) - (BASE / 2);
v /= BASE;
}
return a;
}
@Test
public void testCombination() {
createCombinations().forEach(a -> {
try {
// Clone source array to ensure it is not modified
this.sortAndAssert(a.clone());
this.sortAndAssert(floatCopyFromInt(a));
this.sortAndAssert(doubleCopyFromInt(a));
this.sortAndAssert(longCopyFromInt(a));
this.sortAndAssert(shortCopyFromInt(a));
this.sortAndAssert(charCopyFromInt(a));
} catch (AssertionError sae) {
AssertionError ae = new AssertionError("Sort failed for " + arrayToString(a));
ae.addSuppressed(sae);
throw ae;
}
});
}
String arrayToString(int[] a) {
int[] l = Arrays.copyOfRange(a, 0, WIDTH + 2);
int[] r = Arrays.copyOfRange(a, a.length - (WIDTH + 2), a.length);
StringJoiner sj = new StringJoiner(",", "[", "]");
for (int i : l) {
sj.add(Integer.toString(i));
}
sj.add("...");
for (int i : r) {
sj.add(Integer.toString(i));
}
return sj.toString();
}
public Object[][] createShapes() {
Stream<List<Object>> baseCases = Stream.of(
List.of("hiZeroLowTest", (IntFunction<int[]>) this::hiZeroLowData),
List.of("endLessThanTest", (IntFunction<int[]>) this::endLessThanData),
List.of("highFlatLowTest", (IntFunction<int[]>) this::highFlatLowData),
List.of("identicalTest", (IntFunction<int[]>) this::identicalData),
List.of("sortedReversedSortedTest", (IntFunction<int[]>) this::sortedReversedSortedData),
List.of("pairFlipTest", (IntFunction<int[]>) this::pairFlipData),
List.of("zeroHiTest", (IntFunction<int[]>) this::zeroHiData)
);
// Ensure the following inequality holds for certain sizes
// DualPivotQuicksort.QUICKSORT_THRESHOLD <= size - 1
// < DualPivotQuicksort.COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR
// This guarantees that code paths are taken for checking nearly sorted
// arrays for all primitive types
List<Integer> sizes = List.of(100, 1_000, 10_000, 1_000_000);
return baseCases.
flatMap(l -> sizes.stream().map(s -> append(l, s))).
toArray(Object[][]::new);
}
Object[] append(List<Object> l, Object value) {
List<Object> nl = new ArrayList<>(l);
nl.add(value);
return nl.toArray();
}
@ParameterizedTest
@MethodSource("createShapes")
public void testShapes(String testName, IntFunction<int[]> dataMethod, int size) {
int[] intSourceArray = dataMethod.apply(size);
// Clone source array to ensure it is not modified
this.sortAndAssert(intSourceArray.clone());
this.sortAndAssert(floatCopyFromInt(intSourceArray));
this.sortAndAssert(doubleCopyFromInt(intSourceArray));
this.sortAndAssert(longCopyFromInt(intSourceArray));
this.sortAndAssert(shortCopyFromInt(intSourceArray));
this.sortAndAssert(charCopyFromInt(intSourceArray));
}
private float[] floatCopyFromInt(int[] src) {
float[] result = new float[src.length];
for (int i = 0; i < result.length; i++) {
result[i] = src[i];
}
return result;
}
private double[] doubleCopyFromInt(int[] src) {
double[] result = new double[src.length];
for (int i = 0; i < result.length; i++) {
result[i] = src[i];
}
return result;
}
private long[] longCopyFromInt(int[] src) {
long[] result = new long[src.length];
for (int i = 0; i < result.length; i++) {
result[i] = src[i];
}
return result;
}
private short[] shortCopyFromInt(int[] src) {
short[] result = new short[src.length];
for (int i = 0; i < result.length; i++) {
result[i] = (short) src[i];
}
return result;
}
private char[] charCopyFromInt(int[] src) {
char[] result = new char[src.length];
for (int i = 0; i < result.length; i++) {
result[i] = (char) src[i];
}
return result;
}
private void sortAndAssert(int[] array) {
Arrays.sort(array);
for (int i = 1; i < array.length; i++) {
if (array[i] < array[i - 1]) {
throw new AssertionError("not sorted");
}
}
}
private void sortAndAssert(char[] array) {
Arrays.sort(array);
for (int i = 1; i < array.length; i++) {
if (array[i] < array[i - 1]) {
throw new AssertionError("not sorted");
}
}
}
private void sortAndAssert(short[] array) {
Arrays.sort(array);
for (int i = 1; i < array.length; i++) {
if (array[i] < array[i - 1]) {
throw new AssertionError("not sorted");
}
}
}
private void sortAndAssert(double[] array) {
Arrays.sort(array);
for (int i = 1; i < array.length; i++) {
if (array[i] < array[i - 1]) {
throw new AssertionError("not sorted");
}
}
}
private void sortAndAssert(float[] array) {
Arrays.sort(array);
for (int i = 1; i < array.length; i++) {
if (array[i] < array[i - 1]) {
throw new AssertionError("not sorted");
}
}
}
private void sortAndAssert(long[] array) {
Arrays.sort(array);
for (int i = 1; i < array.length; i++) {
if (array[i] < array[i - 1]) {
throw new AssertionError("not sorted");
}
}
}
private int[] zeroHiData(int size) {
int[] array = new int[size];
int threeQuarters = (int) (size * 0.75);
for (int i = 0; i < threeQuarters; i++) {
array[i] = 0;
}
int k = 1;
for (int i = threeQuarters; i < size; i++) {
array[i] = k;
k++;
}
return array;
}
private int[] hiZeroLowData(int size) {
int[] array = new int[size];
int oneThird = size / 3;
for (int i = 0; i < oneThird; i++) {
array[i] = i;
}
int twoThirds = oneThird * 2;
for (int i = oneThird; i < twoThirds; i++) {
array[i] = 0;
}
for (int i = twoThirds; i < size; i++) {
array[i] = oneThird - i + twoThirds;
}
return array;
}
private int[] highFlatLowData(int size) {
int[] array = new int[size];
int oneThird = size / 3;
for (int i = 0; i < oneThird; i++) {
array[i] = i;
}
int twoThirds = oneThird * 2;
int constant = oneThird - 1;
for (int i = oneThird; i < twoThirds; i++) {
array[i] = constant;
}
for (int i = twoThirds; i < size; i++) {
array[i] = constant - i + twoThirds;
}
return array;
}
private int[] identicalData(int size) {
int[] array = new int[size];
int listNumber = 24;
for (int i = 0; i < size; i++) {
array[i] = listNumber;
}
return array;
}
private int[] endLessThanData(int size) {
int[] array = new int[size];
for (int i = 0; i < size - 1; i++) {
array[i] = 3;
}
array[size - 1] = 1;
return array;
}
private int[] sortedReversedSortedData(int size) {
int[] array = new int[size];
for (int i = 0; i < size / 2; i++) {
array[i] = i;
}
int num = 0;
for (int i = size / 2; i < size; i++) {
array[i] = size - num;
num++;
}
return array;
}
private int[] pairFlipData(int size) {
int[] array = new int[size];
for (int i = 0; i < size; i++) {
array[i] = i;
}
for (int i = 0; i < size; i += 2) {
int temp = array[i];
array[i] = array[i + 1];
array[i + 1] = temp;
}
return array;
}
}

View file

@ -0,0 +1,136 @@
/*
* Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8037857
* @summary tests for stream and spliterator factory methods
* @run junit StreamAndSpliterator
*/
import java.util.Arrays;
import java.util.Spliterators;
import static org.junit.jupiter.api.Assertions.assertThrows;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.function.Executable;
public class StreamAndSpliterator {
@Test
public void testStreamNPEs() {
assertThrowsNPE(() -> Arrays.stream((int[]) null, 0, 0));
assertThrowsNPE(() -> Arrays.stream((long[]) null, 0, 0));
assertThrowsNPE(() -> Arrays.stream((double[]) null, 0, 0));
assertThrowsNPE(() -> Arrays.stream((String[]) null, 0, 0));
}
@Test
public void testStreamAIOBEs() {
// origin > fence
assertThrowsAIOOB(() -> Arrays.stream(new int[]{}, 1, 0));
assertThrowsAIOOB(() -> Arrays.stream(new long[]{}, 1, 0));
assertThrowsAIOOB(() -> Arrays.stream(new double[]{}, 1, 0));
assertThrowsAIOOB(() -> Arrays.stream(new String[]{}, 1, 0));
// bad origin
assertThrowsAIOOB(() -> Arrays.stream(new int[]{}, -1, 0));
assertThrowsAIOOB(() -> Arrays.stream(new long[]{}, -1, 0));
assertThrowsAIOOB(() -> Arrays.stream(new double[]{}, -1, 0));
assertThrowsAIOOB(() -> Arrays.stream(new String[]{}, -1, 0));
// bad fence
assertThrowsAIOOB(() -> Arrays.stream(new int[]{}, 0, 1));
assertThrowsAIOOB(() -> Arrays.stream(new long[]{}, 0, 1));
assertThrowsAIOOB(() -> Arrays.stream(new double[]{}, 0, 1));
assertThrowsAIOOB(() -> Arrays.stream(new String[]{}, 0, 1));
}
@Test
public void testSpliteratorNPEs() {
assertThrowsNPE(() -> Arrays.spliterator((int[]) null, 0, 0));
assertThrowsNPE(() -> Arrays.spliterator((long[]) null, 0, 0));
assertThrowsNPE(() -> Arrays.spliterator((double[]) null, 0, 0));
assertThrowsNPE(() -> Arrays.spliterator((String[]) null, 0, 0));
}
@Test
public void testSpliteratorAIOBEs() {
// origin > fence
assertThrowsAIOOB(() -> Arrays.spliterator(new int[]{}, 1, 0));
assertThrowsAIOOB(() -> Arrays.spliterator(new long[]{}, 1, 0));
assertThrowsAIOOB(() -> Arrays.spliterator(new double[]{}, 1, 0));
assertThrowsAIOOB(() -> Arrays.spliterator(new String[]{}, 1, 0));
// bad origin
assertThrowsAIOOB(() -> Arrays.spliterator(new int[]{}, -1, 0));
assertThrowsAIOOB(() -> Arrays.spliterator(new long[]{}, -1, 0));
assertThrowsAIOOB(() -> Arrays.spliterator(new double[]{}, -1, 0));
assertThrowsAIOOB(() -> Arrays.spliterator(new String[]{}, -1, 0));
// bad fence
assertThrowsAIOOB(() -> Arrays.spliterator(new int[]{}, 0, 1));
assertThrowsAIOOB(() -> Arrays.spliterator(new long[]{}, 0, 1));
assertThrowsAIOOB(() -> Arrays.spliterator(new double[]{}, 0, 1));
assertThrowsAIOOB(() -> Arrays.spliterator(new String[]{}, 0, 1));
}
@Test
public void testSpliteratorNPEsFromSpliterators() {
assertThrowsNPE(() -> Spliterators.spliterator((int[]) null, 0, 0, 0));
assertThrowsNPE(() -> Spliterators.spliterator((long[]) null, 0, 0, 0));
assertThrowsNPE(() -> Spliterators.spliterator((double[]) null, 0, 0, 0));
assertThrowsNPE(() -> Spliterators.spliterator((String[]) null, 0, 0, 0));
}
@Test
public void testSpliteratorAIOBEsFromSpliterators() {
// origin > fence
assertThrowsAIOOB(() -> Spliterators.spliterator(new int[]{}, 1, 0, 0));
assertThrowsAIOOB(() -> Spliterators.spliterator(new long[]{}, 1, 0, 0));
assertThrowsAIOOB(() -> Spliterators.spliterator(new double[]{}, 1, 0, 0));
assertThrowsAIOOB(() -> Spliterators.spliterator(new String[]{}, 1, 0, 0));
// bad origin
assertThrowsAIOOB(() -> Spliterators.spliterator(new int[]{}, -1, 0, 0));
assertThrowsAIOOB(() -> Spliterators.spliterator(new long[]{}, -1, 0, 0));
assertThrowsAIOOB(() -> Spliterators.spliterator(new double[]{}, -1, 0, 0));
assertThrowsAIOOB(() -> Spliterators.spliterator(new String[]{}, -1, 0, 0));
// bad fence
assertThrowsAIOOB(() -> Spliterators.spliterator(new int[]{}, 0, 1, 0));
assertThrowsAIOOB(() -> Spliterators.spliterator(new long[]{}, 0, 1, 0));
assertThrowsAIOOB(() -> Spliterators.spliterator(new double[]{}, 0, 1, 0));
assertThrowsAIOOB(() -> Spliterators.spliterator(new String[]{}, 0, 1, 0));
}
void assertThrowsNPE(Executable r) {
assertThrows(NullPointerException.class, r);
}
void assertThrowsAIOOB(Executable r) {
assertThrows(ArrayIndexOutOfBoundsException.class, r);
}
}

View file

@ -0,0 +1 @@
disallowedActions=testng

View file

@ -0,0 +1,116 @@
/*
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8011944
* @summary Test TimSort stack size
*/
import java.util.Arrays;
import java.util.ArrayDeque;
public class TimSortStackSize {
public static void main(String[] args) {
testComparableTimSort();
testTimSort();
}
static void testComparableTimSort() {
System.out.printf("testComparableTimSort()%n");
Arrays.sort(genData());
}
static void testTimSort() {
System.out.printf("testTimSort()%n");
Arrays.sort(genData(), Integer::compare);
}
private static final int MIN = 16;
private static final int BOUND1 = 2 * MIN + 1;
private static final int BOUND2 = BOUND1 + MIN + 2;
private static final int BOUND3 = BOUND1 + 1 + BOUND2;
private static final int BOUND4 = BOUND2 + 1 + BOUND3;
private static final int BOUND5 = BOUND3 + 1 + BOUND4;
static int build(int size, int B, ArrayDeque<Integer> chunks) {
chunks.addFirst(B);
if (size < BOUND1) {
chunks.addFirst(size);
return size;
}
int asize = (size + 2) / 2;
if (size >= BOUND2 && asize < BOUND1) {
asize = BOUND1;
} else if (size >= BOUND3 && asize < BOUND2) {
asize = BOUND2;
} else if (size >= BOUND4 && asize < BOUND3) {
asize = BOUND3;
} else if (size >= BOUND5 && asize < BOUND4) {
asize = BOUND4;
}
if (size - asize >= B) {
throw new AssertionError(" " + size + " , " + asize + " , " + B);
}
return build(asize, size - asize, chunks);
}
static Integer[] genData() {
ArrayDeque<Integer> chunks = new ArrayDeque<Integer>();
chunks.addFirst(MIN);
int B = MIN + 4;
int A = B + MIN + 1;
for (int i = 0; i < 8; i++) {
int eps = build(A, B, chunks);
B = B + A + 1;
A = B + eps + 1;
}
chunks.addFirst(B);
chunks.addFirst(A);
int total = 0;
for (Integer len : chunks) {
total += len;
}
int pow = MIN;
while (pow < total) {
pow += pow;
}
chunks.addLast(pow - total);
System.out.println(" Total: " + total);
Integer[] array = new Integer[pow];
int off = 0;
int pos = 0;
for (Integer len : chunks) {
for (int i = 0; i < len; i++) {
array[pos++] = Integer.valueOf(i == 0 ? 0 : 1);
}
off++;
}
return array;
}
}

View file

@ -0,0 +1,214 @@
/*
* Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8072909
* @summary Test TimSort stack size on big arrays
* @library /test/lib
* @modules java.management
* @requires (vm.debug == false)
* @build TimSortStackSize2
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
* -XX:+WhiteBoxAPI TimSortStackSize2
*/
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.process.ProcessTools;
import jdk.test.whitebox.WhiteBox;
public class TimSortStackSize2 {
public static void main(String[] args) {
if ( args == null || args.length == 0 ){
startMeWithArgs();
} else {
doTestOfTwoTimSorts(Integer.parseInt(args[0]));
}
}
private static void startMeWithArgs(){
/*
* big tests not for regular execution on all platforms:
* run main/othervm -Xmx8g TimSortStackSize2 1073741824
* run main/othervm -Xmx16g TimSortStackSize2 2147483644
*/
try {
Boolean compressedOops = WhiteBox.getWhiteBox()
.getBooleanVMFlag("UseCompressedOops");
long memory = (compressedOops == null || compressedOops) ? 385 : 770;
final String xmsValue = "-Xms" + memory + "m";
final String xmxValue = "-Xmx" + 2 * memory + "m";
System.out.printf("compressedOops: %s; Test will be started with \"%s %s\"%n",
compressedOops, xmsValue, xmxValue);
OutputAnalyzer output = ProcessTools.executeTestJava(xmsValue,
xmxValue,
"TimSortStackSize2",
"67108864");
System.out.println(output.getOutput());
output.shouldHaveExitValue(0);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
private static void doTestOfTwoTimSorts(final int lengthOfTest){
boolean passed = doTest("TimSort", lengthOfTest,
(Integer [] a) -> Arrays.sort(a));
passed = doTest("ComparableTimSort", lengthOfTest, (Integer [] a) ->
Arrays.sort(a, (Object first, Object second) -> {
return ((Comparable<Object>)first).compareTo(second);
}))
&& passed;
if ( !passed ){
throw new RuntimeException();
}
}
private static boolean doTest(final String msg, final int lengthOfTest,
final Consumer<Integer[]> c){
Integer [] a = null;
try {
a = new TimSortStackSize2(lengthOfTest).createArray();
long begin = System.nanoTime();
c.accept(a);
long end = System.nanoTime();
System.out.println(msg + " OK. Time: " + (end - begin) + "ns");
} catch (ArrayIndexOutOfBoundsException e){
System.out.println(msg + " broken:");
e.printStackTrace();
return false;
} finally {
a = null;
}
return true;
}
private static final int MIN_MERGE = 32;
private final int minRun;
private final int length;
private final List<Long> runs = new ArrayList<Long>();
public TimSortStackSize2(final int len) {
this.length = len;
minRun = minRunLength(len);
fillRunsJDKWorstCase();
}
private static int minRunLength(int n) {
assert n >= 0;
int r = 0; // Becomes 1 if any 1 bits are shifted off
while (n >= MIN_MERGE) {
r |= (n & 1);
n >>= 1;
}
return n + r;
}
/**
* Adds a sequence x_1, ..., x_n of run lengths to <code>runs</code> such that:<br>
* 1. X = x_1 + ... + x_n <br>
* 2. x_j >= minRun for all j <br>
* 3. x_1 + ... + x_{j-2} < x_j < x_1 + ... + x_{j-1} for all j <br>
* These conditions guarantee that TimSort merges all x_j's one by one
* (resulting in X) using only merges on the second-to-last element.
* @param X The sum of the sequence that should be added to runs.
*/
private void generateJDKWrongElem(long X) {
for(long newTotal; X >= 2 * minRun + 1; X = newTotal) {
//Default strategy
newTotal = X / 2 + 1;
//Specialized strategies
if(3 * minRun + 3 <= X && X <= 4*minRun+1) {
// add x_1=MIN+1, x_2=MIN, x_3=X-newTotal to runs
newTotal = 2 * minRun + 1;
} else if (5 * minRun + 5 <= X && X <= 6 * minRun + 5) {
// add x_1=MIN+1, x_2=MIN, x_3=MIN+2, x_4=X-newTotal to runs
newTotal = 3 * minRun + 3;
} else if (8 * minRun + 9 <= X && X <= 10 * minRun + 9) {
// add x_1=MIN+1, x_2=MIN, x_3=MIN+2, x_4=2MIN+2, x_5=X-newTotal to runs
newTotal = 5 * minRun + 5;
} else if (13 * minRun + 15 <= X && X <= 16 * minRun + 17) {
// add x_1=MIN+1, x_2=MIN, x_3=MIN+2, x_4=2MIN+2, x_5=3MIN+4, x_6=X-newTotal to runs
newTotal = 8 * minRun + 9;
}
runs.add(0, X - newTotal);
}
runs.add(0, X);
}
/**
* Fills <code>runs</code> with a sequence of run lengths of the form<br>
* Y_n x_{n,1} x_{n,2} ... x_{n,l_n} <br>
* Y_{n-1} x_{n-1,1} x_{n-1,2} ... x_{n-1,l_{n-1}} <br>
* ... <br>
* Y_1 x_{1,1} x_{1,2} ... x_{1,l_1}<br>
* The Y_i's are chosen to satisfy the invariant throughout execution,
* but the x_{i,j}'s are merged (by <code>TimSort.mergeCollapse</code>)
* into an X_i that violates the invariant.
* X is the sum of all run lengths that will be added to <code>runs</code>.
*/
private void fillRunsJDKWorstCase() {
long runningTotal = 0;
long Y = minRun + 4;
long X = minRun;
while (runningTotal + Y + X <= length) {
runningTotal += X + Y;
generateJDKWrongElem(X);
runs.add(0, Y);
// X_{i+1} = Y_i + x_{i,1} + 1, since runs.get(1) = x_{i,1}
X = Y + runs.get(1) + 1;
// Y_{i+1} = X_{i+1} + Y_i + 1
Y += X + 1;
}
if (runningTotal + X <= length) {
runningTotal += X;
generateJDKWrongElem(X);
}
runs.add(length - runningTotal);
}
private Integer [] createArray() {
Integer [] a = new Integer[length];
Arrays.fill(a, 0);
int endRun = -1;
for (long len : runs) {
a[endRun += len] = 1;
}
a[length - 1] = 0;
return a;
}
}

View file

@ -0,0 +1,350 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.util;
/**
* This class provides access to package-private
* methods of DualPivotQuicksort class.
*
* @author Vladimir Yaroslavskiy
*
* @version 2019.09.19
*
* @since 14
*/
public enum SortingHelper {
DUAL_PIVOT_QUICKSORT("Dual-Pivot Quicksort") {
@Override
public void sort(Object a) {
if (a instanceof int[]) {
DualPivotQuicksort.sort((int[]) a, SEQUENTIAL, 0, ((int[]) a).length);
} else if (a instanceof long[]) {
DualPivotQuicksort.sort((long[]) a, SEQUENTIAL, 0, ((long[]) a).length);
} else if (a instanceof byte[]) {
DualPivotQuicksort.sort((byte[]) a, 0, ((byte[]) a).length);
} else if (a instanceof char[]) {
DualPivotQuicksort.sort((char[]) a, SEQUENTIAL, 0, ((char[]) a).length);
} else if (a instanceof short[]) {
DualPivotQuicksort.sort((short[]) a, SEQUENTIAL, 0, ((short[]) a).length);
} else if (a instanceof float[]) {
DualPivotQuicksort.sort((float[]) a, SEQUENTIAL, 0, ((float[]) a).length);
} else if (a instanceof double[]) {
DualPivotQuicksort.sort((double[]) a, SEQUENTIAL, 0, ((double[]) a).length);
} else {
fail(a);
}
}
@Override
public void sort(Object a, int low, int high) {
if (a instanceof int[]) {
DualPivotQuicksort.sort((int[]) a, SEQUENTIAL, low, high);
} else if (a instanceof long[]) {
DualPivotQuicksort.sort((long[]) a, SEQUENTIAL, low, high);
} else if (a instanceof byte[]) {
DualPivotQuicksort.sort((byte[]) a, low, high);
} else if (a instanceof char[]) {
DualPivotQuicksort.sort((char[]) a, SEQUENTIAL, low, high);
} else if (a instanceof short[]) {
DualPivotQuicksort.sort((short[]) a, SEQUENTIAL, low, high);
} else if (a instanceof float[]) {
DualPivotQuicksort.sort((float[]) a, SEQUENTIAL, low, high);
} else if (a instanceof double[]) {
DualPivotQuicksort.sort((double[]) a, SEQUENTIAL, low, high);
} else {
fail(a);
}
}
@Override
public void sort(Object[] a) {
fail(a);
}
@Override
public void sort(Object[] a, Comparator comparator) {
fail(a);
}
},
PARALLEL_SORT("Parallel sort") {
@Override
public void sort(Object a) {
if (a instanceof int[]) {
DualPivotQuicksort.sort((int[]) a, PARALLEL, 0, ((int[]) a).length);
} else if (a instanceof long[]) {
DualPivotQuicksort.sort((long[]) a, PARALLEL, 0, ((long[]) a).length);
} else if (a instanceof byte[]) {
DualPivotQuicksort.sort((byte[]) a, 0, ((byte[]) a).length);
} else if (a instanceof char[]) {
DualPivotQuicksort.sort((char[]) a, PARALLEL, 0, ((char[]) a).length);
} else if (a instanceof short[]) {
DualPivotQuicksort.sort((short[]) a, PARALLEL, 0, ((short[]) a).length);
} else if (a instanceof float[]) {
DualPivotQuicksort.sort((float[]) a, PARALLEL, 0, ((float[]) a).length);
} else if (a instanceof double[]) {
DualPivotQuicksort.sort((double[]) a, PARALLEL, 0, ((double[]) a).length);
} else {
fail(a);
}
}
@Override
public void sort(Object a, int low, int high) {
if (a instanceof int[]) {
DualPivotQuicksort.sort((int[]) a, PARALLEL, low, high);
} else if (a instanceof long[]) {
DualPivotQuicksort.sort((long[]) a, PARALLEL, low, high);
} else if (a instanceof byte[]) {
DualPivotQuicksort.sort((byte[]) a, low, high);
} else if (a instanceof char[]) {
DualPivotQuicksort.sort((char[]) a, PARALLEL, low, high);
} else if (a instanceof short[]) {
DualPivotQuicksort.sort((short[]) a, PARALLEL, low, high);
} else if (a instanceof float[]) {
DualPivotQuicksort.sort((float[]) a, PARALLEL, low, high);
} else if (a instanceof double[]) {
DualPivotQuicksort.sort((double[]) a, PARALLEL, low, high);
} else {
fail(a);
}
}
@Override
public void sort(Object[] a) {
fail(a);
}
@Override
public void sort(Object[] a, Comparator comparator) {
fail(a);
}
},
HEAP_SORT("Heap sort") {
@Override
public void sort(Object a) {
if (a instanceof int[]) {
DualPivotQuicksort.sort(null, (int[]) a, BIG_DEPTH, 0, ((int[]) a).length);
} else if (a instanceof long[]) {
DualPivotQuicksort.sort(null, (long[]) a, BIG_DEPTH, 0, ((long[]) a).length);
} else if (a instanceof byte[]) {
DualPivotQuicksort.sort((byte[]) a, 0, ((byte[]) a).length);
} else if (a instanceof char[]) {
DualPivotQuicksort.sort((char[]) a, BIG_DEPTH, 0, ((char[]) a).length);
} else if (a instanceof short[]) {
DualPivotQuicksort.sort((short[]) a, BIG_DEPTH, 0, ((short[]) a).length);
} else if (a instanceof float[]) {
DualPivotQuicksort.sort(null, (float[]) a, BIG_DEPTH, 0, ((float[]) a).length);
} else if (a instanceof double[]) {
DualPivotQuicksort.sort(null, (double[]) a, BIG_DEPTH, 0, ((double[]) a).length);
} else {
fail(a);
}
}
@Override
public void sort(Object a, int low, int high) {
if (a instanceof int[]) {
DualPivotQuicksort.sort(null, (int[]) a, BIG_DEPTH, low, high);
} else if (a instanceof long[]) {
DualPivotQuicksort.sort(null, (long[]) a, BIG_DEPTH, low, high);
} else if (a instanceof byte[]) {
DualPivotQuicksort.sort((byte[]) a, low, high);
} else if (a instanceof char[]) {
DualPivotQuicksort.sort((char[]) a, BIG_DEPTH, low, high);
} else if (a instanceof short[]) {
DualPivotQuicksort.sort((short[]) a, BIG_DEPTH, low, high);
} else if (a instanceof float[]) {
DualPivotQuicksort.sort(null, (float[]) a, BIG_DEPTH, low, high);
} else if (a instanceof double[]) {
DualPivotQuicksort.sort(null, (double[]) a, BIG_DEPTH, low, high);
} else {
fail(a);
}
}
@Override
public void sort(Object[] a) {
fail(a);
}
@Override
public void sort(Object[] a, Comparator comparator) {
fail(a);
}
},
ARRAYS_SORT("Arrays.sort") {
@Override
public void sort(Object a) {
if (a instanceof int[]) {
Arrays.sort((int[]) a);
} else if (a instanceof long[]) {
Arrays.sort((long[]) a);
} else if (a instanceof byte[]) {
Arrays.sort((byte[]) a);
} else if (a instanceof char[]) {
Arrays.sort((char[]) a);
} else if (a instanceof short[]) {
Arrays.sort((short[]) a);
} else if (a instanceof float[]) {
Arrays.sort((float[]) a);
} else if (a instanceof double[]) {
Arrays.sort((double[]) a);
} else {
fail(a);
}
}
@Override
public void sort(Object a, int low, int high) {
if (a instanceof int[]) {
Arrays.sort((int[]) a, low, high);
} else if (a instanceof long[]) {
Arrays.sort((long[]) a, low, high);
} else if (a instanceof byte[]) {
Arrays.sort((byte[]) a, low, high);
} else if (a instanceof char[]) {
Arrays.sort((char[]) a, low, high);
} else if (a instanceof short[]) {
Arrays.sort((short[]) a, low, high);
} else if (a instanceof float[]) {
Arrays.sort((float[]) a, low, high);
} else if (a instanceof double[]) {
Arrays.sort((double[]) a, low, high);
} else {
fail(a);
}
}
@Override
public void sort(Object[] a) {
Arrays.sort(a);
}
@Override
@SuppressWarnings("unchecked")
public void sort(Object[] a, Comparator comparator) {
Arrays.sort(a, comparator);
}
},
ARRAYS_PARALLEL_SORT("Arrays.parallelSort") {
@Override
public void sort(Object a) {
if (a instanceof int[]) {
Arrays.parallelSort((int[]) a);
} else if (a instanceof long[]) {
Arrays.parallelSort((long[]) a);
} else if (a instanceof byte[]) {
Arrays.parallelSort((byte[]) a);
} else if (a instanceof char[]) {
Arrays.parallelSort((char[]) a);
} else if (a instanceof short[]) {
Arrays.parallelSort((short[]) a);
} else if (a instanceof float[]) {
Arrays.parallelSort((float[]) a);
} else if (a instanceof double[]) {
Arrays.parallelSort((double[]) a);
} else {
fail(a);
}
}
@Override
public void sort(Object a, int low, int high) {
if (a instanceof int[]) {
Arrays.parallelSort((int[]) a, low, high);
} else if (a instanceof long[]) {
Arrays.parallelSort((long[]) a, low, high);
} else if (a instanceof byte[]) {
Arrays.parallelSort((byte[]) a, low, high);
} else if (a instanceof char[]) {
Arrays.parallelSort((char[]) a, low, high);
} else if (a instanceof short[]) {
Arrays.parallelSort((short[]) a, low, high);
} else if (a instanceof float[]) {
Arrays.parallelSort((float[]) a, low, high);
} else if (a instanceof double[]) {
Arrays.parallelSort((double[]) a, low, high);
} else {
fail(a);
}
}
@Override
@SuppressWarnings("unchecked")
public void sort(Object[] a) {
Arrays.parallelSort((Comparable[]) a);
}
@Override
@SuppressWarnings("unchecked")
public void sort(Object[] a, Comparator comparator) {
Arrays.parallelSort(a, comparator);
}
};
abstract public void sort(Object a);
abstract public void sort(Object a, int low, int high);
abstract public void sort(Object[] a);
abstract public void sort(Object[] a, Comparator comparator);
private SortingHelper(String name) {
this.name = name;
}
@Override
public String toString() {
return name;
}
private static void fail(Object a) {
throw new RuntimeException("Unexpected type of array: " + a.getClass().getName());
}
private String name;
/**
* Parallelism level for sequential and parallel sorting.
*/
private static final int SEQUENTIAL = 0;
private static final int PARALLEL = 87;
/**
* Heap sort will be invoked, if recursion depth is too big.
* Value is taken from DualPivotQuicksort.MAX_RECURSION_DEPTH.
*/
private static final int BIG_DEPTH = 64 * (3 << 1);
}

View file

@ -0,0 +1,313 @@
/*
* Copyright (c) 2013, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8014076 8025067
* @summary unit test for Arrays.ParallelPrefix().
* @modules java.management jdk.management
* @run junit/othervm -Xms256m -Xmx1024m ParallelPrefix
*/
import java.lang.management.ManagementFactory;
import java.util.Arrays;
import java.util.function.BinaryOperator;
import java.util.function.DoubleBinaryOperator;
import java.util.function.Function;
import java.util.function.IntBinaryOperator;
import java.util.function.LongBinaryOperator;
import java.util.stream.IntStream;
import java.util.stream.LongStream;
import com.sun.management.OperatingSystemMXBean;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.function.Executable;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class ParallelPrefix {
//Array size less than MIN_PARTITION
private static final int SMALL_ARRAY_SIZE = 1 << 3;
//Array size equals MIN_PARTITION
private static final int THRESHOLD_ARRAY_SIZE = 1 << 4;
//Array size greater than MIN_PARTITION
private static final int MEDIUM_ARRAY_SIZE = 1 << 8;
//Array size much greater than MIN_PARTITION
private static final int LARGE_ARRAY_SIZE = 1 << 14;
private static int[] arraySizeCollection;
@BeforeAll
public static void setup() {
java.lang.management.OperatingSystemMXBean bean =
ManagementFactory.getOperatingSystemMXBean();
if (bean instanceof OperatingSystemMXBean) {
OperatingSystemMXBean os = (OperatingSystemMXBean)bean;
long physicalMemorySize = os.getTotalPhysicalMemorySize() / (1024 * 1024);
System.out.println("System memory size: " + physicalMemorySize + "M");
// when we can get system memory size, and it's larger than 2G,
// then we enable large array size test below,
// else disable large array size test below.
if (physicalMemorySize > (2 * 1024)) {
arraySizeCollection = new int[]{
SMALL_ARRAY_SIZE,
THRESHOLD_ARRAY_SIZE,
MEDIUM_ARRAY_SIZE,
LARGE_ARRAY_SIZE
};
System.out.println("System memory is large enough, add large array size test");
return;
}
}
arraySizeCollection = new int[]{
SMALL_ARRAY_SIZE,
THRESHOLD_ARRAY_SIZE,
MEDIUM_ARRAY_SIZE
};
System.out.println("System memory is not large enough, remove large array size test");
}
public static Object[][] intSet(){
return genericData(size -> IntStream.range(0, size).toArray(),
new IntBinaryOperator[]{
Integer::sum,
Integer::min});
}
public static Object[][] longSet(){
return genericData(size -> LongStream.range(0, size).toArray(),
new LongBinaryOperator[]{
Long::sum,
Long::min});
}
public static Object[][] doubleSet(){
return genericData(size -> IntStream.range(0, size).mapToDouble(i -> (double)i).toArray(),
new DoubleBinaryOperator[]{
Double::sum,
Double::min});
}
public static Object[][] stringSet(){
Function<Integer, String[]> stringsFunc = size ->
IntStream.range(0, size).mapToObj(Integer::toString).toArray(String[]::new);
BinaryOperator<String> concat = String::concat;
return genericData(stringsFunc,
(BinaryOperator<String>[]) new BinaryOperator[]{
concat });
}
private static <T, OPS> Object[][] genericData(Function<Integer, T> generateFunc, OPS[] ops) {
//test arrays which size is equals n-1, n, n+1, test random data
Object[][] data = new Object[arraySizeCollection.length * 3 * ops.length][4];
for(int n = 0; n < arraySizeCollection.length; n++ ) {
for(int testValue = -1 ; testValue <= 1; testValue++) {
int array_size = arraySizeCollection[n] + testValue;
for(int opsN = 0; opsN < ops.length; opsN++) {
int index = n * 3 * ops.length + (testValue + 1) * ops.length + opsN;
data[index][0] = generateFunc.apply(array_size);
data[index][1] = array_size / 3;
data[index][2] = 2 * array_size / 3;
data[index][3] = ops[opsN];
}
}
}
return data;
}
@ParameterizedTest
@MethodSource("intSet")
public void testParallelPrefixForInt(int[] data, int fromIndex, int toIndex, IntBinaryOperator op) {
int[] sequentialResult = data.clone();
for (int index = fromIndex + 1; index < toIndex; index++) {
sequentialResult[index ] = op.applyAsInt(sequentialResult[index - 1], sequentialResult[index]);
}
int[] parallelResult = data.clone();
Arrays.parallelPrefix(parallelResult, fromIndex, toIndex, op);
assertArraysEqual(sequentialResult, parallelResult);
int[] parallelRangeResult = Arrays.copyOfRange(data, fromIndex, toIndex);
Arrays.parallelPrefix(parallelRangeResult, op);
assertArraysEqual(Arrays.copyOfRange(sequentialResult, fromIndex, toIndex), parallelRangeResult);
}
@ParameterizedTest
@MethodSource("longSet")
public void testParallelPrefixForLong(long[] data, int fromIndex, int toIndex, LongBinaryOperator op) {
long[] sequentialResult = data.clone();
for (int index = fromIndex + 1; index < toIndex; index++) {
sequentialResult[index ] = op.applyAsLong(sequentialResult[index - 1], sequentialResult[index]);
}
long[] parallelResult = data.clone();
Arrays.parallelPrefix(parallelResult, fromIndex, toIndex, op);
assertArraysEqual(sequentialResult, parallelResult);
long[] parallelRangeResult = Arrays.copyOfRange(data, fromIndex, toIndex);
Arrays.parallelPrefix(parallelRangeResult, op);
assertArraysEqual(Arrays.copyOfRange(sequentialResult, fromIndex, toIndex), parallelRangeResult);
}
@ParameterizedTest
@MethodSource("doubleSet")
public void testParallelPrefixForDouble(double[] data, int fromIndex, int toIndex, DoubleBinaryOperator op) {
double[] sequentialResult = data.clone();
for (int index = fromIndex + 1; index < toIndex; index++) {
sequentialResult[index ] = op.applyAsDouble(sequentialResult[index - 1], sequentialResult[index]);
}
double[] parallelResult = data.clone();
Arrays.parallelPrefix(parallelResult, fromIndex, toIndex, op);
assertArraysEqual(sequentialResult, parallelResult);
double[] parallelRangeResult = Arrays.copyOfRange(data, fromIndex, toIndex);
Arrays.parallelPrefix(parallelRangeResult, op);
assertArraysEqual(Arrays.copyOfRange(sequentialResult, fromIndex, toIndex), parallelRangeResult);
}
@ParameterizedTest
@MethodSource("stringSet")
public void testParallelPrefixForStringr(String[] data , int fromIndex, int toIndex, BinaryOperator<String> op) {
String[] sequentialResult = data.clone();
for (int index = fromIndex + 1; index < toIndex; index++) {
sequentialResult[index ] = op.apply(sequentialResult[index - 1], sequentialResult[index]);
}
String[] parallelResult = data.clone();
Arrays.parallelPrefix(parallelResult, fromIndex, toIndex, op);
assertArraysEqual(sequentialResult, parallelResult);
String[] parallelRangeResult = Arrays.copyOfRange(data, fromIndex, toIndex);
Arrays.parallelPrefix(parallelRangeResult, op);
assertArraysEqual(Arrays.copyOfRange(sequentialResult, fromIndex, toIndex), parallelRangeResult);
}
@Test
public void testNPEs() {
// null array
assertThrowsNPE(() -> Arrays.parallelPrefix((int[]) null, Integer::max));
assertThrowsNPE(() -> Arrays.parallelPrefix((long []) null, Long::max));
assertThrowsNPE(() -> Arrays.parallelPrefix((double []) null, Double::max));
assertThrowsNPE(() -> Arrays.parallelPrefix((String []) null, String::concat));
// null array w/ range
assertThrowsNPE(() -> Arrays.parallelPrefix((int[]) null, 0, 0, Integer::max));
assertThrowsNPE(() -> Arrays.parallelPrefix((long []) null, 0, 0, Long::max));
assertThrowsNPE(() -> Arrays.parallelPrefix((double []) null, 0, 0, Double::max));
assertThrowsNPE(() -> Arrays.parallelPrefix((String []) null, 0, 0, String::concat));
// null op
assertThrowsNPE(() -> Arrays.parallelPrefix(new int[] {}, null));
assertThrowsNPE(() -> Arrays.parallelPrefix(new long[] {}, null));
assertThrowsNPE(() -> Arrays.parallelPrefix(new double[] {}, null));
assertThrowsNPE(() -> Arrays.parallelPrefix(new String[] {}, null));
// null op w/ range
assertThrowsNPE(() -> Arrays.parallelPrefix(new int[] {}, 0, 0, null));
assertThrowsNPE(() -> Arrays.parallelPrefix(new long[] {}, 0, 0, null));
assertThrowsNPE(() -> Arrays.parallelPrefix(new double[] {}, 0, 0, null));
assertThrowsNPE(() -> Arrays.parallelPrefix(new String[] {}, 0, 0, null));
}
@Test
public void testIAEs() {
assertThrowsIAE(() -> Arrays.parallelPrefix(new int[] {}, 1, 0, Integer::max));
assertThrowsIAE(() -> Arrays.parallelPrefix(new long[] {}, 1, 0, Long::max));
assertThrowsIAE(() -> Arrays.parallelPrefix(new double[] {}, 1, 0, Double::max));
assertThrowsIAE(() -> Arrays.parallelPrefix(new String[] {}, 1, 0, String::concat));
}
@Test
public void testAIOOBEs() {
// bad "fromIndex"
assertThrowsAIOOB(() -> Arrays.parallelPrefix(new int[] {}, -1, 0, Integer::max));
assertThrowsAIOOB(() -> Arrays.parallelPrefix(new long[] {}, -1, 0, Long::max));
assertThrowsAIOOB(() -> Arrays.parallelPrefix(new double[] {}, -1, 0, Double::max));
assertThrowsAIOOB(() -> Arrays.parallelPrefix(new String[] {}, -1, 0, String::concat));
// bad "toIndex"
assertThrowsAIOOB(() -> Arrays.parallelPrefix(new int[] {}, 0, 1, Integer::max));
assertThrowsAIOOB(() -> Arrays.parallelPrefix(new long[] {}, 0, 1, Long::max));
assertThrowsAIOOB(() -> Arrays.parallelPrefix(new double[] {}, 0, 1, Double::max));
assertThrowsAIOOB(() -> Arrays.parallelPrefix(new String[] {}, 0, 1, String::concat));
}
// "library" code
private void assertThrowsNPE(Executable r) {
assertThrows(NullPointerException.class, r);
}
private void assertThrowsIAE(Executable r) {
assertThrows(IllegalArgumentException.class, r);
}
private void assertThrowsAIOOB(Executable r) {
assertThrows(ArrayIndexOutOfBoundsException.class, r);
}
static void assertArraysEqual(int[] expected, int[] actual) {
try {
assertArrayEquals(expected, actual, "");
} catch (AssertionError x) {
throw new AssertionError(String.format("Expected:%s, actual:%s",
Arrays.toString(expected), Arrays.toString(actual)), x);
}
}
static void assertArraysEqual(long[] expected, long[] actual) {
try {
assertArrayEquals(expected, actual, "");
} catch (AssertionError x) {
throw new AssertionError(String.format("Expected:%s, actual:%s",
Arrays.toString(expected), Arrays.toString(actual)), x);
}
}
static void assertArraysEqual(double[] expected, double[] actual) {
try {
assertArrayEquals(expected, actual, "");
} catch (AssertionError x) {
throw new AssertionError(String.format("Expected:%s, actual:%s",
Arrays.toString(expected), Arrays.toString(actual)), x);
}
}
static void assertArraysEqual(String[] expected, String[] actual) {
try {
assertArrayEquals(expected, actual, "");
} catch (AssertionError x) {
throw new AssertionError(String.format("Expected:%s, actual:%s",
Arrays.toString(expected), Arrays.toString(actual)), x);
}
}
}

View file

@ -0,0 +1,137 @@
/*
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.util.Base64;
import static java.nio.charset.StandardCharsets.US_ASCII;
/**
* @test
* @bug 8007799 8176379
* @summary test Encoder with linemax == 0, line separator should not appear in encoded data
*/
public class Base64GetEncoderTest {
public static void main(String args[]) throws Throwable {
for (int maxlen = -4; maxlen < 4; maxlen++) {
final Base64.Encoder encoder = Base64.getMimeEncoder(maxlen, "$$$".getBytes(US_ASCII));
testEncodeToString(encoder);
testWrapEncode1(encoder);
testEncodeToStringWithLongInputData(encoder);
testWrapEncode2(encoder);
}
}
private static void testWrapEncode2(final Base64.Encoder encoder)
throws IOException {
System.err.println("\nEncoder.wrap test II ");
final byte[] secondTestBuffer =
"api/java_util/Base64/index.html#GetEncoderMimeCustom[noLineSeparatorInEncodedString]"
.getBytes(US_ASCII);
String base64EncodedString;
ByteArrayOutputStream secondEncodingStream = new ByteArrayOutputStream();
OutputStream base64EncodingStream = encoder.wrap(secondEncodingStream);
base64EncodingStream.write(secondTestBuffer);
base64EncodingStream.close();
final byte[] encodedByteArray = secondEncodingStream.toByteArray();
System.err.print("result = " + new String(encodedByteArray, US_ASCII)
+ " after wrap Base64 encoding of string");
base64EncodedString = new String(encodedByteArray, US_ASCII);
if (base64EncodedString.contains("$$$")) {
throw new RuntimeException(
"Base64 encoding contains line separator after wrap 2 invoked ... \n");
}
}
private static void testEncodeToStringWithLongInputData(
final Base64.Encoder encoder) {
System.err.println("\n\nEncoder.encodeToStringWithLongInputData test ");
final byte[] secondTestBuffer =
"api/java_util/Base64/index.html#GetEncoderMimeCustom[noLineSeparatorInEncodedString]"
.getBytes(US_ASCII);
String base64EncodedString;
base64EncodedString = encoder.encodeToString(secondTestBuffer);
System.err.println("Second Base64 encoded string is "
+ base64EncodedString);
if (base64EncodedString.contains("$$$")) {
throw new RuntimeException(
"Base64 encoding contains line separator after encodeToString invoked ... \n");
}
}
private static void testWrapEncode1(final Base64.Encoder encoder)
throws IOException {
System.err.println("\nEncoder.wrap test I ");
final byte[] bytesIn = "fo".getBytes(US_ASCII);
String base64EncodedString;
ByteArrayOutputStream encodingStream = new ByteArrayOutputStream();
OutputStream encoding = encoder.wrap(encodingStream);
encoding.write(bytesIn);
encoding.close();
final byte[] encodedBytes = encodingStream.toByteArray();
System.err.print("result = " + new String(encodedBytes, US_ASCII)
+ " after the Base64 encoding \n");
base64EncodedString = new String(encodedBytes, US_ASCII);
if (base64EncodedString.contains("$$$")) {
throw new RuntimeException(
"Base64 encoding contains line separator after wrap I test ... \n");
}
}
private static void testEncodeToString(final Base64.Encoder encoder) {
final byte[] bytesIn = "fo".getBytes(US_ASCII);
System.err.println("\nEncoder.encodeToString test ");
String base64EncodedString = encoder.encodeToString(bytesIn);
System.err.println("Base64 encoded string is " + base64EncodedString);
if (base64EncodedString.contains("$$$")) {
throw new RuntimeException("Base64 encoding contains line separator after Encoder.encodeToString invoked ... \n");
}
}
}

View file

@ -0,0 +1,636 @@
/*
* Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @bug 4235519 8004212 8005394 8007298 8006295 8006315 8006530 8007379 8008925
* 8014217 8025003 8026330 8028397 8129544 8165243 8176379 8222187
* @summary tests java.util.Base64
* @library /test/lib
* @build jdk.test.lib.RandomFactory
* @run main TestBase64
* @key randomness
*/
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
import java.util.Random;
import jdk.test.lib.RandomFactory;
public class TestBase64 {
private static final Random rnd = RandomFactory.getRandom();
public static void main(String args[]) throws Throwable {
int numRuns = 10;
int numBytes = 200;
if (args.length > 1) {
numRuns = Integer.parseInt(args[0]);
numBytes = Integer.parseInt(args[1]);
}
test(Base64.getEncoder(), Base64.getDecoder(), numRuns, numBytes);
test(Base64.getUrlEncoder(), Base64.getUrlDecoder(), numRuns, numBytes);
test(Base64.getMimeEncoder(), Base64.getMimeDecoder(), numRuns, numBytes);
byte[] nl_1 = new byte[] {'\n'};
byte[] nl_2 = new byte[] {'\n', '\r'};
byte[] nl_3 = new byte[] {'\n', '\r', '\n'};
for (int i = 0; i < 10; i++) {
int len = rnd.nextInt(200) + 4;
test(Base64.getMimeEncoder(len, nl_1),
Base64.getMimeDecoder(),
numRuns, numBytes);
test(Base64.getMimeEncoder(len, nl_2),
Base64.getMimeDecoder(),
numRuns, numBytes);
test(Base64.getMimeEncoder(len, nl_3),
Base64.getMimeDecoder(),
numRuns, numBytes);
}
// test mime case with < 4 length
for (int len = 0; len < 4; len++) {
test(Base64.getMimeEncoder(len, nl_1),
Base64.getMimeDecoder(),
numRuns, numBytes);
test(Base64.getMimeEncoder(len, nl_2),
Base64.getMimeDecoder(),
numRuns, numBytes);
test(Base64.getMimeEncoder(len, nl_3),
Base64.getMimeDecoder(),
numRuns, numBytes);
}
testNull(Base64.getEncoder());
testNull(Base64.getUrlEncoder());
testNull(Base64.getMimeEncoder());
testNull(Base64.getMimeEncoder(10, new byte[]{'\n'}));
testNull(Base64.getDecoder());
testNull(Base64.getUrlDecoder());
testNull(Base64.getMimeDecoder());
checkNull(() -> Base64.getMimeEncoder(10, null));
testIOE(Base64.getEncoder());
testIOE(Base64.getUrlEncoder());
testIOE(Base64.getMimeEncoder());
testIOE(Base64.getMimeEncoder(10, new byte[]{'\n'}));
byte[] src = new byte[1024];
rnd.nextBytes(src);
final byte[] decoded = Base64.getEncoder().encode(src);
testIOE(Base64.getDecoder(), decoded);
testIOE(Base64.getMimeDecoder(), decoded);
testIOE(Base64.getUrlDecoder(), Base64.getUrlEncoder().encode(src));
// illegal line separator
checkIAE(() -> Base64.getMimeEncoder(10, new byte[]{'\r', 'N'}));
// malformed padding/ending
testMalformedPadding();
// illegal base64 character
decoded[2] = (byte)0xe0;
checkIAE(() -> Base64.getDecoder().decode(decoded));
checkIAE(() -> Base64.getDecoder().decode(decoded, new byte[1024]));
checkIAE(() -> Base64.getDecoder().decode(ByteBuffer.wrap(decoded)));
// test single-non-base64 character for mime decoding
testSingleNonBase64MimeDec();
// test decoding of unpadded data
testDecodeUnpadded();
// test mime decoding with ignored character after padding
testDecodeIgnoredAfterPadding();
// given invalid args, encoder should not produce output
testEncoderKeepsSilence(Base64.getEncoder());
testEncoderKeepsSilence(Base64.getUrlEncoder());
testEncoderKeepsSilence(Base64.getMimeEncoder());
// given invalid args, decoder should not consume input
testDecoderKeepsAbstinence(Base64.getDecoder());
testDecoderKeepsAbstinence(Base64.getUrlDecoder());
testDecoderKeepsAbstinence(Base64.getMimeDecoder());
// tests patch addressing JDK-8222187
// https://bugs.openjdk.org/browse/JDK-8222187
testJDK_8222187();
}
private static void test(Base64.Encoder enc, Base64.Decoder dec,
int numRuns, int numBytes) throws Throwable {
enc.encode(new byte[0]);
dec.decode(new byte[0]);
for (boolean withoutPadding : new boolean[] { false, true}) {
if (withoutPadding) {
enc = enc.withoutPadding();
}
for (int i=0; i<numRuns; i++) {
for (int j=1; j<numBytes; j++) {
byte[] orig = new byte[j];
rnd.nextBytes(orig);
// --------testing encode/decode(byte[])--------
byte[] encoded = enc.encode(orig);
byte[] decoded = dec.decode(encoded);
checkEqual(orig, decoded,
"Base64 array encoding/decoding failed!");
if (withoutPadding) {
if (encoded[encoded.length - 1] == '=')
throw new RuntimeException(
"Base64 enc.encode().withoutPadding() has padding!");
}
// --------testing encodetoString(byte[])/decode(String)--------
String str = enc.encodeToString(orig);
if (!Arrays.equals(str.getBytes("ASCII"), encoded)) {
throw new RuntimeException(
"Base64 encodingToString() failed!");
}
byte[] buf = dec.decode(new String(encoded, "ASCII"));
checkEqual(buf, orig, "Base64 decoding(String) failed!");
//-------- testing encode/decode(Buffer)--------
testEncode(enc, ByteBuffer.wrap(orig), encoded);
ByteBuffer bin = ByteBuffer.allocateDirect(orig.length);
bin.put(orig).flip();
testEncode(enc, bin, encoded);
testDecode(dec, ByteBuffer.wrap(encoded), orig);
bin = ByteBuffer.allocateDirect(encoded.length);
bin.put(encoded).flip();
testDecode(dec, bin, orig);
// --------testing decode.wrap(input stream)--------
// 1) random buf length
ByteArrayInputStream bais = new ByteArrayInputStream(encoded);
InputStream is = dec.wrap(bais);
buf = new byte[orig.length + 10];
int len = orig.length;
int off = 0;
while (true) {
int n = rnd.nextInt(len);
if (n == 0)
n = 1;
n = is.read(buf, off, n);
if (n == -1) {
checkEqual(off, orig.length,
"Base64 stream decoding failed");
break;
}
off += n;
len -= n;
if (len == 0)
break;
}
buf = Arrays.copyOf(buf, off);
checkEqual(buf, orig, "Base64 stream decoding failed!");
// 2) read one byte each
bais.reset();
is = dec.wrap(bais);
buf = new byte[orig.length + 10];
off = 0;
int b;
while ((b = is.read()) != -1) {
buf[off++] = (byte)b;
}
buf = Arrays.copyOf(buf, off);
checkEqual(buf, orig, "Base64 stream decoding failed!");
// --------testing encode.wrap(output stream)--------
ByteArrayOutputStream baos = new ByteArrayOutputStream((orig.length + 2) / 3 * 4 + 10);
OutputStream os = enc.wrap(baos);
off = 0;
len = orig.length;
for (int k = 0; k < 5; k++) {
if (len == 0)
break;
int n = rnd.nextInt(len);
if (n == 0)
n = 1;
os.write(orig, off, n);
off += n;
len -= n;
}
if (len != 0)
os.write(orig, off, len);
os.close();
buf = baos.toByteArray();
checkEqual(buf, encoded, "Base64 stream encoding failed!");
// 2) write one byte each
baos.reset();
os = enc.wrap(baos);
off = 0;
while (off < orig.length) {
os.write(orig[off++]);
}
os.close();
buf = baos.toByteArray();
checkEqual(buf, encoded, "Base64 stream encoding failed!");
// --------testing encode(in, out); -> bigger buf--------
buf = new byte[encoded.length + rnd.nextInt(100)];
int ret = enc.encode(orig, buf);
checkEqual(ret, encoded.length,
"Base64 enc.encode(src, null) returns wrong size!");
buf = Arrays.copyOf(buf, ret);
checkEqual(buf, encoded,
"Base64 enc.encode(src, dst) failed!");
// --------testing decode(in, out); -> bigger buf--------
buf = new byte[orig.length + rnd.nextInt(100)];
ret = dec.decode(encoded, buf);
checkEqual(ret, orig.length,
"Base64 enc.encode(src, null) returns wrong size!");
buf = Arrays.copyOf(buf, ret);
checkEqual(buf, orig,
"Base64 dec.decode(src, dst) failed!");
}
}
}
}
private static final byte[] ba_null = null;
private static final String str_null = null;
private static final ByteBuffer bb_null = null;
private static void testNull(Base64.Encoder enc) {
checkNull(() -> enc.encode(ba_null));
checkNull(() -> enc.encodeToString(ba_null));
checkNull(() -> enc.encode(ba_null, new byte[10]));
checkNull(() -> enc.encode(new byte[10], ba_null));
checkNull(() -> enc.encode(bb_null));
checkNull(() -> enc.wrap((OutputStream)null));
}
private static void testNull(Base64.Decoder dec) {
checkNull(() -> dec.decode(ba_null));
checkNull(() -> dec.decode(str_null));
checkNull(() -> dec.decode(ba_null, new byte[10]));
checkNull(() -> dec.decode(new byte[10], ba_null));
checkNull(() -> dec.decode(bb_null));
checkNull(() -> dec.wrap((InputStream)null));
}
@FunctionalInterface
private static interface Testable {
public void test() throws Throwable;
}
private static void testIOE(Base64.Encoder enc) throws Throwable {
ByteArrayOutputStream baos = new ByteArrayOutputStream(8192);
OutputStream os = enc.wrap(baos);
os.write(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9});
os.close();
checkIOE(() -> os.write(10));
checkIOE(() -> os.write(new byte[] {10}));
checkIOE(() -> os.write(new byte[] {10}, 1, 4));
}
private static void testIOE(Base64.Decoder dec, byte[] decoded) throws Throwable {
ByteArrayInputStream bais = new ByteArrayInputStream(decoded);
InputStream is = dec.wrap(bais);
is.read(new byte[10]);
is.close();
checkIOE(() -> is.read());
checkIOE(() -> is.read(new byte[] {10}));
checkIOE(() -> is.read(new byte[] {10}, 1, 4));
checkIOE(() -> is.available());
checkIOE(() -> is.skip(20));
}
private static final void checkNull(Runnable r) {
try {
r.run();
throw new RuntimeException("NPE is not thrown as expected");
} catch (NullPointerException npe) {}
}
private static final void checkIOE(Testable t) throws Throwable {
try {
t.test();
throw new RuntimeException("IOE is not thrown as expected");
} catch (IOException ioe) {}
}
private static final void checkIAE(Runnable r) throws Throwable {
try {
r.run();
throw new RuntimeException("IAE is not thrown as expected");
} catch (IllegalArgumentException iae) {}
}
private static void testDecodeIgnoredAfterPadding() throws Throwable {
for (byte nonBase64 : new byte[] {'#', '(', '!', '\\', '-', '_', '\n', '\r'}) {
byte[][] src = new byte[][] {
"A".getBytes("ascii"),
"AB".getBytes("ascii"),
"ABC".getBytes("ascii"),
"ABCD".getBytes("ascii"),
"ABCDE".getBytes("ascii")
};
Base64.Encoder encM = Base64.getMimeEncoder();
Base64.Decoder decM = Base64.getMimeDecoder();
Base64.Encoder enc = Base64.getEncoder();
Base64.Decoder dec = Base64.getDecoder();
for (int i = 0; i < src.length; i++) {
// decode(byte[])
byte[] encoded = encM.encode(src[i]);
encoded = Arrays.copyOf(encoded, encoded.length + 1);
encoded[encoded.length - 1] = nonBase64;
checkEqual(decM.decode(encoded), src[i], "Non-base64 char is not ignored");
byte[] decoded = new byte[src[i].length];
decM.decode(encoded, decoded);
checkEqual(decoded, src[i], "Non-base64 char is not ignored");
try {
dec.decode(encoded);
throw new RuntimeException("No IAE for non-base64 char");
} catch (IllegalArgumentException iae) {}
}
}
}
private static void testMalformedPadding() throws Throwable {
Object[] data = new Object[] {
"$=#", "", 0, // illegal ending unit
"A", "", 0, // dangling single byte
"A=", "", 0,
"A==", "", 0,
"QUJDA", "ABC", 4,
"QUJDA=", "ABC", 4,
"QUJDA==", "ABC", 4,
"=", "", 0, // unnecessary padding
"QUJD=", "ABC", 4, //"ABC".encode() -> "QUJD"
"AA=", "", 0, // incomplete padding
"QQ=", "", 0,
"QQ=N", "", 0, // incorrect padding
"QQ=?", "", 0,
"QUJDQQ=", "ABC", 4,
"QUJDQQ=N", "ABC", 4,
"QUJDQQ=?", "ABC", 4,
};
Base64.Decoder[] decs = new Base64.Decoder[] {
Base64.getDecoder(),
Base64.getUrlDecoder(),
Base64.getMimeDecoder()
};
for (Base64.Decoder dec : decs) {
for (int i = 0; i < data.length; i += 3) {
final String srcStr = (String)data[i];
final byte[] srcBytes = srcStr.getBytes("ASCII");
final ByteBuffer srcBB = ByteBuffer.wrap(srcBytes);
byte[] expected = ((String)data[i + 1]).getBytes("ASCII");
int pos = (Integer)data[i + 2];
// decode(byte[])
checkIAE(() -> dec.decode(srcBytes));
// decode(String)
checkIAE(() -> dec.decode(srcStr));
// decode(ByteBuffer)
checkIAE(() -> dec.decode(srcBB));
// wrap stream
checkIOE(new Testable() {
public void test() throws IOException {
try (InputStream is = dec.wrap(new ByteArrayInputStream(srcBytes))) {
while (is.read() != -1);
}
}});
}
}
// anything left after padding is "invalid"/IAE, if
// not MIME. In case of MIME, non-base64 character(s)
// is ignored.
checkIAE(() -> Base64.getDecoder().decode("AA==\u00D2"));
checkIAE(() -> Base64.getUrlDecoder().decode("AA==\u00D2"));
Base64.getMimeDecoder().decode("AA==\u00D2");
}
private static void testDecodeUnpadded() throws Throwable {
byte[] srcA = new byte[] { 'Q', 'Q' };
byte[] srcAA = new byte[] { 'Q', 'Q', 'E'};
Base64.Decoder dec = Base64.getDecoder();
byte[] ret = dec.decode(srcA);
if (ret[0] != 'A')
throw new RuntimeException("Decoding unpadding input A failed");
ret = dec.decode(srcAA);
if (ret[0] != 'A' && ret[1] != 'A')
throw new RuntimeException("Decoding unpadding input AA failed");
ret = new byte[10];
if (dec.wrap(new ByteArrayInputStream(srcA)).read(ret) != 1 &&
ret[0] != 'A')
throw new RuntimeException("Decoding unpadding input A from stream failed");
if (dec.wrap(new ByteArrayInputStream(srcA)).read(ret) != 2 &&
ret[0] != 'A' && ret[1] != 'A')
throw new RuntimeException("Decoding unpadding input AA from stream failed");
}
// single-non-base64-char should be ignored for mime decoding, but
// iae for basic decoding
private static void testSingleNonBase64MimeDec() throws Throwable {
for (String nonBase64 : new String[] {"#", "(", "!", "\\", "-", "_"}) {
if (Base64.getMimeDecoder().decode(nonBase64).length != 0) {
throw new RuntimeException("non-base64 char is not ignored");
}
try {
Base64.getDecoder().decode(nonBase64);
throw new RuntimeException("No IAE for single non-base64 char");
} catch (IllegalArgumentException iae) {}
}
}
private static final void testEncode(Base64.Encoder enc, ByteBuffer bin, byte[] expected)
throws Throwable {
ByteBuffer bout = enc.encode(bin);
byte[] buf = new byte[bout.remaining()];
bout.get(buf);
if (bin.hasRemaining()) {
throw new RuntimeException(
"Base64 enc.encode(ByteBuffer) failed!");
}
checkEqual(buf, expected, "Base64 enc.encode(bf, bf) failed!");
}
private static final void testDecode(Base64.Decoder dec, ByteBuffer bin, byte[] expected)
throws Throwable {
ByteBuffer bout = dec.decode(bin);
byte[] buf = new byte[bout.remaining()];
bout.get(buf);
checkEqual(buf, expected, "Base64 dec.decode(bf) failed!");
}
private static final void checkEqual(int v1, int v2, String msg)
throws Throwable {
if (v1 != v2) {
System.out.printf(" v1=%d%n", v1);
System.out.printf(" v2=%d%n", v2);
throw new RuntimeException(msg);
}
}
private static final void checkEqual(byte[] r1, byte[] r2, String msg)
throws Throwable {
if (!Arrays.equals(r1, r2)) {
System.out.printf(" r1[%d]=[%s]%n", r1.length, new String(r1));
System.out.printf(" r2[%d]=[%s]%n", r2.length, new String(r2));
throw new RuntimeException(msg);
}
}
// remove line feeds,
private static final byte[] normalize(byte[] src) {
int n = 0;
boolean hasUrl = false;
for (int i = 0; i < src.length; i++) {
if (src[i] == '\r' || src[i] == '\n')
n++;
if (src[i] == '-' || src[i] == '_')
hasUrl = true;
}
if (n == 0 && hasUrl == false)
return src;
byte[] ret = new byte[src.length - n];
int j = 0;
for (int i = 0; i < src.length; i++) {
if (src[i] == '-')
ret[j++] = '+';
else if (src[i] == '_')
ret[j++] = '/';
else if (src[i] != '\r' && src[i] != '\n')
ret[j++] = src[i];
}
return ret;
}
private static void testEncoderKeepsSilence(Base64.Encoder enc)
throws Throwable {
List<Integer> vals = new ArrayList<>(List.of(Integer.MIN_VALUE,
Integer.MIN_VALUE + 1, -1111, -2, -1, 0, 1, 2, 3, 1111,
Integer.MAX_VALUE - 1, Integer.MAX_VALUE));
vals.addAll(List.of(rnd.nextInt(), rnd.nextInt(), rnd.nextInt(),
rnd.nextInt()));
byte[] buf = new byte[] {1, 0, 91};
for (int off : vals) {
for (int len : vals) {
if (off >= 0 && len >= 0 && off <= buf.length - len) {
// valid args, skip them
continue;
}
// invalid args, test them
System.out.println("testing off=" + off + ", len=" + len);
ByteArrayOutputStream baos = new ByteArrayOutputStream(100);
try (OutputStream os = enc.wrap(baos)) {
os.write(buf, off, len);
throw new RuntimeException("Expected IOOBEx was not thrown");
} catch (IndexOutOfBoundsException expected) {
}
if (baos.size() > 0)
throw new RuntimeException("No output was expected, but got "
+ baos.size() + " bytes");
}
}
}
private static void testDecoderKeepsAbstinence(Base64.Decoder dec)
throws Throwable {
List<Integer> vals = new ArrayList<>(List.of(Integer.MIN_VALUE,
Integer.MIN_VALUE + 1, -1111, -2, -1, 0, 1, 2, 3, 1111,
Integer.MAX_VALUE - 1, Integer.MAX_VALUE));
vals.addAll(List.of(rnd.nextInt(), rnd.nextInt(), rnd.nextInt(),
rnd.nextInt()));
byte[] buf = new byte[3];
for (int off : vals) {
for (int len : vals) {
if (off >= 0 && len >= 0 && off <= buf.length - len) {
// valid args, skip them
continue;
}
// invalid args, test them
System.out.println("testing off=" + off + ", len=" + len);
String input = "AAAAAAAAAAAAAAAAAAAAAA";
ByteArrayInputStream bais =
new ByteArrayInputStream(input.getBytes("Latin1"));
try (InputStream is = dec.wrap(bais)) {
is.read(buf, off, len);
throw new RuntimeException("Expected IOOBEx was not thrown");
} catch (IndexOutOfBoundsException expected) {
}
if (bais.available() != input.length())
throw new RuntimeException("No input should be consumed, "
+ "but consumed " + (input.length() - bais.available())
+ " bytes");
}
}
}
private static void testJDK_8222187() throws Throwable {
byte[] orig = "12345678".getBytes("US-ASCII");
byte[] encoded = Base64.getEncoder().encode(orig);
// decode using different buffer sizes, up to a longer one than needed
for (int bufferSize = 1; bufferSize <= encoded.length + 1; bufferSize++) {
try (
InputStream in = Base64.getDecoder().wrap(
new ByteArrayInputStream(encoded));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
) {
byte[] buffer = new byte[bufferSize];
int read;
while ((read = in.read(buffer, 0, bufferSize)) >= 0) {
baos.write(buffer, 0, read);
}
// compare result, output info if lengths do not match
byte[] decoded = baos.toByteArray();
checkEqual(decoded, orig, "Base64 stream decoding failed!");
}
}
}
}

View file

@ -0,0 +1,181 @@
/*
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 4235519
* @author Eric Wang <yiming.wang@oracle.com>
* @summary tests java.util.Base64
*/
import java.io.BufferedReader;
import java.io.FileReader;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Base64;
import java.util.Base64.Decoder;
import java.util.Base64.Encoder;
import java.util.Objects;
import java.util.Random;
public class TestBase64Golden {
public static void main(String[] args) throws Exception {
test0(Base64Type.BASIC, Base64.getEncoder(), Base64.getDecoder(),
"plain.txt", "baseEncode.txt");
test0(Base64Type.URLSAFE, Base64.getUrlEncoder(), Base64.getUrlDecoder(),
"plain.txt", "urlEncode.txt");
test0(Base64Type.MIME, Base64.getMimeEncoder(), Base64.getMimeDecoder(),
"plain.txt", "mimeEncode.txt");
test1();
}
public static void test0(Base64Type type, Encoder encoder, Decoder decoder,
String srcFile, String encodedFile) throws Exception {
String[] srcLns = Files.readAllLines(Paths.get(SRCDIR, srcFile), DEF_CHARSET)
.toArray(new String[0]);
String[] encodedLns = Files.readAllLines(Paths.get(SRCDIR, encodedFile),
DEF_CHARSET)
.toArray(new String[0]);
int lns = 0;
for (String srcStr : srcLns) {
String encodedStr = null;
if (type != Base64Type.MIME) {
encodedStr = encodedLns[lns++];
} else {
while (lns < encodedLns.length) {
String s = encodedLns[lns++];
if (s.length() == 0)
break;
if (encodedStr != null) {
encodedStr += DEFAULT_CRLF + s;
} else {
encodedStr = s;
}
}
if (encodedStr == null && srcStr.length() == 0) {
encodedStr = "";
}
}
System.out.printf("%n src[%d]: %s%n", srcStr.length(), srcStr);
System.out.printf("encoded[%d]: %s%n", encodedStr.length(), encodedStr);
byte[] srcArr = srcStr.getBytes(DEF_CHARSET);
byte[] encodedArr = encodedStr.getBytes(DEF_CHARSET);
ByteBuffer srcBuf = ByteBuffer.wrap(srcArr);
ByteBuffer encodedBuf = ByteBuffer.wrap(encodedArr);
byte[] resArr = new byte[encodedArr.length];
// test int encode(byte[], byte[])
int len = encoder.encode(srcArr, resArr);
assertEqual(len, encodedArr.length);
assertEqual(resArr, encodedArr);
// test byte[] encode(byte[])
resArr = encoder.encode(srcArr);
assertEqual(resArr, encodedArr);
// test ByteBuffer encode(ByteBuffer)
int limit = srcBuf.limit();
ByteBuffer resBuf = encoder.encode(srcBuf);
assertEqual(srcBuf.position(), limit);
assertEqual(srcBuf.limit(), limit);
assertEqual(resBuf, encodedBuf);
srcBuf.rewind(); // reset for next test
// test String encodeToString(byte[])
String resEncodeStr = encoder.encodeToString(srcArr);
assertEqual(resEncodeStr, encodedStr);
// test int decode(byte[], byte[])
resArr = new byte[srcArr.length];
len = decoder.decode(encodedArr, resArr);
assertEqual(len, srcArr.length);
assertEqual(resArr, srcArr);
// test byte[] decode(byte[])
resArr = decoder.decode(encodedArr);
assertEqual(resArr, srcArr);
// test ByteBuffer decode(ByteBuffer)
limit = encodedBuf.limit();
resBuf = decoder.decode(encodedBuf);
assertEqual(encodedBuf.position(), limit);
assertEqual(encodedBuf.limit(), limit);
assertEqual(resBuf, srcBuf);
encodedBuf.rewind(); // reset for next test
// test byte[] decode(String)
resArr = decoder.decode(encodedStr);
assertEqual(resArr, srcArr);
}
}
private static void test1() throws Exception {
byte[] src = new byte[] {
46, -97, -35, -44, 127, -60, -39, -4, -112, 34, -57, 47, -14, 67,
40, 18, 90, -59, 68, 112, 23, 121, -91, 94, 35, 49, 104, 17, 30,
-80, -104, -3, -53, 27, 38, -72, -47, 113, -52, 18, 5, -126 };
Encoder encoder = Base64.getMimeEncoder(49, new byte[] { 0x7e });
byte[] encoded = encoder.encode(src);
Decoder decoder = Base64.getMimeDecoder();
byte[] decoded = decoder.decode(encoded);
if (!Objects.deepEquals(src, decoded)) {
throw new RuntimeException();
}
}
// helper
enum Base64Type {
BASIC, URLSAFE, MIME
}
private static final String SRCDIR = System.getProperty("test.src", ".");
private static final Charset DEF_CHARSET = StandardCharsets.US_ASCII;
private static final String DEF_EXCEPTION_MSG =
"Assertion failed! The result is not same as expected";
private static final String DEFAULT_CRLF = "\r\n";
private static void assertEqual(Object result, Object expect) {
if (!Objects.deepEquals(result, expect)) {
String resultStr = result.toString();
String expectStr = expect.toString();
if (result instanceof byte[]) {
resultStr = new String((byte[]) result, DEF_CHARSET);
}
if (expect instanceof byte[]) {
expectStr = new String((byte[]) expect, DEF_CHARSET);
}
throw new RuntimeException(DEF_EXCEPTION_MSG +
" result: " + resultStr + " expected: " + expectStr);
}
}
}

View file

@ -0,0 +1,117 @@
/*
* Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import jdk.internal.util.ArraysSupport;
import org.junit.jupiter.api.Test;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Base64;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.fail;
/*
* @test
* @bug 8210583 8217969 8218265 8295153
* @summary White-box test that effectively checks Base64.Encoder.encode and
* Base64.Decoder.decode behavior with large, (Integer.MAX_VALUE) sized
* input array/buffer. Tests the private methods "encodedOutLength" and
* "decodedOutLength".
* @modules java.base/jdk.internal.util
* @run junit/othervm --add-opens java.base/java.util=ALL-UNNAMED TestEncodingDecodingLength
*/
// We perform a white-box test due to the heavy memory usage that testing
// the public API would require which has shown to cause intermittent issues
public class TestEncodingDecodingLength {
// A value large enough to test the desired memory conditions in encode and decode
private static final int LARGE_MEM_SIZE = ArraysSupport.SOFT_MAX_ARRAY_LENGTH;
private static final Base64.Decoder DECODER = Base64.getDecoder();
private static final Base64.Encoder ENCODER = Base64.getEncoder();
// Effectively tests that encode(byte[] src, byte[] dst) throws an
// IllegalArgumentException with array sized near Integer.MAX_VALUE. All the
// encode() methods call encodedOutLength(), which is where the OOME is expected
@Test
public void largeEncodeIAETest() throws IllegalAccessException,
InvocationTargetException, NoSuchMethodException {
Method m = getMethod(ENCODER,
"encodedOutLength", int.class, boolean.class);
// When throwOOME param is false, encodedOutLength should return -1 in
// this situation, which encode() uses to throw IAE
assertEquals(-1, m.invoke(ENCODER, LARGE_MEM_SIZE, false));
}
// Effectively tests that the overloaded encode() and encodeToString() methods
// throw OutOfMemoryError with array/buffer sized near Integer.MAX_VALUE
@Test
public void largeEncodeOOMETest() throws IllegalAccessException, NoSuchMethodException {
Method m = getMethod(ENCODER,
"encodedOutLength", int.class, boolean.class);
try {
m.invoke(ENCODER, LARGE_MEM_SIZE, true);
} catch (InvocationTargetException ex) {
Throwable rootEx = ex.getCause();
assertEquals(OutOfMemoryError.class, rootEx.getClass(),
"OOME should be thrown with Integer.MAX_VALUE input");
assertEquals("Encoded size is too large", rootEx.getMessage());
}
}
// Effectively tests that the overloaded decode() methods do not throw
// OOME nor NASE with array/buffer sized near Integer.MAX_VALUE All the decode
// methods call decodedOutLength(), which is where the previously thrown
// OOME or NASE would occur at.
@Test
public void largeDecodeTest() throws IllegalAccessException, NoSuchMethodException {
Method m = getMethod(DECODER,
"decodedOutLength", byte[].class, int.class, int.class);
byte[] src = {1};
try {
/*
decodedOutLength() takes the src array, position, and limit as params.
The src array will be indexed at limit-1 to search for padding.
To avoid passing an array with Integer.MAX_VALUE memory allocated, we
set position param to be -size. Since the initial length
is calculated as limit - position. This mocks the potential overflow
calculation and still allows the array to be indexed without an AIOBE.
*/
m.invoke(DECODER, src, -LARGE_MEM_SIZE + 1, 1);
} catch (InvocationTargetException ex) {
// 8210583 - decode no longer throws NASE
// 8217969 - decode no longer throws OOME
fail("Decode threw an unexpected exception with " +
"Integer.MAX_VALUE sized input: " + ex.getCause());
}
}
// Utility to get the private visibility method
private static Method getMethod(Object obj, String methodName, Class<?>... params)
throws NoSuchMethodException {
Method m = obj.getClass().getDeclaredMethod(methodName, params);
m.setAccessible(true);
return m;
}
}

View file

@ -0,0 +1,183 @@
VGhpcyB0ZXN0IGRhdGEgaXMgcGFydCBvZiByZmMyMDQ1IHdoaWNoIGluY2x1ZGVzIGFsbCBjaGFyYWN0ZXJzIGF+eiBBflosIDB+OSBhbmQgYWxsIHN5bWJvbHMs
SXQgaXMgdXNlZCB0byB0ZXN0IGphdmEudXRpbC5CYXNlNjQuRW5jb2RlciwgYW5kIHdpbGwgYmUgZW5jb2RlZCBieSBvcmcuYXBhY2hlLmNvbW1vbnMuY29kZWMuYmluYXJ5LkJhc2U2NC5qYXZh
dG8gdGVzdCBqYXZhLnV0aWwuQmFzZTY0LkRlY29kZXI7
RnJlZWQgJiBCb3JlbnN0ZWluICAgICAgICAgIFN0YW5kYXJkcyBUcmFjayAgICAgICAgICAgICAgICAgICAgIFtQYWdlIDFd
UkZDIDIwNDUgICAgICAgICAgICAgICAgSW50ZXJuZXQgTWVzc2FnZSBCb2RpZXMgICAgICAgICAgICBOb3ZlbWJlciAxOTk2
ICAgVGhlc2UgZG9jdW1lbnRzIGFyZSByZXZpc2lvbnMgb2YgUkZDcyAxNTIxLCAxNTIyLCBhbmQgMTU5MCwgd2hpY2g=
ICAgdGhlbXNlbHZlcyB3ZXJlIHJldmlzaW9ucyBvZiBSRkNzIDEzNDEgYW5kIDEzNDIuICBBbiBhcHBlbmRpeCBpbiBSRkM=
ICAgMjA0OSBkZXNjcmliZXMgZGlmZmVyZW5jZXMgYW5kIGNoYW5nZXMgZnJvbSBwcmV2aW91cyB2ZXJzaW9ucy4=
VGFibGUgb2YgQ29udGVudHM=
ICAgMS4gSW50cm9kdWN0aW9uIC4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uICAgIDM=
ICAgMi4gRGVmaW5pdGlvbnMsIENvbnZlbnRpb25zLCBhbmQgR2VuZXJpYyBCTkYgR3JhbW1hciAuLi4uICAgIDU=
ICAgMy4gTUlNRSBIZWFkZXIgRmllbGRzIC4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uICAgIDg=
ICAgNC4gTUlNRS1WZXJzaW9uIEhlYWRlciBGaWVsZCAuLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uICAgIDg=
ICAgNS4gQ29udGVudC1UeXBlIEhlYWRlciBGaWVsZCAuLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uICAgMTA=
ICAgNi4gQ29udGVudC1UcmFuc2Zlci1FbmNvZGluZyBIZWFkZXIgRmllbGQgLi4uLi4uLi4uLi4uLi4uICAgMTQ=
ICAgNy4gQ29udGVudC1JRCBIZWFkZXIgRmllbGQgLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uICAgMjY=
ICAgOC4gQ29udGVudC1EZXNjcmlwdGlvbiBIZWFkZXIgRmllbGQgLi4uLi4uLi4uLi4uLi4uLi4uLi4uICAgMjc=
ICAgOS4gQWRkaXRpb25hbCBNSU1FIEhlYWRlciBGaWVsZHMgLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uICAgMjc=
ICAgMTAuIFN1bW1hcnkgLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uICAgMjc=
ICAgMTEuIFNlY3VyaXR5IENvbnNpZGVyYXRpb25zIC4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uICAgMjc=
ICAgMTIuIEF1dGhvcnMnIEFkZHJlc3NlcyAuLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uICAgMjg=
ICAgQS4gQ29sbGVjdGVkIEdyYW1tYXIgLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uICAgMjk=
RnJlZWQgJiBCb3JlbnN0ZWluICAgICAgICAgIFN0YW5kYXJkcyBUcmFjayAgICAgICAgICAgICAgICAgICAgIFtQYWdlIDdd
UkZDIDIwNDUgICAgICAgICAgICAgICAgSW50ZXJuZXQgTWVzc2FnZSBCb2RpZXMgICAgICAgICAgICBOb3ZlbWJlciAxOTk2
My4gIE1JTUUgSGVhZGVyIEZpZWxkcw==
ICAgTUlNRSBkZWZpbmVzIGEgbnVtYmVyIG9mIG5ldyBSRkMgODIyIGhlYWRlciBmaWVsZHMgdGhhdCBhcmUgdXNlZCB0bw==
ICAgZGVzY3JpYmUgdGhlIGNvbnRlbnQgb2YgYSBNSU1FIGVudGl0eS4gIFRoZXNlIGhlYWRlciBmaWVsZHMgb2NjdXIgaW4=
ICAgYXQgbGVhc3QgdHdvIGNvbnRleHRzOg==
ICAgICgxKSAgIEFzIHBhcnQgb2YgYSByZWd1bGFyIFJGQyA4MjIgbWVzc2FnZSBoZWFkZXIu
ICAgICgyKSAgIEluIGEgTUlNRSBib2R5IHBhcnQgaGVhZGVyIHdpdGhpbiBhIG11bHRpcGFydA==
ICAgICAgICAgIGNvbnN0cnVjdC4=
ICAgVGhlIGZvcm1hbCBkZWZpbml0aW9uIG9mIHRoZXNlIGhlYWRlciBmaWVsZHMgaXMgYXMgZm9sbG93czo=
ICAgICBNSU1FLW1lc3NhZ2UtaGVhZGVycyA6PSBlbnRpdHktaGVhZGVycw==
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWVsZHM=
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2ZXJzaW9uIENSTEY=
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICA7IFRoZSBvcmRlcmluZyBvZiB0aGUgaGVhZGVy
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICA7IGZpZWxkcyBpbXBsaWVkIGJ5IHRoaXMgQk5G
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICA7IGRlZmluaXRpb24gc2hvdWxkIGJlIGlnbm9yZWQu
ICAgICBNSU1FLXBhcnQtaGVhZGVycyA6PSBlbnRpdHktaGVhZGVycw==
ICAgICAgICAgICAgICAgICAgICAgICAgICBbIGZpZWxkcyBd
ICAgICAgICAgICAgICAgICAgICAgICAgICA7IEFueSBmaWVsZCBub3QgYmVnaW5uaW5nIHdpdGg=
ICAgICAgICAgICAgICAgICAgICAgICAgICA7ICJjb250ZW50LSIgY2FuIGhhdmUgbm8gZGVmaW5lZA==
ICAgICAgICAgICAgICAgICAgICAgICAgICA7IG1lYW5pbmcgYW5kIG1heSBiZSBpZ25vcmVkLg==
ICAgICAgICAgICAgICAgICAgICAgICAgICA7IFRoZSBvcmRlcmluZyBvZiB0aGUgaGVhZGVy
ICAgICAgICAgICAgICAgICAgICAgICAgICA7IGZpZWxkcyBpbXBsaWVkIGJ5IHRoaXMgQk5G
ICAgICAgICAgICAgICAgICAgICAgICAgICA7IGRlZmluaXRpb24gc2hvdWxkIGJlIGlnbm9yZWQu
ICAgVGhlIHN5bnRheCBvZiB0aGUgdmFyaW91cyBzcGVjaWZpYyBNSU1FIGhlYWRlciBmaWVsZHMgd2lsbCBiZQ==
ICAgZGVzY3JpYmVkIGluIHRoZSBmb2xsb3dpbmcgc2VjdGlvbnMu
RnJlZWQgJiBCb3JlbnN0ZWluICAgICAgICAgIFN0YW5kYXJkcyBUcmFjayAgICAgICAgICAgICAgICAgICAgW1BhZ2UgMTFd
UkZDIDIwNDUgICAgICAgICAgICAgICAgSW50ZXJuZXQgTWVzc2FnZSBCb2RpZXMgICAgICAgICAgICBOb3ZlbWJlciAxOTk2
NS4xLiAgU3ludGF4IG9mIHRoZSBDb250ZW50LVR5cGUgSGVhZGVyIEZpZWxk
ICAgSW4gdGhlIEF1Z21lbnRlZCBCTkYgbm90YXRpb24gb2YgUkZDIDgyMiwgYSBDb250ZW50LVR5cGUgaGVhZGVyIGZpZWxk
ICAgdmFsdWUgaXMgZGVmaW5lZCBhcyBmb2xsb3dzOg==
ICAgICBjb250ZW50IDo9ICJDb250ZW50LVR5cGUiICI6IiB0eXBlICIvIiBzdWJ0eXBl
ICAgICAgICAgICAgICAgICooIjsiIHBhcmFtZXRlcik=
ICAgICAgICAgICAgICAgIDsgTWF0Y2hpbmcgb2YgbWVkaWEgdHlwZSBhbmQgc3VidHlwZQ==
ICAgICAgICAgICAgICAgIDsgaXMgQUxXQVlTIGNhc2UtaW5zZW5zaXRpdmUu
ICAgICB0eXBlIDo9IGRpc2NyZXRlLXR5cGUgLyBjb21wb3NpdGUtdHlwZQ==
ICAgICBkaXNjcmV0ZS10eXBlIDo9ICJ0ZXh0IiAvICJpbWFnZSIgLyAiYXVkaW8iIC8gInZpZGVvIiAv
ICAgICAgICAgICAgICAgICAgICAgICJhcHBsaWNhdGlvbiIgLyBleHRlbnNpb24tdG9rZW4=
ICAgICBjb21wb3NpdGUtdHlwZSA6PSAibWVzc2FnZSIgLyAibXVsdGlwYXJ0IiAvIGV4dGVuc2lvbi10b2tlbg==
ICAgICBleHRlbnNpb24tdG9rZW4gOj0gaWV0Zi10b2tlbiAvIHgtdG9rZW4=
ICAgICBpZXRmLXRva2VuIDo9IDxBbiBleHRlbnNpb24gdG9rZW4gZGVmaW5lZCBieSBh
ICAgICAgICAgICAgICAgICAgICBzdGFuZGFyZHMtdHJhY2sgUkZDIGFuZCByZWdpc3RlcmVk
ICAgICAgICAgICAgICAgICAgICB3aXRoIElBTkEuPg==
ICAgICB4LXRva2VuIDo9IDxUaGUgdHdvIGNoYXJhY3RlcnMgIlgtIiBvciAieC0iIGZvbGxvd2VkLCB3aXRo
ICAgICAgICAgICAgICAgICBubyBpbnRlcnZlbmluZyB3aGl0ZSBzcGFjZSwgYnkgYW55IHRva2VuPg==
ICAgICBzdWJ0eXBlIDo9IGV4dGVuc2lvbi10b2tlbiAvIGlhbmEtdG9rZW4=
ICAgICBpYW5hLXRva2VuIDo9IDxBIHB1YmxpY2x5LWRlZmluZWQgZXh0ZW5zaW9uIHRva2VuLiBUb2tlbnM=
ICAgICAgICAgICAgICAgICAgICBvZiB0aGlzIGZvcm0gbXVzdCBiZSByZWdpc3RlcmVkIHdpdGggSUFOQQ==
ICAgICAgICAgICAgICAgICAgICBhcyBzcGVjaWZpZWQgaW4gUkZDIDIwNDguPg==
ICAgICBwYXJhbWV0ZXIgOj0gYXR0cmlidXRlICI9IiB2YWx1ZQ==
ICAgICBhdHRyaWJ1dGUgOj0gdG9rZW4=
ICAgICAgICAgICAgICAgICAgOyBNYXRjaGluZyBvZiBhdHRyaWJ1dGVz
ICAgICAgICAgICAgICAgICAgOyBpcyBBTFdBWVMgY2FzZS1pbnNlbnNpdGl2ZS4=
ICAgICB2YWx1ZSA6PSB0b2tlbiAvIHF1b3RlZC1zdHJpbmc=
ICAgICB0b2tlbiA6PSAxKjxhbnkgKFVTLUFTQ0lJKSBDSEFSIGV4Y2VwdCBTUEFDRSwgQ1RMcyw=
ICAgICAgICAgICAgICAgICBvciB0c3BlY2lhbHM+
ICAgICB0c3BlY2lhbHMgOj0gICIoIiAvICIpIiAvICI8IiAvICI+IiAvICJAIiAv
ICAgICAgICAgICAgICAgICAgICIsIiAvICI7IiAvICI6IiAvICJcIiAvIDwiPg==
ICAgICAgICAgICAgICAgICAgICIvIiAvICJbIiAvICJdIiAvICI/IiAvICI9Ig==
ICAgICAgICAgICAgICAgICAgIDsgTXVzdCBiZSBpbiBxdW90ZWQtc3RyaW5nLA==
ICAgICAgICAgICAgICAgICAgIDsgdG8gdXNlIHdpdGhpbiBwYXJhbWV0ZXIgdmFsdWVz
ICAgICBkZXNjcmlwdGlvbiA6PSAiQ29udGVudC1EZXNjcmlwdGlvbiIgIjoiICp0ZXh0
ICAgICBlbmNvZGluZyA6PSAiQ29udGVudC1UcmFuc2Zlci1FbmNvZGluZyIgIjoiIG1lY2hhbmlzbQ==
ICAgICBlbnRpdHktaGVhZGVycyA6PSBbIGNvbnRlbnQgQ1JMRiBd
ICAgICAgICAgICAgICAgICAgICBbIGVuY29kaW5nIENSTEYgXQ==
ICAgICAgICAgICAgICAgICAgICBbIGlkIENSTEYgXQ==
ICAgICAgICAgICAgICAgICAgICBbIGRlc2NyaXB0aW9uIENSTEYgXQ==
ICAgICAgICAgICAgICAgICAgICAqKCBNSU1FLWV4dGVuc2lvbi1maWVsZCBDUkxGICk=
ICAgICBoZXgtb2N0ZXQgOj0gIj0iIDIoRElHSVQgLyAiQSIgLyAiQiIgLyAiQyIgLyAiRCIgLyAiRSIgLyAiRiIp
ICAgICAgICAgICAgICAgOyBPY3RldCBtdXN0IGJlIHVzZWQgZm9yIGNoYXJhY3RlcnMgPiAxMjcsID0s
ICAgICAgICAgICAgICAgOyBTUEFDRXMgb3IgVEFCcyBhdCB0aGUgZW5kcyBvZiBsaW5lcywgYW5kIGlz
ICAgICAgICAgICAgICAgOyByZWNvbW1lbmRlZCBmb3IgYW55IGNoYXJhY3RlciBub3QgbGlzdGVkIGlu
ICAgICAgICAgICAgICAgOyBSRkMgMjA0OSBhcyAibWFpbC1zYWZlIi4=
UkZDIDIwNDUgICAgICAgICAgICAgICAgSW50ZXJuZXQgTWVzc2FnZSBCb2RpZXMgICAgICAgICAgICBOb3ZlbWJlciAxOTk2
ICAgICAgICAgIG11c3QgYmUgdXNlZC4gIEFuIGVxdWFsIHNpZ24gYXMgdGhlIGxhc3QgY2hhcmFjdGVyIG9uIGE=
ICAgICAgICAgIGVuY29kZWQgbGluZSBpbmRpY2F0ZXMgc3VjaCBhIG5vbi1zaWduaWZpY2FudCAoInNvZnQiKQ==
ICAgICAgICAgIGxpbmUgYnJlYWsgaW4gdGhlIGVuY29kZWQgdGV4dC4=
ICAgVGh1cyBpZiB0aGUgInJhdyIgZm9ybSBvZiB0aGUgbGluZSBpcyBhIHNpbmdsZSB1bmVuY29kZWQgbGluZSB0aGF0
ICAgc2F5czo=
ICAgICBOb3cncyB0aGUgdGltZSBmb3IgYWxsIGZvbGsgdG8gY29tZSB0byB0aGUgYWlkIG9mIHRoZWlyIGNvdW50cnku
ICAgVGhpcyBjYW4gYmUgcmVwcmVzZW50ZWQsIGluIHRoZSBRdW90ZWQtUHJpbnRhYmxlIGVuY29kaW5nLCBhczo=
ICAgICBOb3cncyB0aGUgdGltZSA9
ICAgICBmb3IgYWxsIGZvbGsgdG8gY29tZT0=
ICAgICAgdG8gdGhlIGFpZCBvZiB0aGVpciBjb3VudHJ5Lg==
ICAgU2luY2UgdGhlIGh5cGhlbiBjaGFyYWN0ZXIgKCItIikgbWF5IGJlIHJlcHJlc2VudGVkIGFzIGl0c2VsZiBpbiB0aGU=
ICAgUXVvdGVkLVByaW50YWJsZSBlbmNvZGluZywgY2FyZSBtdXN0IGJlIHRha2VuLCB3aGVuIGVuY2Fwc3VsYXRpbmcgYQ==
ICAgcXVvdGVkLXByaW50YWJsZSBlbmNvZGVkIGJvZHkgaW5zaWRlIG9uZSBvciBtb3JlIG11bHRpcGFydCBlbnRpdGllcyw=
ICAgdG8gZW5zdXJlIHRoYXQgdGhlIGJvdW5kYXJ5IGRlbGltaXRlciBkb2VzIG5vdCBhcHBlYXIgYW55d2hlcmUgaW4gdGhl
ICAgZW5jb2RlZCBib2R5LiAgKEEgZ29vZCBzdHJhdGVneSBpcyB0byBjaG9vc2UgYSBib3VuZGFyeSB0aGF0IGluY2x1ZGVz
ICAgYSBjaGFyYWN0ZXIgc2VxdWVuY2Ugc3VjaCBhcyAiPV8iIHdoaWNoIGNhbiBuZXZlciBhcHBlYXIgaW4gYQ==
ICAgcXVvdGVkLXByaW50YWJsZSBib2R5LiAgU2VlIHRoZSBkZWZpbml0aW9uIG9mIG11bHRpcGFydCBtZXNzYWdlcyBpbg==
ICAgUkZDIDIwNDYuKQ==
ICAgICAhIiMkQFtcXV5ge3x9fiU=
RnJlZWQgJiBCb3JlbnN0ZWluICAgICAgICAgIFN0YW5kYXJkcyBUcmFjayAgICAgICAgICAgICAgICAgICAgW1BhZ2UgMjRd
UkZDIDIwNDUgICAgICAgICAgICAgICAgSW50ZXJuZXQgTWVzc2FnZSBCb2RpZXMgICAgICAgICAgICBOb3ZlbWJlciAxOTk2
ICAgICAgICAgICAgICAgICAgICBUYWJsZSAxOiBUaGUgQmFzZTY0IEFscGhhYmV0
ICAgICBWYWx1ZSBFbmNvZGluZyAgVmFsdWUgRW5jb2RpbmcgIFZhbHVlIEVuY29kaW5nICBWYWx1ZSBFbmNvZGluZw==
ICAgICAgICAgMCBBICAgICAgICAgICAgMTcgUiAgICAgICAgICAgIDM0IGkgICAgICAgICAgICA1MSB6
ICAgICAgICAgMSBCICAgICAgICAgICAgMTggUyAgICAgICAgICAgIDM1IGogICAgICAgICAgICA1MiAw
ICAgICAgICAgMiBDICAgICAgICAgICAgMTkgVCAgICAgICAgICAgIDM2IGsgICAgICAgICAgICA1MyAx
ICAgICAgICAgMyBEICAgICAgICAgICAgMjAgVSAgICAgICAgICAgIDM3IGwgICAgICAgICAgICA1NCAy
ICAgICAgICAgNCBFICAgICAgICAgICAgMjEgViAgICAgICAgICAgIDM4IG0gICAgICAgICAgICA1NSAz
ICAgICAgICAgNSBGICAgICAgICAgICAgMjIgVyAgICAgICAgICAgIDM5IG4gICAgICAgICAgICA1NiA0
ICAgICAgICAgNiBHICAgICAgICAgICAgMjMgWCAgICAgICAgICAgIDQwIG8gICAgICAgICAgICA1NyA1
ICAgICAgICAgNyBIICAgICAgICAgICAgMjQgWSAgICAgICAgICAgIDQxIHAgICAgICAgICAgICA1OCA2
ICAgICAgICAgOCBJICAgICAgICAgICAgMjUgWiAgICAgICAgICAgIDQyIHEgICAgICAgICAgICA1OSA3
ICAgICAgICAgOSBKICAgICAgICAgICAgMjYgYSAgICAgICAgICAgIDQzIHIgICAgICAgICAgICA2MCA4
ICAgICAgICAxMCBLICAgICAgICAgICAgMjcgYiAgICAgICAgICAgIDQ0IHMgICAgICAgICAgICA2MSA5
ICAgICAgICAxMSBMICAgICAgICAgICAgMjggYyAgICAgICAgICAgIDQ1IHQgICAgICAgICAgICA2MiAr
ICAgICAgICAxMiBNICAgICAgICAgICAgMjkgZCAgICAgICAgICAgIDQ2IHUgICAgICAgICAgICA2MyAv
ICAgICAgICAxMyBOICAgICAgICAgICAgMzAgZSAgICAgICAgICAgIDQ3IHY=
ICAgICAgICAxNCBPICAgICAgICAgICAgMzEgZiAgICAgICAgICAgIDQ4IHcgICAgICAgICAocGFkKSA9
ICAgICAgICAxNSBQICAgICAgICAgICAgMzIgZyAgICAgICAgICAgIDQ5IHg=
ICAgICAgICAxNiBRICAgICAgICAgICAgMzMgaCAgICAgICAgICAgIDUwIHk=

View file

@ -0,0 +1,391 @@
VGhpcyB0ZXN0IGRhdGEgaXMgcGFydCBvZiByZmMyMDQ1IHdoaWNoIGluY2x1ZGVzIGFsbCBjaGFy
YWN0ZXJzIGF+eiBBflosIDB+OSBhbmQgYWxsIHN5bWJvbHMs
SXQgaXMgdXNlZCB0byB0ZXN0IGphdmEudXRpbC5CYXNlNjQuRW5jb2RlciwgYW5kIHdpbGwgYmUg
ZW5jb2RlZCBieSBvcmcuYXBhY2hlLmNvbW1vbnMuY29kZWMuYmluYXJ5LkJhc2U2NC5qYXZh
dG8gdGVzdCBqYXZhLnV0aWwuQmFzZTY0LkRlY29kZXI7
RnJlZWQgJiBCb3JlbnN0ZWluICAgICAgICAgIFN0YW5kYXJkcyBUcmFjayAgICAgICAgICAgICAg
ICAgICAgIFtQYWdlIDFd
UkZDIDIwNDUgICAgICAgICAgICAgICAgSW50ZXJuZXQgTWVzc2FnZSBCb2RpZXMgICAgICAgICAg
ICBOb3ZlbWJlciAxOTk2
ICAgVGhlc2UgZG9jdW1lbnRzIGFyZSByZXZpc2lvbnMgb2YgUkZDcyAxNTIxLCAxNTIyLCBhbmQg
MTU5MCwgd2hpY2g=
ICAgdGhlbXNlbHZlcyB3ZXJlIHJldmlzaW9ucyBvZiBSRkNzIDEzNDEgYW5kIDEzNDIuICBBbiBh
cHBlbmRpeCBpbiBSRkM=
ICAgMjA0OSBkZXNjcmliZXMgZGlmZmVyZW5jZXMgYW5kIGNoYW5nZXMgZnJvbSBwcmV2aW91cyB2
ZXJzaW9ucy4=
VGFibGUgb2YgQ29udGVudHM=
ICAgMS4gSW50cm9kdWN0aW9uIC4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4u
Li4uICAgIDM=
ICAgMi4gRGVmaW5pdGlvbnMsIENvbnZlbnRpb25zLCBhbmQgR2VuZXJpYyBCTkYgR3JhbW1hciAu
Li4uICAgIDU=
ICAgMy4gTUlNRSBIZWFkZXIgRmllbGRzIC4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4u
Li4uICAgIDg=
ICAgNC4gTUlNRS1WZXJzaW9uIEhlYWRlciBGaWVsZCAuLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4u
Li4uICAgIDg=
ICAgNS4gQ29udGVudC1UeXBlIEhlYWRlciBGaWVsZCAuLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4u
Li4uICAgMTA=
ICAgNi4gQ29udGVudC1UcmFuc2Zlci1FbmNvZGluZyBIZWFkZXIgRmllbGQgLi4uLi4uLi4uLi4u
Li4uICAgMTQ=
ICAgNy4gQ29udGVudC1JRCBIZWFkZXIgRmllbGQgLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4u
Li4uICAgMjY=
ICAgOC4gQ29udGVudC1EZXNjcmlwdGlvbiBIZWFkZXIgRmllbGQgLi4uLi4uLi4uLi4uLi4uLi4u
Li4uICAgMjc=
ICAgOS4gQWRkaXRpb25hbCBNSU1FIEhlYWRlciBGaWVsZHMgLi4uLi4uLi4uLi4uLi4uLi4uLi4u
Li4uICAgMjc=
ICAgMTAuIFN1bW1hcnkgLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4u
Li4uICAgMjc=
ICAgMTEuIFNlY3VyaXR5IENvbnNpZGVyYXRpb25zIC4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4u
Li4uICAgMjc=
ICAgMTIuIEF1dGhvcnMnIEFkZHJlc3NlcyAuLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4u
Li4uICAgMjg=
ICAgQS4gQ29sbGVjdGVkIEdyYW1tYXIgLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4u
Li4uICAgMjk=
RnJlZWQgJiBCb3JlbnN0ZWluICAgICAgICAgIFN0YW5kYXJkcyBUcmFjayAgICAgICAgICAgICAg
ICAgICAgIFtQYWdlIDdd
UkZDIDIwNDUgICAgICAgICAgICAgICAgSW50ZXJuZXQgTWVzc2FnZSBCb2RpZXMgICAgICAgICAg
ICBOb3ZlbWJlciAxOTk2
My4gIE1JTUUgSGVhZGVyIEZpZWxkcw==
ICAgTUlNRSBkZWZpbmVzIGEgbnVtYmVyIG9mIG5ldyBSRkMgODIyIGhlYWRlciBmaWVsZHMgdGhh
dCBhcmUgdXNlZCB0bw==
ICAgZGVzY3JpYmUgdGhlIGNvbnRlbnQgb2YgYSBNSU1FIGVudGl0eS4gIFRoZXNlIGhlYWRlciBm
aWVsZHMgb2NjdXIgaW4=
ICAgYXQgbGVhc3QgdHdvIGNvbnRleHRzOg==
ICAgICgxKSAgIEFzIHBhcnQgb2YgYSByZWd1bGFyIFJGQyA4MjIgbWVzc2FnZSBoZWFkZXIu
ICAgICgyKSAgIEluIGEgTUlNRSBib2R5IHBhcnQgaGVhZGVyIHdpdGhpbiBhIG11bHRpcGFydA==
ICAgICAgICAgIGNvbnN0cnVjdC4=
ICAgVGhlIGZvcm1hbCBkZWZpbml0aW9uIG9mIHRoZXNlIGhlYWRlciBmaWVsZHMgaXMgYXMgZm9s
bG93czo=
ICAgICBNSU1FLW1lc3NhZ2UtaGVhZGVycyA6PSBlbnRpdHktaGVhZGVycw==
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWVsZHM=
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2ZXJzaW9uIENSTEY=
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICA7IFRoZSBvcmRlcmluZyBvZiB0aGUgaGVhZGVy
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICA7IGZpZWxkcyBpbXBsaWVkIGJ5IHRoaXMgQk5G
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICA7IGRlZmluaXRpb24gc2hvdWxkIGJlIGlnbm9y
ZWQu
ICAgICBNSU1FLXBhcnQtaGVhZGVycyA6PSBlbnRpdHktaGVhZGVycw==
ICAgICAgICAgICAgICAgICAgICAgICAgICBbIGZpZWxkcyBd
ICAgICAgICAgICAgICAgICAgICAgICAgICA7IEFueSBmaWVsZCBub3QgYmVnaW5uaW5nIHdpdGg=
ICAgICAgICAgICAgICAgICAgICAgICAgICA7ICJjb250ZW50LSIgY2FuIGhhdmUgbm8gZGVmaW5l
ZA==
ICAgICAgICAgICAgICAgICAgICAgICAgICA7IG1lYW5pbmcgYW5kIG1heSBiZSBpZ25vcmVkLg==
ICAgICAgICAgICAgICAgICAgICAgICAgICA7IFRoZSBvcmRlcmluZyBvZiB0aGUgaGVhZGVy
ICAgICAgICAgICAgICAgICAgICAgICAgICA7IGZpZWxkcyBpbXBsaWVkIGJ5IHRoaXMgQk5G
ICAgICAgICAgICAgICAgICAgICAgICAgICA7IGRlZmluaXRpb24gc2hvdWxkIGJlIGlnbm9yZWQu
ICAgVGhlIHN5bnRheCBvZiB0aGUgdmFyaW91cyBzcGVjaWZpYyBNSU1FIGhlYWRlciBmaWVsZHMg
d2lsbCBiZQ==
ICAgZGVzY3JpYmVkIGluIHRoZSBmb2xsb3dpbmcgc2VjdGlvbnMu
RnJlZWQgJiBCb3JlbnN0ZWluICAgICAgICAgIFN0YW5kYXJkcyBUcmFjayAgICAgICAgICAgICAg
ICAgICAgW1BhZ2UgMTFd
UkZDIDIwNDUgICAgICAgICAgICAgICAgSW50ZXJuZXQgTWVzc2FnZSBCb2RpZXMgICAgICAgICAg
ICBOb3ZlbWJlciAxOTk2
NS4xLiAgU3ludGF4IG9mIHRoZSBDb250ZW50LVR5cGUgSGVhZGVyIEZpZWxk
ICAgSW4gdGhlIEF1Z21lbnRlZCBCTkYgbm90YXRpb24gb2YgUkZDIDgyMiwgYSBDb250ZW50LVR5
cGUgaGVhZGVyIGZpZWxk
ICAgdmFsdWUgaXMgZGVmaW5lZCBhcyBmb2xsb3dzOg==
ICAgICBjb250ZW50IDo9ICJDb250ZW50LVR5cGUiICI6IiB0eXBlICIvIiBzdWJ0eXBl
ICAgICAgICAgICAgICAgICooIjsiIHBhcmFtZXRlcik=
ICAgICAgICAgICAgICAgIDsgTWF0Y2hpbmcgb2YgbWVkaWEgdHlwZSBhbmQgc3VidHlwZQ==
ICAgICAgICAgICAgICAgIDsgaXMgQUxXQVlTIGNhc2UtaW5zZW5zaXRpdmUu
ICAgICB0eXBlIDo9IGRpc2NyZXRlLXR5cGUgLyBjb21wb3NpdGUtdHlwZQ==
ICAgICBkaXNjcmV0ZS10eXBlIDo9ICJ0ZXh0IiAvICJpbWFnZSIgLyAiYXVkaW8iIC8gInZpZGVv
IiAv
ICAgICAgICAgICAgICAgICAgICAgICJhcHBsaWNhdGlvbiIgLyBleHRlbnNpb24tdG9rZW4=
ICAgICBjb21wb3NpdGUtdHlwZSA6PSAibWVzc2FnZSIgLyAibXVsdGlwYXJ0IiAvIGV4dGVuc2lv
bi10b2tlbg==
ICAgICBleHRlbnNpb24tdG9rZW4gOj0gaWV0Zi10b2tlbiAvIHgtdG9rZW4=
ICAgICBpZXRmLXRva2VuIDo9IDxBbiBleHRlbnNpb24gdG9rZW4gZGVmaW5lZCBieSBh
ICAgICAgICAgICAgICAgICAgICBzdGFuZGFyZHMtdHJhY2sgUkZDIGFuZCByZWdpc3RlcmVk
ICAgICAgICAgICAgICAgICAgICB3aXRoIElBTkEuPg==
ICAgICB4LXRva2VuIDo9IDxUaGUgdHdvIGNoYXJhY3RlcnMgIlgtIiBvciAieC0iIGZvbGxvd2Vk
LCB3aXRo
ICAgICAgICAgICAgICAgICBubyBpbnRlcnZlbmluZyB3aGl0ZSBzcGFjZSwgYnkgYW55IHRva2Vu
Pg==
ICAgICBzdWJ0eXBlIDo9IGV4dGVuc2lvbi10b2tlbiAvIGlhbmEtdG9rZW4=
ICAgICBpYW5hLXRva2VuIDo9IDxBIHB1YmxpY2x5LWRlZmluZWQgZXh0ZW5zaW9uIHRva2VuLiBU
b2tlbnM=
ICAgICAgICAgICAgICAgICAgICBvZiB0aGlzIGZvcm0gbXVzdCBiZSByZWdpc3RlcmVkIHdpdGgg
SUFOQQ==
ICAgICAgICAgICAgICAgICAgICBhcyBzcGVjaWZpZWQgaW4gUkZDIDIwNDguPg==
ICAgICBwYXJhbWV0ZXIgOj0gYXR0cmlidXRlICI9IiB2YWx1ZQ==
ICAgICBhdHRyaWJ1dGUgOj0gdG9rZW4=
ICAgICAgICAgICAgICAgICAgOyBNYXRjaGluZyBvZiBhdHRyaWJ1dGVz
ICAgICAgICAgICAgICAgICAgOyBpcyBBTFdBWVMgY2FzZS1pbnNlbnNpdGl2ZS4=
ICAgICB2YWx1ZSA6PSB0b2tlbiAvIHF1b3RlZC1zdHJpbmc=
ICAgICB0b2tlbiA6PSAxKjxhbnkgKFVTLUFTQ0lJKSBDSEFSIGV4Y2VwdCBTUEFDRSwgQ1RMcyw=
ICAgICAgICAgICAgICAgICBvciB0c3BlY2lhbHM+
ICAgICB0c3BlY2lhbHMgOj0gICIoIiAvICIpIiAvICI8IiAvICI+IiAvICJAIiAv
ICAgICAgICAgICAgICAgICAgICIsIiAvICI7IiAvICI6IiAvICJcIiAvIDwiPg==
ICAgICAgICAgICAgICAgICAgICIvIiAvICJbIiAvICJdIiAvICI/IiAvICI9Ig==
ICAgICAgICAgICAgICAgICAgIDsgTXVzdCBiZSBpbiBxdW90ZWQtc3RyaW5nLA==
ICAgICAgICAgICAgICAgICAgIDsgdG8gdXNlIHdpdGhpbiBwYXJhbWV0ZXIgdmFsdWVz
ICAgICBkZXNjcmlwdGlvbiA6PSAiQ29udGVudC1EZXNjcmlwdGlvbiIgIjoiICp0ZXh0
ICAgICBlbmNvZGluZyA6PSAiQ29udGVudC1UcmFuc2Zlci1FbmNvZGluZyIgIjoiIG1lY2hhbmlz
bQ==
ICAgICBlbnRpdHktaGVhZGVycyA6PSBbIGNvbnRlbnQgQ1JMRiBd
ICAgICAgICAgICAgICAgICAgICBbIGVuY29kaW5nIENSTEYgXQ==
ICAgICAgICAgICAgICAgICAgICBbIGlkIENSTEYgXQ==
ICAgICAgICAgICAgICAgICAgICBbIGRlc2NyaXB0aW9uIENSTEYgXQ==
ICAgICAgICAgICAgICAgICAgICAqKCBNSU1FLWV4dGVuc2lvbi1maWVsZCBDUkxGICk=
ICAgICBoZXgtb2N0ZXQgOj0gIj0iIDIoRElHSVQgLyAiQSIgLyAiQiIgLyAiQyIgLyAiRCIgLyAi
RSIgLyAiRiIp
ICAgICAgICAgICAgICAgOyBPY3RldCBtdXN0IGJlIHVzZWQgZm9yIGNoYXJhY3RlcnMgPiAxMjcs
ID0s
ICAgICAgICAgICAgICAgOyBTUEFDRXMgb3IgVEFCcyBhdCB0aGUgZW5kcyBvZiBsaW5lcywgYW5k
IGlz
ICAgICAgICAgICAgICAgOyByZWNvbW1lbmRlZCBmb3IgYW55IGNoYXJhY3RlciBub3QgbGlzdGVk
IGlu
ICAgICAgICAgICAgICAgOyBSRkMgMjA0OSBhcyAibWFpbC1zYWZlIi4=
UkZDIDIwNDUgICAgICAgICAgICAgICAgSW50ZXJuZXQgTWVzc2FnZSBCb2RpZXMgICAgICAgICAg
ICBOb3ZlbWJlciAxOTk2
ICAgICAgICAgIG11c3QgYmUgdXNlZC4gIEFuIGVxdWFsIHNpZ24gYXMgdGhlIGxhc3QgY2hhcmFj
dGVyIG9uIGE=
ICAgICAgICAgIGVuY29kZWQgbGluZSBpbmRpY2F0ZXMgc3VjaCBhIG5vbi1zaWduaWZpY2FudCAo
InNvZnQiKQ==
ICAgICAgICAgIGxpbmUgYnJlYWsgaW4gdGhlIGVuY29kZWQgdGV4dC4=
ICAgVGh1cyBpZiB0aGUgInJhdyIgZm9ybSBvZiB0aGUgbGluZSBpcyBhIHNpbmdsZSB1bmVuY29k
ZWQgbGluZSB0aGF0
ICAgc2F5czo=
ICAgICBOb3cncyB0aGUgdGltZSBmb3IgYWxsIGZvbGsgdG8gY29tZSB0byB0aGUgYWlkIG9mIHRo
ZWlyIGNvdW50cnku
ICAgVGhpcyBjYW4gYmUgcmVwcmVzZW50ZWQsIGluIHRoZSBRdW90ZWQtUHJpbnRhYmxlIGVuY29k
aW5nLCBhczo=
ICAgICBOb3cncyB0aGUgdGltZSA9
ICAgICBmb3IgYWxsIGZvbGsgdG8gY29tZT0=
ICAgICAgdG8gdGhlIGFpZCBvZiB0aGVpciBjb3VudHJ5Lg==
ICAgU2luY2UgdGhlIGh5cGhlbiBjaGFyYWN0ZXIgKCItIikgbWF5IGJlIHJlcHJlc2VudGVkIGFz
IGl0c2VsZiBpbiB0aGU=
ICAgUXVvdGVkLVByaW50YWJsZSBlbmNvZGluZywgY2FyZSBtdXN0IGJlIHRha2VuLCB3aGVuIGVu
Y2Fwc3VsYXRpbmcgYQ==
ICAgcXVvdGVkLXByaW50YWJsZSBlbmNvZGVkIGJvZHkgaW5zaWRlIG9uZSBvciBtb3JlIG11bHRp
cGFydCBlbnRpdGllcyw=
ICAgdG8gZW5zdXJlIHRoYXQgdGhlIGJvdW5kYXJ5IGRlbGltaXRlciBkb2VzIG5vdCBhcHBlYXIg
YW55d2hlcmUgaW4gdGhl
ICAgZW5jb2RlZCBib2R5LiAgKEEgZ29vZCBzdHJhdGVneSBpcyB0byBjaG9vc2UgYSBib3VuZGFy
eSB0aGF0IGluY2x1ZGVz
ICAgYSBjaGFyYWN0ZXIgc2VxdWVuY2Ugc3VjaCBhcyAiPV8iIHdoaWNoIGNhbiBuZXZlciBhcHBl
YXIgaW4gYQ==
ICAgcXVvdGVkLXByaW50YWJsZSBib2R5LiAgU2VlIHRoZSBkZWZpbml0aW9uIG9mIG11bHRpcGFy
dCBtZXNzYWdlcyBpbg==
ICAgUkZDIDIwNDYuKQ==
ICAgICAhIiMkQFtcXV5ge3x9fiU=
RnJlZWQgJiBCb3JlbnN0ZWluICAgICAgICAgIFN0YW5kYXJkcyBUcmFjayAgICAgICAgICAgICAg
ICAgICAgW1BhZ2UgMjRd
UkZDIDIwNDUgICAgICAgICAgICAgICAgSW50ZXJuZXQgTWVzc2FnZSBCb2RpZXMgICAgICAgICAg
ICBOb3ZlbWJlciAxOTk2
ICAgICAgICAgICAgICAgICAgICBUYWJsZSAxOiBUaGUgQmFzZTY0IEFscGhhYmV0
ICAgICBWYWx1ZSBFbmNvZGluZyAgVmFsdWUgRW5jb2RpbmcgIFZhbHVlIEVuY29kaW5nICBWYWx1
ZSBFbmNvZGluZw==
ICAgICAgICAgMCBBICAgICAgICAgICAgMTcgUiAgICAgICAgICAgIDM0IGkgICAgICAgICAgICA1
MSB6
ICAgICAgICAgMSBCICAgICAgICAgICAgMTggUyAgICAgICAgICAgIDM1IGogICAgICAgICAgICA1
MiAw
ICAgICAgICAgMiBDICAgICAgICAgICAgMTkgVCAgICAgICAgICAgIDM2IGsgICAgICAgICAgICA1
MyAx
ICAgICAgICAgMyBEICAgICAgICAgICAgMjAgVSAgICAgICAgICAgIDM3IGwgICAgICAgICAgICA1
NCAy
ICAgICAgICAgNCBFICAgICAgICAgICAgMjEgViAgICAgICAgICAgIDM4IG0gICAgICAgICAgICA1
NSAz
ICAgICAgICAgNSBGICAgICAgICAgICAgMjIgVyAgICAgICAgICAgIDM5IG4gICAgICAgICAgICA1
NiA0
ICAgICAgICAgNiBHICAgICAgICAgICAgMjMgWCAgICAgICAgICAgIDQwIG8gICAgICAgICAgICA1
NyA1
ICAgICAgICAgNyBIICAgICAgICAgICAgMjQgWSAgICAgICAgICAgIDQxIHAgICAgICAgICAgICA1
OCA2
ICAgICAgICAgOCBJICAgICAgICAgICAgMjUgWiAgICAgICAgICAgIDQyIHEgICAgICAgICAgICA1
OSA3
ICAgICAgICAgOSBKICAgICAgICAgICAgMjYgYSAgICAgICAgICAgIDQzIHIgICAgICAgICAgICA2
MCA4
ICAgICAgICAxMCBLICAgICAgICAgICAgMjcgYiAgICAgICAgICAgIDQ0IHMgICAgICAgICAgICA2
MSA5
ICAgICAgICAxMSBMICAgICAgICAgICAgMjggYyAgICAgICAgICAgIDQ1IHQgICAgICAgICAgICA2
MiAr
ICAgICAgICAxMiBNICAgICAgICAgICAgMjkgZCAgICAgICAgICAgIDQ2IHUgICAgICAgICAgICA2
MyAv
ICAgICAgICAxMyBOICAgICAgICAgICAgMzAgZSAgICAgICAgICAgIDQ3IHY=
ICAgICAgICAxNCBPICAgICAgICAgICAgMzEgZiAgICAgICAgICAgIDQ4IHcgICAgICAgICAocGFk
KSA9
ICAgICAgICAxNSBQICAgICAgICAgICAgMzIgZyAgICAgICAgICAgIDQ5IHg=
ICAgICAgICAxNiBRICAgICAgICAgICAgMzMgaCAgICAgICAgICAgIDUwIHk=

View file

@ -0,0 +1,183 @@
This test data is part of rfc2045 which includes all characters a~z A~Z, 0~9 and all symbols,
It is used to test java.util.Base64.Encoder, and will be encoded by org.apache.commons.codec.binary.Base64.java
to test java.util.Base64.Decoder;
Freed & Borenstein Standards Track [Page 1]
RFC 2045 Internet Message Bodies November 1996
These documents are revisions of RFCs 1521, 1522, and 1590, which
themselves were revisions of RFCs 1341 and 1342. An appendix in RFC
2049 describes differences and changes from previous versions.
Table of Contents
1. Introduction ......................................... 3
2. Definitions, Conventions, and Generic BNF Grammar .... 5
3. MIME Header Fields ................................... 8
4. MIME-Version Header Field ............................ 8
5. Content-Type Header Field ............................ 10
6. Content-Transfer-Encoding Header Field ............... 14
7. Content-ID Header Field .............................. 26
8. Content-Description Header Field ..................... 27
9. Additional MIME Header Fields ........................ 27
10. Summary ............................................. 27
11. Security Considerations ............................. 27
12. Authors' Addresses .................................. 28
A. Collected Grammar .................................... 29
Freed & Borenstein Standards Track [Page 7]
RFC 2045 Internet Message Bodies November 1996
3. MIME Header Fields
MIME defines a number of new RFC 822 header fields that are used to
describe the content of a MIME entity. These header fields occur in
at least two contexts:
(1) As part of a regular RFC 822 message header.
(2) In a MIME body part header within a multipart
construct.
The formal definition of these header fields is as follows:
MIME-message-headers := entity-headers
fields
version CRLF
; The ordering of the header
; fields implied by this BNF
; definition should be ignored.
MIME-part-headers := entity-headers
[ fields ]
; Any field not beginning with
; "content-" can have no defined
; meaning and may be ignored.
; The ordering of the header
; fields implied by this BNF
; definition should be ignored.
The syntax of the various specific MIME header fields will be
described in the following sections.
Freed & Borenstein Standards Track [Page 11]
RFC 2045 Internet Message Bodies November 1996
5.1. Syntax of the Content-Type Header Field
In the Augmented BNF notation of RFC 822, a Content-Type header field
value is defined as follows:
content := "Content-Type" ":" type "/" subtype
*(";" parameter)
; Matching of media type and subtype
; is ALWAYS case-insensitive.
type := discrete-type / composite-type
discrete-type := "text" / "image" / "audio" / "video" /
"application" / extension-token
composite-type := "message" / "multipart" / extension-token
extension-token := ietf-token / x-token
ietf-token := <An extension token defined by a
standards-track RFC and registered
with IANA.>
x-token := <The two characters "X-" or "x-" followed, with
no intervening white space, by any token>
subtype := extension-token / iana-token
iana-token := <A publicly-defined extension token. Tokens
of this form must be registered with IANA
as specified in RFC 2048.>
parameter := attribute "=" value
attribute := token
; Matching of attributes
; is ALWAYS case-insensitive.
value := token / quoted-string
token := 1*<any (US-ASCII) CHAR except SPACE, CTLs,
or tspecials>
tspecials := "(" / ")" / "<" / ">" / "@" /
"," / ";" / ":" / "\" / <">
"/" / "[" / "]" / "?" / "="
; Must be in quoted-string,
; to use within parameter values
description := "Content-Description" ":" *text
encoding := "Content-Transfer-Encoding" ":" mechanism
entity-headers := [ content CRLF ]
[ encoding CRLF ]
[ id CRLF ]
[ description CRLF ]
*( MIME-extension-field CRLF )
hex-octet := "=" 2(DIGIT / "A" / "B" / "C" / "D" / "E" / "F")
; Octet must be used for characters > 127, =,
; SPACEs or TABs at the ends of lines, and is
; recommended for any character not listed in
; RFC 2049 as "mail-safe".
RFC 2045 Internet Message Bodies November 1996
must be used. An equal sign as the last character on a
encoded line indicates such a non-significant ("soft")
line break in the encoded text.
Thus if the "raw" form of the line is a single unencoded line that
says:
Now's the time for all folk to come to the aid of their country.
This can be represented, in the Quoted-Printable encoding, as:
Now's the time =
for all folk to come=
to the aid of their country.
Since the hyphen character ("-") may be represented as itself in the
Quoted-Printable encoding, care must be taken, when encapsulating a
quoted-printable encoded body inside one or more multipart entities,
to ensure that the boundary delimiter does not appear anywhere in the
encoded body. (A good strategy is to choose a boundary that includes
a character sequence such as "=_" which can never appear in a
quoted-printable body. See the definition of multipart messages in
RFC 2046.)
!"#$@[\]^`{|}~%
Freed & Borenstein Standards Track [Page 24]
RFC 2045 Internet Message Bodies November 1996
Table 1: The Base64 Alphabet
Value Encoding Value Encoding Value Encoding Value Encoding
0 A 17 R 34 i 51 z
1 B 18 S 35 j 52 0
2 C 19 T 36 k 53 1
3 D 20 U 37 l 54 2
4 E 21 V 38 m 55 3
5 F 22 W 39 n 56 4
6 G 23 X 40 o 57 5
7 H 24 Y 41 p 58 6
8 I 25 Z 42 q 59 7
9 J 26 a 43 r 60 8
10 K 27 b 44 s 61 9
11 L 28 c 45 t 62 +
12 M 29 d 46 u 63 /
13 N 30 e 47 v
14 O 31 f 48 w (pad) =
15 P 32 g 49 x
16 Q 33 h 50 y

View file

@ -0,0 +1,183 @@
VGhpcyB0ZXN0IGRhdGEgaXMgcGFydCBvZiByZmMyMDQ1IHdoaWNoIGluY2x1ZGVzIGFsbCBjaGFyYWN0ZXJzIGF-eiBBflosIDB-OSBhbmQgYWxsIHN5bWJvbHMs
SXQgaXMgdXNlZCB0byB0ZXN0IGphdmEudXRpbC5CYXNlNjQuRW5jb2RlciwgYW5kIHdpbGwgYmUgZW5jb2RlZCBieSBvcmcuYXBhY2hlLmNvbW1vbnMuY29kZWMuYmluYXJ5LkJhc2U2NC5qYXZh
dG8gdGVzdCBqYXZhLnV0aWwuQmFzZTY0LkRlY29kZXI7
RnJlZWQgJiBCb3JlbnN0ZWluICAgICAgICAgIFN0YW5kYXJkcyBUcmFjayAgICAgICAgICAgICAgICAgICAgIFtQYWdlIDFd
UkZDIDIwNDUgICAgICAgICAgICAgICAgSW50ZXJuZXQgTWVzc2FnZSBCb2RpZXMgICAgICAgICAgICBOb3ZlbWJlciAxOTk2
ICAgVGhlc2UgZG9jdW1lbnRzIGFyZSByZXZpc2lvbnMgb2YgUkZDcyAxNTIxLCAxNTIyLCBhbmQgMTU5MCwgd2hpY2g=
ICAgdGhlbXNlbHZlcyB3ZXJlIHJldmlzaW9ucyBvZiBSRkNzIDEzNDEgYW5kIDEzNDIuICBBbiBhcHBlbmRpeCBpbiBSRkM=
ICAgMjA0OSBkZXNjcmliZXMgZGlmZmVyZW5jZXMgYW5kIGNoYW5nZXMgZnJvbSBwcmV2aW91cyB2ZXJzaW9ucy4=
VGFibGUgb2YgQ29udGVudHM=
ICAgMS4gSW50cm9kdWN0aW9uIC4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uICAgIDM=
ICAgMi4gRGVmaW5pdGlvbnMsIENvbnZlbnRpb25zLCBhbmQgR2VuZXJpYyBCTkYgR3JhbW1hciAuLi4uICAgIDU=
ICAgMy4gTUlNRSBIZWFkZXIgRmllbGRzIC4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uICAgIDg=
ICAgNC4gTUlNRS1WZXJzaW9uIEhlYWRlciBGaWVsZCAuLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uICAgIDg=
ICAgNS4gQ29udGVudC1UeXBlIEhlYWRlciBGaWVsZCAuLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uICAgMTA=
ICAgNi4gQ29udGVudC1UcmFuc2Zlci1FbmNvZGluZyBIZWFkZXIgRmllbGQgLi4uLi4uLi4uLi4uLi4uICAgMTQ=
ICAgNy4gQ29udGVudC1JRCBIZWFkZXIgRmllbGQgLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uICAgMjY=
ICAgOC4gQ29udGVudC1EZXNjcmlwdGlvbiBIZWFkZXIgRmllbGQgLi4uLi4uLi4uLi4uLi4uLi4uLi4uICAgMjc=
ICAgOS4gQWRkaXRpb25hbCBNSU1FIEhlYWRlciBGaWVsZHMgLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uICAgMjc=
ICAgMTAuIFN1bW1hcnkgLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uICAgMjc=
ICAgMTEuIFNlY3VyaXR5IENvbnNpZGVyYXRpb25zIC4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uICAgMjc=
ICAgMTIuIEF1dGhvcnMnIEFkZHJlc3NlcyAuLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uICAgMjg=
ICAgQS4gQ29sbGVjdGVkIEdyYW1tYXIgLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uICAgMjk=
RnJlZWQgJiBCb3JlbnN0ZWluICAgICAgICAgIFN0YW5kYXJkcyBUcmFjayAgICAgICAgICAgICAgICAgICAgIFtQYWdlIDdd
UkZDIDIwNDUgICAgICAgICAgICAgICAgSW50ZXJuZXQgTWVzc2FnZSBCb2RpZXMgICAgICAgICAgICBOb3ZlbWJlciAxOTk2
My4gIE1JTUUgSGVhZGVyIEZpZWxkcw==
ICAgTUlNRSBkZWZpbmVzIGEgbnVtYmVyIG9mIG5ldyBSRkMgODIyIGhlYWRlciBmaWVsZHMgdGhhdCBhcmUgdXNlZCB0bw==
ICAgZGVzY3JpYmUgdGhlIGNvbnRlbnQgb2YgYSBNSU1FIGVudGl0eS4gIFRoZXNlIGhlYWRlciBmaWVsZHMgb2NjdXIgaW4=
ICAgYXQgbGVhc3QgdHdvIGNvbnRleHRzOg==
ICAgICgxKSAgIEFzIHBhcnQgb2YgYSByZWd1bGFyIFJGQyA4MjIgbWVzc2FnZSBoZWFkZXIu
ICAgICgyKSAgIEluIGEgTUlNRSBib2R5IHBhcnQgaGVhZGVyIHdpdGhpbiBhIG11bHRpcGFydA==
ICAgICAgICAgIGNvbnN0cnVjdC4=
ICAgVGhlIGZvcm1hbCBkZWZpbml0aW9uIG9mIHRoZXNlIGhlYWRlciBmaWVsZHMgaXMgYXMgZm9sbG93czo=
ICAgICBNSU1FLW1lc3NhZ2UtaGVhZGVycyA6PSBlbnRpdHktaGVhZGVycw==
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWVsZHM=
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2ZXJzaW9uIENSTEY=
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICA7IFRoZSBvcmRlcmluZyBvZiB0aGUgaGVhZGVy
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICA7IGZpZWxkcyBpbXBsaWVkIGJ5IHRoaXMgQk5G
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICA7IGRlZmluaXRpb24gc2hvdWxkIGJlIGlnbm9yZWQu
ICAgICBNSU1FLXBhcnQtaGVhZGVycyA6PSBlbnRpdHktaGVhZGVycw==
ICAgICAgICAgICAgICAgICAgICAgICAgICBbIGZpZWxkcyBd
ICAgICAgICAgICAgICAgICAgICAgICAgICA7IEFueSBmaWVsZCBub3QgYmVnaW5uaW5nIHdpdGg=
ICAgICAgICAgICAgICAgICAgICAgICAgICA7ICJjb250ZW50LSIgY2FuIGhhdmUgbm8gZGVmaW5lZA==
ICAgICAgICAgICAgICAgICAgICAgICAgICA7IG1lYW5pbmcgYW5kIG1heSBiZSBpZ25vcmVkLg==
ICAgICAgICAgICAgICAgICAgICAgICAgICA7IFRoZSBvcmRlcmluZyBvZiB0aGUgaGVhZGVy
ICAgICAgICAgICAgICAgICAgICAgICAgICA7IGZpZWxkcyBpbXBsaWVkIGJ5IHRoaXMgQk5G
ICAgICAgICAgICAgICAgICAgICAgICAgICA7IGRlZmluaXRpb24gc2hvdWxkIGJlIGlnbm9yZWQu
ICAgVGhlIHN5bnRheCBvZiB0aGUgdmFyaW91cyBzcGVjaWZpYyBNSU1FIGhlYWRlciBmaWVsZHMgd2lsbCBiZQ==
ICAgZGVzY3JpYmVkIGluIHRoZSBmb2xsb3dpbmcgc2VjdGlvbnMu
RnJlZWQgJiBCb3JlbnN0ZWluICAgICAgICAgIFN0YW5kYXJkcyBUcmFjayAgICAgICAgICAgICAgICAgICAgW1BhZ2UgMTFd
UkZDIDIwNDUgICAgICAgICAgICAgICAgSW50ZXJuZXQgTWVzc2FnZSBCb2RpZXMgICAgICAgICAgICBOb3ZlbWJlciAxOTk2
NS4xLiAgU3ludGF4IG9mIHRoZSBDb250ZW50LVR5cGUgSGVhZGVyIEZpZWxk
ICAgSW4gdGhlIEF1Z21lbnRlZCBCTkYgbm90YXRpb24gb2YgUkZDIDgyMiwgYSBDb250ZW50LVR5cGUgaGVhZGVyIGZpZWxk
ICAgdmFsdWUgaXMgZGVmaW5lZCBhcyBmb2xsb3dzOg==
ICAgICBjb250ZW50IDo9ICJDb250ZW50LVR5cGUiICI6IiB0eXBlICIvIiBzdWJ0eXBl
ICAgICAgICAgICAgICAgICooIjsiIHBhcmFtZXRlcik=
ICAgICAgICAgICAgICAgIDsgTWF0Y2hpbmcgb2YgbWVkaWEgdHlwZSBhbmQgc3VidHlwZQ==
ICAgICAgICAgICAgICAgIDsgaXMgQUxXQVlTIGNhc2UtaW5zZW5zaXRpdmUu
ICAgICB0eXBlIDo9IGRpc2NyZXRlLXR5cGUgLyBjb21wb3NpdGUtdHlwZQ==
ICAgICBkaXNjcmV0ZS10eXBlIDo9ICJ0ZXh0IiAvICJpbWFnZSIgLyAiYXVkaW8iIC8gInZpZGVvIiAv
ICAgICAgICAgICAgICAgICAgICAgICJhcHBsaWNhdGlvbiIgLyBleHRlbnNpb24tdG9rZW4=
ICAgICBjb21wb3NpdGUtdHlwZSA6PSAibWVzc2FnZSIgLyAibXVsdGlwYXJ0IiAvIGV4dGVuc2lvbi10b2tlbg==
ICAgICBleHRlbnNpb24tdG9rZW4gOj0gaWV0Zi10b2tlbiAvIHgtdG9rZW4=
ICAgICBpZXRmLXRva2VuIDo9IDxBbiBleHRlbnNpb24gdG9rZW4gZGVmaW5lZCBieSBh
ICAgICAgICAgICAgICAgICAgICBzdGFuZGFyZHMtdHJhY2sgUkZDIGFuZCByZWdpc3RlcmVk
ICAgICAgICAgICAgICAgICAgICB3aXRoIElBTkEuPg==
ICAgICB4LXRva2VuIDo9IDxUaGUgdHdvIGNoYXJhY3RlcnMgIlgtIiBvciAieC0iIGZvbGxvd2VkLCB3aXRo
ICAgICAgICAgICAgICAgICBubyBpbnRlcnZlbmluZyB3aGl0ZSBzcGFjZSwgYnkgYW55IHRva2VuPg==
ICAgICBzdWJ0eXBlIDo9IGV4dGVuc2lvbi10b2tlbiAvIGlhbmEtdG9rZW4=
ICAgICBpYW5hLXRva2VuIDo9IDxBIHB1YmxpY2x5LWRlZmluZWQgZXh0ZW5zaW9uIHRva2VuLiBUb2tlbnM=
ICAgICAgICAgICAgICAgICAgICBvZiB0aGlzIGZvcm0gbXVzdCBiZSByZWdpc3RlcmVkIHdpdGggSUFOQQ==
ICAgICAgICAgICAgICAgICAgICBhcyBzcGVjaWZpZWQgaW4gUkZDIDIwNDguPg==
ICAgICBwYXJhbWV0ZXIgOj0gYXR0cmlidXRlICI9IiB2YWx1ZQ==
ICAgICBhdHRyaWJ1dGUgOj0gdG9rZW4=
ICAgICAgICAgICAgICAgICAgOyBNYXRjaGluZyBvZiBhdHRyaWJ1dGVz
ICAgICAgICAgICAgICAgICAgOyBpcyBBTFdBWVMgY2FzZS1pbnNlbnNpdGl2ZS4=
ICAgICB2YWx1ZSA6PSB0b2tlbiAvIHF1b3RlZC1zdHJpbmc=
ICAgICB0b2tlbiA6PSAxKjxhbnkgKFVTLUFTQ0lJKSBDSEFSIGV4Y2VwdCBTUEFDRSwgQ1RMcyw=
ICAgICAgICAgICAgICAgICBvciB0c3BlY2lhbHM-
ICAgICB0c3BlY2lhbHMgOj0gICIoIiAvICIpIiAvICI8IiAvICI-IiAvICJAIiAv
ICAgICAgICAgICAgICAgICAgICIsIiAvICI7IiAvICI6IiAvICJcIiAvIDwiPg==
ICAgICAgICAgICAgICAgICAgICIvIiAvICJbIiAvICJdIiAvICI_IiAvICI9Ig==
ICAgICAgICAgICAgICAgICAgIDsgTXVzdCBiZSBpbiBxdW90ZWQtc3RyaW5nLA==
ICAgICAgICAgICAgICAgICAgIDsgdG8gdXNlIHdpdGhpbiBwYXJhbWV0ZXIgdmFsdWVz
ICAgICBkZXNjcmlwdGlvbiA6PSAiQ29udGVudC1EZXNjcmlwdGlvbiIgIjoiICp0ZXh0
ICAgICBlbmNvZGluZyA6PSAiQ29udGVudC1UcmFuc2Zlci1FbmNvZGluZyIgIjoiIG1lY2hhbmlzbQ==
ICAgICBlbnRpdHktaGVhZGVycyA6PSBbIGNvbnRlbnQgQ1JMRiBd
ICAgICAgICAgICAgICAgICAgICBbIGVuY29kaW5nIENSTEYgXQ==
ICAgICAgICAgICAgICAgICAgICBbIGlkIENSTEYgXQ==
ICAgICAgICAgICAgICAgICAgICBbIGRlc2NyaXB0aW9uIENSTEYgXQ==
ICAgICAgICAgICAgICAgICAgICAqKCBNSU1FLWV4dGVuc2lvbi1maWVsZCBDUkxGICk=
ICAgICBoZXgtb2N0ZXQgOj0gIj0iIDIoRElHSVQgLyAiQSIgLyAiQiIgLyAiQyIgLyAiRCIgLyAiRSIgLyAiRiIp
ICAgICAgICAgICAgICAgOyBPY3RldCBtdXN0IGJlIHVzZWQgZm9yIGNoYXJhY3RlcnMgPiAxMjcsID0s
ICAgICAgICAgICAgICAgOyBTUEFDRXMgb3IgVEFCcyBhdCB0aGUgZW5kcyBvZiBsaW5lcywgYW5kIGlz
ICAgICAgICAgICAgICAgOyByZWNvbW1lbmRlZCBmb3IgYW55IGNoYXJhY3RlciBub3QgbGlzdGVkIGlu
ICAgICAgICAgICAgICAgOyBSRkMgMjA0OSBhcyAibWFpbC1zYWZlIi4=
UkZDIDIwNDUgICAgICAgICAgICAgICAgSW50ZXJuZXQgTWVzc2FnZSBCb2RpZXMgICAgICAgICAgICBOb3ZlbWJlciAxOTk2
ICAgICAgICAgIG11c3QgYmUgdXNlZC4gIEFuIGVxdWFsIHNpZ24gYXMgdGhlIGxhc3QgY2hhcmFjdGVyIG9uIGE=
ICAgICAgICAgIGVuY29kZWQgbGluZSBpbmRpY2F0ZXMgc3VjaCBhIG5vbi1zaWduaWZpY2FudCAoInNvZnQiKQ==
ICAgICAgICAgIGxpbmUgYnJlYWsgaW4gdGhlIGVuY29kZWQgdGV4dC4=
ICAgVGh1cyBpZiB0aGUgInJhdyIgZm9ybSBvZiB0aGUgbGluZSBpcyBhIHNpbmdsZSB1bmVuY29kZWQgbGluZSB0aGF0
ICAgc2F5czo=
ICAgICBOb3cncyB0aGUgdGltZSBmb3IgYWxsIGZvbGsgdG8gY29tZSB0byB0aGUgYWlkIG9mIHRoZWlyIGNvdW50cnku
ICAgVGhpcyBjYW4gYmUgcmVwcmVzZW50ZWQsIGluIHRoZSBRdW90ZWQtUHJpbnRhYmxlIGVuY29kaW5nLCBhczo=
ICAgICBOb3cncyB0aGUgdGltZSA9
ICAgICBmb3IgYWxsIGZvbGsgdG8gY29tZT0=
ICAgICAgdG8gdGhlIGFpZCBvZiB0aGVpciBjb3VudHJ5Lg==
ICAgU2luY2UgdGhlIGh5cGhlbiBjaGFyYWN0ZXIgKCItIikgbWF5IGJlIHJlcHJlc2VudGVkIGFzIGl0c2VsZiBpbiB0aGU=
ICAgUXVvdGVkLVByaW50YWJsZSBlbmNvZGluZywgY2FyZSBtdXN0IGJlIHRha2VuLCB3aGVuIGVuY2Fwc3VsYXRpbmcgYQ==
ICAgcXVvdGVkLXByaW50YWJsZSBlbmNvZGVkIGJvZHkgaW5zaWRlIG9uZSBvciBtb3JlIG11bHRpcGFydCBlbnRpdGllcyw=
ICAgdG8gZW5zdXJlIHRoYXQgdGhlIGJvdW5kYXJ5IGRlbGltaXRlciBkb2VzIG5vdCBhcHBlYXIgYW55d2hlcmUgaW4gdGhl
ICAgZW5jb2RlZCBib2R5LiAgKEEgZ29vZCBzdHJhdGVneSBpcyB0byBjaG9vc2UgYSBib3VuZGFyeSB0aGF0IGluY2x1ZGVz
ICAgYSBjaGFyYWN0ZXIgc2VxdWVuY2Ugc3VjaCBhcyAiPV8iIHdoaWNoIGNhbiBuZXZlciBhcHBlYXIgaW4gYQ==
ICAgcXVvdGVkLXByaW50YWJsZSBib2R5LiAgU2VlIHRoZSBkZWZpbml0aW9uIG9mIG11bHRpcGFydCBtZXNzYWdlcyBpbg==
ICAgUkZDIDIwNDYuKQ==
ICAgICAhIiMkQFtcXV5ge3x9fiU=
RnJlZWQgJiBCb3JlbnN0ZWluICAgICAgICAgIFN0YW5kYXJkcyBUcmFjayAgICAgICAgICAgICAgICAgICAgW1BhZ2UgMjRd
UkZDIDIwNDUgICAgICAgICAgICAgICAgSW50ZXJuZXQgTWVzc2FnZSBCb2RpZXMgICAgICAgICAgICBOb3ZlbWJlciAxOTk2
ICAgICAgICAgICAgICAgICAgICBUYWJsZSAxOiBUaGUgQmFzZTY0IEFscGhhYmV0
ICAgICBWYWx1ZSBFbmNvZGluZyAgVmFsdWUgRW5jb2RpbmcgIFZhbHVlIEVuY29kaW5nICBWYWx1ZSBFbmNvZGluZw==
ICAgICAgICAgMCBBICAgICAgICAgICAgMTcgUiAgICAgICAgICAgIDM0IGkgICAgICAgICAgICA1MSB6
ICAgICAgICAgMSBCICAgICAgICAgICAgMTggUyAgICAgICAgICAgIDM1IGogICAgICAgICAgICA1MiAw
ICAgICAgICAgMiBDICAgICAgICAgICAgMTkgVCAgICAgICAgICAgIDM2IGsgICAgICAgICAgICA1MyAx
ICAgICAgICAgMyBEICAgICAgICAgICAgMjAgVSAgICAgICAgICAgIDM3IGwgICAgICAgICAgICA1NCAy
ICAgICAgICAgNCBFICAgICAgICAgICAgMjEgViAgICAgICAgICAgIDM4IG0gICAgICAgICAgICA1NSAz
ICAgICAgICAgNSBGICAgICAgICAgICAgMjIgVyAgICAgICAgICAgIDM5IG4gICAgICAgICAgICA1NiA0
ICAgICAgICAgNiBHICAgICAgICAgICAgMjMgWCAgICAgICAgICAgIDQwIG8gICAgICAgICAgICA1NyA1
ICAgICAgICAgNyBIICAgICAgICAgICAgMjQgWSAgICAgICAgICAgIDQxIHAgICAgICAgICAgICA1OCA2
ICAgICAgICAgOCBJICAgICAgICAgICAgMjUgWiAgICAgICAgICAgIDQyIHEgICAgICAgICAgICA1OSA3
ICAgICAgICAgOSBKICAgICAgICAgICAgMjYgYSAgICAgICAgICAgIDQzIHIgICAgICAgICAgICA2MCA4
ICAgICAgICAxMCBLICAgICAgICAgICAgMjcgYiAgICAgICAgICAgIDQ0IHMgICAgICAgICAgICA2MSA5
ICAgICAgICAxMSBMICAgICAgICAgICAgMjggYyAgICAgICAgICAgIDQ1IHQgICAgICAgICAgICA2MiAr
ICAgICAgICAxMiBNICAgICAgICAgICAgMjkgZCAgICAgICAgICAgIDQ2IHUgICAgICAgICAgICA2MyAv
ICAgICAgICAxMyBOICAgICAgICAgICAgMzAgZSAgICAgICAgICAgIDQ3IHY=
ICAgICAgICAxNCBPICAgICAgICAgICAgMzEgZiAgICAgICAgICAgIDQ4IHcgICAgICAgICAocGFkKSA9
ICAgICAgICAxNSBQICAgICAgICAgICAgMzIgZyAgICAgICAgICAgIDQ5IHg=
ICAgICAgICAxNiBRICAgICAgICAgICAgMzMgaCAgICAgICAgICAgIDUwIHk=

View file

@ -0,0 +1,43 @@
/*
* Copyright (c) 1999, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @bug 4201163
* @summary test the BitSet.and() method
*/
import java.util.BitSet;
public final class And {
public static void main(String[] args) throws Exception {
BitSet a = new BitSet();
BitSet b = new BitSet();
a.set(0);
a.set(70);
b.set(40);
a.and(b);
if (a.length() != 0)
throw new RuntimeException("Incorrect length after and().");
}
}

View file

@ -0,0 +1,986 @@
/*
* Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/* @test
* @bug 4098239 4107540 4080736 4261102 4274710 4305272
* 4979017 4979028 4979031 5030267 6222207 8040806
* @summary Test the operation of the methods of BitSet class
* @author Mike McCloskey, Martin Buchholz
* @run main/othervm BSMethods
* @key randomness
*/
import java.util.*;
/**
* This is a simple test class created to run tests on the BitSet class.
*
*/
public class BSMethods {
private static Random generator = new Random();
private static boolean failure = false;
private static void fail(String diagnostic) {
new Error(diagnostic).printStackTrace();
failure = true;
}
private static void check(boolean condition) {
check(condition, "something's fishy");
}
private static void check(boolean condition, String diagnostic) {
if (! condition)
fail(diagnostic);
}
private static void checkEmpty(BitSet s) {
check(s.isEmpty(), "isEmpty");
check(s.length() == 0, "length");
check(s.cardinality() == 0, "cardinality");
check(s.equals(new BitSet()) , "equals");
check(s.equals(new BitSet(0)) , "equals");
check(s.equals(new BitSet(127)), "equals");
check(s.equals(new BitSet(128)), "equals");
check(s.nextSetBit(0) == -1, "nextSetBit");
check(s.nextSetBit(127) == -1, "nextSetBit");
check(s.nextSetBit(128) == -1, "nextSetBit");
check(s.nextClearBit(0) == 0, "nextClearBit");
check(s.nextClearBit(127) == 127, "nextClearBit");
check(s.nextClearBit(128) == 128, "nextClearBit");
check(s.toString().equals("{}"), "toString");
check(! s.get(0), "get");
}
private static BitSet makeSet(int... elts) {
BitSet s = new BitSet();
for (int elt : elts)
s.set(elt);
return s;
}
private static void checkEquality(BitSet s, BitSet t) {
checkSanity(s, t);
check(s.equals(t), "equals");
check(s.toString().equals(t.toString()), "equal strings");
check(s.length() == t.length(), "equal lengths");
check(s.cardinality() == t.cardinality(), "equal cardinalities");
}
private static void checkSanity(BitSet... sets) {
for (BitSet s : sets) {
int len = s.length();
int cardinality1 = s.cardinality();
int cardinality2 = 0;
for (int i = s.nextSetBit(0); i >= 0; i = s.nextSetBit(i+1)) {
check(s.get(i));
cardinality2++;
}
check(s.nextSetBit(len) == -1, "last set bit");
check(s.nextClearBit(len) == len, "last set bit");
check(s.isEmpty() == (len == 0), "emptiness");
check(cardinality1 == cardinality2, "cardinalities");
check(len <= s.size(), "length <= size");
check(len >= 0, "length >= 0");
check(cardinality1 >= 0, "cardinality >= 0");
}
}
public static void main(String[] args) {
//testFlipTime();
// These are the single bit versions
testSetGetClearFlip();
// Test the ranged versions
testClear();
testFlip();
testSet();
testGet();
// BitSet interaction calls
testAndNot();
testAnd();
testOr();
testXor();
// Miscellaneous calls
testLength();
testEquals();
testNextSetBit();
testNextClearBit();
testIntersects();
testCardinality();
testEmpty();
testEmpty2();
testToString();
testLogicalIdentities();
if (failure)
throw new RuntimeException("One or more BitSet failures.");
}
private static void report(String testName, int failCount) {
System.err.println(testName+": " +
(failCount==0 ? "Passed":"Failed("+failCount+")"));
if (failCount > 0)
failure = true;
}
private static void testFlipTime() {
// Make a fairly random bitset
BitSet b1 = new BitSet();
b1.set(1000);
long startTime = System.currentTimeMillis();
for(int x=0; x<100000; x++) {
b1.flip(100, 900);
}
long endTime = System.currentTimeMillis();
long total = endTime - startTime;
System.out.println("Multiple word flip Time "+total);
startTime = System.currentTimeMillis();
for(int x=0; x<100000; x++) {
b1.flip(2, 44);
}
endTime = System.currentTimeMillis();
total = endTime - startTime;
System.out.println("Single word flip Time "+total);
}
private static void testNextSetBit() {
int failCount = 0;
for (int i=0; i<100; i++) {
int numberOfSetBits = generator.nextInt(100) + 1;
BitSet testSet = new BitSet();
int[] history = new int[numberOfSetBits];
// Set some random bits and remember them
int nextBitToSet = 0;
for (int x=0; x<numberOfSetBits; x++) {
nextBitToSet += generator.nextInt(30)+1;
history[x] = nextBitToSet;
testSet.set(nextBitToSet);
}
// Verify their retrieval using nextSetBit()
int historyIndex = 0;
for(int x=testSet.nextSetBit(0); x>=0; x=testSet.nextSetBit(x+1)) {
if (x != history[historyIndex++])
failCount++;
}
checkSanity(testSet);
}
report("NextSetBit ", failCount);
}
private static void testNextClearBit() {
int failCount = 0;
for (int i=0; i<1000; i++) {
BitSet b = new BitSet(256);
int[] history = new int[10];
// Set all the bits
for (int x=0; x<256; x++)
b.set(x);
// Clear some random bits and remember them
int nextBitToClear = 0;
for (int x=0; x<10; x++) {
nextBitToClear += generator.nextInt(24)+1;
history[x] = nextBitToClear;
b.clear(nextBitToClear);
}
// Verify their retrieval using nextClearBit()
int historyIndex = 0;
for(int x=b.nextClearBit(0); x<256; x=b.nextClearBit(x+1)) {
if (x != history[historyIndex++])
failCount++;
}
checkSanity(b);
}
// regression test for 4350178
BitSet bs = new BitSet();
if (bs.nextClearBit(0) != 0)
failCount++;
for (int i = 0; i < 64; i++) {
bs.set(i);
if (bs.nextClearBit(0) != i+1)
failCount++;
}
checkSanity(bs);
report("NextClearBit ", failCount);
}
private static void testSetGetClearFlip() {
int failCount = 0;
for (int i=0; i<100; i++) {
BitSet testSet = new BitSet();
HashSet<Integer> history = new HashSet<Integer>();
// Set a random number of bits in random places
// up to a random maximum
int nextBitToSet = 0;
int numberOfSetBits = generator.nextInt(100) + 1;
int highestPossibleSetBit = generator.nextInt(1000) + 1;
for (int x=0; x<numberOfSetBits; x++) {
nextBitToSet = generator.nextInt(highestPossibleSetBit);
history.add(new Integer(nextBitToSet));
testSet.set(nextBitToSet);
}
// Make sure each bit is set appropriately
for (int x=0; x<highestPossibleSetBit; x++) {
if (testSet.get(x) != history.contains(new Integer(x)))
failCount++;
}
// Clear the bits
Iterator<Integer> setBitIterator = history.iterator();
while (setBitIterator.hasNext()) {
Integer setBit = setBitIterator.next();
testSet.clear(setBit.intValue());
}
// Verify they were cleared
for (int x=0; x<highestPossibleSetBit; x++)
if (testSet.get(x))
failCount++;
if(testSet.length() != 0)
failCount++;
// Set them with set(int, boolean)
setBitIterator = history.iterator();
while (setBitIterator.hasNext()) {
Integer setBit = setBitIterator.next();
testSet.set(setBit.intValue(), true);
}
// Make sure each bit is set appropriately
for (int x=0; x<highestPossibleSetBit; x++) {
if (testSet.get(x) != history.contains(new Integer(x)))
failCount++;
}
// Clear them with set(int, boolean)
setBitIterator = history.iterator();
while (setBitIterator.hasNext()) {
Integer setBit = (Integer)setBitIterator.next();
testSet.set(setBit.intValue(), false);
}
// Verify they were cleared
for (int x=0; x<highestPossibleSetBit; x++)
if (testSet.get(x))
failCount++;
if(testSet.length() != 0)
failCount++;
// Flip them on
setBitIterator = history.iterator();
while (setBitIterator.hasNext()) {
Integer setBit = (Integer)setBitIterator.next();
testSet.flip(setBit.intValue());
}
// Verify they were flipped
for (int x=0; x<highestPossibleSetBit; x++) {
if (testSet.get(x) != history.contains(new Integer(x)))
failCount++;
}
// Flip them off
setBitIterator = history.iterator();
while (setBitIterator.hasNext()) {
Integer setBit = (Integer)setBitIterator.next();
testSet.flip(setBit.intValue());
}
// Verify they were flipped
for (int x=0; x<highestPossibleSetBit; x++)
if (testSet.get(x))
failCount++;
if(testSet.length() != 0)
failCount++;
checkSanity(testSet);
}
report("SetGetClearFlip ", failCount);
}
private static void testAndNot() {
int failCount = 0;
for (int i=0; i<100; i++) {
BitSet b1 = new BitSet(256);
BitSet b2 = new BitSet(256);
// Set some random bits in first set and remember them
int nextBitToSet = 0;
for (int x=0; x<10; x++)
b1.set(generator.nextInt(255));
// Set some random bits in second set and remember them
for (int x=10; x<20; x++)
b2.set(generator.nextInt(255));
// andNot the sets together
BitSet b3 = (BitSet)b1.clone();
b3.andNot(b2);
// Examine each bit of b3 for errors
for(int x=0; x<256; x++) {
boolean bit1 = b1.get(x);
boolean bit2 = b2.get(x);
boolean bit3 = b3.get(x);
if (!(bit3 == (bit1 & (!bit2))))
failCount++;
}
checkSanity(b1, b2, b3);
}
report("AndNot ", failCount);
}
private static void testAnd() {
int failCount = 0;
for (int i=0; i<100; i++) {
BitSet b1 = new BitSet(256);
BitSet b2 = new BitSet(256);
// Set some random bits in first set and remember them
int nextBitToSet = 0;
for (int x=0; x<10; x++)
b1.set(generator.nextInt(255));
// Set more random bits in second set and remember them
for (int x=10; x<20; x++)
b2.set(generator.nextInt(255));
// And the sets together
BitSet b3 = (BitSet)b1.clone();
b3.and(b2);
// Examine each bit of b3 for errors
for(int x=0; x<256; x++) {
boolean bit1 = b1.get(x);
boolean bit2 = b2.get(x);
boolean bit3 = b3.get(x);
if (!(bit3 == (bit1 & bit2)))
failCount++;
}
checkSanity(b1, b2, b3);
}
// `and' that happens to clear the last word
BitSet b4 = makeSet(2, 127);
b4.and(makeSet(2, 64));
checkSanity(b4);
if (!(b4.equals(makeSet(2))))
failCount++;
report("And ", failCount);
}
private static void testOr() {
int failCount = 0;
for (int i=0; i<100; i++) {
BitSet b1 = new BitSet(256);
BitSet b2 = new BitSet(256);
int[] history = new int[20];
// Set some random bits in first set and remember them
int nextBitToSet = 0;
for (int x=0; x<10; x++) {
nextBitToSet = generator.nextInt(255);
history[x] = nextBitToSet;
b1.set(nextBitToSet);
}
// Set more random bits in second set and remember them
for (int x=10; x<20; x++) {
nextBitToSet = generator.nextInt(255);
history[x] = nextBitToSet;
b2.set(nextBitToSet);
}
// Or the sets together
BitSet b3 = (BitSet)b1.clone();
b3.or(b2);
// Verify the set bits of b3 from the history
int historyIndex = 0;
for(int x=0; x<20; x++) {
if (!b3.get(history[x]))
failCount++;
}
// Examine each bit of b3 for errors
for(int x=0; x<256; x++) {
boolean bit1 = b1.get(x);
boolean bit2 = b2.get(x);
boolean bit3 = b3.get(x);
if (!(bit3 == (bit1 | bit2)))
failCount++;
}
checkSanity(b1, b2, b3);
}
report("Or ", failCount);
}
private static void testXor() {
int failCount = 0;
for (int i=0; i<100; i++) {
BitSet b1 = new BitSet(256);
BitSet b2 = new BitSet(256);
// Set some random bits in first set and remember them
int nextBitToSet = 0;
for (int x=0; x<10; x++)
b1.set(generator.nextInt(255));
// Set more random bits in second set and remember them
for (int x=10; x<20; x++)
b2.set(generator.nextInt(255));
// Xor the sets together
BitSet b3 = (BitSet)b1.clone();
b3.xor(b2);
// Examine each bit of b3 for errors
for(int x=0; x<256; x++) {
boolean bit1 = b1.get(x);
boolean bit2 = b2.get(x);
boolean bit3 = b3.get(x);
if (!(bit3 == (bit1 ^ bit2)))
failCount++;
}
checkSanity(b1, b2, b3);
b3.xor(b3); checkEmpty(b3);
}
// xor that happens to clear the last word
BitSet b4 = makeSet(2, 64, 127);
b4.xor(makeSet(64, 127));
checkSanity(b4);
if (!(b4.equals(makeSet(2))))
failCount++;
report("Xor ", failCount);
}
private static void testEquals() {
int failCount = 0;
for (int i=0; i<100; i++) {
// Create BitSets of different sizes
BitSet b1 = new BitSet(generator.nextInt(1000)+1);
BitSet b2 = new BitSet(generator.nextInt(1000)+1);
// Set some random bits
int nextBitToSet = 0;
for (int x=0; x<10; x++) {
nextBitToSet += generator.nextInt(50)+1;
b1.set(nextBitToSet);
b2.set(nextBitToSet);
}
// Verify their equality despite different storage sizes
if (!b1.equals(b2))
failCount++;
checkEquality(b1,b2);
}
report("Equals ", failCount);
}
private static void testLength() {
int failCount = 0;
// Test length after set
for (int i=0; i<100; i++) {
BitSet b1 = new BitSet(256);
int highestSetBit = 0;
for(int x=0; x<100; x++) {
int nextBitToSet = generator.nextInt(255);
if (nextBitToSet > highestSetBit)
highestSetBit = nextBitToSet;
b1.set(nextBitToSet);
if (b1.length() != highestSetBit + 1)
failCount++;
}
checkSanity(b1);
}
// Test length after flip
for (int i=0; i<100; i++) {
BitSet b1 = new BitSet(256);
for(int x=0; x<100; x++) {
// Flip a random range twice
int rangeStart = generator.nextInt(100);
int rangeEnd = rangeStart + generator.nextInt(100);
b1.flip(rangeStart);
b1.flip(rangeStart);
if (b1.length() != 0)
failCount++;
b1.flip(rangeStart, rangeEnd);
b1.flip(rangeStart, rangeEnd);
if (b1.length() != 0)
failCount++;
}
checkSanity(b1);
}
// Test length after or
for (int i=0; i<100; i++) {
BitSet b1 = new BitSet(256);
BitSet b2 = new BitSet(256);
int bit1 = generator.nextInt(100);
int bit2 = generator.nextInt(100);
int highestSetBit = (bit1 > bit2) ? bit1 : bit2;
b1.set(bit1);
b2.set(bit2);
b1.or(b2);
if (b1.length() != highestSetBit + 1)
failCount++;
checkSanity(b1, b2);
}
report("Length ", failCount);
}
private static void testClear() {
int failCount = 0;
for (int i=0; i<1000; i++) {
BitSet b1 = new BitSet();
// Make a fairly random bitset
int numberOfSetBits = generator.nextInt(100) + 1;
int highestPossibleSetBit = generator.nextInt(1000) + 1;
for (int x=0; x<numberOfSetBits; x++)
b1.set(generator.nextInt(highestPossibleSetBit));
BitSet b2 = (BitSet)b1.clone();
// Clear out a random range
int rangeStart = generator.nextInt(100);
int rangeEnd = rangeStart + generator.nextInt(100);
// Use the clear(int, int) call on b1
b1.clear(rangeStart, rangeEnd);
// Use a loop on b2
for (int x=rangeStart; x<rangeEnd; x++)
b2.clear(x);
// Verify their equality
if (!b1.equals(b2)) {
System.out.println("rangeStart = " + rangeStart);
System.out.println("rangeEnd = " + rangeEnd);
System.out.println("b1 = " + b1);
System.out.println("b2 = " + b2);
failCount++;
}
checkEquality(b1,b2);
}
report("Clear ", failCount);
}
private static void testSet() {
int failCount = 0;
// Test set(int, int)
for (int i=0; i<1000; i++) {
BitSet b1 = new BitSet();
// Make a fairly random bitset
int numberOfSetBits = generator.nextInt(100) + 1;
int highestPossibleSetBit = generator.nextInt(1000) + 1;
for (int x=0; x<numberOfSetBits; x++)
b1.set(generator.nextInt(highestPossibleSetBit));
BitSet b2 = (BitSet)b1.clone();
// Set a random range
int rangeStart = generator.nextInt(100);
int rangeEnd = rangeStart + generator.nextInt(100);
// Use the set(int, int) call on b1
b1.set(rangeStart, rangeEnd);
// Use a loop on b2
for (int x=rangeStart; x<rangeEnd; x++)
b2.set(x);
// Verify their equality
if (!b1.equals(b2)) {
System.out.println("Set 1");
System.out.println("rangeStart = " + rangeStart);
System.out.println("rangeEnd = " + rangeEnd);
System.out.println("b1 = " + b1);
System.out.println("b2 = " + b2);
failCount++;
}
checkEquality(b1,b2);
}
// Test set(int, int, boolean)
for (int i=0; i<100; i++) {
BitSet b1 = new BitSet();
// Make a fairly random bitset
int numberOfSetBits = generator.nextInt(100) + 1;
int highestPossibleSetBit = generator.nextInt(1000) + 1;
for (int x=0; x<numberOfSetBits; x++)
b1.set(generator.nextInt(highestPossibleSetBit));
BitSet b2 = (BitSet)b1.clone();
boolean setOrClear = generator.nextBoolean();
// Set a random range
int rangeStart = generator.nextInt(100);
int rangeEnd = rangeStart + generator.nextInt(100);
// Use the set(int, int, boolean) call on b1
b1.set(rangeStart, rangeEnd, setOrClear);
// Use a loop on b2
for (int x=rangeStart; x<rangeEnd; x++)
b2.set(x, setOrClear);
// Verify their equality
if (!b1.equals(b2)) {
System.out.println("Set 2");
System.out.println("b1 = " + b1);
System.out.println("b2 = " + b2);
failCount++;
}
checkEquality(b1,b2);
}
report("Set ", failCount);
}
private static void testFlip() {
int failCount = 0;
for (int i=0; i<1000; i++) {
BitSet b1 = new BitSet();
// Make a fairly random bitset
int numberOfSetBits = generator.nextInt(100) + 1;
int highestPossibleSetBit = generator.nextInt(1000) + 1;
for (int x=0; x<numberOfSetBits; x++)
b1.set(generator.nextInt(highestPossibleSetBit));
BitSet b2 = (BitSet)b1.clone();
// Flip a random range
int rangeStart = generator.nextInt(100);
int rangeEnd = rangeStart + generator.nextInt(100);
// Use the flip(int, int) call on b1
b1.flip(rangeStart, rangeEnd);
// Use a loop on b2
for (int x=rangeStart; x<rangeEnd; x++)
b2.flip(x);
// Verify their equality
if (!b1.equals(b2))
failCount++;
checkEquality(b1,b2);
}
report("Flip ", failCount);
}
private static void testGet() {
int failCount = 0;
for (int i=0; i<1000; i++) {
BitSet b1 = new BitSet();
// Make a fairly random bitset
int numberOfSetBits = generator.nextInt(100) + 1;
int highestPossibleSetBit = generator.nextInt(1000) + 1;
for (int x=0; x<numberOfSetBits; x++)
b1.set(generator.nextInt(highestPossibleSetBit));
// Get a new set from a random range
int rangeStart = generator.nextInt(100);
int rangeEnd = rangeStart + generator.nextInt(100);
BitSet b2 = b1.get(rangeStart, rangeEnd);
BitSet b3 = new BitSet();
for(int x=rangeStart; x<rangeEnd; x++)
b3.set(x-rangeStart, b1.get(x));
// Verify their equality
if (!b2.equals(b3)) {
System.out.println("start="+rangeStart);
System.out.println("end="+rangeEnd);
System.out.println(b1);
System.out.println(b2);
System.out.println(b3);
failCount++;
}
checkEquality(b2,b3);
}
report("Get ", failCount);
}
private static void testIntersects() {
int failCount = 0;
for (int i=0; i<100; i++) {
BitSet b1 = new BitSet(256);
BitSet b2 = new BitSet(256);
// Set some random bits in first set
int nextBitToSet = 0;
for (int x=0; x<30; x++) {
nextBitToSet = generator.nextInt(255);
b1.set(nextBitToSet);
}
// Set more random bits in second set
for (int x=0; x<30; x++) {
nextBitToSet = generator.nextInt(255);
b2.set(nextBitToSet);
}
// Make sure they intersect
nextBitToSet = generator.nextInt(255);
b1.set(nextBitToSet);
b2.set(nextBitToSet);
if (!b1.intersects(b2))
failCount++;
// Remove the common set bits
b1.andNot(b2);
// Make sure they don't intersect
if (b1.intersects(b2))
failCount++;
checkSanity(b1, b2);
}
report("Intersects ", failCount);
}
private static void testCardinality() {
int failCount = 0;
for (int i=0; i<100; i++) {
BitSet b1 = new BitSet(256);
// Set a random number of increasing bits
int nextBitToSet = 0;
int iterations = generator.nextInt(20)+1;
for (int x=0; x<iterations; x++) {
nextBitToSet += generator.nextInt(20)+1;
b1.set(nextBitToSet);
}
if (b1.cardinality() != iterations) {
System.out.println("Iterations is "+iterations);
System.out.println("Cardinality is "+b1.cardinality());
failCount++;
}
checkSanity(b1);
}
report("Cardinality ", failCount);
}
private static void testEmpty() {
int failCount = 0;
BitSet b1 = new BitSet();
if (!b1.isEmpty())
failCount++;
int nextBitToSet = 0;
int numberOfSetBits = generator.nextInt(100) + 1;
int highestPossibleSetBit = generator.nextInt(1000) + 1;
for (int x=0; x<numberOfSetBits; x++) {
nextBitToSet = generator.nextInt(highestPossibleSetBit);
b1.set(nextBitToSet);
if (b1.isEmpty())
failCount++;
b1.clear(nextBitToSet);
if (!b1.isEmpty())
failCount++;
}
report("Empty ", failCount);
}
private static void testEmpty2() {
{BitSet t = new BitSet(); t.set(100); t.clear(3,600); checkEmpty(t);}
checkEmpty(new BitSet(0));
checkEmpty(new BitSet(342));
BitSet s = new BitSet(0);
checkEmpty(s);
s.clear(92); checkEmpty(s);
s.clear(127,127); checkEmpty(s);
s.set(127,127); checkEmpty(s);
s.set(128,128); checkEmpty(s);
BitSet empty = new BitSet();
{BitSet t = new BitSet(); t.and (empty); checkEmpty(t);}
{BitSet t = new BitSet(); t.or (empty); checkEmpty(t);}
{BitSet t = new BitSet(); t.xor (empty); checkEmpty(t);}
{BitSet t = new BitSet(); t.andNot(empty); checkEmpty(t);}
{BitSet t = new BitSet(); t.and (t); checkEmpty(t);}
{BitSet t = new BitSet(); t.or (t); checkEmpty(t);}
{BitSet t = new BitSet(); t.xor (t); checkEmpty(t);}
{BitSet t = new BitSet(); t.andNot(t); checkEmpty(t);}
{BitSet t = new BitSet(); t.and(makeSet(1)); checkEmpty(t);}
{BitSet t = new BitSet(); t.and(makeSet(127)); checkEmpty(t);}
{BitSet t = new BitSet(); t.and(makeSet(128)); checkEmpty(t);}
{BitSet t = new BitSet(); t.flip(7);t.flip(7); checkEmpty(t);}
{BitSet t = new BitSet(); checkEmpty(t.get(200,300));}
{BitSet t = makeSet(2,5); check(t.get(2,6).equals(makeSet(0,3)),"");}
}
private static void testToString() {
check(new BitSet().toString().equals("{}"));
check(makeSet(2,3,42,43,234).toString().equals("{2, 3, 42, 43, 234}"));
final long MB = 1024*1024;
if (Runtime.getRuntime().maxMemory() >= 512*MB) {
// only run it if we have enough memory
try {
check(makeSet(Integer.MAX_VALUE-1).toString().equals(
"{" + (Integer.MAX_VALUE-1) + "}"));
check(makeSet(Integer.MAX_VALUE).toString().equals(
"{" + Integer.MAX_VALUE + "}"));
check(makeSet(0, 1, Integer.MAX_VALUE-1, Integer.MAX_VALUE).toString().equals(
"{0, 1, " + (Integer.MAX_VALUE-1) + ", " + Integer.MAX_VALUE + "}"));
} catch (IndexOutOfBoundsException exc) {
fail("toString() with indices near MAX_VALUE");
}
}
}
private static void testLogicalIdentities() {
int failCount = 0;
// Verify that (!b1)|(!b2) == !(b1&b2)
for (int i=0; i<50; i++) {
// Construct two fairly random bitsets
BitSet b1 = new BitSet();
BitSet b2 = new BitSet();
int numberOfSetBits = generator.nextInt(100) + 1;
int highestPossibleSetBit = generator.nextInt(1000) + 1;
for (int x=0; x<numberOfSetBits; x++) {
b1.set(generator.nextInt(highestPossibleSetBit));
b2.set(generator.nextInt(highestPossibleSetBit));
}
BitSet b3 = (BitSet) b1.clone();
BitSet b4 = (BitSet) b2.clone();
for (int x=0; x<highestPossibleSetBit; x++) {
b1.flip(x);
b2.flip(x);
}
b1.or(b2);
b3.and(b4);
for (int x=0; x<highestPossibleSetBit; x++)
b3.flip(x);
if (!b1.equals(b3))
failCount++;
checkSanity(b1, b2, b3, b4);
}
// Verify that (b1&(!b2)|(b2&(!b1) == b1^b2
for (int i=0; i<50; i++) {
// Construct two fairly random bitsets
BitSet b1 = new BitSet();
BitSet b2 = new BitSet();
int numberOfSetBits = generator.nextInt(100) + 1;
int highestPossibleSetBit = generator.nextInt(1000) + 1;
for (int x=0; x<numberOfSetBits; x++) {
b1.set(generator.nextInt(highestPossibleSetBit));
b2.set(generator.nextInt(highestPossibleSetBit));
}
BitSet b3 = (BitSet) b1.clone();
BitSet b4 = (BitSet) b2.clone();
BitSet b5 = (BitSet) b1.clone();
BitSet b6 = (BitSet) b2.clone();
for (int x=0; x<highestPossibleSetBit; x++)
b2.flip(x);
b1.and(b2);
for (int x=0; x<highestPossibleSetBit; x++)
b3.flip(x);
b3.and(b4);
b1.or(b3);
b5.xor(b6);
if (!b1.equals(b5))
failCount++;
checkSanity(b1, b2, b3, b4, b5, b6);
}
report("Logical Identities ", failCount);
}
}

View file

@ -0,0 +1,45 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @bug 8225397
* @summary Integer value miscalculation in toString() method of BitSet
* @run main/othervm -Xms250m HugeToString
*/
import java.util.BitSet;
public final class HugeToString {
public static void main(String[] args) {
BitSet bs = new BitSet(500_000_000);
bs.flip(0, 500_000_000);
try {
bs.toString();
} catch (OutOfMemoryError expected) {
} catch (Throwable t) {
throw new AssertionError("Unexpected exception", t);
}
}
}

View file

@ -0,0 +1,100 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @summary Basic tests of immutable BitSets
* @modules java.base/jdk.internal.util
* @run junit ImmutableBitSet
*/
import jdk.internal.util.ImmutableBitSetPredicate;
import org.junit.jupiter.api.Test;
import java.util.BitSet;
import java.util.Random;
import java.util.function.IntPredicate;
import java.util.stream.IntStream;
import static org.junit.jupiter.api.Assertions.*;
public class ImmutableBitSet {
@Test
void empty() {
BitSet bs = new BitSet();
IntPredicate ibs = ImmutableBitSetPredicate.of(bs);
test(bs, ibs);
}
@Test
void negativeIndex() {
IntStream.of(0, 127, 128, 129, 143, 4711).forEach(k -> {
BitSet bs = new BitSet(k);
IntPredicate ibs = ImmutableBitSetPredicate.of(bs);
assertFalse(ibs.test(-1));
assertFalse(ibs.test(Integer.MIN_VALUE));
});
}
@Test
void basic() {
IntStream.of(0, 16, 127, 128, 129, 143, 4711).forEach(k -> basic(k));
}
void basic(int length) {
BitSet bs = createReference(length);
IntPredicate ibs = ImmutableBitSetPredicate.of(bs);
test(bs, ibs);
}
@Test
void clearedAtTheTail() {
IntStream.of(0, 16, 127, 128, 129, 143, 4711).forEach(k -> {
for (int i = Long.BYTES - 1; i < Long.BYTES + 2; i++) {
BitSet bs = createReference(k + i);
for (int j = bs.length() - 1; j > Long.BYTES - 1; j--) {
bs.clear(j);
}
IntPredicate ibs = ImmutableBitSetPredicate.of(bs);
test(bs, ibs);
}
});
}
static void test(BitSet expected, IntPredicate actual) {
for (int i = 0; i < expected.length() + 17; i++) {
assertEquals(expected.get(i), actual.test(i), "at index " + i);
}
}
private static BitSet createReference(int length) {
BitSet result = new BitSet(length);
Random random = new Random(length);
for (int i = 0; i < length; i++) {
result.set(i, random.nextBoolean());
}
return result;
}
}

View file

@ -0,0 +1,156 @@
/*
* Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 5037068
* @summary Test import/export constructors and methods
* @author Martin Buchholz
* @key randomness
*/
import java.nio.*;
import java.util.*;
public class ImportExport {
final Random rnd = new Random();
void equal(byte[] x, byte[] y) {
check(Arrays.equals(x, y));
}
void equal(long[] x, long[] y) {
check(Arrays.equals(x, y));
}
void equal(byte[] bytes, BitSet s) {
equal(s, BitSet.valueOf(bytes));
equal(s, BitSet.valueOf(ByteBuffer.wrap(bytes)));
equal(s, BitSet.valueOf(
ByteBuffer.wrap(
Arrays.copyOf(bytes, bytes.length + 8 + rnd.nextInt(8)))
.order(ByteOrder.LITTLE_ENDIAN)
.asLongBuffer()));
}
void checkEmptyBitSet(BitSet s) {
equal(s.toByteArray(), new byte[0]);
equal(s.toLongArray(), new long[0]);
check(s.isEmpty());
}
void test(String[] args) throws Throwable {
for (int i = 0; i < 17; i++) {
byte[] bytes = new byte[i];
BitSet s = new BitSet();
equal(bytes, s);
equal(BitSet.valueOf(bytes).toByteArray(), new byte[0]);
if (i > 0) {
int k = rnd.nextInt(i);
for (int j = 0; j < 8; j++) {
bytes[k] |= 1 << j;
s.set(8*k+j);
equal(bytes, s);
byte[] expected = new byte[k+1]; expected[k] = bytes[k];
equal(BitSet.valueOf(bytes).toByteArray(), expected);
ByteBuffer bb = ByteBuffer.wrap(bytes);
bb.position(k);
equal(BitSet.valueOf(bb).toByteArray(),
new byte[]{bytes[k]});
}
}
}
for (int i = 0; i < 100; i++) {
byte[] bytes = new byte[rnd.nextInt(17)];
for (int j = 0; j < bytes.length; j++)
bytes[j] = (byte) rnd.nextInt(0x100);
BitSet s = BitSet.valueOf(bytes);
byte[] expected = s.toByteArray();
equal(expected.length, (s.length()+7)/8);
if (bytes.length == 0)
continue;
if (expected.length > 0)
check(expected[expected.length-1] != 0);
if (bytes[bytes.length-1] != 0)
equal(bytes, expected);
int n = rnd.nextInt(8 * bytes.length);
equal(s.get(n), ((bytes[n/8] & (1<<(n%8))) != 0));
}
for (int i = 0; i < 3; i++) {
checkEmptyBitSet(BitSet.valueOf(new byte[i]));
checkEmptyBitSet(BitSet.valueOf(ByteBuffer.wrap(new byte[i])));
checkEmptyBitSet(BitSet.valueOf(new byte[i*64]));
checkEmptyBitSet(BitSet.valueOf(ByteBuffer.wrap(new byte[i*64])));
checkEmptyBitSet(BitSet.valueOf(new long[i]));
checkEmptyBitSet(BitSet.valueOf(LongBuffer.wrap(new long[i])));
}
{
long[] longs = new long[rnd.nextInt(10)];
for (int i = 0; i < longs.length; i++)
longs[i] = rnd.nextLong();
LongBuffer b1 = LongBuffer.wrap(longs);
LongBuffer b2 = LongBuffer.allocate(longs.length + 10);
for (int i = 0; i < b2.limit(); i++)
b2.put(i, rnd.nextLong());
int beg = rnd.nextInt(10);
b2.position(beg);
b2.put(longs);
b2.limit(b2.position());
b2.position(beg);
BitSet s1 = BitSet.valueOf(longs);
BitSet s2 = BitSet.valueOf(b1);
BitSet s3 = BitSet.valueOf(b2);
equal(s1, s2);
equal(s1, s3);
if (longs.length > 0 && longs[longs.length -1] != 0) {
equal(longs, s1.toLongArray());
equal(longs, s2.toLongArray());
equal(longs, s3.toLongArray());
}
for (int i = 0; i < 64 * longs.length; i++) {
equal(s1.get(i), ((longs [i/64] & (1L<<(i%64))) != 0));
equal(s2.get(i), ((b1.get(i/64) & (1L<<(i%64))) != 0));
equal(s3.get(i), ((b2.get(b2.position()+i/64) & (1L<<(i%64))) != 0));
}
}
}
//--------------------- Infrastructure ---------------------------
volatile int passed = 0, failed = 0;
void pass() {passed++;}
void fail() {failed++; Thread.dumpStack();}
void fail(String msg) {System.err.println(msg); fail();}
void unexpected(Throwable t) {failed++; t.printStackTrace();}
void check(boolean cond) {if (cond) pass(); else fail();}
void equal(Object x, Object y) {
if (x == null ? y == null : x.equals(y)) pass();
else fail(x + " not equal to " + y);}
public static void main(String[] args) throws Throwable {
new ImportExport().instanceMain(args);}
void instanceMain(String[] args) throws Throwable {
try {test(args);} catch (Throwable t) {unexpected(t);}
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
if (failed > 0) throw new AssertionError("Some tests failed");}
}

View file

@ -0,0 +1,56 @@
/*
* Copyright (c) 1997, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 4091185
* @summary Repeatedly OR BitSets; No OutOfMemoryException should result
*/
import java.util.*;
/**
* This is a simple test class that repeatedly ORs two
* BitSets of unequal size together. Previously this
* caused an exponential growth in the memory underlying
* the BitSets quickly using all available memory
*/
public class MemoryLeak {
public static void main(String[] args) {
//create 2 test bitsets
BitSet setOne = new BitSet();
BitSet setTwo = new BitSet();
setOne.set(64);
setTwo.set(129);
//test for bug #4091185
//exponential set growth causing memory depletion
for (int i = 0; i < 50; i++) {
setOne.or(setTwo);
setTwo.or(setOne);
}
}
}

View file

@ -0,0 +1,158 @@
/*
* Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 6410729 6586631
* @summary Test previousClearBit, previousSetBit
* @key randomness
*/
import java.util.*;
public class PreviousBits {
void testHashCode(final BitSet s) {
long h = 1234;
long[] words = s.toLongArray();
for (int i = words.length; --i >= 0; )
h ^= words[i] * (i + 1);
equal((int)((h >> 32) ^ h), s.hashCode());
}
void testOutOfBounds(final BitSet s) {
THROWS(IndexOutOfBoundsException.class,
new F(){void f(){ s.previousSetBit(-2);}},
new F(){void f(){ s.previousClearBit(-2);}},
new F(){void f(){ s.previousSetBit(Integer.MIN_VALUE);}},
new F(){void f(){ s.previousClearBit(Integer.MIN_VALUE);}},
new F(){void f(){ s.nextSetBit(-1);}},
new F(){void f(){ s.nextClearBit(-1);}},
new F(){void f(){ s.nextSetBit(Integer.MIN_VALUE);}},
new F(){void f(){ s.nextClearBit(Integer.MIN_VALUE);}});
}
void test(String[] args) throws Throwable {
final BitSet s = new BitSet();
// Test empty bitset
testOutOfBounds(s);
testHashCode(s);
for (int i = -1; i < 93;) {
equal(-1, s.previousSetBit(i));
equal( i, s.previousClearBit(i));
i++;
equal(-1, s.nextSetBit(i));
equal( i, s.nextClearBit(i));
}
// Test "singleton" bitsets
for (int j = 0; j < 161; j++) {
s.clear();
s.set(j);
testOutOfBounds(s);
testHashCode(s);
for (int i = -1; i < j; i++) {
equal(-1, s.previousSetBit(i));
equal( i, s.previousClearBit(i));
if (i >= 0) {
equal(j, s.nextSetBit(i));
equal(i, s.nextClearBit(i));
}
}
equal(j, s.previousSetBit(j));
equal(j-1, s.previousClearBit(j));
equal(j, s.nextSetBit(j));
equal(j+1, s.nextClearBit(j));
for (int i = j+1; i < j+100; i++) {
equal(j, s.previousSetBit(i));
equal(i, s.previousClearBit(i));
equal(-1, s.nextSetBit(i));
equal(i, s.nextClearBit(i));
}
}
// set even bits
s.clear();
for (int i = 0; i <= 128; i+=2)
s.set(i);
testHashCode(s);
for (int i = 1; i <= 128; i++) {
equal(s.previousSetBit(i),
((i & 1) == 0) ? i : i - 1);
equal(s.previousClearBit(i),
((i & 1) == 0) ? i - 1 : i);
}
// set odd bits as well
for (int i = 1; i <= 128; i+=2)
s.set(i);
testHashCode(s);
for (int i = 1; i <= 128; i++) {
equal(s.previousSetBit(i), i);
equal(s.previousClearBit(i), -1);
}
// Test loops documented in javadoc
Random rnd = new Random();
s.clear();
for (int i = 0; i < 10; i++)
s.set(rnd.nextInt(1066));
List<Integer> down = new ArrayList<Integer>();
for (int i = s.length(); (i = s.previousSetBit(i-1)) >= 0; )
down.add(i);
List<Integer> up = new ArrayList<Integer>();
for (int i = s.nextSetBit(0); i >= 0; i = s.nextSetBit(i+1))
up.add(i);
Collections.reverse(up);
equal(up, down);
}
//--------------------- Infrastructure ---------------------------
volatile int passed = 0, failed = 0;
void pass() {passed++;}
void fail() {failed++; Thread.dumpStack();}
void fail(String msg) {System.err.println(msg); fail();}
void unexpected(Throwable t) {failed++; t.printStackTrace();}
void check(boolean cond) {if (cond) pass(); else fail();}
void equal(Object x, Object y) {
if (x == null ? y == null : x.equals(y)) pass();
else fail(x + " not equal to " + y);}
public static void main(String[] args) throws Throwable {
new PreviousBits().instanceMain(args);}
void instanceMain(String[] args) throws Throwable {
try {test(args);} catch (Throwable t) {unexpected(t);}
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
if (failed > 0) throw new AssertionError("Some tests failed");}
abstract class F {abstract void f() throws Throwable;}
void THROWS(Class<? extends Throwable> k, F... fs) {
for (F f : fs)
try {f.f(); fail("Expected " + k.getName() + " not thrown");}
catch (Throwable t) {
if (k.isAssignableFrom(t.getClass())) pass();
else unexpected(t);}}
}

View file

@ -0,0 +1,103 @@
/*
* Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 6404711
* @summary Check capacity management
* @author Martin Buchholz
*/
import java.io.*;
import java.util.*;
public class StickySize {
static void equalClones(BitSet s, int expectedSize) {
equal(expectedSize, clone(s).size());
equal(expectedSize, serialClone(s).size());
equal(expectedSize, s.size());
equal(clone(s), serialClone(s));
}
private static void realMain(String[] args) {
BitSet s;
s = new BitSet(); // non-sticky
equal(s.size(), 64);
equalClones(s, 0);
s.set(3*64);
s.set(7*64);
equal(s.size(), 8*64);
equalClones(s, 8*64);
s.clear(7*64);
equal(s.size(), 8*64);
equalClones(s, 4*64);
s = new BitSet(8*64); // sticky
equalClones(s, 8*64);
s.set(3*64);
s.set(7*64);
equalClones(s, 8*64);
s.clear(7*64);
equalClones(s, 8*64);
equalClones(clone(s), 8*64);
equalClones(serialClone(s), 8*64);
s.set(17*64); // Expand beyond sticky size
equalClones(s, 18*64);
s.clear(17*64);
equalClones(s, 4*64);
}
static BitSet clone(BitSet s) {
return (BitSet) s.clone();
}
//--------------------- Infrastructure ---------------------------
static volatile int passed = 0, failed = 0;
static void pass() {passed++;}
static void fail() {failed++; Thread.dumpStack();}
static void fail(String msg) {System.out.println(msg); fail();}
static void unexpected(Throwable t) {failed++; t.printStackTrace();}
static void check(boolean cond) {if (cond) pass(); else fail();}
static void equal(Object x, Object y) {
if (x == null ? y == null : x.equals(y)) pass();
else fail(x + " not equal to " + y);}
public static void main(String[] args) throws Throwable {
try {realMain(args);} catch (Throwable t) {unexpected(t);}
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
if (failed > 0) throw new AssertionError("Some tests failed");}
static byte[] serializedForm(Object obj) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
new ObjectOutputStream(baos).writeObject(obj);
return baos.toByteArray();
} catch (IOException e) { throw new RuntimeException(e); }}
static Object readObject(byte[] bytes)
throws IOException, ClassNotFoundException {
InputStream is = new ByteArrayInputStream(bytes);
return new ObjectInputStream(is).readObject();}
@SuppressWarnings("unchecked")
static <T> T serialClone(T obj) {
try { return (T) readObject(serializedForm(obj)); }
catch (Exception e) { throw new RuntimeException(e); }}
}

View file

@ -0,0 +1,241 @@
/*
* Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.util.ArrayList;
import java.util.BitSet;
import java.util.Collection;
import java.util.List;
import java.util.PrimitiveIterator;
import java.util.Random;
import java.util.Spliterator;
import java.util.SpliteratorOfIntDataBuilder;
import java.util.SpliteratorTestHelper;
import java.util.function.IntConsumer;
import java.util.function.IntSupplier;
import java.util.function.Supplier;
import java.util.stream.IntStream;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static java.util.stream.Collectors.toList;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertThrows;
import static org.testng.Assert.assertTrue;
/**
* @test
* @summary test BitSet stream
* @bug 8012645 8076442
* @requires os.maxMemory >= 2g
* @library /lib/testlibrary/bootlib
* @build java.base/java.util.SpliteratorTestHelper
* java.base/java.util.SpliteratorOfIntDataBuilder
* @run testng/othervm -Xms512m -Xmx1024m BitSetStreamTest
*/
public class BitSetStreamTest extends SpliteratorTestHelper {
static class Fibs implements IntSupplier {
private int n1 = 0;
private int n2 = 1;
static int fibs(int n) {
Fibs f = new Fibs();
while (n-- > 0) f.getAsInt();
return f.getAsInt();
}
public int getAsInt() { int s = n1; n1 = n2; n2 = s + n1; return s; }
}
@Test
public void testFibs() {
Fibs f = new Fibs();
assertEquals(0, f.getAsInt());
assertEquals(1, f.getAsInt());
assertEquals(1, f.getAsInt());
assertEquals(2, f.getAsInt());
assertEquals(3, f.getAsInt());
assertEquals(5, f.getAsInt());
assertEquals(8, f.getAsInt());
assertEquals(13, f.getAsInt());
assertEquals(987, Fibs.fibs(16));
}
@DataProvider(name = "cases")
public static Object[][] produceCases() {
return new Object[][] {
{ "none", IntStream.empty() },
{ "index 0", IntStream.of(0) },
{ "index 255", IntStream.of(255) },
{ "index 0 and 255", IntStream.of(0, 255) },
{ "index Integer.MAX_VALUE", IntStream.of(Integer.MAX_VALUE) },
{ "index Integer.MAX_VALUE - 1", IntStream.of(Integer.MAX_VALUE - 1) },
{ "index 0 and Integer.MAX_VALUE", IntStream.of(0, Integer.MAX_VALUE) },
{ "every bit", IntStream.range(0, 255) },
{ "step 2", IntStream.range(0, 255).map(f -> f * 2) },
{ "step 3", IntStream.range(0, 255).map(f -> f * 3) },
{ "step 5", IntStream.range(0, 255).map(f -> f * 5) },
{ "step 7", IntStream.range(0, 255).map(f -> f * 7) },
{ "1, 10, 100, 1000", IntStream.of(1, 10, 100, 1000) },
{ "25 fibs", IntStream.generate(new Fibs()).limit(25) }
};
}
@Test(dataProvider = "cases")
public void testBitsetStream(String name, IntStream data) {
BitSet bs = data.collect(BitSet::new, BitSet::set, BitSet::or);
assertEquals(bs.cardinality(), bs.stream().count());
int[] indexHolder = new int[] { -1 };
bs.stream().forEach(i -> {
int ei = indexHolder[0];
indexHolder[0] = bs.nextSetBit(ei + 1);
assertEquals(i, indexHolder[0]);
});
PrimitiveIterator.OfInt it = bs.stream().iterator();
for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i + 1)) {
assertTrue(it.hasNext());
assertEquals(it.nextInt(), i);
if (i == Integer.MAX_VALUE)
break; // or (i + 1) would overflow
}
assertFalse(it.hasNext());
}
static Object[][] spliteratorOfIntDataProvider;
@DataProvider(name = "BitSet.stream.spliterator")
public static Object[][] spliteratorOfIntDataProvider() {
if (spliteratorOfIntDataProvider != null) {
return spliteratorOfIntDataProvider;
}
List<Object[]> data = new ArrayList<>();
Object[][] bitStreamTestcases = new Object[][] {
{ "none", IntStream.empty().toArray() },
{ "index 0", IntStream.of(0).toArray() },
{ "index 255", IntStream.of(255).toArray() },
{ "index 0 and 255", IntStream.of(0, 255).toArray() },
{ "index Integer.MAX_VALUE", IntStream.of(Integer.MAX_VALUE).toArray() },
{ "index Integer.MAX_VALUE - 1", IntStream.of(Integer.MAX_VALUE - 1).toArray() },
{ "index 0 and Integer.MAX_VALUE", IntStream.of(0, Integer.MAX_VALUE).toArray() },
{ "every bit", IntStream.range(0, 255).toArray() },
{ "step 2", IntStream.range(0, 255).map(f -> f * 2).toArray() },
{ "step 3", IntStream.range(0, 255).map(f -> f * 3).toArray() },
{ "step 5", IntStream.range(0, 255).map(f -> f * 5).toArray() },
{ "step 7", IntStream.range(0, 255).map(f -> f * 7).toArray() },
{ "1, 10, 100, 1000", IntStream.of(1, 10, 100, 1000).toArray() },
};
for (Object[] tc : bitStreamTestcases) {
String description = (String)tc[0];
int[] exp = (int[])tc[1];
SpliteratorOfIntDataBuilder db = new SpliteratorOfIntDataBuilder(
data, IntStream.of(exp).boxed().collect(toList()));
db.add("BitSet.stream.spliterator() {" + description + "}", () ->
IntStream.of(exp).collect(BitSet::new, BitSet::set, BitSet::or).
stream().spliterator()
);
}
return spliteratorOfIntDataProvider = data.toArray(new Object[0][]);
}
@Test(dataProvider = "BitSet.stream.spliterator")
public void testIntNullPointerException(String description, Collection<Integer> exp, Supplier<Spliterator.OfInt> s) {
assertThrows(NullPointerException.class, () -> s.get().forEachRemaining((IntConsumer) null));
assertThrows(NullPointerException.class, () -> s.get().tryAdvance((IntConsumer) null));
}
@Test(dataProvider = "BitSet.stream.spliterator")
public void testIntForEach(String description, Collection<Integer> exp, Supplier<Spliterator.OfInt> s) {
testForEach(exp, s, intBoxingConsumer());
}
@Test(dataProvider = "BitSet.stream.spliterator")
public void testIntTryAdvance(String description, Collection<Integer> exp, Supplier<Spliterator.OfInt> s) {
testTryAdvance(exp, s, intBoxingConsumer());
}
@Test(dataProvider = "BitSet.stream.spliterator")
public void testIntMixedTryAdvanceForEach(String description, Collection<Integer> exp, Supplier<Spliterator.OfInt> s) {
testMixedTryAdvanceForEach(exp, s, intBoxingConsumer());
}
@Test(dataProvider = "BitSet.stream.spliterator")
public void testIntMixedTraverseAndSplit(String description, Collection<Integer> exp, Supplier<Spliterator.OfInt> s) {
testMixedTraverseAndSplit(exp, s, intBoxingConsumer());
}
@Test(dataProvider = "BitSet.stream.spliterator")
public void testIntSplitAfterFullTraversal(String description, Collection<Integer> exp, Supplier<Spliterator.OfInt> s) {
testSplitAfterFullTraversal(s, intBoxingConsumer());
}
@Test(dataProvider = "BitSet.stream.spliterator")
public void testIntSplitOnce(String description, Collection<Integer> exp, Supplier<Spliterator.OfInt> s) {
testSplitOnce(exp, s, intBoxingConsumer());
}
@Test(dataProvider = "BitSet.stream.spliterator")
public void testIntSplitSixDeep(String description, Collection<Integer> exp, Supplier<Spliterator.OfInt> s) {
testSplitSixDeep(exp, s, intBoxingConsumer());
}
@Test(dataProvider = "BitSet.stream.spliterator")
public void testIntSplitUntilNull(String description, Collection<Integer> exp, Supplier<Spliterator.OfInt> s) {
testSplitUntilNull(exp, s, intBoxingConsumer());
}
@Test
public void testRandomStream() {
final int size = 1024 * 1024;
final int[] seeds = {
2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41,
43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97};
final byte[] bytes = new byte[size];
for (int seed : seeds) {
final Random random = new Random(seed);
random.nextBytes(bytes);
BitSet bitSet = BitSet.valueOf(bytes);
testBitSetContents(bitSet, bitSet.stream().toArray());
testBitSetContents(bitSet, bitSet.stream().parallel().toArray());
}
}
void testBitSetContents(BitSet bitSet, int[] array) {
int cardinality = bitSet.cardinality();
assertEquals(array.length, cardinality);
int nextSetBit = -1;
for (int i = 0; i < cardinality; i++) {
nextSetBit = bitSet.nextSetBit(nextSetBit + 1);
assertEquals(array[i], nextSetBit);
}
}
}

View file

@ -0,0 +1,244 @@
/*
* Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 4817812 4847186 4956227 4956479
* @summary Confirm that BuddhistCalendar's add(), roll(), set(), and toString()
* work correctly with Buddhist Era years.
* @run junit BuddhistCalendarTest
*/
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Locale;
import java.util.stream.Stream;
import static java.util.Calendar.APRIL;
import static java.util.Calendar.DATE;
import static java.util.Calendar.DECEMBER;
import static java.util.Calendar.ERA;
import static java.util.Calendar.FEBRUARY;
import static java.util.Calendar.JANUARY;
import static java.util.Calendar.MAY;
import static java.util.Calendar.MONTH;
import static java.util.Calendar.WEEK_OF_YEAR;
import static java.util.Calendar.YEAR;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
public class BuddhistCalendarTest {
private static final Locale THAI_LOCALE = Locale.of("th", "TH");
/*
* Test some add values for the BuddhistCalendar. This test compares the same field
* as the one added.
*/
@ParameterizedTest
@MethodSource("addDataProvider")
public void buddhistAddTest(Calendar cal, int amount, int fieldToAdd) {
int base = cal.get(YEAR);
cal.add(fieldToAdd, amount);
int yearAfterRoll = cal.get(YEAR);
assertEquals(yearAfterRoll, base+amount, String.format(
"Added: %s to field: %s", amount, fieldToAdd));
}
/*
* Given in the format: Calendar, amount to add, and field to add.
* Test adding of positive and negative year values.
*/
private static Stream<Arguments> addDataProvider() {
return Stream.of(
Arguments.of(getBuddhistCalendar(), 1, YEAR),
Arguments.of(getBuddhistCalendar(), -3, YEAR)
);
}
/*
* Test some add values for the BuddhistCalendar. Compare a bigger field
* (year) than the one added (month). Larger field should roll over.
*/
@ParameterizedTest
@MethodSource("alternateAddDataProvider")
public void buddhistAlternateAddTest(Calendar cal, int amount, int fieldToAdd) {
int base = cal.get(YEAR);
cal.add(fieldToAdd, amount);
int yearAfterRoll = cal.get(YEAR);
assertEquals(yearAfterRoll, (amount>0) ? (base+1): (base-1), String.format(
"Added: %s to field: %s", amount, fieldToAdd));
}
/*
* Given in the format: Calendar, amount to add, and field to add.
* Test adding of positive and negative month values.
*/
private static Stream<Arguments> alternateAddDataProvider() {
return Stream.of(
Arguments.of(getBuddhistCalendarBuilder().set(MONTH, DECEMBER).build(), 2, MONTH),
Arguments.of(getBuddhistCalendarBuilder().set(MONTH, FEBRUARY).build(), -4, MONTH)
);
}
/*
* Test some roll values for the BuddhistCalendar. Compare same field
* that was rolled, value should change.
*/
@ParameterizedTest
@MethodSource("rollProvider")
public void buddhistRollTest(Calendar cal, int amount, int fieldToRoll) {
int base = cal.get(YEAR);
cal.roll(fieldToRoll, amount);
int year = cal.get(YEAR);
assertEquals(year, base+amount, "Rolling field should change value");
}
/*
* Given in the format: Calendar, amount to roll, and field to roll.
* Test rolling of positive and negative year values.
*/
private static Stream<Arguments> rollProvider() {
return Stream.of(
Arguments.of(getBuddhistCalendar(), 2, YEAR),
Arguments.of(getBuddhistCalendar(), -4, YEAR)
);
}
/*
* Set some calendar values and roll, however, measure a different
* field than the field that was rolled. Rolling should not change the
* larger field.
*/
@ParameterizedTest
@MethodSource("alternateRollProvider")
public void buddhistAlternateRollTest(Calendar cal, int amount, int fieldToRoll) {
int base = cal.get(YEAR);
cal.roll(fieldToRoll, amount);
int year = cal.get(YEAR);
assertEquals(year, base, "Rolling smaller field should not change bigger field");
}
/*
* Given in the format: Calendar, amount to roll, and field to roll.
* Test rolling of positive and negative week_of_year values.
*/
private static Stream<Arguments> alternateRollProvider() {
return Stream.of(
Arguments.of(getBuddhistCalendarBuilder().set(YEAR, 2543)
.set(MONTH, DECEMBER).set(DATE, 31).build(), 10, WEEK_OF_YEAR),
Arguments.of(getBuddhistCalendarBuilder().set(YEAR, 2543)
.set(MONTH, JANUARY).set(DATE, 1).build(), -10, WEEK_OF_YEAR)
);
}
// Test the overloaded set() methods. Check year value.
@Test
public void buddhistSetTest() {
Calendar cal = getBuddhistCalendar();
cal.set(3001, APRIL, 10);
assertEquals(cal.get(YEAR), 3001);
cal.set(3020, MAY, 20, 9, 10);
assertEquals(cal.get(YEAR), 3020);
cal.set(3120, MAY, 20, 9, 10, 52 );
assertEquals(cal.get(YEAR), 3120);
}
/*
* Test BuddhistCalendar.getActualMaximum(YEAR);
* set(YEAR)/get(YEAR) in this method doesn't affect the real
* YEAR value because a clone is used with set() and get().
*/
@Test
public void buddhistActualMaximumTest() {
Calendar cal = getBuddhistCalendar();
int base = cal.get(YEAR);
int ignored = cal.getActualMaximum(YEAR);
int year = cal.get(YEAR);
assertEquals(year, base, "BuddhistCalendar.getActualMaximum(YEAR)");
}
// Test BuddhistCalendar.getActualMinimum(YEAR), doesn't call set(YEAR) nor get(YEAR).
@Test
public void buddhistActualMinimumTest() {
Calendar cal = getBuddhistCalendar();
int base = cal.get(YEAR);
int ignored = cal.getActualMinimum(YEAR);
int year = cal.get(YEAR);
assertEquals(year, base, "BuddhistCalendar.getActualMinimum(YEAR)");
}
// 4847186: BuddhistCalendar: toString() returns Gregorian year
@Test
public void buddhistToStringTest() {
Calendar cal = getBuddhistCalendar();
int year = cal.get(YEAR);
String s = cal.toString();
String y = s.replaceAll(".+,YEAR=(\\d+),.+", "$1");
assertEquals(year, Integer.parseInt(y), "Wrong year value");
}
// 4956479: BuddhistCalendar methods may return wrong values after exception
@Test
public void buddhistValuesAfterExceptionTest() {
Calendar cal = getBuddhistCalendar();
int year = cal.get(YEAR);
assertThrows(IllegalArgumentException.class, ()-> cal.add(100, +1));
int year2 = cal.get(YEAR);
assertEquals(year2, year, "Wrong year value after exception thrown");
}
// 4956227: getLeastMaximum(WEEK_OF_MONTH) return diff. val. for Greg. and Buddhist Calendar
@Test
public void buddhistLeastMaximumTest() {
Calendar bc = getBuddhistCalendar();
// Specify THAI_LOCALE to get the same params for WEEK
// calculations (6904680).
Calendar gc = new GregorianCalendar(THAI_LOCALE);
for (int f = 0; f < Calendar.FIELD_COUNT; f++) {
if (f == ERA || f == YEAR) {
continue;
}
int bn = bc.getLeastMaximum(f);
int gn = gc.getLeastMaximum(f);
assertEquals(bn, gn, "Inconsistent Least Max value for " + Koyomi.getFieldName(f));
}
}
// Utility to get a new Buddhist Calendar Builder (to allow setting of other values)
private static Calendar.Builder getBuddhistCalendarBuilder() {
return new Calendar.Builder().setLocale(THAI_LOCALE);
}
// Utility to get a new Buddhist calendar
private static Calendar getBuddhistCalendar() {
return Calendar.getInstance(THAI_LOCALE);
}
}

View file

@ -0,0 +1,47 @@
/*
* Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 4302966 8176841
* @modules jdk.localedata
* @summary In Czech Republic first day of week is Monday not Sunday
* @run junit Bug4302966
*/
import java.util.Calendar;
import java.util.Locale;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class Bug4302966 {
// Specific day of week test for Czech locale
public void czechDayOfWeekTest() {
Calendar czechCalendar = Calendar.getInstance(Locale.of("cs", "CZ"));
int firstDayOfWeek = czechCalendar.getFirstDayOfWeek();
assertEquals(firstDayOfWeek, Calendar.MONDAY);
}
}

View file

@ -0,0 +1,58 @@
/*
* Copyright (c) 2002, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 4766302
* @summary Make sure that calling computeTime doesn't reset the isTimeSet value.
* @run junit Bug4766302
*/
import java.util.GregorianCalendar;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class Bug4766302 {
// Extend GregorianCalendar to check the protected value of isTimeSet
@SuppressWarnings("serial")
static class MyCalendar extends GregorianCalendar {
boolean isTimeStillSet() {
return isTimeSet;
}
protected void computeTime() {
super.computeTime();
}
}
// Check the value of isTimeStillSet() after calling computeTime()
@Test
public void validateIsTimeSetTest() {
MyCalendar cal = new MyCalendar();
cal.computeTime();
assertTrue(cal.isTimeStillSet(), "computeTime() call reset isTimeSet.");
}
}

View file

@ -0,0 +1,59 @@
/*
* Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 4851640
* @summary Make sure not to set UNSET fields to COMPUTED after time calculation.
*/
import java.util.GregorianCalendar;
import static java.util.Calendar.*;
public class Bug4851640 {
public static void main(String args[]) {
GregorianCalendar cal = new GregorianCalendar();
cal.clear();
cal.set(YEAR, 2003);
long t = cal.getTime().getTime();
// For the time calculation, the MONTH and DAY_OF_MONTH fields
// (with the default values) have been used for determining
// the date. However, both the MONTH and DAY_OF_MONTH fields
// should be kept UNSET after the time calculation.
if (cal.isSet(MONTH) || cal.isSet(DAY_OF_MONTH)) {
throw new RuntimeException("After getTime(): MONTH field=" + cal.isSet(MONTH)
+ ", DAY_OF_MONTH field=" + cal.isSet(DAY_OF_MONTH));
}
// After calling get() for any field, all field values are
// recalculated and their field states are set to
// COMPUTED. isSet() must return true.
int y = cal.get(YEAR);
if (!(cal.isSet(MONTH) && cal.isSet(DAY_OF_MONTH))) {
throw new RuntimeException("After get(): MONTH field=" + cal.isSet(MONTH)
+ ", DAY_OF_MONTH field=" + cal.isSet(DAY_OF_MONTH));
}
}
}

View file

@ -0,0 +1,257 @@
/*
* Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 4958050
* @summary Make sure that add() and roll() handle time zone offset changes (both raw and DST) correctly.
*/
import java.util.Locale;
import java.util.TimeZone;
import static java.util.Calendar.*;
public class Bug4958050 {
static int errorCount = 0;
public static void main(String[] args) {
// All the test cases depend on historical GMT offset changes
// of Asia/Novosibirsk.
Koyomi cal = new Koyomi(TimeZone.getTimeZone("Asia/Novosibirsk"), Locale.US);
System.out.println("Time zone = " + cal.getTimeZone().getID());
// Test the week fields
int[] weekFields = {WEEK_OF_YEAR, WEEK_OF_MONTH, DAY_OF_WEEK_IN_MONTH};
for (int i = 0; i < weekFields.length; i++) {
int field = weekFields[i];
// add()
cal.clear();
cal.set(1919, DECEMBER, 14 - 7, 23, 50, 00);
cal.add(weekFields[i], +1);
if (!cal.checkDate(1919, DECEMBER, 14)) {
error("1919/12/07: add(" + Koyomi.getFieldName(weekFields[i]) + ", +1)\n"
+ cal.getMessage() + " " + cal.toDateTimeString());
}
cal.clear();
cal.set(1930, JUNE, 21 - 7);
cal.add(weekFields[i], +1);
if (!cal.checkDateTime(1930, JUNE, 21, 01, 00, 00, 000)) {
error("1930/6/14: add(" + Koyomi.getFieldName(weekFields[i]) + ", +1)\n"
+ cal.getMessage() + " " + cal.toDateTimeString());
}
// roll()
cal.clear();
cal.set(1919, DECEMBER, 14 - 7, 23, 50, 00);
cal.roll(weekFields[i], +1);
if (!cal.checkDate(1919, DECEMBER, 14)) {
error("1919/12/07: roll(" + Koyomi.getFieldName(weekFields[i]) + ", +1)\n"
+ cal.getMessage() + " " + cal.toDateTimeString());
}
cal.clear();
cal.set(1930, JUNE, 21 - 7);
cal.roll(weekFields[i], +1);
if (!cal.checkDateTime(1930, JUNE, 21, 01, 00, 00, 000)) {
error("1930/6/14: roll(" + Koyomi.getFieldName(weekFields[i]) + ", +1)\n"
+ cal.getMessage() + " " + cal.toDateTimeString());
}
}
// Test the day fields
int[] dayFields = {DAY_OF_MONTH, DAY_OF_YEAR, DAY_OF_WEEK};
for (int i = 0; i < dayFields.length; i++) {
int field = dayFields[i];
// add()
cal.clear();
cal.set(1919, DECEMBER, 14 - 1, 23, 50, 00);
cal.add(field, +1);
if (!cal.checkDate(1919, DECEMBER, 14)) {
error("1919/12/13: add(" + Koyomi.getFieldName(field) + ", +1)\n"
+ cal.getMessage() + " " + cal.toDateTimeString());
}
cal.clear();
cal.set(1919, DECEMBER, 14, 00, 00, 00);
cal.add(field, -1);
if (!cal.checkDate(1919, DECEMBER, 13)) {
error("1919/12/14: add(" + Koyomi.getFieldName(field) + ", -1)\n"
+ cal.getMessage() + " " + cal.toDateTimeString());
}
cal.clear();
cal.set(1930, JUNE, 21 - 1);
cal.add(field, +1);
if (!cal.checkDateTime(1930, JUNE, 21, 01, 00, 00, 000)) {
error("1930/6/20: add(" + Koyomi.getFieldName(field) + ", +1)\n"
+ cal.getMessage() + cal.toDateTimeString());
}
cal.clear();
cal.set(1930, JUNE, 21, 01, 00, 00);
cal.add(field, -1);
if (!cal.checkDateTime(1930, JUNE, 20, 01, 00, 00, 000)) {
error("1930/6/21: add(" + Koyomi.getFieldName(field) + ", -1)\n"
+ cal.getMessage() + " " + cal.toDateTimeString());
}
// roll()
cal.clear();
cal.set(1930, JUNE, 21 - 1);
int amount = +1;
if (field == DAY_OF_WEEK) {
amount += 700;
}
cal.roll(field, amount);
if (!cal.checkDateTime(1930, JUNE, 21, 01, 00, 00, 000)) {
error("1930/6/20: roll(" + Koyomi.getFieldName(field) + ", +" + amount + ")\n"
+ cal.getMessage() + " " + cal.toDateTimeString());
}
cal.clear();
cal.set(1930, JUNE, 21, 01, 00, 00);
amount = -1;
if (field == DAY_OF_WEEK) {
amount -= 700;
}
cal.roll(field, amount);
if (!cal.checkDateTime(1930, JUNE, 20, 01, 00, 00, 000)) {
error("1930/6/21: roll(" + Koyomi.getFieldName(field) + ", " + amount + ")\n"
+ cal.getMessage() + " " + cal.toDateTimeString());
}
}
// Test the AM_PM field
// add()
cal.clear();
cal.set(1919, DECEMBER, 14 - 1, 23, 50, 00);
cal.add(AM_PM, +1);
if (!cal.checkDate(1919, DECEMBER, 14)
|| !cal.checkFieldValue(AM_PM, AM)) {
error("1919/12/13: add(AM_PM, +1)\n"
+ cal.getMessage() + " " + cal.toDateTimeString());
}
cal.clear();
cal.set(1930, JUNE, 21 - 1, 12, 00, 00);
cal.add(AM_PM, +1);
if (!cal.checkDate(1930, JUNE, 21)
|| !cal.checkFieldValue(AM_PM, AM)) {
error("1930/6/20: add(AM_PM, +1)\n"
+ cal.getMessage() + " " + cal.toDateTimeString());
}
cal.clear();
cal.set(1930, JUNE, 21 - 2, 12, 00, 00);
cal.add(AM_PM, +3);
if (!cal.checkDate(1930, JUNE, 21)
|| !cal.checkFieldValue(AM_PM, AM)) {
error("1930/6/10: add(AM_PM, +3)\n"
+ cal.getMessage() + " " + cal.toDateTimeString());
}
cal.clear();
cal.set(1919, DECEMBER, 14, 11, 50, 00);
cal.add(AM_PM, -1);
if (!cal.checkDateTime(1919, DECEMBER, 14 - 1, 23, 50, 00, 000)
|| !cal.checkFieldValue(AM_PM, PM)) {
error("1919/12/14 11:50:00: add(AM_PM, -1)\n"
+ cal.getMessage() + " " + cal.toDateTimeString());
}
cal.clear();
cal.set(1930, JUNE, 21, 01, 00, 00);
cal.add(AM_PM, -1);
if (!cal.checkDateTime(1930, JUNE, 21 - 1, 01 + 12, 00, 00, 000)
|| !cal.checkFieldValue(AM_PM, PM)) {
error("1930/6/20: add(AM_PM, -1)\n"
+ cal.getMessage() + " " + cal.toDateTimeString());
}
cal.clear();
cal.set(1930, JUNE, 21, 01, 00, 00);
cal.add(AM_PM, -3);
if (!cal.checkDateTime(1930, JUNE, 21 - 2, 01 + 12, 00, 00, 000)
|| !cal.checkFieldValue(AM_PM, PM)) {
error("1930/6/10: add(AM_PM, -3)\n"
+ cal.getMessage() + " " + cal.toDateTimeString());
}
// roll() (should NOT change the date)
cal.clear();
cal.set(1919, DECEMBER, 14 - 1, 23, 50, 00);
cal.roll(AM_PM, +1);
if (!cal.checkDateTime(1919, DECEMBER, 14 - 1, 23 - 12, 50, 00, 000)
|| !cal.checkFieldValue(AM_PM, AM)) {
error("1919/12/13: roll(AM_PM, +1)\n"
+ cal.getMessage() + " " + cal.toDateTimeString());
}
cal.clear();
cal.set(1930, JUNE, 21 - 1, 12, 00, 00);
cal.roll(AM_PM, +1);
if (!cal.checkDateTime(1930, JUNE, 21 - 1, 12 - 12, 00, 00, 000)
|| !cal.checkFieldValue(AM_PM, AM)) {
error("1930/6/20: roll(AM_PM, +1)\n"
+ cal.getMessage() + " " + cal.toDateTimeString());
}
cal.clear();
cal.set(1930, JUNE, 21 - 2, 12, 00, 00);
cal.roll(AM_PM, +3);
if (!cal.checkDateTime(1930, JUNE, 21 - 2, 12 - 12, 00, 00, 000)
|| !cal.checkFieldValue(AM_PM, AM)) {
error("1930/6/10: roll(AM_PM, +3)\n"
+ cal.getMessage() + " " + cal.toDateTimeString());
}
// Test the HOUR_OF_DAY field
// add()
cal.clear();
cal.set(1930, JUNE, 20, 23, 00, 00);
cal.add(HOUR_OF_DAY, +1);
if (!cal.checkDateTime(1930, JUNE, 21, 01, 00, 00, 000)) {
error("1930/6/20 23:00:00: add(HOUR_OF_DAY, +1)\n"
+ cal.getMessage() + " " + cal.toDateTimeString());
}
// roll() (should NOT change the date)
cal.clear();
cal.set(1930, JUNE, 20, 23, 00, 00);
cal.roll(HOUR_OF_DAY, +1);
if (!cal.checkDateTime(1930, JUNE, 20, 00, 00, 00, 000)) {
error("1930/6/20 23:00:00: roll(HOUR_OF_DAY, +1)\n"
+ cal.getMessage() + " " + cal.toDateTimeString());
}
checkErrors();
}
static void error(String s) {
System.out.println(s);
errorCount++;
}
static void checkErrors() {
if (errorCount > 0) {
throw new RuntimeException("Failed: " + errorCount + " error(s)");
}
}
}

View file

@ -0,0 +1,100 @@
/*
* Copyright (c) 2004, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 5078053
* @summary Make sure that Calendar.complete() normalizes stamp[] to
* COMPUTED. This can be observed through add() and roll().
*/
import java.util.TimeZone;
import static java.util.Calendar.*;
public class Bug5078053 {
static int errorCount = 0;
public static void main(String[] args) {
TimeZone defaultTz = TimeZone.getDefault();
try {
TimeZone tz = TimeZone.getTimeZone("Australia/Adelaide");
TimeZone.setDefault(tz);
Koyomi cal = new Koyomi();
cal.setFirstDayOfWeek(2);
cal.setMinimalDaysInFirstWeek(4);
// test roll()
cal.clear();
// 2002-01-01T00:00:00 in Australia/Adelaide
cal.setTimeInMillis(1009805400000L);
System.out.println(cal.getTime());
// The following set calls shouldn't affect roll() and add()
cal.set(DAY_OF_WEEK, cal.get(DAY_OF_WEEK));
cal.set(WEEK_OF_YEAR, cal.get(WEEK_OF_YEAR));
cal.getTime();
cal.roll(MONTH, +1);
System.out.println("roll: " + cal.getTime());
if (!cal.checkDate(2002, FEBRUARY, 1)) {
error("roll(MONTH, +1): " + cal.getMessage());
}
cal.roll(MONTH, -1);
if (!cal.checkDate(2002, JANUARY, 1)) {
error("roll(MONTH, -1): " + cal.getMessage());
}
// test add()
cal.clear();
// 2002-01-01T00:00:00+0930 in Australia/Adelaide
cal.setTimeInMillis(1009805400000L);
cal.set(DAY_OF_WEEK, cal.get(DAY_OF_WEEK));
cal.set(WEEK_OF_YEAR, cal.get(WEEK_OF_YEAR));
cal.getTime();
cal.add(MONTH, +1);
System.out.println(" add: " + cal.getTime());
if (!cal.checkDate(2002, FEBRUARY, 1)) {
error("add(MONTH, +1): " + cal.getMessage());
}
cal.add(MONTH, -1);
if (!cal.checkDate(2002, JANUARY, 1)) {
error("add(MONTH, -1): " + cal.getMessage());
}
}
finally {
TimeZone.setDefault(defaultTz);
}
checkErrors();
}
static void error(String s) {
System.out.println(s);
errorCount++;
}
static void checkErrors() {
if (errorCount > 0) {
throw new RuntimeException("Failed: " + errorCount + " error(s)");
}
}
}

View file

@ -0,0 +1,50 @@
/*
* Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 6178071 6440854
* @summary Make sure that setting HOUR right after a construction works
* as expected.
*/
import java.util.GregorianCalendar;
import static java.util.Calendar.*;
public class Bug6178071 {
public static void main(String[] args) {
GregorianCalendar cal = new GregorianCalendar(2004, JANUARY, 1);
cal.set(HOUR, 1);
if (cal.get(HOUR_OF_DAY) != 1 ||
cal.get(HOUR) != 1 || cal.get(AM_PM) != AM) {
throw new RuntimeException("Unexpected hour of day: " + cal.getTime());
}
// Test case for 6440854
GregorianCalendar gc = new GregorianCalendar(2006,5,16);
gc.setLenient(false);
gc.set(HOUR_OF_DAY, 10);
// The following line shouldn't throw an IllegalArgumentException.
gc.get(YEAR);
}
}

View file

@ -0,0 +1,97 @@
/*
* Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 6234795
* @summary Rolling of HOUR or HOUR_OF_SET must set the other hour field.
*/
import java.util.GregorianCalendar;
import static java.util.Calendar.AM;
import static java.util.Calendar.AM_PM;
import static java.util.Calendar.HOUR;
import static java.util.Calendar.HOUR_OF_DAY;
import static java.util.Calendar.SEPTEMBER;
import java.util.Locale;
import java.util.TimeZone;
public class Bug6234795 {
public static void main(String[] args) {
testRoll(HOUR);
testRoll(HOUR_OF_DAY);
}
static void testRoll(int field) {
GregorianCalendar cal = new GregorianCalendar(TimeZone.getTimeZone("GMT"), Locale.US);
cal.clear();
cal.set(2005, SEPTEMBER, 12);
int otherField = (field == HOUR) ? HOUR_OF_DAY : HOUR;
int unit = (field == HOUR) ? 12 : 24;
int h;
for (h = 0; h <= 72; h++) {
int hour = cal.get(otherField);
int expected = h % 12;
if (hour != expected) {
throw new RuntimeException((field == HOUR ? "HOUR" : "HOUR_OF_DAY")
+ "+: h=" + h + ", got " + hour
+ ", expected " + expected);
}
if (field == HOUR_OF_DAY) {
int ampm = cal.get(AM_PM);
expected = (h % unit) / 12;
if (ampm != expected) {
throw new RuntimeException((field == HOUR ? "HOUR" : "HOUR_OF_DAY")
+ "+: h=" + h + ", got "
+ toString(ampm)
+ ", expected " + toString(expected));
}
}
cal.roll(field, +1);
}
for (; h >= 0; h--) {
int hour = cal.get(otherField);
int expected = h % 12;
if (hour != expected) {
throw new RuntimeException((field == HOUR ? "HOUR" : "HOUR_OF_DAY")
+ "-: h=" + h + ", got " + hour
+ ", expected " + expected);
}
if (field == HOUR_OF_DAY) {
int ampm = cal.get(AM_PM);
expected = (h % unit) / 12;
if (ampm != expected) {
throw new RuntimeException((field == HOUR ? "HOUR" : "HOUR_OF_DAY")
+ "-: h=" + h + ", got " + toString(ampm)
+ ", expected " + toString(expected));
}
}
cal.roll(field, -1);
}
}
static String toString(int ampm) {
return ampm == AM ? "AM" : "PM";
}
}

View file

@ -0,0 +1,58 @@
/*
* Copyright (c) 2006, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 6448234
* @summary Make sure indexing of DAY_OF_WEEK is correct in JapaneseImperialCalendar.getDisplayName.
*/
import java.util.Calendar;
import java.util.Locale;
import static java.util.Calendar.*;
public class Bug6448234 {
public static void main(String[] args) {
Calendar jcal = Calendar.getInstance(Locale.of("ja", "JP", "JP"));
Calendar gcal = Calendar.getInstance(Locale.US);
for (int i = SUNDAY; i <= SATURDAY; i++) {
jcal.set(DAY_OF_WEEK, i);
gcal.set(DAY_OF_WEEK, i);
// Test LONG
String j = jcal.getDisplayName(DAY_OF_WEEK, LONG, Locale.US);
String g = gcal.getDisplayName(DAY_OF_WEEK, LONG, Locale.US);
if (!j.equals(g)) {
throw new RuntimeException("Got " + j + ", expected " + g);
}
// Test SHORT
j = jcal.getDisplayName(DAY_OF_WEEK, SHORT, Locale.US);
g = gcal.getDisplayName(DAY_OF_WEEK, SHORT, Locale.US);
if (!j.equals(g)) {
throw new RuntimeException("Got " + j + ", expected " + g);
}
}
}
}

View file

@ -0,0 +1,47 @@
/*
* Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 6645263
* @summary Test field normalization in non-lenient from the partially normalized state
*/
import java.util.*;
public class Bug6645263 {
public static void main(String[] args) {
Calendar cal = new GregorianCalendar(Locale.US);
cal.setLenient(false);
cal.set(Calendar.YEAR, 2007);
cal.set(Calendar.MONTH, Calendar.NOVEMBER);
cal.set(Calendar.WEEK_OF_MONTH, 4);
cal.set(Calendar.DAY_OF_WEEK, 1);
// Let cal calculate the time from the given fields
cal.getTime();
// Change DAY_OF_MONTH
cal.set(Calendar.DAY_OF_MONTH, 1);
// The following line shouldn't throw an IllegalArgumentException.
cal.getTime();
}
}

View file

@ -0,0 +1,70 @@
/*
* Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 6902861
* @summary Test for a workaround when WEEK_OF_YEAR and YEAR are out of sync.
* @modules jdk.localedata
*/
import java.util.*;
import static java.util.GregorianCalendar.*;
public class Bug6902861 {
static int errors = 0;
public static void main(String [] args) {
Locale loc = Locale.getDefault();
try {
Locale.setDefault(Locale.GERMANY);
test(2010, JANUARY, 1, +1, 1);
test(2010, JANUARY, 1, +2, 2);
test(2010, JANUARY, 1, -1, 52);
test(2010, JANUARY, 1, -2, 51);
test(2008, DECEMBER, 31, +1, 1);
test(2008, DECEMBER, 31, +2, 2);
test(2008, DECEMBER, 31, -1, 52);
test(2008, DECEMBER, 31, -2, 51);
if (errors > 0) {
throw new RuntimeException("Failed");
}
} finally {
Locale.setDefault(loc);
}
}
static void test(int year, int month, int dayOfMonth, int amount, int expected) {
Calendar calendar = new GregorianCalendar(year, month, dayOfMonth);
int week = calendar.get(WEEK_OF_YEAR); // fix the date
calendar.roll(WEEK_OF_YEAR, amount);
int got = calendar.get(WEEK_OF_YEAR);
int y = calendar.get(YEAR);
if (got != expected || y != year) {
String date = String.format("%04d-%02d-%02d", year, month+1, dayOfMonth);
System.err.printf("%s: roll %+d: got: %d,%2d; expected: %d,%2d%n",
date, amount, y, got, year, expected);
errors++;
}
}
}

View file

@ -0,0 +1,125 @@
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 7017458
* @summary Test of multithreaded serialization/deserialization of Calendar.
*/
import java.io.*;
import java.util.Calendar;
public class Bug7017458 {
static volatile boolean err = false;
public static void main(String[] args) {
try {
new Bug7017458().perform();
}
catch (Exception e) {
e.printStackTrace();
err = true;
}
if (err) {
throw new RuntimeException("Multithreaded serialization/deserialization test failed.");
} else {
System.out.println("Multithreaded serialization/deserialization test passed.");
}
}
public void perform() throws Exception {
int nbThreads = 8;
Calendar cal = Calendar.getInstance();
SerializationThread[] threads = new SerializationThread[nbThreads];
for (int i = 0; i < nbThreads; i++) {
threads[i] = new SerializationThread(cal);
}
for (int i = 0; i < nbThreads; i++) {
threads[i].start();
}
for (int i = 0; i < nbThreads; i++) {
threads[i].join();
}
DeserializationThread[] threads2 = new DeserializationThread[nbThreads];
for (int i = 0; i < nbThreads; i++) {
threads2[i] = new DeserializationThread(threads[i].data);
}
for (int i = 0; i < nbThreads; i++) {
threads2[i].start();
}
for (int i = 0; i < nbThreads; i++) {
threads2[i].join();
}
}
public class SerializationThread extends Thread {
private Calendar cal;
public byte[] data;
public SerializationThread(Calendar cal) {
this.cal = cal;
}
public void run() {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(cal);
oos.flush();
oos.close();
data = baos.toByteArray();
}
catch (Exception e) {
e.printStackTrace();
err = true;
}
}
}
public class DeserializationThread extends Thread {
public Calendar cal;
public byte[] data;
public DeserializationThread(byte[] data) {
this.data = data;
}
public void run() {
try {
ByteArrayInputStream bais = new ByteArrayInputStream(data);
ObjectInputStream ois = new ObjectInputStream(bais);
cal = (Calendar) ois.readObject();
ois.close();
}
catch (Exception e) {
e.printStackTrace();
err = true;
}
}
}
}

View file

@ -0,0 +1,111 @@
/*
* Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8007038 8247781 8174269
* @summary Verify ArrayIndexOutOfBoundsException is not thrown
* on calling localizedDateTime().print() with JapaneseChrono
* @modules java.base/sun.util.locale.provider
* @modules jdk.localedata
* @compile -XDignore.symbol.file Bug8007038.java
* @run main Bug8007038 CLDR
*/
import java.util.*;
import static java.util.Calendar.*;
import sun.util.locale.provider.CalendarDataUtility;
public class Bug8007038 {
private static final String[] calTypes = {
"gregory",
"buddhist",
"japanese",
"roc",
"islamic",
};
private static final int[][] eraMinMax = {
{GregorianCalendar.BC, GregorianCalendar.AD},
{0, 1},
{0, 5},
{0, 1},
{0, 1},
{0, 1},
};
private static final Locale[] testLocs = {
Locale.ROOT,
Locale.forLanguageTag("ja-JP-u-ca-japanese"),
Locale.forLanguageTag("th-TH"),
Locale.forLanguageTag("th-TH-u-ca-buddhist"),
Locale.forLanguageTag("zh-TW-u-ca-roc"),
Locale.forLanguageTag("ar-EG-u-ca-islamic"),
Locale.forLanguageTag("xx-YY-u-ca-bogus"),
};
public static void main(String[] args) {
for (int calIdx = 0; calIdx < calTypes.length; calIdx++) {
for (int locIdx = 0; locIdx < testLocs.length; locIdx++) {
// era
for (int fieldIdx = eraMinMax[calIdx][0]; fieldIdx <= eraMinMax[calIdx][1]; fieldIdx++) {
checkValueRange(calTypes[calIdx], ERA, fieldIdx, LONG, testLocs[locIdx], true);
}
checkValueRange(calTypes[calIdx], ERA, eraMinMax[calIdx][0]-1, LONG,
testLocs[locIdx], false);
checkValueRange(calTypes[calIdx], ERA, eraMinMax[calIdx][1]+1,
LONG, testLocs[locIdx], false);
// month
for (int fieldIdx = JANUARY; fieldIdx <= UNDECIMBER ; fieldIdx++) {
checkValueRange(calTypes[calIdx], MONTH, fieldIdx, LONG, testLocs[locIdx], true);
}
checkValueRange(calTypes[calIdx], MONTH, JANUARY-1, LONG, testLocs[locIdx], false);
checkValueRange(calTypes[calIdx], MONTH, UNDECIMBER+1, LONG, testLocs[locIdx], false);
// day-of-week
for (int fieldIdx = SUNDAY; fieldIdx <= SATURDAY; fieldIdx++) {
checkValueRange(calTypes[calIdx], DAY_OF_WEEK, fieldIdx, LONG, testLocs[locIdx], true);
}
checkValueRange(calTypes[calIdx], DAY_OF_WEEK, SUNDAY-1, LONG, testLocs[locIdx], false);
checkValueRange(calTypes[calIdx], DAY_OF_WEEK, SATURDAY+1, LONG, testLocs[locIdx], false);
// am/pm
int lastIndex = args[0].equals("CLDR") ? 11 : PM;
for (int fieldIdx = AM; fieldIdx <= lastIndex; fieldIdx++) {
checkValueRange(calTypes[calIdx], AM_PM, fieldIdx, LONG, testLocs[locIdx], true);
}
checkValueRange(calTypes[calIdx], AM_PM, AM-1, LONG, testLocs[locIdx], false);
checkValueRange(calTypes[calIdx], AM_PM, lastIndex+1, LONG, testLocs[locIdx], false);
}
}
}
private static void checkValueRange(String calType, int field, int value, int style, Locale l, boolean isNonNull) {
String ret = CalendarDataUtility.retrieveJavaTimeFieldValueName(calType, field, value, style, l);
System.out.print("retrieveFieldValueName("+calType+", "+field+", "+value+", "+style+", "+l+")");
if ((ret != null) == isNonNull) {
System.out.println(" returned "+ret);
} else {
throw new RuntimeException("The call returned "+ret);
}
}
}

View file

@ -0,0 +1,108 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @bug 8075548
* @summary Make sure that the format form of month names are produced when there are
* no stand-alone ones available.
*/
import java.text.*;
import java.util.*;
import static java.util.Calendar.*;
public class Bug8075548 {
static int errors = 0;
public static void main(String[] args) throws Throwable {
Date date = new SimpleDateFormat("yyyy-MM-dd", Locale.US).parse("2010-09-15");
String[][] FORMAT_PAIRS = {
{ "LLLL", "MMMM" },
{ "LLL", "MMM" }
};
Locale[] LOCALES = {
Locale.ENGLISH, Locale.JAPANESE
};
for (Locale locale : LOCALES) {
for (String[] formats : FORMAT_PAIRS) {
String el = new SimpleDateFormat(formats[0], locale).format(date);
String em = new SimpleDateFormat(formats[1], locale).format(date);
if (!el.equals(em)) {
errors++;
System.err.println(locale + ": " +
formats[0] + " -> " + el + ", " +
formats[1] + " -> " + em);
}
}
}
// Test Calendar.getDisplayName() and .getDisplayNames().
for (Locale locale : LOCALES) {
testDisplayNames(locale, LONG_FORMAT, LONG_STANDALONE);
testDisplayNames(locale, SHORT_FORMAT, SHORT_STANDALONE);
testDisplayNames(locale, NARROW_FORMAT, NARROW_STANDALONE);
}
if (errors > 0) {
throw new RuntimeException("Failed");
}
}
private static void testDisplayNames(Locale locale, int formatStyle, int standaloneStyle) {
Map<String, Integer> map = new HashMap<>();
for (int month = JANUARY; month <= DECEMBER; month++) {
Calendar cal = new GregorianCalendar(2015, month, 1);
String format = cal.getDisplayName(MONTH, formatStyle, locale);
String standalone = cal.getDisplayName(MONTH, standaloneStyle, locale);
if (!format.equals(standalone)) {
System.err.println("Calendar.getDisplayName: " + (month+1) +
", locale=" + locale +
", format=" + format + ", standalone=" + standalone);
errors++;
}
if (standalone != null) {
map.put(standalone, month);
}
}
if (formatStyle == NARROW_FORMAT) {
// Narrow styles don't support unique names.
// (e.g., "J" for JANUARY, JUNE, and JULY)
return;
}
Calendar cal = new GregorianCalendar(2015, JANUARY, 1);
Map<String, Integer> mapStandalone = cal.getDisplayNames(MONTH, standaloneStyle, locale);
if (!map.equals(mapStandalone)) {
System.err.printf("Calendar.getDisplayNames: locale=%s%n map=%s%n mapStandalone=%s%n",
locale, map, mapStandalone);
errors++;
}
Map<String, Integer> mapAll = cal.getDisplayNames(MONTH, ALL_STYLES, locale);
if (!mapAll.entrySet().containsAll(map.entrySet())) {
System.err.printf("Calendar.getDisplayNames: locale=%s%n map=%s%n mapAll=%s%n",
locale, map, mapAll);
errors++;
}
}
}

View file

@ -0,0 +1,135 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @bug 8152077
* @summary Make sure that roll() with HOUR/HOUR_OF_DAY works around standard/daylight
* time transitions
*/
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.TimeZone;
import static java.util.Calendar.*;
public class Bug8152077 {
private static final TimeZone LA = TimeZone.getTimeZone("America/Los_Angeles");
private static final TimeZone BR = TimeZone.getTimeZone("America/Sao_Paulo");
private static final int[] ALLDAY_HOURS = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23
};
private static final int[] AM_HOURS = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
};
private static final int[] PM_HOURS = { // in 24-hour clock
12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23
};
private static int errors;
public static void main(String[] args) {
TimeZone initialTz = TimeZone.getDefault();
try {
testRoll(LA, new int[] { 2016, MARCH, 13 },
new int[] { 0, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11,
12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23 });
testRoll(LA, new int[] { 2016, MARCH, 13 },
new int[] { 0, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11 });
testRoll(LA, new int[] { 2016, MARCH, 13 }, PM_HOURS);
testRoll(LA, new int[] { 2016, NOVEMBER, 6 }, ALLDAY_HOURS);
testRoll(LA, new int[] { 2016, NOVEMBER, 6 }, AM_HOURS);
testRoll(LA, new int[] { 2016, NOVEMBER, 6 }, PM_HOURS);
testRoll(BR, new int[] { 2016, FEBRUARY, 21 }, ALLDAY_HOURS);
testRoll(BR, new int[] { 2016, FEBRUARY, 21 }, AM_HOURS);
testRoll(BR, new int[] { 2016, FEBRUARY, 21 }, PM_HOURS);
testRoll(BR, new int[] { 2016, OCTOBER, 15 }, ALLDAY_HOURS);
testRoll(BR, new int[] { 2016, OCTOBER, 15 }, PM_HOURS);
testRoll(BR, new int[] { 2016, OCTOBER, 16 },
new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23 });
testRoll(BR, new int[] { 2016, OCTOBER, 16 },
new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 });
testRoll(BR, new int[] { 2016, OCTOBER, 16 }, PM_HOURS);
} finally {
TimeZone.setDefault(initialTz);
}
if (errors > 0) {
throw new RuntimeException("Test failed");
}
}
private static void testRoll(TimeZone tz, int[] params, int[] sequence) {
TimeZone.setDefault(tz);
for (int i = 0; i < sequence.length; i++) {
testRoll(+1, params, sequence, i);
testRoll(-1, params, sequence, i);
}
}
// amount must be 1 or -1.
private static void testRoll(int amount, int[] params, int[] sequence, int startIndex) {
int year = params[0];
int month = params[1];
int dayOfMonth = params[2];
int hourOfDay = sequence[startIndex];
Calendar cal = new GregorianCalendar(year, month, dayOfMonth,
hourOfDay, 0, 0);
int ampm = cal.get(AM_PM);
int length = sequence.length;
int count = length * 2;
int field = (length > 12) ? HOUR_OF_DAY : HOUR;
System.out.printf("roll(%s, %2d) starting from %s%n",
(field == HOUR) ? "HOUR" : "HOUR_OF_DAY", amount, cal.getTime());
for (int i = 0; i < count; i++) {
int index = (amount > 0) ? (startIndex + i + 1) % length
: Math.floorMod(startIndex - i - 1, length);
int expected = sequence[index];
if (field == HOUR) {
expected %= 12;
}
cal.roll(field, amount);
int value = cal.get(field);
if (value != expected) {
System.out.println("Unexpected field value: got=" + value
+ ", expected=" + expected);
errors++;
}
if (cal.get(DAY_OF_MONTH) != dayOfMonth) {
System.out.println("DAY_OF_MONTH changed: " + dayOfMonth
+ " to " + cal.get(DAY_OF_MONTH));
}
if (field == HOUR && cal.get(AM_PM) != ampm) {
System.out.println("AM_PM changed: " + ampm + " to " + cal.get(AM_PM));
errors++;
}
}
}
}

View file

@ -0,0 +1,153 @@
/*
* Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8167273 8251317 8258794 8174269
* @summary Test
* Era names retrieved from Calendar and DateFormatSymbols class
* should match for default providers preference
* Empty era names are not retrieved from DateFormatSymbols class.
* Equivalent locales specified for [zh-HK, no-NO, no] for
* CLDR Provider works correctly.
* Implicit COMPAT Locale nb is reflected in available locales
* @modules java.base/sun.util.locale.provider
* java.base/sun.util.spi
* jdk.localedata
* @run main Bug8167273 testEraName
* @run main Bug8167273 testCldr
* @run main Bug8167273 testEmptyEraNames
*/
import java.text.DateFormatSymbols;
import java.util.Arrays;
import java.util.Calendar;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import sun.util.locale.provider.LocaleProviderAdapter;
import sun.util.locale.provider.LocaleProviderAdapter.Type;
public class Bug8167273 {
public static void main(String[] args) throws Exception {
switch (args[0]) {
case "testEraName":
testEraName();
break;
case "testEmptyEraNames":
testEmptyEraNames();
break;
case "testCldr":
testCldrSupportedLocales();
break;
default:
throw new RuntimeException("no test was specified.");
}
}
/**
* tests that era names retrieved from Calendar.getDisplayNames map should
* match with that of Era names retrieved from DateFormatSymbols.getEras()
* method for all Gregorian Calendar locales .
*/
public static void testEraName() {
Set<Locale> allLocales = Set.of(Locale.getAvailableLocales());
Set<Locale> JpThlocales = Set.of(
Locale.of("th", "TH"), Locale.forLanguageTag("th-Thai-TH"),
Locale.of("ja", "JP", "JP"), Locale.of("th", "TH", "TH")
);
Set<Locale> allLocs = new HashSet<>(allLocales);
// Removing Japanese and Thai Locales to check Gregorian Calendar Locales
allLocs.removeAll(JpThlocales);
allLocs.forEach((locale) -> {
Calendar cal = Calendar.getInstance(locale);
Map<String, Integer> names = cal.getDisplayNames(Calendar.ERA, Calendar.ALL_STYLES, locale);
DateFormatSymbols symbols = new DateFormatSymbols(locale);
String[] eras = symbols.getEras();
for (String era : eras) {
if (!names.containsKey(era)) {
reportMismatch(names.keySet(), eras, locale);
}
}
});
}
private static void reportMismatch(Set<String> CalendarEras, String[] dfsEras, Locale locale) {
System.out.println("For Locale " + locale + "era names in calendar map are " + CalendarEras);
for (String era : dfsEras) {
System.out.println("For Locale " + locale + " era names in DateFormatSymbols era array are " + era);
}
throw new RuntimeException(" Era name retrieved from Calendar class do not match with"
+ " retrieved from DateFormatSymbols for Locale " + locale);
}
/**
* tests that Eras names returned from DateFormatSymbols.getEras()
* and Calendar.getDisplayNames() should not be empty for any Locale.
*/
private static void testEmptyEraNames() {
Set<Locale> allLocales = Set.of(Locale.getAvailableLocales());
allLocales.forEach((loc) -> {
DateFormatSymbols dfs = new DateFormatSymbols(loc);
Calendar cal = Calendar.getInstance(loc);
Map<String, Integer> names = cal.getDisplayNames(Calendar.ERA, Calendar.ALL_STYLES, loc);
Set<String> CalendarEraNames = names.keySet();
String[] eras = dfs.getEras();
for (String era : eras) {
if (era.isEmpty()) {
throw new RuntimeException("Empty era names retrieved for DateFomatSymbols.getEras"
+ " for locale " + loc);
}
}
CalendarEraNames.stream().filter((erakey) -> (erakey.isEmpty())).forEachOrdered((l) -> {
throw new RuntimeException("Empty era names retrieved for Calendar.getDisplayName"
+ " for locale " + loc);
});
});
}
/**
* tests that CLDR provider should return true for locale zh_HK, no-NO and
* no.
*/
private static void testCldrSupportedLocales() {
Set<Locale> locales = Set.of(Locale.forLanguageTag("zh-HK"),
Locale.forLanguageTag("no-NO"),
Locale.forLanguageTag("no"));
LocaleProviderAdapter cldr = LocaleProviderAdapter.forType(Type.CLDR);
Set<Locale> availableLocs = Set.of(cldr.getAvailableLocales());
Set<String> langtags = new HashSet<>();
availableLocs.forEach((loc) -> {
langtags.add(loc.toLanguageTag());
});
locales.stream().filter((loc) -> (!cldr.isSupportedProviderLocale(loc, langtags))).forEachOrdered((loc) -> {
throw new RuntimeException("Locale " + loc + " is not supported by CLDR Locale Provider");
});
}
}

View file

@ -0,0 +1,52 @@
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @bug 8176847
* @summary Make sure that style value of '3' throws IllegalArgumentException
* in Calendar.getDisplayName(s) methods.
*/
import java.util.Calendar;
import java.util.Locale;
public class Bug8176847 {
public static void main(String[] args) {
Calendar c = new Calendar.Builder().build();
try {
c.getDisplayName(Calendar.MONTH, 3, Locale.US);
throw new RuntimeException("IllegalArgumentException was not thrown");
} catch (IllegalArgumentException iae) {
// success
}
try {
c.getDisplayNames(Calendar.MONTH, 3, Locale.US);
throw new RuntimeException("IllegalArgumentException was not thrown");
} catch (IllegalArgumentException iae) {
// success
}
}
}

View file

@ -0,0 +1,300 @@
/*
* Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 4745761 8350646
* @summary Unit test for Calendar.Builder.
* @run main BuilderTest
*/
import java.time.LocalDateTime;
import java.util.*;
import static java.util.Calendar.*;
public class BuilderTest {
private static final Locale jaJPJP = Locale.of("ja", "JP", "JP");
private static final Locale thTH = Locale.of("th", "TH");
private static final TimeZone LA = TimeZone.getTimeZone("America/Los_Angeles");
private static final TimeZone TOKYO = TimeZone.getTimeZone("Asia/Tokyo");
private static int error;
public static void main(String[] args) {
TimeZone tz = TimeZone.getDefault();
Locale loc = Locale.getDefault();
try {
TimeZone.setDefault(TimeZone.getTimeZone("GMT"));
Locale.setDefault(Locale.US);
Calendar.Builder calb;
Calendar cal, expected;
// set instant
calb = builder();
long time = System.currentTimeMillis();
cal = calb.setInstant(time).build();
expected = new GregorianCalendar();
expected.setTimeInMillis(time);
check(cal, expected);
calb = builder();
cal = calb.setInstant(new Date(time)).build();
check(cal, expected);
// set time zone
calb = builder();
cal = calb.setTimeZone(LA).setInstant(time).build();
expected = new GregorianCalendar(LA, Locale.US);
expected.setTimeInMillis(time);
check(cal, expected);
calb = builder();
cal = calb.setTimeZone(TOKYO).setInstant(time).build();
expected = new GregorianCalendar(TOKYO, Locale.US);
expected.setTimeInMillis(time);
check(cal, expected);
// set vs. setFields
calb = builder();
cal = calb.set(YEAR, 2013).set(MONTH, JANUARY).set(DAY_OF_MONTH, 31)
.set(HOUR_OF_DAY, 10).set(MINUTE, 20).set(SECOND, 30).set(MILLISECOND, 40).build();
expected = new GregorianCalendar(2013, JANUARY, 31, 10, 20, 30);
expected.set(MILLISECOND, 40);
check(cal, expected);
calb = builder();
cal = calb.setFields(YEAR, 2013, MONTH, JANUARY, DAY_OF_MONTH, 31,
HOUR_OF_DAY, 10, MINUTE, 20, SECOND, 30, MILLISECOND, 40).build();
check(cal, expected);
// field resolution
calb = builder();
cal = calb.setFields(YEAR, 2013, MONTH, DECEMBER, DAY_OF_MONTH, 31,
HOUR_OF_DAY, 10, MINUTE, 20, SECOND, 30, MILLISECOND, 40)
.set(DAY_OF_YEAR, 31).build(); // DAY_OF_YEAR wins.
check(cal, expected);
// setDate/setTimeOfDay
calb = builder();
cal = calb.setDate(2013, JANUARY, 31).setTimeOfDay(10, 20, 30, 40).build();
check(cal, expected);
// week date (ISO 8601)
calb = builder().setCalendarType("iso8601");
cal = calb.setWeekDate(2013, 1, MONDAY).setTimeOfDay(10, 20, 30).build();
expected = getISO8601();
expected.set(2012, DECEMBER, 31, 10, 20, 30);
check(cal, expected);
// default YEAR == 1970
cal = builder().setFields(MONTH, JANUARY,
DAY_OF_MONTH, 9).build();
check(cal, new GregorianCalendar(1970, JANUARY, 9));
// no parameters are given.
calb = builder();
cal = calb.build();
expected = new GregorianCalendar();
expected.clear();
check(cal, expected);
// Thai Buddhist calendar
calb = builder();
cal = calb.setCalendarType("buddhist").setDate(2556, JANUARY, 31).build();
expected = Calendar.getInstance(thTH);
expected.clear();
expected.set(2556, JANUARY, 31);
check(cal, expected);
// setLocale
calb = builder();
cal = calb.setLocale(thTH).setDate(2556, JANUARY, 31).build();
check(cal, expected);
// Japanese Imperial calendar
cal = builder().setCalendarType("japanese")
.setFields(YEAR, 1, DAY_OF_YEAR, 1).build();
expected = Calendar.getInstance(jaJPJP);
expected.clear();
if (LocalDateTime.now().isBefore(LocalDateTime.of(2019, 5, 1, 0, 0))) {
expected.set(1, JANUARY, 8);
} else {
expected.set(1, MAY, 1);
}
check(cal, expected);
// setLocale
calb = builder();
cal = calb.setLocale(jaJPJP).setFields(YEAR, 1, DAY_OF_YEAR, 1).build();
check(cal, expected);
testExceptions();
} finally {
// Restore default Locale and TimeZone
Locale.setDefault(loc);
TimeZone.setDefault(tz);
}
if (error > 0) {
throw new RuntimeException("Failed");
}
}
private static void testExceptions() {
Calendar.Builder calb;
Calendar cal;
// NPE
try {
calb = builder().setInstant((Date)null);
noException("setInstant((Date)null)");
} catch (NullPointerException npe) {
}
try {
calb = builder().setCalendarType(null);
noException("setCalendarType(null)");
} catch (NullPointerException npe) {
}
try {
calb = builder().setLocale(null);
noException("setLocale(null)");
} catch (NullPointerException npe) {
}
try {
calb = builder().setTimeZone(null);
noException("setTimeZone(null)");
} catch (NullPointerException npe) {
}
// IllegalArgumentException
try {
// invalid field index in set
calb = builder().set(100, 2013);
noException("set(100, 2013)");
} catch (IllegalArgumentException e) {
}
try {
// invalid field index in setField
calb = builder().setFields(100, 2013);
noException("setFields(100, 2013)");
} catch (IllegalArgumentException e) {
}
try {
// odd number of arguments
calb = builder().setFields(YEAR, 2013, MONTH);
noException("setFields(YEAR, 2013, MONTH)");
} catch (IllegalArgumentException e) {
}
try {
// unknown calendar type
calb = builder().setCalendarType("foo");
noException("setCalendarType(\"foo\")");
} catch (IllegalArgumentException e) {
}
try {
// invalid week definition parameter
calb = builder().setWeekDefinition(8, 1);
noException("setWeekDefinition(8, 1)");
} catch (IllegalArgumentException e) {
}
try {
// invalid week definition parameter
calb = builder().setWeekDefinition(SUNDAY, 0);
noException("setWeekDefinition(8, 1)");
} catch (IllegalArgumentException e) {
}
try {
// sets both instant and field parameters
calb = builder().setInstant(new Date()).setDate(2013, JANUARY, 1);
noException("setInstant(new Date()).setDate(2013, JANUARY, 1)");
} catch (IllegalStateException e) {
}
try {
// sets both field parameters and instant
calb = builder().setDate(2013, JANUARY, 1).setInstant(new Date());
noException("setDate(2013, JANUARY, 1).setInstant(new Date())");
} catch (IllegalStateException e) {
}
try {
// sets inconsistent calendar types
calb = builder().setCalendarType("iso8601").setCalendarType("japanese");
noException("setCalendarType(\"iso8601\").setCalendarType(\"japanese\")");
} catch (IllegalStateException e) {
}
// IllegalArgumentException in build()
calb = nonLenientBuilder().set(MONTH, 100);
checkException(calb, IllegalArgumentException.class);
calb = nonLenientBuilder().setTimeOfDay(23, 59, 70);
checkException(calb, IllegalArgumentException.class);
calb = builder().setCalendarType("japanese").setWeekDate(2013, 1, MONDAY);
checkException(calb, IllegalArgumentException.class);
// JDK-8350646 : Ensure IAE (instead of AIOOBE) for ERA over largest supported
calb = builder().setCalendarType("japanese").setFields(ERA, 6);
checkException(calb, IllegalArgumentException.class);
// Note that we don't check ERAs under BEFORE_MEIJI, i.e. -1, -2, ... as
// historically JapaneseImperialCalendar ignores such values when normalizing
}
private static Calendar.Builder builder() {
return new Calendar.Builder();
}
private static Calendar.Builder nonLenientBuilder() {
return builder().setLenient(false);
}
private static Calendar getISO8601() {
GregorianCalendar cal = new GregorianCalendar();
cal.setFirstDayOfWeek(MONDAY);
cal.setMinimalDaysInFirstWeek(4);
cal.setGregorianChange(new Date(Long.MIN_VALUE));
cal.clear();
return cal;
}
private static void check(Calendar cal, Calendar expected) {
if (!cal.equals(expected)) {
error++;
System.err.println("FAILED:");
System.err.println("\t cal = "+cal.getTime());
System.err.println("\texpected = "+expected.getTime());
System.err.printf("\tcal = %s%n\texp = %s%n", cal, expected);
}
}
private static void checkException(Calendar.Builder calb, Class<? extends Exception> exception) {
try {
Calendar cal = calb.build();
error++;
System.err.println("expected exception: " + exception);
} catch (Exception e) {
if (!e.getClass().equals(exception)) {
error++;
System.err.println("unexpected exception: " + e.getClass() + ", expected: " + exception);
}
}
}
private static void noException(String msg) {
error++;
System.err.println("no exception with "+msg);
}
}

View file

@ -0,0 +1,109 @@
/*
* Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @bug 8190918 8202537 8221432 8231273 8265315 8284840 8333582
* 8354548
* @summary Tests for region dependent calendar data, i.e.,
* firstDayOfWeek and minimalDaysInFirstWeek.
* @modules jdk.localedata
* @run main CalendarDataTest
*/
import java.util.Calendar;
import java.util.List;
import java.util.Locale;
import java.util.Optional;
import java.util.stream.IntStream;
public class CalendarDataTest {
// golden data from CLDR
private static final List<List<String>> FIRSTDAYDATA = List.of(
List.of("1", "AG AS BD BR BS BT BW BZ CA CO DM DO ET GT " +
"GU HK HN ID IL IN IS JM JP KE KH KR LA MH MM MO MT MX MZ " +
"NI NP PA PE PH PK PR PT PY SA SG SV TH TT TW UM US VE " +
"VI WS YE ZA ZW"),
List.of("2", "001 AD AE AI AL AM AN AR AT AU AX AZ BA BE BG BM BN BY " +
"CH CL CM CN CR CY CZ DE DK EC EE ES FI FJ FO FR GB GE GF GP " +
"GR HR HU IE IT KG KZ LB LI LK LT LU LV MC MD ME MK MN MQ " +
"MY NL NO NZ PL RE RO RS RU SE SI SK SM TJ TM TR UA UY UZ " +
"VA VN XK"),
List.of("6", "MV"),
List.of("7", "AF BH DJ DZ EG IQ IR JO KW LY OM QA SD SY"));
private static final List<List<String>> MINDAYSDATA = List.of(
List.of("1", "001 GU UM US VI"),
List.of("4", "AD AN AT AX BE BG CH CZ DE DK EE ES FI FJ FO FR " +
"GB GF GG GI GP GR HU IE IM IS IT JE LI LT LU MC MQ NL NO " +
"PL PT RE RU SE SJ SK SM VA"));
public static void main(String... args) throws Exception {
// world
Calendar cal = Calendar.getInstance(Locale.of("", "001"));
checkResult("001",
cal.getFirstDayOfWeek(),
cal.getMinimalDaysInFirstWeek());
// two letter country codes
IntStream.range(0x41, 0x5b)
.forEach(c1 -> {
IntStream.range(0x41, 0x5b)
.mapToObj(c2 -> String.valueOf((char)c1) + String.valueOf((char)c2))
.forEach(region -> {
Calendar c = Calendar.getInstance(Locale.of("", region));
checkResult(region,
c.getFirstDayOfWeek(),
c.getMinimalDaysInFirstWeek());
});
});
}
private static void checkResult(String region, int firstDay, int minDays) {
// first day of week
int expected = Integer.parseInt(findEntry(region, FIRSTDAYDATA)
.orElse(findEntry("001", FIRSTDAYDATA).orElse(List.of("1")))
.get(0));
if (firstDay != expected) {
throw new RuntimeException("firstDayOfWeek is incorrect for the region: " +
region + ". Returned: " + firstDay + ", Expected: " + expected);
}
// minimal days in first week
expected = Integer.parseInt(findEntry(region, MINDAYSDATA)
.orElse(findEntry("001", MINDAYSDATA).orElse(List.of("1")))
.get(0));
if (minDays != expected) {
throw new RuntimeException("minimalDaysInFirstWeek is incorrect for the region: " +
region + ". Returned: " + minDays + ", Expected: " + expected);
}
}
private static Optional<List<String>> findEntry(String region, List<List<String>> data) {
return data.stream()
.filter(l -> l.get(1).contains(region))
.findAny();
}
}

View file

@ -0,0 +1,65 @@
/*
* Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.util.Calendar;
import java.util.Locale;
import java.util.Map;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
/**
* @test
* @bug 8262108 8174269
* @summary Verify the results returned by Calendar.getDisplayNames() API
* @comment Locale providers: CLDR,SPI
* @run junit/othervm -Djava.locale.providers=CLDR,SPI CalendarDisplayNamesTest
* @comment Locale providers: default
* @run junit CalendarDisplayNamesTest
*/
public class CalendarDisplayNamesTest {
/**
* Test that the {@link Calendar#getDisplayNames(int, int, Locale)} returns valid field values
* for the {@link Calendar#AM_PM} field in various locales and styles
*/
@Test
public void testAM_PMDisplayNameValues() {
final int[] styles = new int[]{Calendar.ALL_STYLES, Calendar.SHORT_FORMAT, Calendar.LONG_FORMAT,
Calendar.SHORT_STANDALONE, Calendar.LONG_STANDALONE, Calendar.SHORT, Calendar.LONG};
for (final Locale locale : Locale.getAvailableLocales()) {
for (final int style : styles) {
final Calendar cal = Calendar.getInstance();
final Map<String, Integer> names = cal.getDisplayNames(Calendar.AM_PM, style, locale);
if (names == null) {
continue;
}
for (final Integer fieldValue : names.values()) {
Assertions.assertTrue(fieldValue == Calendar.AM || fieldValue == Calendar.PM,
"Invalid field value " + fieldValue + " for calendar field AM_PM, in locale "
+ locale + " with style " + style);
}
}
}
}
}

View file

@ -0,0 +1,129 @@
/*
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8331646
* @summary confirm that Calendar.add() works correctly with leap year calculations
* @run junit CalendarLeapYearAddTest
*/
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Locale;
import java.util.stream.Stream;
import static java.util.Calendar.APRIL;
import static java.util.Calendar.DATE;
import static java.util.Calendar.DAY_OF_MONTH;
import static java.util.Calendar.DAY_OF_WEEK;
import static java.util.Calendar.DAY_OF_WEEK_IN_MONTH;
import static java.util.Calendar.DAY_OF_YEAR;
import static java.util.Calendar.FEBRUARY;
import static java.util.Calendar.LONG;
import static java.util.Calendar.MARCH;
import static java.util.Calendar.MONTH;
import static java.util.Calendar.WEEK_OF_YEAR;
import static java.util.Calendar.YEAR;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class CalendarLeapYearAddTest {
/**
* 8331646 Calendar add for leap year
*/
@ParameterizedTest
@MethodSource("calendarAddSource")
public void testAddLeapYear(String testName, int calendarDate, int calendarMonth, int calendarYear,
int value, int calendarField, int expectedDate, int expectedMonth,
int expectedYear) {
Calendar calendar = new GregorianCalendar(calendarYear, calendarMonth, calendarDate);
calendar.add(calendarField, value);
assertEquals(expectedDate, calendar.get(DATE), testName
+ " Expected " + expectedDate + " of " + expectedMonth + expectedYear + " but got " + calendar.getTime());
assertEquals(expectedMonth, calendar.get(MONTH), testName
+ " Expected " + expectedMonth + " but got " + calendar.getDisplayName(MONTH, LONG, Locale.getDefault()));
}
/**
* 8331646 Calendar month and year add/subtract for leap/non-leap year
*/
@Test
public void testMonthYearAddSubtractNonLeapYear() {
Calendar calendar = new GregorianCalendar(2024, FEBRUARY, 29);
calendar.add(MONTH, 1);
calendar.add(YEAR, -1);
calendar.add(MONTH, -1);
/* When month added date jumps to 29th of March 2024, after year subtracted date jumps to 29th of March 2023
after month subtracted date jumps to 28th of Feb 2023 as non leap year
*/
assertEquals(28, calendar.get(DATE),
"testMonthYearAddSubtractNonLeapYear Expected 28th of February 2024 but got " + calendar.getTime());
assertEquals(FEBRUARY, calendar.get(MONTH),
" testMonthYearAddSubtractNonLeapYear Expected February but got " + calendar.getDisplayName(MONTH, LONG, Locale.getDefault()));
}
/**
* 8331646 Calendar add/subtract for leap year
*/
@ParameterizedTest
@MethodSource("calendarAddSubtractSource")
public void testAddSubtractLeapYear(String testName, int calendarDate, int calendarMonth, int calendarYear,
int firstValue, int secondValue, int calendarField, int expectedDate,
int expectedMonth, int expectedYear) {
Calendar calendar = new GregorianCalendar(calendarYear, calendarMonth, calendarDate);
calendar.add(calendarField, firstValue);
calendar.add(calendarField, secondValue);
assertEquals(expectedDate, calendar.get(DATE), testName
+ " Expected " + expectedDate + " of " + expectedMonth + expectedYear + " but got " + calendar.getTime());
assertEquals(expectedMonth, calendar.get(MONTH), testName
+ " Expected " + expectedMonth + " but got " + calendar.getDisplayName(MONTH, LONG, Locale.getDefault()));
}
private static Stream<Arguments> calendarAddSubtractSource() {
return Stream.of(
Arguments.of("testMonthAddSubtractLeapYearReversed", 31, MARCH, 2024, -1, 1, MONTH, 29, MARCH, 2024),
Arguments.of("testMonthAddSubtractLeapYear", 29, FEBRUARY, 2024, 1, -1, MONTH, 29, FEBRUARY, 2024),
Arguments.of("testYearAddSubtractLeapYear", 29, FEBRUARY, 2024, 1, -1, YEAR, 28, FEBRUARY, 2024),
Arguments.of("testDayOfYearAddSubtractLeapYear", 29, FEBRUARY, 2024, 365, -365, DAY_OF_YEAR, 29, FEBRUARY, 2024),
Arguments.of("testDateAddSubtractLeapYear", 29, FEBRUARY, 2024, 365, -365, DATE, 29, FEBRUARY, 2024),
Arguments.of("testWeekOfYearAddSubtractLeapYear", 29, FEBRUARY, 2024, 52, -52, WEEK_OF_YEAR, 29, FEBRUARY, 2024),
Arguments.of("testDayOfMonthAddSubtractLeapYear", 29, FEBRUARY, 2024, 31, -31, DAY_OF_MONTH, 29, FEBRUARY, 2024),
Arguments.of("testDayOfWeekInMonthAddSubtractLeapYear", 29, FEBRUARY, 2024, 6, -6, DAY_OF_WEEK_IN_MONTH, 29, FEBRUARY, 2024),
Arguments.of("testDayOfWeekAddSubtractLeapYear", 29, FEBRUARY, 2024, 6, -6, DAY_OF_WEEK, 29, FEBRUARY, 2024)
);
}
private static Stream<Arguments> calendarAddSource() {
return Stream.of(
Arguments.of("testMonthAddLeapYear", 29, FEBRUARY, 2024, 1, MONTH, 29, MARCH, 2024),
Arguments.of("testOneMonthSubtractLeapYear", 31, MARCH, 2024, -1, MONTH, 29, FEBRUARY, 2024),
Arguments.of("testTwoMonthSubtractLeapYear", 30, APRIL, 2024, -2, MONTH, 29, FEBRUARY, 2024)
);
}
}

View file

@ -0,0 +1,190 @@
/*
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8331851
* @summary confirm that Calendar.roll() works correctly with leap year calculations
* @run junit CalendarLeapYearRollTest
*/
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Locale;
import java.util.stream.Stream;
import static java.util.Calendar.APRIL;
import static java.util.Calendar.DATE;
import static java.util.Calendar.DAY_OF_MONTH;
import static java.util.Calendar.DAY_OF_WEEK;
import static java.util.Calendar.DAY_OF_WEEK_IN_MONTH;
import static java.util.Calendar.DAY_OF_YEAR;
import static java.util.Calendar.FEBRUARY;
import static java.util.Calendar.LONG;
import static java.util.Calendar.MARCH;
import static java.util.Calendar.MONTH;
import static java.util.Calendar.WEEK_OF_YEAR;
import static java.util.Calendar.YEAR;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class CalendarLeapYearRollTest {
/**
* 8331851 Calendar roll for leap year
*/
@ParameterizedTest
@MethodSource("calendarRollSource")
public void testRollLeapYear(String testName, int calendarDate, int calendarMonth, int calendarYear,
int value, int calendarField, int expectedDate, int expectedMonth,
int expectedYear) {
Calendar calendar = new GregorianCalendar(calendarYear, calendarMonth, calendarDate);
calendar.roll(calendarField, value);
assertEquals(expectedDate, calendar.get(DATE), testName
+ " Expected " + expectedDate + " of " + expectedMonth + expectedYear + " but got " + calendar.getTime());
assertEquals(expectedMonth, calendar.get(MONTH), testName
+ " Expected " + expectedMonth + " but got " + calendar.getDisplayName(MONTH, LONG, Locale.getDefault()));
assertEquals(expectedYear, calendar.get(YEAR), testName
+ " Expected " + expectedYear + " but got " + calendar.get(YEAR));
}
/**
* 8331851 Calendar roll up/down for leap year
*/
@ParameterizedTest
@MethodSource("calendarRollUpDownSource")
public void testRollUpDownLeapYear(String testName, int calendarDate, int calendarMonth, int calendarYear,
int firstValue, int secondValue, int calendarField, int expectedDate,
int expectedMonth, int expectedYear) {
Calendar calendar = new GregorianCalendar(calendarYear, calendarMonth, calendarDate);
calendar.roll(calendarField, firstValue);
calendar.roll(calendarField, secondValue);
assertEquals(expectedDate, calendar.get(DATE), testName
+ " Expected " + expectedDate + " of " + expectedMonth + expectedYear + " but got " + calendar.getTime());
assertEquals(expectedMonth, calendar.get(MONTH), testName
+ " Expected " + expectedMonth + " but got " + calendar.getDisplayName(MONTH, LONG, Locale.getDefault()));
assertEquals(expectedYear, calendar.get(YEAR), testName
+ " Expected " + expectedYear + " but got " + calendar.get(YEAR));
}
/**
* 8331851 Calendar roll boolean for leap year
*/
@ParameterizedTest
@MethodSource("calendarBooleanRollSource")
public void testBooleanRollLeapYear(String testName, int calendarDate, int calendarMonth, int calendarYear,
boolean value, int calendarField, int expectedDate,
int expectedMonth, int expectedYear) {
Calendar calendar = new GregorianCalendar(calendarYear, calendarMonth, calendarDate);
calendar.roll(calendarField, value);
assertEquals(expectedDate, calendar.get(DATE), testName
+ " Expected " + expectedDate + " of " + expectedMonth + expectedYear + " but got " + calendar.getTime());
assertEquals(expectedMonth, calendar.get(MONTH), testName
+ " Expected " + expectedMonth + " but got " + calendar.getDisplayName(MONTH, LONG, Locale.getDefault()));
assertEquals(expectedYear, calendar.get(YEAR), testName
+ " Expected " + expectedYear + " but got " + calendar.get(YEAR));
}
/**
* 8331851 Calendar month and year roll for leap/non-leap year
*/
@Test
public void testMonthYearRollUpDownNonLeapYear() {
Calendar calendar = new GregorianCalendar(2024, FEBRUARY, 29);
calendar.roll(MONTH, 1);
calendar.roll(YEAR, -1);
calendar.roll(MONTH, -1);
assertEquals(28, calendar.get(DATE),
"testMonthYearRollUpDownNonLeapYear Expected 28th of February 2024 but got " + calendar.getTime());
assertEquals(FEBRUARY, calendar.get(MONTH),
"testMonthYearRollUpDownNonLeapYear Expected February but got " + calendar.getDisplayName(MONTH, LONG, Locale.getDefault()));
assertEquals(2023, calendar.get(YEAR),
"testMonthYearRollUpDownNonLeapYear Expected 2023 but got " + calendar.get(YEAR));
}
private static Stream<Arguments> calendarRollUpDownSource() {
return Stream.of(
Arguments.of("testMonthRollDownUpLeapYearReversed", 31, MARCH, 2024, -1, 1, MONTH, 29, MARCH, 2024),
Arguments.of("testMonthRollUpDownLeapYearReversed", 29, FEBRUARY, 2024, 1, -1, MONTH, 29, FEBRUARY, 2024),
Arguments.of("testYearRollUpDownLeapYear", 29, FEBRUARY, 2024, 1, -1, YEAR, 1, MARCH, 2024),
Arguments.of("testFourYearRollUpDownLeapYear", 29, FEBRUARY, 2024, 4, -4, YEAR, 29, FEBRUARY, 2024),
Arguments.of("testDayOfYearRollUpDownLeapYear", 29, FEBRUARY, 2024, 365, -365, DAY_OF_YEAR, 29, FEBRUARY, 2024),
Arguments.of("testDateRollUpDownLeapYear", 29, FEBRUARY, 2024, 365, -365, DATE, 29, FEBRUARY, 2024),
Arguments.of("testWeekOfYearRollUpDownLeapYear", 29, FEBRUARY, 2024, 52, -52, WEEK_OF_YEAR, 29, FEBRUARY, 2024),
Arguments.of("testDayOfMonthRollUpDownLeapYear", 29, FEBRUARY, 2024, 31, -31, DAY_OF_MONTH, 29, FEBRUARY, 2024),
Arguments.of("testDayOfWeekInMonthRollUpDownLeapYear", 29, FEBRUARY, 2024, 6, -6, DAY_OF_WEEK_IN_MONTH, 29, FEBRUARY, 2024),
Arguments.of("testDayOfWeekRollUpDownLeapYear", 29, FEBRUARY, 2024, 6, -6, DAY_OF_WEEK, 29, FEBRUARY, 2024)
);
}
private static Stream<Arguments> calendarRollSource() {
return Stream.of(
Arguments.of("testMonthRollUpLeapYear", 29, FEBRUARY, 2024, 1, MONTH, 29, MARCH, 2024),
Arguments.of("testOneMonthRollDownLeapYear", 31, MARCH, 2024, -1, MONTH, 29, FEBRUARY, 2024),
Arguments.of("testTwoMonthDownEndOfMonthLeapYear", 30, APRIL, 2024, -2, MONTH, 29, FEBRUARY, 2024),
Arguments.of("testTwoMonthDownSameDateLeapYear", 29, APRIL, 2024, -2, MONTH, 29, FEBRUARY, 2024),
Arguments.of("testFourYearRollUpLeapYear", 29, FEBRUARY, 2024, 4, YEAR, 29, FEBRUARY, 2028),
Arguments.of("testTwelveMonthRollDownLeapYear", 29, FEBRUARY, 2024, 12, MONTH, 29, FEBRUARY, 2024),
Arguments.of("testYearRollUpLeapYear", 29, FEBRUARY, 2024, 1, YEAR, 1, MARCH, 2025),
Arguments.of("testYearRollDownLeapYear", 29, FEBRUARY, 2024, -1, YEAR, 1, MARCH, 2023),
Arguments.of("testDayOfYearRollDownLeapYear", 29, FEBRUARY, 2024, -1, DAY_OF_YEAR, 28, FEBRUARY, 2024),
Arguments.of("testDayOfYearRollUpLeapYear", 29, FEBRUARY, 2024, 1, DAY_OF_YEAR, 1, MARCH, 2024),
Arguments.of("testDateRollDownLeapYear", 29, FEBRUARY, 2024, -1, DATE, 28, FEBRUARY, 2024),
Arguments.of("testDateRollUpLeapYear", 29, FEBRUARY, 2024, 1, DATE, 1, FEBRUARY, 2024),
Arguments.of("testWeekOfYearRollUpLeapYear", 29, FEBRUARY, 2024, 1, WEEK_OF_YEAR, 7, MARCH, 2024),
Arguments.of("testWeekOfYearRollDownLeapYear", 29, FEBRUARY, 2024, -1, WEEK_OF_YEAR, 22, FEBRUARY, 2024),
Arguments.of("testDayOfMonthRollUpLeapYear", 29, FEBRUARY, 2024, 1, DAY_OF_MONTH, 1, FEBRUARY, 2024),
Arguments.of("testDayOfMonthRollDownLeapYear", 29, FEBRUARY, 2024, -1, DAY_OF_MONTH, 28, FEBRUARY, 2024),
Arguments.of("testDayOfWeekInMonthRollUpLeapYear", 29, FEBRUARY, 2024, 1, DAY_OF_WEEK_IN_MONTH, 1, FEBRUARY, 2024),
Arguments.of("testDayOfWeekInMonthRollDownLeapYear", 29, FEBRUARY, 2024, -1, DAY_OF_WEEK_IN_MONTH, 22, FEBRUARY, 2024),
Arguments.of("testDayOfWeekRollUpLeapYear", 29, FEBRUARY, 2024, 1, DAY_OF_WEEK, 1, MARCH, 2024),
Arguments.of("testDayOfWeekRollDownLeapYear", 29, FEBRUARY, 2024, -1, DAY_OF_WEEK, 28, FEBRUARY, 2024)
);
}
private static Stream<Arguments> calendarBooleanRollSource() {
return Stream.of(
Arguments.of("testBooleanMonthRollDownLeapYear", 31, MARCH, 2024, false, MONTH, 29, FEBRUARY, 2024),
Arguments.of("testBooleanMonthRollUpLeapYear", 29, FEBRUARY, 2024, true, MONTH, 29, MARCH, 2024),
Arguments.of("testBooleanYearRollUpLeapYear", 29, FEBRUARY, 2024, true, YEAR, 1, MARCH, 2025),
Arguments.of("testBooleanYearRollDownLeapYear", 29, FEBRUARY, 2024, false, YEAR, 1, MARCH, 2023),
Arguments.of("testBooleanDayOfYearRollDownLeapYear", 29, FEBRUARY, 2024, false, DAY_OF_YEAR, 28, FEBRUARY, 2024),
Arguments.of("testBooleanDayOfYearRollUpLeapYear", 29, FEBRUARY, 2024, true, DAY_OF_YEAR, 1, MARCH, 2024),
Arguments.of("testBooleanDateRollDownLeapYear", 29, FEBRUARY, 2024, false, DATE, 28, FEBRUARY, 2024),
Arguments.of("testBooleanDateRollUpLeapYear", 29, FEBRUARY, 2024, true, DATE, 1, FEBRUARY, 2024),
Arguments.of("testBooleanWeekOfYearRollUpLeapYear", 29, FEBRUARY, 2024, true, WEEK_OF_YEAR, 7, MARCH, 2024),
Arguments.of("testBooleanWeekOfYearRollDownLeapYear", 29, FEBRUARY, 2024, false, WEEK_OF_YEAR, 22, FEBRUARY, 2024),
Arguments.of("testBooleanDayOfMonthRollUpLeapYear", 29, FEBRUARY, 2024, true, DAY_OF_MONTH, 1, FEBRUARY, 2024),
Arguments.of("testBooleanDayOfMonthRollDownLeapYear", 29, FEBRUARY, 2024, false, DAY_OF_MONTH, 28, FEBRUARY, 2024),
Arguments.of("testBooleanDayOfWeekInMonthRollUpLeapYear", 29, FEBRUARY, 2024, true, DAY_OF_WEEK_IN_MONTH, 1, FEBRUARY, 2024),
Arguments.of("testBooleanDayOfWeekInMonthRollDownLeapYear", 29, FEBRUARY, 2024, false, DAY_OF_WEEK_IN_MONTH, 22, FEBRUARY, 2024),
Arguments.of("testBooleanDayOfWeekRollUpLeapYear", 29, FEBRUARY, 2024, true, DAY_OF_WEEK, 1, MARCH, 2024),
Arguments.of("testBooleanDayOfWeekRollDownLeapYear", 29, FEBRUARY, 2024, false, DAY_OF_WEEK, 28, FEBRUARY, 2024)
);
}
}

View file

@ -0,0 +1,207 @@
/*
* Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @bug 4033662
* @summary test for limit on Calendar
* @library /java/text/testlib
* @run junit CalendarLimitTest
*/
import java.util.*;
import java.text.*;
import org.junit.jupiter.api.Assumptions;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.fail;
/**
* This test verifies the behavior of Calendar around the very earliest limits
* which it can handle. It also verifies the behavior for large values of millis.
*
* Note: There used to be a limit, due to a bug, for early times. There is
* currently no limit.
*
* March 17, 1998: Added code to make sure big + dates are big + AD years, and
* big - dates are big + BC years.
*/
public class CalendarLimitTest
{
// This number determined empirically; this is the old limit,
// which we test for to make sure it isn't there anymore.
static final long EARLIEST_SUPPORTED_MILLIS = -210993120000000L;
static final int EPOCH_JULIAN_DAY = 2440588; // Jaunary 1, 1970 (Gregorian)
static final int JAN_1_1_JULIAN_DAY = 1721426; // January 1, year 1 (Gregorian)
// Useful millisecond constants
static final int ONE_SECOND = 1000;
static final int ONE_MINUTE = 60*ONE_SECOND;
static final int ONE_HOUR = 60*ONE_MINUTE;
static final int ONE_DAY = 24*ONE_HOUR;
static final int ONE_WEEK = 7*ONE_DAY;
static final long ONE_YEAR = (long)(365.2425 * ONE_DAY);
static long ORIGIN; // This is the *approximate* point at which BC switches to AD
/**
* Converts Julian day to time as milliseconds.
* @param julian the given Julian day number.
* @return time as milliseconds.
*/
private static final long julianDayToMillis(long julian) {
return (julian - EPOCH_JULIAN_DAY) * ONE_DAY;
}
/**
* Verify that the given time is processed without problem.
* @return the adjust year, with 0 = 1 BC, -1 = 2 BC, etc.
*/
int test(long millis, Calendar cal, DateFormat fmt)
{
Exception exception = null;
String theDate = "";
try {
Date d= new Date(millis);
cal.setTime(d);
theDate = fmt.format(d);
}
catch (IllegalArgumentException e) {
exception = e;
}
String s = "0x" + Long.toHexString(millis) + " " + theDate;
int era=cal.get(Calendar.ERA), year=cal.get(Calendar.YEAR),
dom=cal.get(Calendar.DATE), mon=cal.get(Calendar.MONTH);
cal.clear();
cal.set(year, mon, dom);
cal.set(Calendar.ERA, era);
Date rt = cal.getTime();
boolean ok = true;
if (exception != null) {
fail("FAIL: Exception " + s);
ok = false;
}
if (((millis >= ORIGIN) && (era != GregorianCalendar.AD)) ||
((millis < ORIGIN) && (era != GregorianCalendar.BC)) ||
(year < 1)) {
fail("FAIL: Bad year/era " + s);
ok = false;
}
if (dom<1 || dom>31) {
fail("FAIL: Bad DOM " + s);
ok = false;
}
if (Math.abs(millis - rt.getTime()) > ONE_DAY) {
fail("FAIL: RT fail " + s + " -> 0x" +
Long.toHexString(rt.getTime()) + " " +
fmt.format(rt));
ok = false;
}
if (ok) System.out.println(s);
if (era==GregorianCalendar.BC) year = 1-year;
return year;
}
@Test
public void TestCalendarLimit()
{
Locale locale = Locale.getDefault();
Assumptions.assumeTrue(TestUtils.usesGregorianCalendar(locale),
locale + " does not use a Gregorian calendar");
ORIGIN = julianDayToMillis(JAN_1_1_JULIAN_DAY);
Calendar cal = Calendar.getInstance();
// You must set the time zone to GMT+0 or the edge cases like
// Long.MIN_VALUE, Long.MAX_VALUE, and right around the threshold
// won't work, since before converting to fields the calendar code
// will add the offset for the zone.
cal.setTimeZone(TimeZone.getTimeZone("Africa/Casablanca"));
DateFormat dateFormat = DateFormat.getDateInstance();
dateFormat.setCalendar(cal); // Make sure you do this -- same reason as above
((SimpleDateFormat)dateFormat).applyPattern("MMM d, yyyy G");
// Don't expect any failure for positive longs
int lastYear=0;
boolean first=true;
for (long m = Long.MAX_VALUE; m > 0; m >>= 1)
{
int y = test(m, cal, dateFormat);
if (!first && y > lastYear)
fail("FAIL: Years should be decreasing " + lastYear + " " + y);
first = false;
lastYear = y;
}
// Expect failures for negative millis below threshold
first = true;
for (long m = Long.MIN_VALUE; m < 0; m /= 2) // Don't use m >>= 1
{
int y = test(m, cal, dateFormat);
if (!first && y < lastYear)
fail("FAIL: Years should be increasing " + lastYear + " " + y);
first = false;
lastYear = y;
}
// Test right around the threshold
test(EARLIEST_SUPPORTED_MILLIS, cal, dateFormat);
test(EARLIEST_SUPPORTED_MILLIS-1, cal, dateFormat);
// Test a date that should work
test(Long.MIN_VALUE + ONE_DAY, cal, dateFormat);
// Try hours in the earliest day or two
// JUST FOR DEBUGGING:
if (false) {
((SimpleDateFormat)dateFormat).applyPattern("H:mm MMM d, yyyy G");
for (int dom=2; dom<=3; ++dom) {
for (int h=0; h<24; ++h) {
cal.clear();
cal.set(Calendar.ERA, GregorianCalendar.BC);
cal.set(292269055, Calendar.DECEMBER, dom, h, 0);
Date d = cal.getTime();
cal.setTime(d);
System.out.println("" + h + ":00 Dec "+dom+", 292269055 BC -> " +
Long.toHexString(d.getTime()) + " -> " +
dateFormat.format(cal.getTime()));
}
}
// Other way
long t = 0x80000000018c5c00L; // Dec 3, 292269055 BC
while (t<0) {
cal.setTime(new Date(t));
System.out.println("0x" + Long.toHexString(t) + " -> " +
dateFormat.format(cal.getTime()));
t -= ONE_HOUR;
}
}
}
}
//eof

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,437 @@
/*
* Copyright (c) 2007, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.util.Calendar;
import sun.util.calendar.CalendarUtils;
public class CalendarAdapter extends Calendar {
public static enum Type {
GREGORIAN, BUDDHIST, JAPANESE;
}
static final String[] FIELD_NAMES = {
"ERA", "YEAR", "MONTH", "WEEK_OF_YEAR", "WEEK_OF_MONTH", "DAY_OF_MONTH",
"DAY_OF_YEAR", "DAY_OF_WEEK", "DAY_OF_WEEK_IN_MONTH", "AM_PM", "HOUR",
"HOUR_OF_DAY", "MINUTE", "SECOND", "MILLISECOND", "ZONE_OFFSET",
"DST_OFFSET"
};
Calendar cal;
GregorianAdapter gcal;
private Type type;
public CalendarAdapter(Calendar cal) {
if (cal == null)
throw new NullPointerException();
this.cal = cal;
if (cal instanceof sun.util.BuddhistCalendar) {
type = Type.BUDDHIST;
} else if (cal instanceof GregorianAdapter) {
type = Type.GREGORIAN;
gcal = (GregorianAdapter) cal;
} else {
type = Type.JAPANESE;
}
}
public void setFirstDayOfWeek(int w) {
cal.setFirstDayOfWeek(w);
}
public int getFirstDayOfWeek() {
return cal.getFirstDayOfWeek();
}
public void setMinimalDaysInFirstWeek(int value) {
cal.setMinimalDaysInFirstWeek(value);
}
public int getMinimalDaysInFirstWeek() {
return getMinimalDaysInFirstWeek();
}
public long getTimeInMillis() {
return cal.getTimeInMillis();
}
public void setTimeInMillis(long millis) {
cal.setTimeInMillis(millis);
}
public int get(int field) {
return cal.get(field);
}
public void set(int field, int value) {
cal.set(field, value);
}
public void add(int field, int amount) {
cal.add(field, amount);
}
public void roll(int field, boolean dir) {
cal.roll(field, dir);
}
public void roll(int field, int amount) {
cal.roll(field, amount);
}
public void setDate(int year, int month, int date)
{
cal.set(year, month, date);
}
public void setDate(int era, int year, int month, int date) {
cal.set(ERA, era);
cal.set(year, month, date);
}
public void setDateTime(int year, int month, int date, int hourOfDay, int minute, int second)
{
cal.set(year, month, date, hourOfDay, minute, second);
}
public void clearAll() {
cal.clear();
}
public void clearField(int field)
{
cal.clear(field);
}
public boolean isSetField(int field)
{
return cal.isSet(field);
}
public int getMaximum(int field) {
return cal.getMaximum(field);
}
public int getLeastMaximum(int field) {
return cal.getLeastMaximum(field);
}
public int getActualMaximum(int field) {
return cal.getActualMaximum(field);
}
public int getMinimum(int field) {
return cal.getMinimum(field);
}
public int getGreatestMinimum(int field) {
return cal.getGreatestMinimum(field);
}
public int getActualMinimum(int field) {
return cal.getActualMinimum(field);
}
public void setLenient(boolean lenient) {
cal.setLenient(lenient);
}
public String toString() {
return cal.toString();
}
protected void computeFields() {
}
protected void computeTime() {
}
void setTimeOfDay(int hourOfDay, int minute, int second, int ms) {
cal.set(HOUR_OF_DAY, hourOfDay);
cal.set(MINUTE, minute);
cal.set(SECOND, second);
cal.set(MILLISECOND, ms);
}
// GregorianAdapter specific methods
// When gcal is null, the methods throw a NPE.
int getSetStateFields() {
return gcal.getSetStateFields();
}
int[] getFields() {
return gcal.getFields();
}
boolean checkInternalDate(int year, int month, int dayOfMonth) {
return gcal.checkInternalDate(year, month, dayOfMonth);
}
boolean checkInternalDate(int year, int month, int dayOfMonth, int dayOfWeek) {
return gcal.checkInternalDate(year, month, dayOfMonth, dayOfWeek);
}
boolean checkInternalField(int field, int expectedValue) {
return checkInternalField(field, expectedValue);
}
// check methods
boolean checkAllSet() {
initTest();
for (int i = 0; i < FIELD_COUNT; i++) {
checkFieldState(i, true);
}
return getStatus();
}
boolean checkMaximum(int field, int expectedValue) {
int val;
if ((val = getMaximum(field)) != expectedValue) {
appendMessage("getMaximum("+FIELD_NAMES[field]+"): got " + val
+ " expected " + expectedValue);
}
return getStatus();
}
boolean checkActualMaximum(int field, int expectedValue) {
int val;
if ((val = getActualMaximum(field)) != expectedValue) {
appendMessage("getActualMaximum("+FIELD_NAMES[field]+"): got " + val
+ " expected " + expectedValue);
}
return getStatus();
}
boolean checkLeastMaximum(int field, int expectedValue) {
int val;
if ((val = getLeastMaximum(field)) != expectedValue) {
appendMessage("getLeastMaximum("+FIELD_NAMES[field]+"): got " + val
+ " expected " + expectedValue);
}
return getStatus();
}
boolean checkMinimum(int field, int expectedValue) {
int val;
if ((val = getMinimum(field)) != expectedValue) {
appendMessage("getMinimum("+FIELD_NAMES[field]+"): got " + val
+ " expected " + expectedValue);
}
return getStatus();
}
boolean checkActualMinimum(int field, int expectedValue) {
int val;
if ((val = getActualMinimum(field)) != expectedValue) {
appendMessage("getActualMinimum("+FIELD_NAMES[field]+"): got " + val
+ " expected " + expectedValue);
}
return getStatus();
}
boolean checkGreatestMinimum(int field, int expectedValue) {
int val;
if ((val = getGreatestMinimum(field)) != expectedValue) {
appendMessage("getGreatestMinimum("+FIELD_NAMES[field]+"): got " + val
+ " expected " + expectedValue);
}
return getStatus();
}
boolean checkDate(int year, int month, int dayOfMonth) {
initTest();
checkField(YEAR, year);
checkField(MONTH, month);
checkField(DAY_OF_MONTH, dayOfMonth);
return getStatus();
}
boolean checkDate(int era, int year, int month, int dayOfMonth) {
initTest();
checkField(ERA, era);
checkField(YEAR, year);
checkField(MONTH, month);
checkField(DAY_OF_MONTH, dayOfMonth);
return getStatus();
}
boolean checkDateTime(int year, int month, int dayOfMonth,
int hourOfDay, int minute, int second) {
initTest();
checkField(YEAR, year);
checkField(MONTH, month);
checkField(DAY_OF_MONTH, dayOfMonth);
checkField(HOUR_OF_DAY, hourOfDay);
checkField(MINUTE, minute);
checkField(SECOND, second);
return getStatus();
}
boolean checkDateTime(int year, int month, int dayOfMonth,
int hourOfDay, int minute, int second, int ms) {
initTest();
checkField(YEAR, year);
checkField(MONTH, month);
checkField(DAY_OF_MONTH, dayOfMonth);
checkField(HOUR_OF_DAY, hourOfDay);
checkField(MINUTE, minute);
checkField(SECOND, second);
checkField(MILLISECOND, ms);
return getStatus();
}
boolean checkTimeOfDay(int hourOfDay, int minute, int second, int ms) {
initTest();
checkField(HOUR_OF_DAY, hourOfDay);
checkField(MINUTE, minute);
checkField(SECOND, second);
checkField(MILLISECOND, ms);
return getStatus();
}
boolean checkMillis(long millis) {
initTest();
long t = cal.getTimeInMillis();
if (t != millis) {
appendMessage("wrong millis: got " + t + ", expected " + millis);
return false;
}
return true;
}
boolean checkFieldState(int field, boolean expectedState) {
if (isSet(field) != expectedState) {
appendMessage(FIELD_NAMES[field] + " state is not " + expectedState + "; ");
return false;
}
return true;
}
boolean checkField(int field, int expectedValue) {
int val;
if ((val = get(field)) != expectedValue) {
appendMessage("get(" + FIELD_NAMES[field] + "): got " + val +
", expected " + expectedValue + "; ");
return false;
}
return true;
}
static final String fieldName(int field) {
return FIELD_NAMES[field];
}
String toDateString() {
StringBuffer sb = new StringBuffer();
String[] eraNames = null;
switch (type) {
case GREGORIAN:
eraNames = new String[] { "BCE", "" };
break;
case BUDDHIST:
eraNames = new String[] { "Before BE", "BE"};
break;
case JAPANESE:
eraNames = new String[] {
"BeforeMeiji",
"Meiji",
"Taisho",
"Showa",
"Heisei",
"Reiwa"
};
break;
}
sb.append(eraNames[cal.get(ERA)]);
if (sb.length() > 0)
sb.append(' ');
CalendarUtils.sprintf0d(sb, cal.get(YEAR), 4).append('-');
CalendarUtils.sprintf0d(sb, cal.get(MONTH)+1, 2).append('-');
CalendarUtils.sprintf0d(sb, cal.get(DAY_OF_MONTH), 2);
return sb.toString();
}
String toTimeString() {
StringBuffer sb = new StringBuffer();
CalendarUtils.sprintf0d(sb, cal.get(HOUR_OF_DAY), 2).append(':');
CalendarUtils.sprintf0d(sb, cal.get(MINUTE), 2).append(':');
CalendarUtils.sprintf0d(sb, cal.get(SECOND),2 ).append('.');
CalendarUtils.sprintf0d(sb, cal.get(MILLISECOND), 3);
int zoneOffset = cal.get(ZONE_OFFSET) + cal.get(DST_OFFSET);
if (zoneOffset == 0) {
sb.append('Z');
} else {
int offset;
char sign;
if (zoneOffset > 0) {
offset = zoneOffset;
sign = '+';
} else {
offset = -zoneOffset;
sign = '-';
}
offset /= 60000;
sb.append(sign);
CalendarUtils.sprintf0d(sb, offset / 60, 2);
CalendarUtils.sprintf0d(sb, offset % 60, 2);
}
return sb.toString();
}
String toDateTimeString() {
return toDateString() + "T" + toTimeString();
}
// Message handling
StringBuffer msg = new StringBuffer();
private void initTest() {
msg = new StringBuffer();
}
String getMessage() {
String s = msg.toString();
msg = new StringBuffer();
return " " + s;
}
private void setMessage(String msg) {
this.msg = new StringBuffer(msg);
}
private void appendMessage(String msg) {
this.msg.append(msg);
}
boolean getStatus() {
return msg.length() == 0;
}
}

View file

@ -0,0 +1,782 @@
/*
* Copyright (c) 2007, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.*;
public class CalendarTestEngine {
private static File file;
private static BufferedReader in;
private static int testCount;
private static int lineno;
private static Locale locale;
private static TimeZone timezone;
private static boolean leniency = true;
public static void main(String[] args) throws Exception {
Locale loc = Locale.getDefault();
TimeZone tz = TimeZone.getDefault();
locale = loc;
timezone = tz;
try {
for (String arg : args) {
file = new File(arg);
FileInputStream fis = new FileInputStream(file);
System.out.println("Starting " + file.getName() + "...");
in = new BufferedReader(new InputStreamReader(fis));
testCount = lineno = 0;
run();
System.out.println("Completed " + file.getName());
}
} finally {
Locale.setDefault(loc);
TimeZone.setDefault(tz);
}
}
private static void run() throws Exception {
String line;
int section = 0;
Map<String, CalendarAdapter> cals = new HashMap<String, CalendarAdapter>();
CalendarAdapter calendar = null;
Result result = new Result();
while ((line = in.readLine()) != null) {
lineno++;
line = line.trim();
// Skip blank and comment lines
if (line.length() == 0 || line.charAt(0) == '#') {
continue;
}
int comment = line.indexOf('#');
if (comment != -1) {
line = line.substring(0, comment).trim();
}
Scanner sc = new Scanner(line);
String token = sc.next();
Symbol operation = symbol(token);
if (operation == null) {
throw new RuntimeException(lineno() + "wrong op? " + token);
}
if (operation.type == Symbol.Type.EXCEPTION) {
String className = sc.next();
Class clazz = Exceptions.get(className);
Exception e = result.getException();
if (!clazz.isInstance(e)) {
throw new RuntimeException(lineno() + "unexpected exception: got: " + e
+ ", expected=" + clazz);
}
}
Exception x = result.getException();
if (x != null) {
throw new RuntimeException(lineno(result.getLineno()) + "Unexpected exception", x);
}
try {
switch (operation.type) {
case LOCALE:
{
String lang = sc.next();
String country = "", var = "";
if (sc.hasNext()) {
country = sc.next();
if (sc.hasNext()) {
var = sc.next();
}
}
locale = Locale.of(lang, country, var);
}
break;
case TIMEZONE:
{
if (sc.hasNext()) {
String id = sc.next();
timezone = TimeZone.getTimeZone(id);
if (!timezone.getID().equals(id)) {
System.err.printf("Warning: line %d: may get wrong time zone? "
+"(specified: %s vs. actual: %s)%n",
lineno, id, timezone.getID());
}
}
}
break;
case NEW:
{
Symbol op = symbol(sc.next());
Calendar cal = null;
switch (op.type) {
case INSTANCE:
cal = Calendar.getInstance(timezone, locale);
break;
case GREGORIAN:
cal = new GregorianAdapter(timezone, locale);
break;
default:
symbolError(op);
break;
}
cal.setLenient(leniency);
calendar = new CalendarAdapter(cal);
if (sc.hasNext()) {
String name = sc.next();
cals.put(name.toLowerCase(Locale.ROOT), calendar);
if (!leniency) {
System.out.printf("%s%s is non-lenient%n", lineno(), name);
}
} else {
throw new RuntimeException(lineno() + "Missing associated name");
}
}
break;
case TEST:
testCount++;
if (sc.hasNext()) {
System.out.printf("Test#%d:%s%n", testCount, sc.findInLine(".+"));
} else {
System.out.printf("Test#%d:%n", testCount);
}
break;
case USE:
{
String name = sc.next().toLowerCase(Locale.ROOT);
CalendarAdapter c = cals.get(name);
if (c == null) {
throw new CalendarTestException(lineno() + "calendar " + name
+ " not found.");
}
calendar = c;
}
break;
case ASSIGN:
{
long v = getLong(sc);
String to = sc.next().toLowerCase(Locale.ROOT);
boolean assign = true;
if (sc.hasNext()) {
Symbol condition = symbol(sc.next());
if (condition.type == Symbol.Type.IF) {
long v1 = getLong(sc);
Symbol op = symbol(sc.next());
long v2 = getLong(sc);
assign = relation(v1, op, v2);
} else {
symbolError(condition);
}
}
if (assign)
Variable.newVar(to, v);
}
break;
case EVAL:
{
long v1 = getLong(sc);
String op = sc.next();
Symbol operator = symbol(op);
if (operator == null) {
throw new RuntimeException("op " + op + " invalid");
}
long v2 = getLong(sc);
if (operator.isArithmetic()) {
long value = 0;
switch (operator.type) {
case PLUS:
value = v1 + v2;
break;
case MINUS:
value = v1 - v2;
break;
case MULTIPLY:
value = v1 * v2;
break;
case DIVIDE:
value = v1 / v2;
break;
case MOD:
value = v1 % v2;
break;
default:
symbolError(operator);
break;
}
result.setValue(value);
} else {
if (!relation(v1, operator, v2)) {
throw new RuntimeException("not " + v1 + " " + op + " " + v2);
}
}
}
break;
case CLEAR:
{
Symbol sym = symbol(sc.next());
if (sym.type == Symbol.Type.ALL) {
calendar.clearAll();
} else if (sym.type == Symbol.Type.FIELD) {
int f = sym.value();
calendar.clearField(f);
} else {
symbolError(sym);
}
}
break;
case GET:
{
Symbol sym = symbol(sc.next());
switch (sym.type) {
case FIELD:
{
int f = sym.value();
int v = calendar.get(f);
result.setValue(v);
}
break;
case MILLIS:
{
long v = calendar.getTimeInMillis();
result.setValue(v);
}
break;
case MINIMUM:
{
int f = getInt(sc);
int v = calendar.getMinimum(f);
result.setValue(v);
}
break;
case GREATESTMINIMUM:
{
int f = getInt(sc);
int v = calendar.getGreatestMinimum(f);
result.setValue(v);
}
break;
case ACTUALMINIMUM:
{
int f = getInt(sc);
int v = calendar.getActualMinimum(f);
result.setValue(v);
}
break;
case MAXIMUM:
{
int f = getInt(sc);
int v = calendar.getMaximum(f);
result.setValue(v);
}
break;
case LEASTMAXIMUM:
{
int f = getInt(sc);
int v = calendar.getLeastMaximum(f);
result.setValue(v);
}
break;
case ACTUALMAXIMUM:
{
int f = getInt(sc);
int v = calendar.getActualMaximum(f);
result.setValue(v);
}
break;
case FIRSTDAYOFWEEK:
{
result.setValue(calendar.getFirstDayOfWeek());
}
break;
case MINIMALDAYSINFIRSTWEEK:
{
int v = calendar.getMinimalDaysInFirstWeek();
result.setValue(v);
}
break;
default:
symbolError(sym);
break;
}
}
break;
case ADD:
case ROLL:
{
Symbol sym = symbol(sc.next());
if (sym.type == Symbol.Type.FIELD) {
int f = sym.value();
int v = sc.nextInt();
switch (operation.type) {
case ADD:
calendar.add(f, v);
break;
case ROLL:
calendar.roll(f, v);
break;
}
} else {
symbolError(sym);
}
}
break;
case SET:
{
Symbol sym = symbol(sc.next());
switch (sym.type) {
case FIELD:
{
int f = sym.value();
int v = getInt(sc);
calendar.set(f, v);
}
break;
case MILLIS:
{
long v = getLong(sc);
calendar.setTimeInMillis(v);
}
break;
case DATE:
{
int a = getInt(sc);
int b = getInt(sc);
int c = getInt(sc);
if (sc.hasNext()) {
int d = getInt(sc);
// era, year, month, dayOfMonth
calendar.setDate(a, b, c, d);
} else {
// year, month, dayOfMonth
calendar.setDate(a, b, c);
}
}
break;
case DATETIME:
{
int y = getInt(sc);
int m = getInt(sc);
int d = getInt(sc);
int hh = getInt(sc);
int mm = getInt(sc);
int ss = getInt(sc);
calendar.setDateTime(y, m, d, hh, mm, ss);
}
break;
case TIMEOFDAY:
{
int hh = getInt(sc);
int mm = getInt(sc);
int ss = getInt(sc);
int ms = getInt(sc);
calendar.setTimeOfDay(hh, mm, ss, ms);
}
break;
case FIRSTDAYOFWEEK:
{
int v = getInt(sc);
calendar.setFirstDayOfWeek(v);
}
break;
case MINIMALDAYSINFIRSTWEEK:
{
int v = getInt(sc);
calendar.setMinimalDaysInFirstWeek(v);
}
break;
case LENIENT:
if (calendar != null) {
calendar.setLenient(true);
}
leniency = true;
break;
case NONLENIENT:
if (calendar != null) {
calendar.setLenient(false);
}
leniency = false;
break;
default:
symbolError(sym);
}
if (sc.hasNext()) {
throw new RuntimeException(lineno() + "extra param(s) "
+ sc.findInLine(".+"));
}
}
break;
case CHECK:
{
Symbol sym = symbol(sc.next());
boolean stat = false;
switch (sym.type) {
case MILLIS:
{
long millis = getLong(sc);
stat = calendar.checkMillis(millis);
}
break;
case FIELD:
{
int f = sym.value();
int v = getInt(sc);
stat = calendar.checkField(f, v);
}
break;
case DATE:
{
int a = getInt(sc);
int b = getInt(sc);
int c = getInt(sc);
if (sc.hasNext()) {
int d = getInt(sc);
// era year month dayOfMonth
stat = calendar.checkDate(a, b, c, d);
} else {
// year month dayOfMonth
stat = calendar.checkDate(a, b, c);
}
}
break;
case DATETIME:
{
int y = getInt(sc);
int m = getInt(sc);
int d = getInt(sc);
int hh = getInt(sc);
int mm = getInt(sc);
int ss = getInt(sc);
if (sc.hasNext()) {
int ms = getInt(sc);
stat = calendar.checkDateTime(y, m, d, hh, mm, ss, ms);
} else {
stat = calendar.checkDateTime(y, m, d, hh, mm, ss);
}
}
break;
case TIMEOFDAY:
{
int hh = sc.nextInt();
int mm = sc.nextInt();
int ss = sc.nextInt();
int millis = sc.nextInt();
stat = calendar.checkTimeOfDay(hh, mm, ss, millis);
}
break;
case MINIMUM:
{
int f = getInt(sc);
int v = getInt(sc);
stat = calendar.checkMinimum(f, v);
}
break;
case GREATESTMINIMUM:
{
int f = getInt(sc);
int v = getInt(sc);
stat = calendar.checkGreatestMinimum(f, v);
}
break;
case ACTUALMINIMUM:
{
int f = getInt(sc);
int v = getInt(sc);
stat = calendar.checkActualMinimum(f, v);
}
break;
case MAXIMUM:
{
int f = getInt(sc);
int v = getInt(sc);
stat = calendar.checkMaximum(f, v);
}
break;
case LEASTMAXIMUM:
{
int f = getInt(sc);
int v = getInt(sc);
stat = calendar.checkLeastMaximum(f, v);
}
break;
case ACTUALMAXIMUM:
{
int f = getInt(sc);
int v = getInt(sc);
stat = calendar.checkActualMaximum(f, v);
}
break;
default:
throw new RuntimeException(lineno() + "Unknown operand");
}
if (!stat) {
throw new RuntimeException(lineno() + calendar.getMessage());
}
}
break;
case PRINT:
{
String s = sc.next();
if (s.charAt(0) == '$') {
Variable var = variable(s);
if (var == null)
throw new RuntimeException(lineno() + "Unknown token: " + s);
System.out.printf("%s%s=%d%n", lineno(), s, var.longValue());
break;
}
Symbol sym = symbol(s);
switch (sym.type) {
case INSTANCE:
{
Calendar cal = calendar;
String name = "current";
if (sc.hasNext()) {
name = sc.next();
cal = cals.get(name.toLowerCase(Locale.ROOT));
}
System.out.printf("%s%s=%s%n", lineno(), name, cal);
}
break;
case FIELD:
{
int f = sym.value();
String remark = "";
if (sc.hasNext()) {
remark = sc.findInLine(".+");
}
System.out.printf("%s%s=%d %s%n", lineno(), calendar.fieldName(f),
calendar.get(f), remark);
}
break;
case MILLIS:
{
String remark = "";
if (sc.hasNext()) {
remark = sc.findInLine(".+");
}
System.out.printf("%sMillis=%d %s%n", lineno(),
calendar.getTimeInMillis(), remark);
}
break;
case MINIMUM:
System.out.printf("%s%s=%d%n", lineno(),
s, calendar.getMinimum(getInt(sc)));
break;
case GREATESTMINIMUM:
System.out.printf("%s%s=%d%n", lineno(),
s, calendar.getGreatestMinimum(getInt(sc)));
break;
case ACTUALMINIMUM:
System.out.printf("%s%s=%d%n", lineno(),
s, calendar.getActualMinimum(getInt(sc)));
break;
case MAXIMUM:
System.out.printf("%s%s=%d%n", lineno(),
s, calendar.getMaximum(getInt(sc)));
break;
case LEASTMAXIMUM:
System.out.printf("%s%s=%d%n", lineno(),
s, calendar.getLeastMaximum(getInt(sc)));
break;
case ACTUALMAXIMUM:
System.out.printf("%s%s=%d%n", lineno(),
s, calendar.getActualMaximum(getInt(sc)));
break;
case DATE:
System.out.println(lineno() + calendar.toDateString());
break;
case DATETIME:
System.out.println(lineno() + calendar.toDateTimeString());
break;
case TIMEZONE:
System.out.println(lineno() + "timezone=" + timezone);
break;
case LOCALE:
System.out.println(lineno() + "locale=" + locale);
break;
}
}
}
} catch (CalendarTestException cte) {
throw cte;
} catch (NoSuchElementException nsee) {
throw new NoSuchElementException(lineno() + "syntax error");
} catch (Exception e) {
result.setException(e);
result.setLineno(lineno);
}
}
Exception x = result.getException();
if (x != null) {
throw new RuntimeException(lineno(result.getLineno()) + "Unexpected exception", x);
}
}
private static Symbol symbol(String s) {
return Symbol.get(s.toLowerCase(Locale.ROOT));
}
private static Variable variable(String s) {
return Variable.get(s.toLowerCase(Locale.ROOT));
}
private static int getInt(Scanner sc) {
if (sc.hasNextInt()) {
return sc.nextInt();
}
String s = sc.next();
if (s.charAt(0) == '$') {
Variable var = variable(s);
if (var == null)
throw new RuntimeException(lineno() + "Unknown token: " + s);
return var.intValue();
}
Symbol sym = symbol(s);
if (sym == null)
throw new RuntimeException(lineno() + "Unknown token: " + s);
return sym.value();
}
private static long getLong(Scanner sc) {
if (sc.hasNextLong()) {
return sc.nextLong();
}
String s = sc.next();
if (s.charAt(0) == '$') {
Variable var = variable(s);
if (var == null)
throw new RuntimeException(lineno() + "Unknown token: " + s);
return var.longValue();
}
Symbol sym = symbol(s);
if (sym == null)
throw new RuntimeException(lineno() + "Unknown token: " + s);
return sym.value();
}
private static boolean relation(long v1, Symbol relop, long v2) {
boolean result = false;
switch (relop.type) {
case GT:
result = v1 > v2;
break;
case GE:
result = v1 >= v2;
break;
case EQ:
result = v1 == v2;
break;
case NEQ:
result = v1 != v2;
break;
case LE:
result = v1 <= v2;
break;
case LT:
result = v1 < v2;
break;
}
return result;
}
private static String lineno() {
return lineno(lineno);
}
private static String lineno(int ln) {
return file.getName() + ":" + ln + ": ";
}
private static void symbolError(Symbol sym) {
throw new RuntimeException(lineno + ": unexpected symbol: " + sym);
}
}

View file

@ -0,0 +1,36 @@
/*
* Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
public class CalendarTestException extends RuntimeException {
public CalendarTestException() {
super();
}
public CalendarTestException(String msg) {
super(msg);
}
public CalendarTestException(String msg, Throwable t) {
super(msg, t);
}
}

View file

@ -0,0 +1,46 @@
/*
* Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
public class Exceptions {
private static Map<String, Class> exceptions = new HashMap<String, Class>();
static {
put("nullpointerexception", NullPointerException.class);
put("illegalargumentexception", IllegalArgumentException.class);
}
private static void put(String key, Class clazz) {
Class c = exceptions.put(key, clazz);
if (c != null) {
throw new RuntimeException(key + " already exisits");
}
}
public static Class get(String key) {
return exceptions.get(key.toLowerCase(Locale.ROOT));
}
}

View file

@ -0,0 +1,125 @@
/*
* Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.util.GregorianCalendar;
import java.util.Locale;
import java.util.TimeZone;
public class GregorianAdapter extends GregorianCalendar {
static final int ALL_FIELDS = (1 << FIELD_COUNT) - 1;
public GregorianAdapter() {
super();
}
public GregorianAdapter(TimeZone tz) {
super(tz);
}
public GregorianAdapter(Locale loc) {
super(loc);
}
public GregorianAdapter(TimeZone tz, Locale loc) {
super(tz, loc);
}
public void computeTime() {
super.computeTime();
}
public void computeFields() {
super.computeFields();
}
public void complete() {
super.complete();
}
StringBuffer msg = new StringBuffer();
void initTest() {
msg = new StringBuffer();
}
String getMessage() {
String s = msg.toString();
msg = new StringBuffer();
return " " + s;
}
void setMessage(String msg) {
this.msg = new StringBuffer(msg);
}
void appendMessage(String msg) {
this.msg.append(msg);
}
boolean getStatus() {
return msg.length() == 0;
}
int getSetStateFields() {
int mask = 0;
for (int i = 0; i < FIELD_COUNT; i++) {
if (isSet(i)) {
mask |= 1 << i;
}
}
return mask;
}
int[] getFields() {
int[] fds = new int[fields.length];
System.arraycopy(fields, 0, fds, 0, fds.length);
return fds;
}
boolean checkInternalDate(int year, int month, int dayOfMonth) {
initTest();
checkInternalField(YEAR, year);
checkInternalField(MONTH, month);
checkInternalField(DAY_OF_MONTH, dayOfMonth);
return getStatus();
}
boolean checkInternalDate(int year, int month, int dayOfMonth, int dayOfWeek) {
initTest();
checkInternalField(YEAR, year);
checkInternalField(MONTH, month);
checkInternalField(DAY_OF_MONTH, dayOfMonth);
checkInternalField(DAY_OF_WEEK, dayOfWeek);
return getStatus();
}
boolean checkInternalField(int field, int expectedValue) {
int val;
if ((val = internalGet(field)) != expectedValue) {
appendMessage("internalGet(" + CalendarAdapter.FIELD_NAMES[field] + "): got " + val +
", expected " + expectedValue + "; ");
return false;
}
return true;
}
}

View file

@ -0,0 +1,131 @@
/*
* Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.io.PrintWriter;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.GregorianCalendar;
import java.util.Locale;
import static java.util.Calendar.*;
public class JapaneseRollDayOfWeekTestGenerator {
private static final String[] ERAS = {
"BeforeMeiji", "Meiji", "Taisho", "Showa", "Heisei"
};
private static final String[] DAYOFWEEK = {
null, "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
};
private static final int[] DAYOFMONTH = {
25, 26, 27, 28, 29, 30, 31,
1, 2, 3, 4, 5, 6, 7
};
private static final int DOM_BASE = 7;
//Usage: JapaneseRollDayOfWeekTestGenerator will generate test script into
// file rolldow.cts.
public static void generateTestScript(String[] args) throws Exception{
Locale.setDefault(Locale.ROOT);
//This test generator assumes that Heisei has (nYears - 1) or more years.
int nYears = (args.length == 1) ?
Math.max(3, Math.min(Integer.parseInt(args[0]), 40)) : 28;
// Start from Showa 63
int era = 3;
int year = 63;
Path testPath = Paths.get(System.getProperty("test.classes"));
String scFileName = testPath + "/rolldow.cts";
try (PrintWriter out = new PrintWriter(scFileName)){
out.println("locale ja JP JP\n" + "new instance jcal\n" + "use jcal");
for (int y = 0; y < nYears; y++) {
out.printf("\nTest %s %d\n", ERAS[era], year);
for (int fdw = SUNDAY; fdw <= SATURDAY; fdw++) {
int endFdw = fdw + 6;
if (endFdw > SATURDAY) {
endFdw -= 7;
}
for (int mdifw = 1; mdifw <= 7; mdifw++) {
int domIndex = DOM_BASE;
out.println(" clear all");
out.printf(" set FirstDayOfWeek %s\n", DAYOFWEEK[fdw]);
out.printf(" set MinimalDaysInFirstWeek %d\n", mdifw);
out.printf(" set date %s %d Jan 1\n", ERAS[era], year);
out.println(" get week_of_year\n" + " assign $result $woy");
out.println(" get day_of_week\n" + " assign $result $doy");
int gyear = year + (year >= 60 ? 1925 : 1988);
int next = new GregorianCalendar(gyear, JANUARY, 1).get(DAY_OF_WEEK);
for (int i = 0; i < 10; i++) {
out.println(" roll day_of_week 1");
next = nextFdw(next, fdw, endFdw);
if (next == fdw) {
domIndex -= 6;
} else {
domIndex++;
}
int dom = DAYOFMONTH[domIndex];
out.printf("\tcheck date %d %s %d%n", (dom >= 25) ? year - 1 : year,
(dom >= 25) ? "Dec" : "Jan", dom);
out.println("\teval $doy + 1");
out.println("\tassign $result $doy");
out.println("\tassign Sun $doy if $doy > Sat");
out.println("\tcheck day_of_week $doy");
out.println("\tcheck week_of_year $woy");
}
for (int i = 0; i < 10; i++) {
out.println("\troll day_of_week -1");
out.println("\teval $doy - 1");
out.println("\tassign $result $doy");
out.println("\tassign Sat $doy if $doy < Sun");
out.println("\tcheck day_of_week $doy");
out.println("\tcheck week_of_year $woy");
}
}
}
if (year == 64 && era == 3) {
era++;
year = 2;
} else {
year++;
}
}
}
}
private static int nextFdw(int x, int start, int end) {
if (x == end)
return start;
x++;
if (x > SATURDAY)
x = SUNDAY;
return x;
}
}

View file

@ -0,0 +1,88 @@
/*
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @summary tests Japanese Calendar.
* @bug 4609228
* @modules java.base/sun.util
* java.base/sun.util.calendar
* @compile
* CalendarAdapter.java
* CalendarTestEngine.java
* CalendarTestException.java
* Exceptions.java
* GregorianAdapter.java
* Result.java
* Symbol.java
* Variable.java
* JapaneseRollDayOfWeekTestGenerator.java
* @run main/timeout=120/othervm JapaneseRollTests
*/
import java.io.File;
import java.io.FilenameFilter;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class JapaneseRollTests {
private static List<String> TZ_TEST_LIST = Arrays.asList(
"tz_japan.cts", "tz_pst.cts");
private static Path srcPath = Paths.get(System.getProperty("test.src"));
private static Path testPath = Paths.get(System.getProperty("test.classes"));
public static void main(String[] args) throws Throwable {
List<String> modeList = getFileNameList("params");
//Test only 3 years by default
String[] jpyear ={"3"};
JapaneseRollDayOfWeekTestGenerator.generateTestScript(jpyear);
for (String tz : TZ_TEST_LIST) {
for(String mode:modeList){
String[] ts = { srcPath + "/timezones/" + tz,
srcPath + "/params/" + mode,
testPath + "/rolldow.cts"};
CalendarTestEngine.main(ts);
}
}
}
private static List<String> getFileNameList(String type ){
List<String> fileList = new ArrayList<>();
File dir = new File(srcPath + "/"+ type);
File[] testFiles = dir.listFiles(new FilenameFilter() {
public boolean accept(File dir, String name) {
return name.toLowerCase().endsWith(".cts");
}
});
for (File f:testFiles) {
fileList.add(f.getName());
}
return fileList;
}
}

View file

@ -0,0 +1,100 @@
/*
* Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @summary tests Japanese Calendar.
* @bug 4609228 8187649 8273924
* @modules java.base/sun.util
* java.base/sun.util.calendar
* @compile
* CalendarAdapter.java
* CalendarTestEngine.java
* CalendarTestException.java
* Exceptions.java
* GregorianAdapter.java
* Result.java
* Symbol.java
* Variable.java
* @run main/othervm/timeout=120 JapaneseTests
*/
import java.io.File;
import java.io.FilenameFilter;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class JapaneseTests {
private static List<String> SET_LENIENT = Arrays.asList(
"japanese_minmax.cts",
"japanese_add.cts",
"japanese_roll.cts",
"japanese_exceptions.cts");
private static List<String> DEFAULT_LENIENT = Arrays.asList(
"japanese.cts",
"japanese_normalization.cts");
private static Path srcPath = Paths.get(System.getProperty("test.src"));
public static void main(String[] args) throws Throwable {
List<String> tzList = getFileNameList("timezones");
List<String> modeList = getFileNameList("params");
for (String jaTest: DEFAULT_LENIENT) {
for (String tz : tzList) {
String[] ts = { srcPath + "/timezones/" + tz,
srcPath + "/japanese/" + jaTest};
CalendarTestEngine.main(ts);
}
}
for (String jaTest: SET_LENIENT) {
for (String tz : tzList) {
for (String mode : modeList) {
String[] ts = { srcPath + "/timezones/" + tz,
srcPath + "/params/" + mode,
srcPath + "/japanese/" + jaTest };
CalendarTestEngine.main(ts);
}
}
}
}
private static List<String> getFileNameList(String type ){
List<String> fileList = new ArrayList<>();
File dir = new File(srcPath + "/"+ type);
File[] testFiles = dir.listFiles(new FilenameFilter() {
public boolean accept(File dir, String name) {
return name.toLowerCase().endsWith(".cts");
}
});
for (File f:testFiles) {
fileList.add(f.getName());
}
return fileList;
}
}

View file

@ -0,0 +1,566 @@
Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
This code is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License version 2 only, as
published by the Free Software Foundation.
This code is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
version 2 for more details (a copy is included in the LICENSE file that
accompanied this code).
You should have received a copy of the GNU General Public License version
2 along with this work; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
or visit www.oracle.com if you need additional information or have any
questions.
CALENDAR TEST SCRIPT
Masayoshi Okutsu
2005-03-18
Introduction
------------
Calendar Test Script is a simple scripting language to describe test cases
for java.util.Calendar and its subclasses. It should be much more
productive to use this script language than writing test programs in Java.
A script looks like below.
1 locale ja JP JP
2 timezone Asia/Tokyo
3 new instance jcal
4 test day of week on Heisei 1 Jan 8
5 use jcal
6 clear all
7 set date Heisei 1 Jan 8
8 check day_of_week Sun
The first line defines a Locale to be used for creating Calendar
instances. Line 2 defines the current TimeZone to be Asia/Tokyo that is
used creating Calendar instances. Line 3 creates a Calendar instance with
the Locale and TimeZone instances. Its reference name is `jcal'. Line 4
indicates a start point for a test case with a short test case
description. Line 5 designates `jcal' as the current Calendar
instance. All calendar operation commands are applied to the current
Calendar instance. Line 6 clears all of the calendar fields (e.g., ERA,
YEAR, MONTH, etc.). Line 7 sets the ERA, YEAR, MONTH and DAY_OF_MONTH
fields to Heisei, 1, JANUARY and 8, respectively. Line 8 checks if the
DAY_OF_WEEK value is SUNDAY. If it's not, then a RuntimeException is
thrown.
Script Grammar
--------------
A line is a comment, blank or command line. Any text after '#' is always
treated as a comment and ignored, like a shell script.
# This is a comment line.
A command line consists of a command and its parameters, optionally
followed by a comment. For example,
set date Heisei 1 Jan 8 # The first day of Heisei
`set' is a command to set `date' to Heisei year 1 January 8th. `Heisei' is
a constant for the Japanese Heisei era value which is consistent with the
Japanese imperial calendar implementation. `Jan' is a constant for
Calendar.SUNDAY. The text after '#' is ignored.
Keywords are case-insensitive.
set DAY_OF_WEEK MON
SET day_of_week Mon
are the same thing.
Lexical analysis is very simple. A command must be complete in a single
line. Keywords and symbols must be separated by white space. For example,
"$result+1" is parsed as one token. It must be written as "$result + 1".
Variables
---------
Variables can be used in any context to store an integer value and are
referenced in any contexts where an integer value is required. A variable
name must start with a '$', such as `$maxyear'. The integer value is
handled as a long.
`$result' is reserved for storing a result of a get commend operation. For
example, executing the following command:
get day_of_month
sets $result to the get(Calendar.DAY_OF_MONTH) value of the current
Calendar instance. (See NEW and USE commands for the current Calendar
instance.)
Commands
--------
The following defines each command and its syntax. Keywords are described
in upper case below.
LOCALE language [country [variant]]
Creates a Locale instance by calling new Locale(language, country,
variant). country and variant are optional. Defining LOCALE overrides
the previously defined Locale value if any. The initial Locale value
is Locale.getDefault().
TIMEZONE tzid
Creates a TimeZone instance by calling
TimeZone.getTimeZone(tzid). Defining TIMEZONE overrides the previously
defined Locale value if any. The initial TimeZone value is
TimeZone.getDefault().
NEW INSTANCE calendarname
Creates a Calendar instance by calling Calendar.getInstance(TimeZone,
Locale). TimeZone and Locale are those defined by TIMEZONE and LOCALE
commands (or their initial values), respectively. The instance is
associated with `calendarname' and becomes the current Calendar
instance to be used for testing.
NEW GREGORIAN calendarname
Creates a Calendar instance by calling new GregorianCalendar(TimeZone,
Locale). TimeZone and Locale are those defined by TIMEZONE and LOCALE
commands (or their initial values), respectively. The instance is
associated with `calendarname' and becomes the current Calendar
instance to be used for testing.
TEST [comments...]
Declares the beginning of a test case. `comments...' gives a short
description of a test case. (Multiple lines are not supported.) The
test system displays `comments...' to System.out. For example, the
following command:
test A test case for non-lenient mode
will output:
Test #n: A test case for non-lenient mode
where `n' is a sequence number of TEST command lines appeared in a
test script file.
USE calendarname
Specifies the current Calendar instance to use for testing by
`calendarname'. If you need to use more than one Calendar instances,
then you have to switch those Calendar instances by the USE command.
ASSIGN value variable
Assigns `value' to `variable'. `value' can be an integer literal, a
variable name or a constant. Examples are:
assign 2005 $year
assign $result $temp
assign Sun $Microsystems
ASSIGN value variable IF condition
Assigns `value' to `variable' if `condition' is true. `condition' is a
relational expression as:
value1 relOp value2
`relOp' must be one of >, >=, ==, !=, <=, <.
EVAL expression
Evaluates the given *simple* expression and assigns the expression
value to $result if `op' is one of the arithmetic operators (+, -, *,
/, %). If `op' is one of the relational operators (>, >=, ==, !=, <=,
<), then EVAL throws an exception if the expression value is false, or
does nothing if the value is true. Note that an operator and values
must be separated by white space.
The following is an example of the ASSIGN and EVAL commands usage to
get the next day of week value. Then, it's used to check the
roll(DAY_OF_WEEK) result.
get day_of_week
eval $result + 1
assign $result $nextDayOfWeek
assign Sun $nextDayOfWeek if $nextDayOfWeek > Sat
roll day_of_week 1
check day_of_week $nextDayOfWeek
CLEAR ALL
Clears all the calendar fields of the current Calendar instance by
calling Calendar.clear().
CLEAR field
Clears the specified calendar `field' of the current Calendar instance
by calling Calendar.clear(field).`field' must be one of the Calendar
field indices, ERA, YEAR, MONTH, DAY_OF_MONTH, WEEK_OF_YEAR, etc.
GET MILLIS
Gets the millisecond value of the current Calendar instance by calling
Calendar.getTimeInMillis(). The value is assigned to $result.
GET field
Gets the `field' value specified of the current Calendar instance by
calling Calendar.get(field). The value is assigned to $result.
GET MIN field
Gets the minimum value of the specified `field' of the current
Calendar instance by calling Calendar.getMinimum(field). The value is
assigned to $result.
GET GREATESTMIN field
Gets the greatest minimum value of the specified `field' of the
current Calendar instance by calling
Calendar.getGreatestMinimum(field). The value is assigned to $result.
GET ACTUALMIN field
Gets the actual minimum value of the specified `field' of the current
Calendar instance by calling Calendar.getActualMinimum(field). The
value is assigned to $result.
GET MAX field
Gets the maximum value of the specified `field' of the current
Calendar instance by calling Calendar.getMaximum(field). The value is
assigned to $result.
GET LEASTMAX field
Gets the least maximum value of the specified `field' of the current
Calendar instance by calling Calendar.getLeastMaximum(field). The
value is assigned to $result.
GET ACTUALMAX field
Gets the actual maximum value of the specified `field' of the current
Calendar instance by calling Calendar.getActualMaximum(field). The
value is assigned to $result.
GET FIRSTDAYOFWEEK
Gets the first day of week value of the current Calendar instance by
calling Calendar.getFirstDayOfWeek(). The value is assigned to
$result.
GET MINIMALDAYSINFIRSTWEEK
Gets the minimal days in first week value of the current Calendar
instance by calling Calendar.getMinimalDaysInFirstWeek(). The value is
assigned to $result.
ADD field amount
Adds `amount' to the specified `field' of the current Calendar
instance by calling Calendar.add(field, amount).
ROLL field amount
Rolls `amount' of the specified `field' of the current Calendar
instance by calling Calendar.roll(field, amount).
SET MILLIS value
Sets the millisecond value of the current Calendar instance to `value'
by calling Calendar.setTimeInMillis(value).
SET field value
Sets the `field' value of the current Calendar instance to `value' by
calling Calendar.set(field, value).
SET DATE era year month dayOfMonth
Sets the date of the current Calendar instance to the date specified
by `era', `year', `month' and `dayOfMonth' by calling
Calendar.set(ERA, era) and Calendar.set(year, month,
dayOfMonth). Please note that `month' follows the Calendar convention
and is 0-based. (e.g., JANUARY is 0)
SET DATE year month dayOfMonth
Sets the date of the current Calendar instance to the date specified
by `year', `month' and `dayOfMonth' by calling
Calendar.set(year, month, dayOfMont). Please note that `month'
follows the Calendar convention and is 0-based. (e.g., JANUARY is 0)
SET DATETIME year month dayOfMonth hourOfDay minute second
Sets the date and time of the current Calendar instance to the date
and time specified by `year', `month', `dayOfMonth', `hourOfDay',
`minute', and `second' by calling Calendar.set(year, month,
dayOfMonth, hourOfDay, minute, second). Please note that `hourOfDay'
is the 24-hour clock.
SET TIMEOFDAY hourOfDay minute second millisecond
Sets the date and time of the current Calendar instance to the date
and time specified by `year', `month', `dayOfMonth', `hourOfDay',
`minute', and `second' by calling Calendar.set(HOUR_OF_DAY,
hourOfDay), Calendar.set(MINUTE, minute), and Calendar.set(SECOND,
second).
SET FIRSTDAYOFWEEK value
Sets the first day of week value of the current Calendar instance to
`value' by calling Calendar.setFirstDayOfWeek(value).
SET MINIMALDAYSINFIRSTWEEK value
Sets the minimal days in the first week value of the current Calendar
instance to `value' by calling Calendar.setMinimalDaysInFirstWeek(value).
SET LENIENT
Sets the lenient mode in the current Calendar instance by calling
Calendar.setLenient(true).
SET NON-LENIENT
Sets the non-lenient mode in the current Calendar instance by calling
Calendar.setLenient(false).
CHECK MILLIS value
Checks if the specified `value' is the same as the millisecond value
of the current Calendar instance given by calling
Calendar.getTimeInMillis(). If the values are different, an exception
is thrown.
CHECK DATE era year month dayOfMonth
Checks if the date specified by `era', `year', `month' and
`dayOfMonth' is the same date of the current Calendar instance. The
calendar date is given by calling Calendar.get(ERA),
Calendar.get(YEAR), Calendar.get(MONTH), and
Calendar.get(DAY_OF_MONTH). If the dates are different, an exception
is thrown.
CHECK DATE year month dayOfMonth
Checks if the date specified by `year', `month' and `dayOfMonth' is
the same date of the current Calendar instance. The calendar date is
given by calling Calendar.get(YEAR), Calendar.get(MONTH), and
Calendar.get(DAY_OF_MONTH). If the dates are different, an exception
is thrown.
CHECK DATETIME year month dayOfMonth hourOfDay minute second
Checks if the date and time specified by `year', `month',
`dayOfMonth', `hourOfDay', `minute', and `second' are the same ones of
the current Calendar instance. The calendar date and time are given by
calling Calendar.get(YEAR), Calendar.get(MONTH),
Calendar.get(DAY_OF_MONTH), Calendar.get(HOUR_OF_DAY),
Calendar.get(MINUTE) and Calendar.get(SECOND). If the dates or times
are different, an exception is thrown.
CHECK DATETIME year month dayOfMonth hourOfDay minute second millisecond
Checks if the date and time specified by `year', `month',
`dayOfMonth', `hourOfDay', `minute', `second' and `millisecond' are
the same ones of the current Calendar instance. The calendar date and
time are given by calling Calendar.get(YEAR), Calendar.get(MONTH),
Calendar.get(DAY_OF_MONTH), Calendar.get(HOUR_OF_DAY),
Calendar.get(MINUTE), Calendar.get(SECOND) and
Calendar.get(MILLISECOND). If the dates or times are different, an
exception is thrown.
CHECK TIMEOFDAY hourOfDay minute second millisecond
Checks if the time of day specified by `hourOfDay', `minute', `second'
and `millisecond' are the same ones of the current Calendar
instance. The calendar date and time are given by calling
Calendar.get(HOUR_OF_DAY), Calendar.get(MINUTE), Calendar.get(SECOND)
and Calendar.get(MILLISECOND). If the times are different, an
exception is thrown.
CHECK field value
Checks if the value of the given `field' of the current Calendar
instance is equal to the given `value'. If it doesn't, an exception is
thrown.
CHECK MIN field value
Checks if the minimum value of the specified `field' of the current
Calendar instance is equal to the specified `value'. If not, an
exception is thrown.
CHECK GREATESTMIN field value
Checks if the greatest minimum value of the specified `field' of the
current Calendar instance is equal to the specified `value'. If not,
an exception is thrown.
CHECK ACTUALMIN field value
Checks if the actual minimum value of the specified `field' of the
current Calendar instance is equal to the specified `value'. If not,
an exception is thrown.
CHECK MAX field value
Checks if the maximum value of the specified `field' of the current
Calendar instance is equal to the specified `value'. If not, an
exception is thrown.
CHECK LEASTMAX field value
Checks if the least maximum value of the specified `field' of the
current Calendar instance is equal to the specified `value'. If not,
an exception is thrown.
CHECK ACTUALMAX field value
Checks if the actual maximum value of the specified `field' of the
current Calendar instance is equal to the specified `value'. If not,
an exception is thrown.
EXCEPTION exceptionname
Checks if the previous command threw the specified exception by
`exceptionname'. For example, the following tests invalid date
detection in non-lenient.
set non-lenient
set date 2005 Feb 29 # 2005 isn't a leap year.
get millis
exception IllegalArgumentException
PRINT variable
Prints the value of `variable'.
PRINT INSTANCE [calendarname]
Prints the Calendar.toString() value of the current Calendar instance
or the instance given by `calendarname'.
PRINT field
Prints the value of the specified `field' of the current Calendar
instance. The value is obtained by calling Calendar.get(field).
PRINT MILLIS
Prints the millisecond value of the current Calendar instance. The
value is obtained by calling Calendar.getTimeInMillis().
PRINT MIN field
Prints the minimum value of the specified field by `field' of the
current Calendar instance. The value is obtained by calling
Calendar.getMinimum(field).
PRINT GREATESTMIN field
Prints the greatest minimum value of the specified field by `field' of
the current Calendar instance. The value is obtained by calling
Calendar.getGreatestMinimum(field).
PRINT ACTUALMIN field
Prints the actual minimum value of the specified field by `field' of
the current Calendar instance by calling
Calendar.getActualMinimum(field).
PRINT MAX field
Prints the maximum value of the specified field by `field' of the
current Calendar instance. The value is obtained by calling
Calendar.getMaximum(field).
PRINT LEASTMAX field
Prints the least maximum value of the specified field by `field' of
the current Calendar instance. The value is obtained by calling
Calendar.getLeastMaximum(field).
PRINT ACTUALMAX field
Prints the actual maximum value of the specified field by `field' of
the current Calendar instance. The value is obtained by calling
Calendar.getActualMaximum(field).
PRINT DATE
Prints the date of the current Calendar instance in format
"[ERA] yyyy-MM-dd". The date is obtained by calling Calendar.get(ERA),
Calendar.get(YEAR), Calendar.get(MONTH), and
Calendar.get(DAY_OF_MONTH).
PRINT DATETIME
Prints the date and time of the current Calendar instance in an ISO
8601-style format "[ERA] yyyy-MM-ddTHH:mm:ss.SSS{Z|{+|-}hhmm}". The
date and time are obtained by calling Calendar.get(ERA),
Calendar.get(YEAR), Calendar.get(MONTH), Calendar.get(DAY_OF_MONTH),
Calendar.get(HOUR_OF_DAY), Calendar.get(MINUTE), Calendar.get(SECOND),
Calendar.get(MILLISECOND), Calendar.get(ZONE_OFFSET), and
Calendar.get(DST_OFFSET).
PRINT TIMEZONE
Prints the toString() value of the current TimeZone.
PRINT LOCALE
Prints the toString() value of the current Locale.
Usage
-----
The usage of the test script system at this directory is:
$ javac -d classes --add-exports java.base/sun.util=ALL-UNNAMED --add-exports java.base/sun.util.calendar=ALL-UNNAMED *.java
$ java -cp classes CalendarTestEngine scriptfiles...
A script file has suffix ".cts" by convention. If multiple script files
are specified. Those files are sequentially executed as if those are a
single test script. For example, if we have the following script files:
file1.cts:
locale ja JP JP
timezone Asia/Tokyo
file2.cts:
new instance jcal
new gregorian gcal
test example
use jcal
print datetime
get millis
print $result
use gcal
set millis $result
print datetime
running CalendarTestEngine with those files will produce:
$ java -cp classes CalendarTestEngine file1.cts file2.cts
Starting file1.cts...
Completed file1.cts
Starting file2.cts...
Test #1: example
file2.cts:5: Heisei 0017-03-18T20:00:25.402+0900
file2.cts:7: $result=1111143625402
file2.cts:10: 2005-03-18T20:00:25.402+0900
Completed file2.cts
[end of README]

View file

@ -0,0 +1,53 @@
/*
* Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
public class Result extends Variable {
private Exception e;
private int lineno;
public Result() {
super("$result", 0);
put("$result", this);
}
public void setLineno(int lineno) {
this.lineno = lineno;
}
public int getLineno() {
return lineno;
}
public void setException(Exception e) {
if (this.e != null) {
throw new RuntimeException("existing exception: " + e, e);
}
this.e = e;
}
public Exception getException() {
Exception e = this.e;
this.e = null;
return e;
}
}

View file

@ -0,0 +1,327 @@
/*
* Copyright (c) 2007, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import static java.util.GregorianCalendar.*;
public class Symbol {
private static Map<String, Symbol> symbols;
String name;
Type type;
int value;
boolean isArithmetic;
private Symbol(Type type, Integer value) {
this(type, value, false);
}
private Symbol(Type type) {
this(type, null, false);
}
private Symbol(Type type, boolean isArithmetic) {
this(type, null, isArithmetic);
}
private Symbol(Type type, Integer value, boolean isArithmetic) {
this.name = type.toString().toLowerCase(Locale.ROOT);
this.type = type;
if (value != null)
this.value = value;
this.isArithmetic = isArithmetic;
}
public int value() {
return value;
}
public String toString() {
return type.name();
}
public boolean isArithmetic() {
return isArithmetic;
}
public static Symbol get(String s) {
return symbols.get(s);
}
public static enum Type {
// Directives
TEST,
// Commands
LOCALE, TIMEZONE, NEW, USE, ASSIGN, EVAL,
CLEAR, SET, GET, ADD, ROLL, CHECK, PRINT, EXCEPTION,
IF,
// Operands
INSTANCE, GREGORIAN, ALL, MILLIS, DATE, DATETIME, TIMEOFDAY,
LENIENT, NONLENIENT,
MINIMUM, GREATESTMINIMUM, ACTUALMINIMUM,
MAXIMUM, LEASTMAXIMUM, ACTUALMAXIMUM,
FIRSTDAYOFWEEK, MINIMALDAYSINFIRSTWEEK,
// Arithmetic operators
PLUS, MINUS, MULTIPLY, DIVIDE, MOD,
// Relational operators
GT, GE, EQ, NEQ, LE, LT,
// Calendar field indices
FIELD,
// Day of week
DAYOFWEEK,
// Month
MONTH,
// AM/PM
AMPM,
// Era values
ERA;
}
private static final void put(String key, Symbol sym) {
Symbol s = symbols.put(key, sym);
if (s != null) {
throw new RuntimeException("duplicated key: " + key);
}
}
static {
symbols = new HashMap<String, Symbol>();
Symbol sym;
// Directives
put("test", new Symbol(Type.TEST));
// Commands
put("locale", new Symbol(Type.LOCALE));
sym = new Symbol(Type.TIMEZONE);
put("tz", sym);
put("timezone", sym);
put("new", new Symbol(Type.NEW));
put("use", new Symbol(Type.USE));
put("assign", new Symbol(Type.ASSIGN));
put("eval", new Symbol(Type.EVAL));
put("clear", new Symbol(Type.CLEAR));
put("set", new Symbol(Type.SET));
put("get", new Symbol(Type.GET));
put("add", new Symbol(Type.ADD));
put("roll", new Symbol(Type.ROLL));
put("check", new Symbol(Type.CHECK));
put("print", new Symbol(Type.PRINT));
put("exception", new Symbol(Type.EXCEPTION));
put("throw", get("exception"));
put("if", new Symbol(Type.IF));
// Operands
put("instance", new Symbol(Type.INSTANCE));
put("gregorian", new Symbol(Type.GREGORIAN));
put("all", new Symbol(Type.ALL));
put("millis", new Symbol(Type.MILLIS));
put("date", new Symbol(Type.DATE));
put("datetime", new Symbol(Type.DATETIME));
put("timeofday", new Symbol(Type.TIMEOFDAY));
put("lenient", new Symbol(Type.LENIENT));
sym = new Symbol(Type.NONLENIENT);
put("non-lenient", sym);
put("nonlenient", sym);
put("firstdayofweek", new Symbol(Type.FIRSTDAYOFWEEK));
put("minimaldaysinfirstweek", new Symbol(Type.MINIMALDAYSINFIRSTWEEK));
sym = new Symbol(Type.MINIMUM);
put("minimum", sym);
put("min", sym);
sym = new Symbol(Type.GREATESTMINIMUM);
put("greatestminimum", sym);
put("greatestmin", sym);
sym = new Symbol(Type.ACTUALMINIMUM);
put("actualminimum", sym);
put("actualmin", sym);
sym = new Symbol(Type.MAXIMUM);
put("maximum", sym);
put("max", sym);
sym = new Symbol(Type.LEASTMAXIMUM);
put("leastmaximum", sym);
put("leastmax", sym);
sym = new Symbol(Type.ACTUALMAXIMUM);
put("actualmaximum", sym);
put("actualmax", sym);
// Arithmetic operators
put("+", new Symbol(Type.PLUS, true));
put("-", new Symbol(Type.MINUS, true));
put("*", new Symbol(Type.MULTIPLY, true));
put("/", new Symbol(Type.DIVIDE, true));
put("%", new Symbol(Type.MOD, true));
// Relational operators
put(">", new Symbol(Type.GT, false));
put(">=", new Symbol(Type.GE, false));
put("==", new Symbol(Type.EQ, false));
put("!=", new Symbol(Type.NEQ, false));
put("<=", new Symbol(Type.LE, false));
put("<", new Symbol(Type.LT, false));
// Calendar Fields
put("era", new Symbol(Type.FIELD, ERA));
put("year", new Symbol(Type.FIELD, YEAR));
put("month", new Symbol(Type.FIELD, MONTH));
sym = new Symbol(Type.FIELD, WEEK_OF_YEAR);
put("week_of_year", sym);
put("weekofyear", sym);
put("woy", sym);
sym = new Symbol(Type.FIELD, WEEK_OF_MONTH);
put("week_of_month", sym);
put("weekofmonth", sym);
put("wom", sym);
sym = new Symbol(Type.FIELD, DAY_OF_MONTH);
put("day_of_month", sym);
put("dayofmonth", sym);
put("dom", sym);
sym = new Symbol(Type.FIELD, DAY_OF_YEAR);
put("day_of_year", sym);
put("dayofyear", sym);
put("doy", sym);
sym = new Symbol(Type.FIELD, DAY_OF_WEEK);
put("day_of_week", sym);
put("dayofweek", sym);
put("dow", sym);
sym = new Symbol(Type.FIELD, DAY_OF_WEEK_IN_MONTH);
put("day_of_week_in_month", sym);
put("dayofweekinmonth", sym);
put("dowim", sym);
sym = new Symbol(Type.FIELD, AM_PM);
put("am_pm", sym);
put("ampm", sym);
put("hour", new Symbol(Type.FIELD, HOUR));
sym = new Symbol(Type.FIELD, HOUR_OF_DAY);
put("hour_of_day", sym);
put("hourofday", sym);
put("hod", sym);
put("minute", new Symbol(Type.FIELD, MINUTE));
put("second", new Symbol(Type.FIELD, SECOND));
put("millisecond", new Symbol(Type.FIELD, MILLISECOND));
sym = new Symbol(Type.FIELD, ZONE_OFFSET);
put("zone_offset", sym);
put("zoneoffset", sym);
put("zo", sym);
sym = new Symbol(Type.FIELD, DST_OFFSET);
put("dst_offset", sym);
put("dstoffset", sym);
put("do", sym);
// Day of week
sym = new Symbol(Type.DAYOFWEEK, SUNDAY);
put("sunday", sym);
put("sun", sym);
sym = new Symbol(Type.DAYOFWEEK, MONDAY);
put("monday", sym);
put("mon", sym);
sym = new Symbol(Type.DAYOFWEEK, TUESDAY);
put("tuesday", sym);
put("tue", sym);
sym = new Symbol(Type.DAYOFWEEK, WEDNESDAY);
put("wednesday", sym);
put("wed", sym);
sym = new Symbol(Type.DAYOFWEEK, THURSDAY);
put("thursday", sym);
put("thu", sym);
sym = new Symbol(Type.DAYOFWEEK, FRIDAY);
put("friday", sym);
put("fri", sym);
sym = new Symbol(Type.DAYOFWEEK, SATURDAY);
put("saturday", sym);
put("sat", sym);
// Month
sym = new Symbol(Type.MONTH, JANUARY);
put("january", sym);
put("jan", sym);
sym = new Symbol(Type.MONTH, FEBRUARY);
put("february", sym);
put("feb", sym);
sym = new Symbol(Type.MONTH, MARCH);
put("march", sym);
put("mar", sym);
sym = new Symbol(Type.MONTH, APRIL);
put("april", sym);
put("apr", sym);
sym = new Symbol(Type.MONTH, MAY);
put("may", sym);
sym = new Symbol(Type.MONTH, JUNE);
put("june", sym);
put("jun", sym);
sym = new Symbol(Type.MONTH, JULY);
put("july", sym);
put("jul", sym);
sym = new Symbol(Type.MONTH, AUGUST);
put("august", sym);
put("aug", sym);
sym = new Symbol(Type.MONTH, SEPTEMBER);
put("september", sym);
put("sep", sym);
sym = new Symbol(Type.MONTH, OCTOBER);
put("octobwe", sym);
put("oct", sym);
sym = new Symbol(Type.MONTH, NOVEMBER);
put("november", sym);
put("nov", sym);
sym = new Symbol(Type.MONTH, DECEMBER);
put("december", sym);
put("dec", sym);
sym = new Symbol(Type.MONTH, UNDECIMBER);
put("undecimber", sym);
// AM/PM
put("am", new Symbol(Type.AMPM, AM));
put("pm", new Symbol(Type.AMPM, PM));
// Eras
// Julian eras
sym = new Symbol(Type.ERA, BC);
put("bc", sym);
put("bce", sym);
sym = new Symbol(Type.ERA, AD);
put("ad", sym);
put("ce", sym);
// Buddhist era
put("be", new Symbol(Type.ERA, 1));
// Japanese imperial eras
sym = new Symbol(Type.ERA, 0);
put("before_meiji", sym);
put("beforemeiji", sym);
put("meiji", new Symbol(Type.ERA, 1));
put("taisho", new Symbol(Type.ERA, 2));
put("showa", new Symbol(Type.ERA, 3));
put("heisei", new Symbol(Type.ERA, 4));
put("reiwa", new Symbol(Type.ERA, 5));
}
}

View file

@ -0,0 +1,76 @@
/*
* Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
public class Variable {
private static Map<String,Variable> vars = new HashMap<String,Variable>();
private String name;
private long value;
Variable(String name, long value) {
this.name = name;
this.value = value;
}
public String getName() {
return name;
}
public int intValue() {
if (value > Integer.MAX_VALUE || value < Integer.MIN_VALUE) {
throw new RuntimeException("Overflow/Underflow: " + value);
}
return (int) value;
}
public long longValue() {
return value;
}
public void setValue(int v) { value = v; }
public void setValue(long v) { value = v; }
// static methods
public static Variable newVar(String name, long value) {
if (name.charAt(0) != '$') {
throw new RuntimeException("wrong var name: " + name);
}
String s = name.toLowerCase(Locale.ROOT);
Variable v = new Variable(name, value);
put(name, v);
return v;
}
static void put(String s, Variable var) {
vars.put(s, var);
}
public static Variable get(String name) {
return vars.get(name);
}
}

View file

@ -0,0 +1,331 @@
#
#
#
locale ja JP JP
new instance jcal
new gregorian gcal
test Default dates
# Default for all unset fields
# 1970-01-01T00:00:00.000 local time (Gregorian)
# which is equivalent to Showa 45.
use gcal
clear all
get millis
# get the default milliseconds from the Epoch. It's time zone
# dependent.
assign $result $defmillis
use jcal
clear all
get millis
eval $result == $defmillis
check era Showa
check datetime 45 Jan 1 0 0 0
check millisecond 0
# If each era is set, then January 1 of each Gan-nen is the
# default.
clear all
set era BeforeMeiji
check era BeforeMeiji
check datetime 1 Jan 1 0 0 0
check millisecond 0
clear all
set era Meiji
check era Meiji
check datetime 1 Jan 1 0 0 0
check millisecond 0
clear all
set era Taisho
check era Meiji
check datetime 45 Jan 1 0 0 0
check millisecond 0
clear all
set era Showa
check era Taisho
check datetime 15 Jan 1 0 0 0
check millisecond 0
clear all
set era Heisei
check era Showa
check datetime 64 Jan 1 0 0 0
check millisecond 0
clear all
set era Reiwa
check era Heisei
check datetime 31 Jan 1 0 0 0
check millisecond 0
#
# Field resolution tests
#
clear all
get firstdayofweek
# The test cases below assume that the first day of week is
# Sunday. So we should make sure it is.
eval $result == Sun
assign $result $fdow
test Field resolution: YEAR + MONTH + WEEK_OF_MONTH + DAY_OF_WEEK
set era Showa
set year 64
set week_of_month 1
check day_of_week $fdow
check date 64 Jan 1
clear all
set era Showa
set year 64
set week_of_month 1
set day_of_week Thu
check era Showa
check day_of_week Thu
check date 64 Jan 5
clear all
# Heise 1 January and Showa 64 January are the same month. Its
# first week should be the same week. (January is the default
# month.)
set era Heisei
set year 1
set week_of_month 1
check day_of_week $fdow
check era Showa
check date 64 Jan 1
# Test aggregation
clear all
set date Heisei 17 Mar 16
set week_of_month 1
set day_of_week Tue
check date Heisei 17 Mar 1
clear all
set week_of_month 1
set date Heisei 17 Mar 16
set day_of_week Tue
check date Heisei 17 Mar 1
clear all
set day_of_week Tue
set date Heisei 17 Mar 16
set week_of_month 1
check date Heisei 17 Mar 1
clear all
set day_of_week Tue
set date Heisei 17 Mar 16
set week_of_year 10
set week_of_month 1
check date Heisei 17 Mar 1
clear all
set day_of_week Tue
set date Heisei 17 Mar 16
set day_of_year 300
set week_of_month 1
check date Heisei 17 Mar 1
test Field resolution: YEAR + MONTH + DAY_OF_WEEK_IN_MONTH + DAY_OF_WEEK
clear all
set era Meiji
set year 45
set month Jul
set day_of_week_in_month 5
set day_of_week Mon
check date Meiji 45 Jul 29
clear all
set era Meiji
set year 45
set month Jul
set day_of_week_in_month 4
check date Meiji 45 Jul 28
clear all
set era Meiji
set year 45
set month Jul
set day_of_week_in_month 5
set day_of_week Tue
check date Taisho 1 Jul 30
clear all
set era Taisho
set year 1
set month Jul
set day_of_week_in_month 1
set day_of_week Tue
check date Meiji 45 Jul 2
# Test aggregation
clear all
set date Heisei 17 Mar 16
set day_of_week_in_month 1
set day_of_week Wed
check date Heisei 17 Mar 2
clear all
set day_of_week_in_month 1
set date Heisei 17 Mar 16
set day_of_week Wed
check date Heisei 17 Mar 2
clear all
set day_of_week Wed
set date Heisei 17 Mar 16
set day_of_week_in_month 1
check date Heisei 17 Mar 2
clear all
set day_of_week Wed
set date Heisei 17 Mar 16
set week_of_month 4
set day_of_week_in_month 1
check date Heisei 17 Mar 2
clear all
set day_of_week Wed
set date Heisei 17 Mar 16
set day_of_year 365
set day_of_week_in_month 1
check date Heisei 17 Mar 2
clear all
set day_of_week Wed
set date Heisei 17 Mar 16
set week_of_year 50
set day_of_week_in_month 1
check date Heisei 17 Mar 2
test Field resolution: YEAR + DAY_OF_YEAR
clear all
set era Showa
set year 64
set day_of_year 7
check date Showa 64 Jan 7
clear all
set era Showa
set year 64
set day_of_year 10
check date Heisei 1 Jan 10
clear all
set era Showa
set year 64
check date Showa 64 Jan 1
check day_of_year 1
clear all
set era Heisei
set year 1
set day_of_year 10
check date Heisei 1 Jan 17
clear all
set era Heisei
set year 1
set day_of_year 1
check date Heisei 1 Jan 8
clear all
set era Heisei
set year 1
set day_of_year -1
check date Showa 64 Jan 6
clear all
set date Heisei 17 Mar 16
set day_of_year 31
check date Heisei 17 Jan 31
clear all
set date Heisei 17 Mar 16
set week_of_year 50
set day_of_week Wed
set day_of_year 31
check date Heisei 17 Jan 31
clear all
set date Heisei 17 Mar 16
set week_of_month 5
set day_of_week Wed
set day_of_year 31
check date Heisei 17 Jan 31
test Field resolution: YEAR + DAY_OF_WEEK + WEEK_OF_YEAR
clear all
set era Showa
set year 64
set week_of_year 1
check day_of_week $fdow
check date 64 Jan 1
clear all
set era Showa
set year 64
set week_of_year 1
set day_of_week Wed
check date Showa 64 Jan 4
clear all
set era Heisei
set year 1
set week_of_year 1
check day_of_week $fdow
check date 1 Jan 8
clear all
set date Heisei 17 Mar 16
set week_of_year 2
set day_of_week Thu
check date Heisei 17 Jan 6
clear all
set week_of_year 2
set date Heisei 17 Mar 16
set day_of_week Thu
check date Heisei 17 Jan 6
clear all
set day_of_week Thu
set date Heisei 17 Mar 16
set week_of_year 2
check date Heisei 17 Jan 6
test zone offsets
# Tests here depend on the GMT offset.
timezone GMT+09:00
new instance cal0900
use cal0900
clear all
set date Heisei 17 Mar 12
get millis
assign $result $H17Mar12
clear all
set date Heisei 17 Mar 12
set zone_offset 0
get millis
eval $result - 32400000 # -9 hours
eval $result == $H17Mar12
clear all
set date Heisei 17 Mar 12
set zone_offset 28800000 # 8 hours
set dst_offset 3600000 # 1 hour
get millis
eval $result == $H17Mar12
clear all
set date Heisei 17 Mar 12
set zone_offset 18000000 # 5 hours
set dst_offset 14400000 # 4 hours
get millis
eval $result == $H17Mar12

View file

@ -0,0 +1,541 @@
#
# %i%
#
# The test cases in this file assume the first day of week is Sunday
# and the minimal days in the first week is 1.
locale ja JP JP
new instance jcal
timezone Asia/Tokyo
new instance tokyocal
set non-lenient
test add ERA
use jcal
clear all
set date Reiwa 17 Mar 8
add era 10
# as of Reiwa 17 March 8
check era Reiwa
add era -100
check era BeforeMeiji
test add HOUR_OF_DAY
use jcal
clear all
set era Heisei
set datetime 1 Jan 8 23 59 59
add hour_of_day 1
check datetime 1 Jan 9 0 59 59
check ampm AM
check hour 0
add hour_of_day -1
check datetime 1 Jan 8 23 59 59
add hour_of_day 24
check datetime 1 Jan 9 23 59 59
add hour_of_day -24
check datetime 1 Jan 8 23 59 59
test add HOUR
use jcal
clear all
set era Showa
set datetime 64 Jan 7 11 59 59
check era Showa
check hour 11
check ampm AM
add hour 1
check hour 0
check ampm PM
check datetime 64 Jan 7 12 59 59
add hour -1
check datetime 64 Jan 7 11 59 59
add hour 240
check era Heisei
check datetime 1 Jan 17 11 59 59
add hour -240
check era Showa
check datetime 64 Jan 7 11 59 59
clear all
set era Showa
set datetime 64 Jan 7 23 59 59
check era Showa
check hour 11
check ampm PM
add hour 1
check hour 0
check ampm AM
check era Heisei
check datetime 1 Jan 8 0 59 59
add hour -1
check datetime 64 Jan 7 23 59 59
add hour 240
check era Heisei
check datetime 1 Jan 17 23 59 59
add hour -240
check era Showa
check datetime 64 Jan 7 23 59 59
clear all
set era Heisei
set datetime 1 Jan 8 23 59 59
check date Heisei 1 Jan 8
check hour 11
check ampm PM
add hour 1
check hour 0
check ampm AM
check era Heisei
check datetime 1 Jan 9 0 59 59
add hour -1
check datetime 1 Jan 8 23 59 59
add hour 240
check datetime 1 Jan 18 23 59 59
add hour -240
check datetime 1 Jan 8 23 59 59
test add YEAR
use jcal
clear all
# check if pinDayOfMonth works correctly.
# Heisei 12 (Y2K) is a leap year.
set date Heisei 12 Feb 29
add year 5
check date Heisei 17 Feb 28
add year -5
check date Heisei 12 Feb 28 # not 29!
clear all
set date BeforeMeiji 1867 Jan 1
add year 1
check date Meiji 1 Jan 1
add year -1
check date BeforeMeiji 1867 Jan 1
clear all
set date Meiji 45 Jul 29
add year 1
check date Taisho 2 Jul 29
add year -1
check date Meiji 45 Jul 29
clear all
set date Meiji 44 Jul 30
add year 1
check date Taisho 1 Jul 30
add year -1
check date Meiji 44 Jul 30
clear all
set date Taisho 15 Aug 1
add year 1
check date Showa 2 Aug 1
add year -1
check date Taisho 15 Aug 1
clear all
set date Taisho 14 Dec 31
add year 1
check date Showa 1 Dec 31
add year -1
check date Taisho 14 Dec 31
clear all
set date Showa 63 Feb 1
add year 1
check date Heisei 1 Feb 1
add year -1
check date Showa 63 Feb 1
set date Showa 63 Dec 30
add year 1
check date Heisei 1 Dec 30
add year -1
check date Showa 63 Dec 30
set date Showa 64 Jan 7
add year 1
check date Heisei 2 Jan 7
add year -1
check date Showa 64 Jan 7
set date Heisei 2 Jan 7
add year -1
check date Showa 64 Jan 7
add year 1
check date Heisei 2 Jan 7
test add MONTH
clear all
# Check pinDayOfMonth works correctly.
# Heisei 12 is a leap year.
set date Heisei 12 Jan 31
add month 1
check date Heisei 12 Feb 29
add month -1
check date Heisei 12 Jan 29
# Another leap year
set date Showa 63 Jan 31
add month 1
check date Showa 63 Feb 29
add month -1
check date Showa 63 Jan 29
# Non leap year
set date Heisei 15 Jan 31
add month 1
check date Heisei 15 Feb 28
add month -1
check date Heisei 15 Jan 28
set date Heisei 15 Mar 31
add month 1
check date Heisei 15 Apr 30
add month -1
check date Heisei 15 Mar 30
set date Heisei 15 May 31
add month 1
check date Heisei 15 Jun 30
add month -1
check date Heisei 15 May 30
set date Heisei 15 Aug 31
add month 1
check date Heisei 15 Sep 30
add month -1
check date Heisei 15 Aug 30
set date Heisei 15 Oct 31
add month 1
check date Heisei 15 Nov 30
add month -1
check date Heisei 15 Oct 30
set date Heisei 15 Dec 31
add month -1
check date Heisei 15 Nov 30
add month 1
check date Heisei 15 Dec 30
set date Heisei 15 Dec 31
add month 2
check date Heisei 16 Feb 29
add month -1
check date Heisei 16 Jan 29
# end of pinDayOfMonth tests
set date BeforeMeiji 1867 Dec 1
add month 1
check date Meiji 1 Jan 1
add month -1
check date BeforeMeiji 1867 Dec 1
add month 14
check date Meiji 2 Feb 1
add month -14
check date BeforeMeiji 1867 Dec 1
set date Meiji 1 Dec 1
add month 1
check date Meiji 2 Jan 1
add month -1
check date Meiji 1 Dec 1
add month 13
check date Meiji 3 Jan 1
add month -13
check date Meiji 1 Dec 1
set date Meiji 45 Jun 30
add month 1
check date Taisho 1 Jul 30
add month -1
check date Meiji 45 Jun 30
set date Meiji 45 Jun 30
add month 14
check date Taisho 2 Aug 30
add month -14
check date Meiji 45 Jun 30
# Taisho Gan-nen (year 1) has only 6 months.
set date Taisho 1 Jul 30
add month -1
check date Meiji 45 Jun 30
add month 1
check date Taisho 1 Jul 30
add month -18
check date Meiji 44 Jan 30
add month 18
check date Taisho 1 Jul 30
set date Taisho 15 Jan 20
add month 11
check date Taisho 15 Dec 20
set date Taisho 15 Jan 25
add month 11
check date Showa 1 Dec 25
set date Showa 1 Dec 25
add month 1
check date Showa 2 Jan 25
add month -1
check date Showa 1 Dec 25
add month 17
check date Showa 3 May 25
add month -17
check date Showa 1 Dec 25
set date Showa 64 Jan 7
add month 1
check date Heisei 1 Feb 7
set date Heisei 1 Feb 1
add month -1
# Heisei starts from Jan 8.
check date Showa 64 Jan 1
add month 1
check date Heisei 1 Feb 1
set date Heisei 1 Feb 8
add month -1
check date Heisei 1 Jan 8
set date Heisei 1 Dec 1
add month 1
check date Heisei 2 Jan 1
add month -1
check date Heisei 1 Dec 1
set date Heisei 1 Dec 8
add month 1
check date Heisei 2 Jan 8
add month -1
check date Heisei 1 Dec 8
# time zone dependent tests
use tokyocal
clear all
set date BeforeMeiji 1 Jan 1
get min year
assign $result $minyear
# actual min date: -292275055.05.17T01:47:04.192+0900
set date BeforeMeiji $minyear Dec 17
set timeofday 1 47 4 192
add month -7
check date BeforeMeiji $minyear May 17
check timeofday 1 47 4 192
add month 7
check date BeforeMeiji $minyear Dec 17
check timeofday 1 47 4 192
set date BeforeMeiji $minyear Dec 17
set timeofday 1 47 4 191
add month -7
check date BeforeMeiji $minyear May 18
check timeofday 1 47 4 191
set date Reiwa 17 Jan 1
get max year
assign $result $max
set date Reiwa $max Jul 17
add month 1
check date Reiwa $max Aug 17
# set date Heisei $max Jul 28
# set timeofday 23 59 59 999
# add month 1
# check date Heisei $max Aug 16
# check timeofday 23 59 59 999
# JDK-8273924
set date Reiwa 2 Mar 1
add month -10
check date Reiwa 1 May 1
set date Reiwa 2 Mar 1
add month -11
check date Heisei 31 Apr 1
set date Reiwa 2 Mar 1
add month -12
check date Heisei 31 Mar 1
set date Reiwa 2 Mar 1
add month -13
check date Heisei 31 Feb 1
set date Reiwa 2 Mar 1
add month -14
check date Heisei 31 Jan 1
set date Reiwa 2 Mar 1
add month -15
check date Heisei 30 Dec 1
test add WEEK_OF_YEAR
use jcal
clear all
# 1867 Dec 23 is Monday.
set date BeforeMeiji 1867 Dec 23
add week_of_year 2
check day_of_week Mon
check date Meiji 1 Jan 6
add week_of_year -2
check day_of_week Mon
check date BeforeMeiji 1867 Dec 23
# 1867 Dec 23 is Wednesday.
set date Meiji 1 Dec 23
add week_of_year 2
check day_of_week Wed
check date Meiji 2 Jan 6
add week_of_year -2
check day_of_week Wed
check date Meiji 1 Dec 23
# Meiji 45 July 23 is Tuesday.
set date Meiji 45 Jul 23
add week_of_year 1
check day_of_week Tue
check date Taisho 1 Jul 30
add week_of_year -1
check day_of_week Tue
check date Meiji 45 Jul 23
# Taisho 15 December 23 is Thursday.
set date Taisho 15 Dec 23
add week_of_year 1
check day_of_week Thu
check date Showa 1 Dec 30
add week_of_year -1
check day_of_week Thu
check date Taisho 15 Dec 23
# Showa Gan-nen December 30 is Thursday. Showa Gan-nen has
# only one week. Rolling any number of weeks brings to the
# same date.
set date Showa 1 Dec 30
add week_of_year 1
check day_of_week Thu
check date Showa 2 Jan 6
add week_of_year -1
check day_of_week Thu
check date Showa 1 Dec 30
# Showa 64 January 7 is Saturday. The year has only one week.
set date Showa 64 Jan 7
add week_of_year 1
check day_of_week Sat
check date Heisei 1 Jan 14
add week_of_year -1
check day_of_week Sat
check date Showa 64 Jan 7
use tokyocal
clear all
set date BeforeMeiji $minyear Dec 25
check day_of_week Sat
eval $minyear + 1
assign $result $minyear_plus_1
add week_of_year 1
check day_of_week Sat
check date BeforeMeiji $minyear_plus_1 Jan 1
add week_of_year -1
check day_of_week Sat
check date BeforeMeiji $minyear Dec 25
test WEEK_OF_MONTH
use jcal
clear all
test DAY_OF_MONTH
use jcal
clear all
test DAY_OF_YEAR
use jcal
clear all
# 1867 is a regular Gregorian year.
set date BeforeMeiji 1867 Dec 31
add day_of_year 1
check date Meiji 1 Jan 1
add day_of_year -1
check date BeforeMeiji 1867 Dec 31
add day_of_year 26
check date Meiji 1 Jan 26
add day_of_year -26
check date BeforeMeiji 1867 Dec 31
# Meiji 1 starts from Jan 1. It's a regular year as well.
set date Meiji 1 Dec 31
add day_of_year 1
check date Meiji 2 Jan 1
add day_of_year -1
check date Meiji 1 Dec 31
add day_of_year 26
check date Meiji 2 Jan 26
add day_of_year -26
check date Meiji 1 Dec 31
# The last year of Meiji (45) has an irregularity. Meiji 45
# July 30 is actually Taisho 1 July 30.
set date Meiji 45 Jul 29
add day_of_year 1
check date Taisho 1 Jul 30
add day_of_year -1
check date Meiji 45 Jul 29
# The first day of Taisho, July 30.
set date Taisho 1 Jul 30
add day_of_year -1
check date Meiji 45 Jul 29
add day_of_year 1
check date Taisho 1 Jul 30
set date Taisho 15 Dec 24
add day_of_year 1
check date Showa 1 Dec 25
add day_of_year -1
check date Taisho 15 Dec 24
set date Showa 1 Dec 31
add day_of_year 1
check date Showa 2 Jan 1
add day_of_year -1
check date Showa 1 Dec 31
add day_of_year 25
check date Showa 2 Jan 25
add day_of_year -25
check date Showa 1 Dec 31
set date Showa 64 Jan 7
add day_of_year 1
check date Heisei 1 Jan 8
add day_of_year -1
check date Showa 64 Jan 7
set date Heisei 1 Dec 31
add day_of_year 5
check date Heisei 2 Jan 5
add day_of_year -5
check date Heisei 1 Dec 31
use tokyocal
clear all
set date BeforeMeiji $minyear Dec 31
set timeofday 1 47 4 192
add day_of_year 1
check date BeforeMeiji $minyear_plus_1 Jan 1
check timeofday 1 47 4 192
add day_of_year -1
check date BeforeMeiji $minyear Dec 31
check timeofday 1 47 4 192
test DAY_OF_WEEK_IN_MONTH
use jcal
clear all

View file

@ -0,0 +1,204 @@
#
#
#
locale ja JP JP
# Use jcal in non-lenient mode for all test cases.
set non-lenient
new instance jcal
use jcal
clear all
test Invalid BeforeMeiji dates
set date BeforeMeiji 1868 Jan 1
get millis
exception IllegalArgumentException
set date BeforeMeiji 1868 Jan 32
get millis
exception IllegalArgumentException
set date BeforeMeiji 2005 Mar 9
get millis
exception IllegalArgumentException
test Invalid Meiji dates
set date Meiji -1 Jan 1
get millis
exception IllegalArgumentException
set date Meiji 1 Feb 30
get millis
exception IllegalArgumentException
set date Meiji 45 Jul 30
get millis
exception IllegalArgumentException
set date Meiji 46 Jan 1
get millis
exception IllegalArgumentException
test Invalid Taisho dates
set date Taisho -1 Jan 1
get millis
exception IllegalArgumentException
set date Taisho 1 Jan 1
get millis
exception IllegalArgumentException
set date Taisho 1 Apr 1
get millis
exception IllegalArgumentException
set date Taisho 15 Dec 30
get millis
exception IllegalArgumentException
set date Taisho 15 Feb 29
get millis
exception IllegalArgumentException
test Invalid Showa dates
set date Showa -11 Jan 1
get millis
exception IllegalArgumentException
set date Showa 1 Jan 1
get millis
exception IllegalArgumentException
set date Showa 1 Jun 1
get millis
exception IllegalArgumentException
set date Showa 1 Jul 29
get millis
exception IllegalArgumentException
set date Showa 64 Jan 8
get millis
exception IllegalArgumentException
set date Showa 64 Dec 8
get millis
exception IllegalArgumentException
set date Showa 65 Jan 1
get millis
exception IllegalArgumentException
test Invalid Heisei dates
clear all
set date Heisei -1 Jan 1
get millis
exception IllegalArgumentException
set date Heisei 1 Jan 1
get millis
exception IllegalArgumentException
set date Heisei 1 Jan 7
get millis
exception IllegalArgumentException
set date Heisei 1 Jan 8
get max year
eval $result + 1
set date Heisei $result Jan 1
get millis
exception IllegalArgumentException
test Invalid ERA
get max era
eval $result + 1
set era $result # max era + 1
get era
exception IllegalArgumentException
set era 100
get era
exception IllegalArgumentException
set era -100
get era
exception IllegalArgumentException
test Invalid HOUR_OF_DAY
clear all
set date Heisei 17 Mar 14
set hour_of_day 25
get millis
exception IllegalArgumentException
set hour_of_day -9
get millis
exception IllegalArgumentException
test Invalid AMPM
clear all
set date Heisei 17 Mar 14
set ampm -1
set hour 1
get millis
exception IllegalArgumentException
set ampm 5
set hour 1
get millis
exception IllegalArgumentException
test Invalid HOUR
clear all
set date Heisei 17 Mar 14
set ampm AM
set hour 13
get millis
exception IllegalArgumentException
set ampm PM
set hour -1
get millis
exception IllegalArgumentException
test Invalid MINUTE
clear all
set date Heisei 17 Mar 14
set minute 61
get millis
exception IllegalArgumentException
set minute -2
get millis
exception IllegalArgumentException
test Invalid SECOND
clear all
set date Heisei 17 Mar 14
set second 61
get millis
exception IllegalArgumentException
set second -2
get millis
exception IllegalArgumentException
test Invalid MILLISECOND
clear all
set date Heisei 17 Mar 14
set millisecond 1000
get millis
exception IllegalArgumentException
set millisecond -2
get millis
exception IllegalArgumentException
test Invalid ZONE_OFFSET
clear all
set date Heisei 17 Mar 14
set zone_offset -360000000
get millis
exception IllegalArgumentException
set zone_offset -360000000
get year
exception IllegalArgumentException
set zone_offset 360000000
get millis
exception IllegalArgumentException
set zone_offset 360000000
get year
exception IllegalArgumentException
test Invalid DST_OFFSET
clear all
set date Heisei 17 Mar 14
set dst_offset -360000000
get millis
exception IllegalArgumentException
set dst_offset -360000000
get year
exception IllegalArgumentException
set dst_offset 360000000
get millis
exception IllegalArgumentException
set dst_offset 360000000
get year
exception IllegalArgumentException

View file

@ -0,0 +1,336 @@
#
#
#
locale ja JP JP
new instance jcal
new gregorian gcal
# Use GMT+09:00 for max day of year test which depends on time zone
# offsets.
timezone GMT+09:00
new instance tokyocal
test Make sure that the maximum year value doesn't depent on era
use jcal
# Note: the max year value is as of Reiwa
assign 292276976 $max
clear all
set date Reiwa 1 May 1
get millis
check max year $max
assign $max $maxyear
clear all
set date Heisei 20 May 5
get millis
check max year $maxyear
clear all
set date Showa 35 May 5
get millis
check max year $maxyear
clear all
set date BeforeMeiji 1 Jun 1
get millis
check max year $max
test Max of ERA
use jcal
# Assumption: Reiwa is the current era
check maximum era Reiwa
check leastmax era Reiwa
test Actual max MONTH
use jcal
clear all
set date BeforeMeiji 1867 Jan 31
check actualmax month Dec
# Make sure that the same value is returned after
# normalization.
get millis
check actualmax month Dec
clear all
set date Meiji 45 Mar 31
check actualmax month Jul
get millis
check actualmax month Jul
clear all
set date Taisho 15 June 1
check actualmax month Dec
get millis
check actualmax month Dec
clear all
set date Showa 64 Jan 4
check actualmax month Jan
get millis
check actualmax month Jan
clear all
set date Heisei 31 Jan 4
check actualmax month Apr
get millis
check actualmax month Apr
clear all
set date Reiwa 2 Jan 1
set year $maxyear
check actualmax month Aug
get millis
check actualmax month Aug
clear all
set date 17 Mar 1
check actualmax month Dec
get millis
check actualmax month Dec
test Actual max DAY_OF_YEAR
use jcal
clear all
set date Meiji 1 Dec 31
# Meiji Gan-nen is a leap year.
check actualmax day_of_year 366
check day_of_year 366
clear all
set date Meiji 45 Jan 1
# Meiji 45 or Taishi Gan-nen is also a leap year.
check actualmax day_of_year 211 # 31+29+31+30+31+30+29
set date Meiji 45 Jul 29
check day_of_year 211
set date Taisho 1 Jul 31
get millis
check actualmax day_of_year 155 # 366 - 211
set date Taisho 1 Dec 31
check day_of_year 155
clear all
set date Taisho 15 Sep 23
check actualmax day_of_year 358 # 365 - 7
set date Taisho 15 Dec 24
check day_of_year 358
set date Showa 1 Dec 25
check actualmax day_of_year 7
set date Showa 1 Dec 31
check day_of_year 7
clear all
set date Showa 64 Jan 3
check actualmax day_of_year 7
set date Showa 64 Jan 7
check day_of_year 7
set date Heisei 1 Aug 9
check actualmax day_of_year 358 # 365 - 7
set date Heisei 1 Dec 31
check day_of_year 358
# time zone dependent
use tokyocal
clear all
set date Reiwa $maxyear Jan 1
# the last date of Reiwa is R292276976.08.17T16:12:55.807+0900
check actualmax day_of_year 229 # 31+28+31+30+31+30+31+17
test Actual max WEEK_OF_YEAR
use jcal
clear all
set date Meiji 1 Jan 1
# Meiji gan-nen is a leap year.
check actualmax week_of_year 52
clear all
set date Meiji 45 Jan 1
check actualmax week_of_year 30
set date Taisho 1 July 31
check actualmax week_of_year 22
clear all
set date Taisho 15 Sep 23
check actualmax week_of_year 51
set date Showa 1 Dec 25
check actualmax week_of_year 1
clear all
set date Showa 64 Jan 3
check actualmax week_of_year 1
set date Heisei 1 Aug 9
check actualmax week_of_year 51
clear all
set date Heisei 31 Apr 28
check actualmax week_of_year 17
set date Reiwa 1 Aug 9
check actualmax week_of_year 35
use tokyocal
set date Reiwa $maxyear Jan 1
# the last date of Reiwa is R292276976.08.17T16:12:55.807+0900 (Sunday)
# The year is equivalent to 2003 (Gregorian).
check actualmax week_of_year 34
test Actual max WEEK_OF_MONTH
use jcal
clear all
set date Meiji 45 Jul 1
check actualmax week_of_month 5
set date Taisho 1 Jul 31
check actualmax week_of_month 5
clear all
set date Taisho 15 Dec 1
check actualmax week_of_month 5
set date Showa 1 Dec 25
check actualmax week_of_month 5
clear all
set date Showa 64 Jan 1
check actualmax week_of_month 5
set date Heisei 1 Jan 8
check actualmax week_of_month 5
clear all
set date Heisei 31 Apr 30
check actualmax week_of_month 5
set date Reiwa 1 May 1
check actualmax week_of_month 5
use tokyocal
set date Reiwa $maxyear Jan 1
# the last date of Reiwa is R292276976.08.17T16:12:55.807+0900 (Sunday)
# The year is equivalent to 2003 (Gregorian).
check actualmax week_of_month 4
test Actual max DAY_OF_WEEK_IN_MONTH
use jcal
clear all
set date Meiji 45 Jul 1
check actualmax week_of_month 5
set date Taisho 1 Jul 31
check actualmax week_of_month 5
clear all
set date Taisho 15 Dec 1
check actualmax week_of_month 5
set date Showa 1 Dec 25
check actualmax week_of_month 5
clear all
set date Showa 64 Jan 1
check actualmax week_of_month 5
set date Heisei 1 Jan 8
check actualmax week_of_month 5
clear all
set date Heisei 31 Apr 30
check actualmax week_of_month 5
set date Reiwa 1 May 1
check actualmax week_of_month 5
use tokyocal
clear all
set date Reiwa $maxyear Jan 1
# the last date of Reiwa is R292276976.08.17T16:12:55.807+0900 (Sunday)
# The year is equivalent to 2003 (Gregorian).
check actualmax week_of_month 4
test Actual max YEAR
use jcal
clear all
set date BeforeMeiji 1 Jan 1
check actualmax year 1867
set date Meiji 1 Jan 1
check actualmax year 45
set date Meiji 1 Jul 30
check actualmax year 44
set date Taisho 1 Jul 30
check actualmax year 15
set date Taisho 1 Dec 25
check actualmax year 14
set date Showa 2 Jan 1
check actualmax year 64
set date Showa 1 Dec 25
check actualmax year 63
set date Heisei 1 Jan 7
check actualmax year 64
set date Heisei 1 Aug 18
check actualmax year 30
set date Reiwa 1 Apr 30
check actualmax year 31
# Date/time beyond the last date in the max year.
set date Reiwa 1 Aug 18
check actualmax year 292276975
test Least max YEAR
set date Heisei 17 Mar 1
# Taisho is the shortest era, 14 years.
# (See above actual max YEAR case.)
check leastmax year 14
test Acutual min YEAR
# Get minimum values for comparison
clear all
set era BeforeMeiji
get min year
assign $result $minyear
set date $minyear Dec 31
eval $minyear + 1
assign $result $minyear_plus_one
# BeforeMeiji 1 Dec 31 should exist in the minimum year which
# should be the same value as the getMinimum() value.
set date BeforeMeiji 1 Dec 31
check actualmin year $minyear
# Jan 1 shouldn't exist in the same year. So the actual minimum is
# $minyear + 1.
set date 1 Jan 1
check actualmin year $minyear_plus_one
# 1 should be returned if it's on a date of the last
# year which also exists in the first year of each era.
clear all
set date Meiji 45 Jan 1
check actualmin year 1
clear all
set date Taisho 14 Jul 30
check actualmin year 1
clear all
set date Showa 60 Dec 25
check actualmin year 1
clear all
set date Heisei 17 Jan 8
check actualmin year 1
# 2 should be returned if it's on a date of the last year which
# doesn't exist in the first year of each era. (Meiji is an
# exception.)
clear all
set date Taisho 14 Jul 29
check actualmin year 2
clear all
set date Showa 60 Dec 23
check actualmin year 2
clear all
set date Heisei 17 Jan 7
check actualmin year 2

View file

@ -0,0 +1,97 @@
#
#
#
locale ja JP JP
tz Asia/Tokyo
new instance jcal
new gregorian gcal
test Normalize year 0 and -1 (Showa)
use jcal
clear all
set date Showa 1 Jan 1
check date Taisho 15 Jan 1
clear all
set date Showa 0 Jan 1
check era Taisho
check date 14 Jan 1
clear all
set date Showa -1 Jan 1
check era Taisho
check date 13 Jan 1
test Normalize year max and max+1 (Showa)
clear all
set date Showa 64 Aug 9
check date Heisei 1 Aug 9
clear all
set date Showa 65 Aug 9
check date Heisei 2 Aug 9
test Normalize year 0 and -1 (Heisei)
use jcal
clear all
set date Heisei 1 Jan 1
check date Showa 64 Jan 1
clear all
set date Heisei 0 Jan 1
check date Showa 63 Jan 1
clear all
set date Heisei -1 Jan 1
check date Showa 62 Jan 1
test Normalize year max and max+1 (Taisho)
clear all
set date Taisho 15 Dec 25
check date Showa 1 Dec 25
clear all
set date Taisho 16 Dec 25
check date Showa 2 Dec 25
test Normalize day of month 0 and -1 (Heisei)
use jcal
clear all
set date Heisei 1 Jan 1
check date Showa 64 Jan 1
clear all
set date Heisei 1 Jan 0
check date Showa 63 Dec 31
clear all
set date Heisei 1 Jan -1
check date Showa 63 Dec 30
test Normalize hour of day -1:00 (Heisei)
clear all
set era Heisei
set datetime 1 Jan 1 0 0 0
check era Showa
check datetime 64 Jan 1 0 0 0
clear all
set era Heisei
set datetime 1 Jan 1 -1 0 0
check era Showa
check datetime 63 Dec 31 23 0 0
test Normalize hour of day 25:00 (Taisho)
clear all
set era Taisho
set datetime 15 Dec 25 25 0 0
check era Showa
check datetime 1 Dec 26 1 0 0
test Normalize hour of day 25:00 (Showa)
clear all
set era Showa
set datetime 64 Jan 7 25 0 0
check era Heisei
check datetime 1 Jan 8 1 0 0

Some files were not shown because too many files have changed in this diff Show more