summaryrefslogtreecommitdiffstats
path: root/luni/src/test/java
diff options
context:
space:
mode:
Diffstat (limited to 'luni/src/test/java')
-rw-r--r--luni/src/test/java/libcore/icu/DateIntervalFormatTest.java133
-rw-r--r--luni/src/test/java/libcore/icu/ICUTest.java24
-rw-r--r--luni/src/test/java/libcore/icu/LocaleDataTest.java12
-rw-r--r--luni/src/test/java/libcore/icu/RelativeDateTimeFormatterTest.java667
-rw-r--r--luni/src/test/java/libcore/io/OsTest.java173
-rw-r--r--luni/src/test/java/libcore/java/io/FileDescriptorTest.java6
-rw-r--r--luni/src/test/java/libcore/java/io/FileInputStreamTest.java2
-rw-r--r--luni/src/test/java/libcore/java/io/RandomAccessFileTest.java57
-rw-r--r--luni/src/test/java/libcore/java/lang/FloatTest.java16
-rwxr-xr-x[-rw-r--r--]luni/src/test/java/libcore/java/lang/OldAndroidMonitorTest.java14
-rw-r--r--luni/src/test/java/libcore/java/lang/OldClassTest.java5
-rw-r--r--luni/src/test/java/libcore/java/lang/PackageTest.java7
-rw-r--r--luni/src/test/java/libcore/java/lang/ProcessBuilderTest.java2
-rw-r--r--luni/src/test/java/libcore/java/lang/TestPackageAnnotation.java26
-rw-r--r--luni/src/test/java/libcore/java/lang/package-info.java18
-rw-r--r--luni/src/test/java/libcore/java/lang/reflect/FieldTest.java52
-rw-r--r--luni/src/test/java/libcore/java/lang/reflect/MethodTest.java18
-rw-r--r--luni/src/test/java/libcore/java/lang/reflect/ModifierTest.java5
-rw-r--r--luni/src/test/java/libcore/java/net/InetAddressTest.java86
-rw-r--r--luni/src/test/java/libcore/java/net/InetSocketAddressTest.java32
-rw-r--r--luni/src/test/java/libcore/java/net/OldSocketTest.java27
-rw-r--r--luni/src/test/java/libcore/java/net/SocketTest.java33
-rw-r--r--luni/src/test/java/libcore/java/net/URLConnectionTest.java659
-rw-r--r--luni/src/test/java/libcore/java/nio/channels/SelectorTest.java21
-rw-r--r--luni/src/test/java/libcore/java/nio/charset/CharsetEncoderTest.java69
-rw-r--r--luni/src/test/java/libcore/java/nio/charset/SettableCharsetProvider.java57
-rw-r--r--luni/src/test/java/libcore/java/security/KeyPairGeneratorTest.java5
-rw-r--r--luni/src/test/java/libcore/java/security/ProviderTest.java2
-rw-r--r--luni/src/test/java/libcore/java/security/SignatureTest.java18
-rw-r--r--luni/src/test/java/libcore/java/security/cert/CertificateFactoryTest.java40
-rw-r--r--luni/src/test/java/libcore/java/security/cert/X509CRLTest.java10
-rw-r--r--luni/src/test/java/libcore/java/sql/TimestampTest.java8
-rw-r--r--luni/src/test/java/libcore/java/text/BreakIteratorTest.java28
-rw-r--r--luni/src/test/java/libcore/java/text/DateFormatSymbolsTest.java14
-rw-r--r--luni/src/test/java/libcore/java/text/NumberFormatTest.java16
-rw-r--r--luni/src/test/java/libcore/java/util/CalendarTest.java72
-rw-r--r--luni/src/test/java/libcore/java/util/CollectionsTest.java91
-rw-r--r--luni/src/test/java/libcore/java/util/CurrencyTest.java2
-rw-r--r--luni/src/test/java/libcore/java/util/LocaleTest.java57
-rw-r--r--luni/src/test/java/libcore/java/util/OldTimeZoneTest.java14
-rw-r--r--luni/src/test/java/libcore/java/util/TimeZoneTest.java46
-rw-r--r--luni/src/test/java/libcore/java/util/jar/StrictJarFileTest.java4
-rw-r--r--luni/src/test/java/libcore/java/util/zip/AbstractZipFileTest.java548
-rw-r--r--luni/src/test/java/libcore/java/util/zip/DeflaterTest.java22
-rw-r--r--luni/src/test/java/libcore/java/util/zip/GZIPInputStreamTest.java36
-rw-r--r--luni/src/test/java/libcore/java/util/zip/InflaterTest.java31
-rw-r--r--luni/src/test/java/libcore/java/util/zip/Zip64FileTest.java102
-rw-r--r--luni/src/test/java/libcore/java/util/zip/ZipEntryTest.java34
-rw-r--r--luni/src/test/java/libcore/java/util/zip/ZipFileTest.java491
-rw-r--r--luni/src/test/java/libcore/java/util/zip/ZipOutputStreamTest.java1
-rw-r--r--luni/src/test/java/libcore/javax/crypto/CipherTest.java79
-rw-r--r--luni/src/test/java/libcore/javax/crypto/KeyAgreementTest.java70
-rw-r--r--luni/src/test/java/libcore/javax/crypto/KeyGeneratorTest.java9
-rw-r--r--luni/src/test/java/libcore/javax/crypto/MockKeyAgreementSpi.java91
-rw-r--r--luni/src/test/java/libcore/javax/net/ssl/DefaultHostnameVerifierTest.java373
-rw-r--r--luni/src/test/java/libcore/javax/net/ssl/HttpsURLConnectionTest.java115
-rw-r--r--luni/src/test/java/libcore/javax/net/ssl/SSLContextTest.java26
-rw-r--r--luni/src/test/java/libcore/javax/net/ssl/SSLEngineTest.java124
-rw-r--r--luni/src/test/java/libcore/javax/net/ssl/SSLServerSocketFactoryTest.java2
-rw-r--r--luni/src/test/java/libcore/javax/net/ssl/SSLServerSocketTest.java2
-rw-r--r--luni/src/test/java/libcore/javax/net/ssl/SSLSocketFactoryTest.java2
-rw-r--r--luni/src/test/java/libcore/javax/net/ssl/SSLSocketTest.java200
-rw-r--r--luni/src/test/java/libcore/net/MimeUtilsTest.java6
-rw-r--r--luni/src/test/java/libcore/net/NetworkSecurityPolicyTest.java315
-rw-r--r--luni/src/test/java/libcore/net/http/ResponseUtilsTest.java52
-rw-r--r--luni/src/test/java/libcore/util/HexEncodingTest.java76
-rw-r--r--luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/ExemptionMechanismTest.java41
-rw-r--r--luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/MacTest.java31
68 files changed, 4566 insertions, 961 deletions
diff --git a/luni/src/test/java/libcore/icu/DateIntervalFormatTest.java b/luni/src/test/java/libcore/icu/DateIntervalFormatTest.java
index 1c1296b..7adad72 100644
--- a/luni/src/test/java/libcore/icu/DateIntervalFormatTest.java
+++ b/luni/src/test/java/libcore/icu/DateIntervalFormatTest.java
@@ -16,10 +16,12 @@
package libcore.icu;
-import java.util.Calendar;
-import java.util.Locale;
-import java.util.TimeZone;
-import static libcore.icu.DateIntervalFormat.*;
+import android.icu.util.Calendar;
+import android.icu.util.TimeZone;
+import android.icu.util.ULocale;
+
+import static libcore.icu.DateIntervalFormat.formatDateRange;
+import static libcore.icu.DateUtilsBridge.*;
public class DateIntervalFormatTest extends junit.framework.TestCase {
private static final long MINUTE = 60 * 1000;
@@ -32,7 +34,7 @@ public class DateIntervalFormatTest extends junit.framework.TestCase {
public void test_formatDateInterval() throws Exception {
TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles");
- Calendar c = Calendar.getInstance(tz, Locale.US);
+ Calendar c = Calendar.getInstance(tz, ULocale.US);
c.set(Calendar.MONTH, Calendar.JANUARY);
c.set(Calendar.DAY_OF_MONTH, 19);
c.set(Calendar.HOUR_OF_DAY, 3);
@@ -51,10 +53,10 @@ public class DateIntervalFormatTest extends junit.framework.TestCase {
long noonDuration = (8 * 60 + 30) * 60 * 1000 - 15 * 1000;
long midnightDuration = (3 * 60 + 30) * 60 * 1000 + 15 * 1000;
- Locale de_DE = new Locale("de", "DE");
- Locale en_US = new Locale("en", "US");
- Locale es_ES = new Locale("es", "ES");
- Locale es_US = new Locale("es", "US");
+ ULocale de_DE = new ULocale("de", "DE");
+ ULocale en_US = new ULocale("en", "US");
+ ULocale es_ES = new ULocale("es", "ES");
+ ULocale es_US = new ULocale("es", "US");
assertEquals("Monday", formatDateRange(en_US, tz, fixedTime, fixedTime + HOUR, FORMAT_SHOW_WEEKDAY));
assertEquals("January 19", formatDateRange(en_US, tz, timeWithCurrentYear, timeWithCurrentYear + HOUR, FORMAT_SHOW_DATE));
@@ -81,11 +83,11 @@ public class DateIntervalFormatTest extends junit.framework.TestCase {
assertEquals("1/19/2009 – 2/9/2012", formatDateRange(en_US, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
assertEquals("19.1.2009", formatDateRange(de_DE, tz, fixedTime, fixedTime + HOUR, FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
- assertEquals("19.01.2009 - 22.01.2009", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
- assertEquals("19.01.2009 - 22.04.2009", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
- assertEquals("19.01.2009 - 09.02.2012", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
+ assertEquals("19.01.2009 – 22.01.2009", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
+ assertEquals("19.01.2009 – 22.04.2009", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
+ assertEquals("19.01.2009 – 09.02.2012", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
- assertEquals("1/19/2009", formatDateRange(es_US, tz, fixedTime, fixedTime + HOUR, FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
+ assertEquals("19/1/2009", formatDateRange(es_US, tz, fixedTime, fixedTime + HOUR, FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
assertEquals("19/1/2009–22/1/2009", formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
assertEquals("19/1/2009–22/4/2009", formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
assertEquals("19/1/2009–9/2/2012", formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
@@ -114,60 +116,61 @@ public class DateIntervalFormatTest extends junit.framework.TestCase {
// The same tests but for de_DE.
- assertEquals("19.-22. Januar 2009", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * DAY, 0));
- assertEquals("19.-22. Jan. 2009", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
- assertEquals("Mo., 19. - Do., 22. Jan. 2009", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL));
- assertEquals("Montag, 19. - Donnerstag, 22. Januar 2009", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_WEEKDAY));
+ assertEquals("19.–22. Januar 2009", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * DAY, 0));
+ assertEquals("19.–22. Jan. 2009", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
+ assertEquals("Mo., 19. – Do., 22. Jan. 2009", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL));
+ assertEquals("Montag, 19. – Donnerstag, 22. Januar 2009", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_WEEKDAY));
- assertEquals("19. Januar - 22. April 2009", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * MONTH, 0));
- assertEquals("19. Jan. - 22. Apr. 2009", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
- assertEquals("Mo., 19. Jan. - Mi., 22. Apr. 2009", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL));
- assertEquals("Januar-April 2009", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_NO_MONTH_DAY));
+ assertEquals("19. Januar – 22. April 2009", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * MONTH, 0));
+ assertEquals("19. Jan. – 22. Apr. 2009", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
+ assertEquals("Mo., 19. Jan. – Mi., 22. Apr. 2009", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL));
+ assertEquals("Januar–April 2009", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_NO_MONTH_DAY));
- assertEquals("19. Jan. 2009 - 9. Feb. 2012", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
- assertEquals("Jan. 2009 - Feb. 2012", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_NO_MONTH_DAY | FORMAT_ABBREV_ALL));
- assertEquals("19. Januar 2009 - 9. Februar 2012", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * YEAR, 0));
- assertEquals("Montag, 19. Januar 2009 - Donnerstag, 9. Februar 2012", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_SHOW_WEEKDAY));
+ assertEquals("19. Jan. 2009 – 9. Feb. 2012", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
+ assertEquals("Jan. 2009 – Feb. 2012", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_NO_MONTH_DAY | FORMAT_ABBREV_ALL));
+ assertEquals("19. Januar 2009 – 9. Februar 2012", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * YEAR, 0));
+ assertEquals("Montag, 19. Januar 2009 – Donnerstag, 9. Februar 2012", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_SHOW_WEEKDAY));
// The same tests but for es_US.
- assertEquals("19–22 enero 2009", formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * DAY, 0));
- assertEquals("19–22 ene. 2009", formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
- assertEquals("lun., 19 ene.–jue., 22 ene. de 2009", formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL));
- assertEquals("lunes, 19 enero–jueves, 22 enero de 2009", formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_WEEKDAY));
+ assertEquals("19–22 de enero de 2009", formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * DAY, 0));
+ assertEquals("19 – 22 de ene. de 2009", formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
+ assertEquals("lun., 19 de ene. – jue., 22 de ene. de 2009", formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL));
+ assertEquals("lunes, 19 de enero–jueves, 22 de enero de 2009", formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_WEEKDAY));
- assertEquals("19 enero–22 abril de 2009", formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * MONTH, 0));
- assertEquals("19 ene.–22 abr. de 2009", formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
- assertEquals("lun., 19 ene.–mié., 22 abr. de 2009", formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL));
+ assertEquals("19 de enero–22 de abril de 2009", formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * MONTH, 0));
+ assertEquals("19 de ene. – 22 de abr. de 2009", formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
+ assertEquals("lun., 19 de ene. – mié., 22 de abr. de 2009", formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL));
assertEquals("enero–abril de 2009", formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_NO_MONTH_DAY));
- assertEquals("19 ene. de 2009–9 feb. de 2012", formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
- assertEquals("ene. 2009–feb. 2012", formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_NO_MONTH_DAY | FORMAT_ABBREV_ALL));
- assertEquals("19 enero de 2009–9 febrero de 2012", formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * YEAR, 0));
- assertEquals("lunes, 19 enero de 2009–jueves, 9 febrero de 2012", formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_SHOW_WEEKDAY));
+ assertEquals("19 de ene. de 2009 – 9 de feb. de 2012", formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
+ assertEquals("ene. de 2009 – feb. de 2012", formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_NO_MONTH_DAY | FORMAT_ABBREV_ALL));
+
+ assertEquals("19 de enero de 2009–9 de febrero de 2012", formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * YEAR, 0));
+ assertEquals("lunes, 19 de enero de 2009–jueves, 9 de febrero de 2012", formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_SHOW_WEEKDAY));
// The same tests but for es_ES.
- assertEquals("19–22 enero 2009", formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * DAY, 0));
+ assertEquals("19–22 de enero de 2009", formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * DAY, 0));
assertEquals("19–22 ene. 2009", formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
- assertEquals("lun., 19 ene.–jue., 22 ene. de 2009", formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL));
- assertEquals("lunes, 19 enero–jueves, 22 enero de 2009", formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_WEEKDAY));
+ assertEquals("lun., 19 ene.–jue., 22 ene. 2009", formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL));
+ assertEquals("lunes, 19 de enero–jueves, 22 de enero de 2009", formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_WEEKDAY));
- assertEquals("19 enero–22 abril de 2009", formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * MONTH, 0));
- assertEquals("19 ene.–22 abr. de 2009", formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
- assertEquals("lun., 19 ene.–mié., 22 abr. de 2009", formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL));
+ assertEquals("19 de enero–22 de abril de 2009", formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * MONTH, 0));
+ assertEquals("19 ene.–22 abr. 2009", formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
+ assertEquals("lun., 19 ene.–mié., 22 abr. 2009", formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL));
assertEquals("enero–abril de 2009", formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_NO_MONTH_DAY));
- assertEquals("19 ene. de 2009–9 feb. de 2012", formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
+ assertEquals("19 ene. 2009–9 feb. 2012", formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
assertEquals("ene. 2009–feb. 2012", formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_NO_MONTH_DAY | FORMAT_ABBREV_ALL));
- assertEquals("19 enero de 2009–9 febrero de 2012", formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * YEAR, 0));
- assertEquals("lunes, 19 enero de 2009–jueves, 9 febrero de 2012", formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_SHOW_WEEKDAY));
+ assertEquals("19 de enero de 2009–9 de febrero de 2012", formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * YEAR, 0));
+ assertEquals("lunes, 19 de enero de 2009–jueves, 9 de febrero de 2012", formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_SHOW_WEEKDAY));
}
// http://b/8862241 - we should be able to format dates past 2038.
// See also http://code.google.com/p/android/issues/detail?id=13050.
public void test8862241() throws Exception {
- Locale l = Locale.US;
+ ULocale l = ULocale.US;
TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles");
Calendar c = Calendar.getInstance(tz, l);
c.clear();
@@ -181,7 +184,7 @@ public class DateIntervalFormatTest extends junit.framework.TestCase {
// http://b/10089890 - we should take the given time zone into account.
public void test10089890() throws Exception {
- Locale l = Locale.US;
+ ULocale l = ULocale.US;
TimeZone utc = TimeZone.getTimeZone("UTC");
TimeZone pacific = TimeZone.getTimeZone("America/Los_Angeles");
int flags = FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL | FORMAT_SHOW_TIME | FORMAT_24HOUR;
@@ -203,7 +206,7 @@ public class DateIntervalFormatTest extends junit.framework.TestCase {
int abbr12 = time12 | FORMAT_ABBREV_ALL;
int abbr24 = time24 | FORMAT_ABBREV_ALL;
- Locale l = Locale.US;
+ ULocale l = ULocale.US;
TimeZone utc = TimeZone.getTimeZone("UTC");
// Full length on-the-hour times.
@@ -230,7 +233,7 @@ public class DateIntervalFormatTest extends junit.framework.TestCase {
// http://b/10560853 - when the time is not displayed, an end time 0 ms into the next day is
// considered to belong to the previous day.
public void test10560853_when_time_not_displayed() throws Exception {
- Locale l = Locale.US;
+ ULocale l = ULocale.US;
TimeZone utc = TimeZone.getTimeZone("UTC");
long midnight = 0;
@@ -254,7 +257,7 @@ public class DateIntervalFormatTest extends junit.framework.TestCase {
// http://b/10560853 - when the start and end times are otherwise on the same day,
// an end time 0 ms into the next day is considered to belong to the previous day.
public void test10560853_for_single_day_events() throws Exception {
- Locale l = Locale.US;
+ ULocale l = ULocale.US;
TimeZone utc = TimeZone.getTimeZone("UTC");
int flags = FORMAT_SHOW_TIME | FORMAT_24HOUR | FORMAT_SHOW_DATE;
@@ -266,7 +269,7 @@ public class DateIntervalFormatTest extends junit.framework.TestCase {
// The fix for http://b/10560853 didn't work except for the day around the epoch, which was
// all the unit test checked!
public void test_single_day_events_later_than_epoch() throws Exception {
- Locale l = Locale.US;
+ ULocale l = ULocale.US;
TimeZone utc = TimeZone.getTimeZone("UTC");
int flags = FORMAT_SHOW_TIME | FORMAT_24HOUR | FORMAT_SHOW_DATE;
@@ -284,7 +287,7 @@ public class DateIntervalFormatTest extends junit.framework.TestCase {
// The fix for http://b/10560853 didn't work except for UTC, which was
// all the unit test checked!
public void test_single_day_events_not_in_UTC() throws Exception {
- Locale l = Locale.US;
+ ULocale l = ULocale.US;
TimeZone pacific = TimeZone.getTimeZone("America/Los_Angeles");
int flags = FORMAT_SHOW_TIME | FORMAT_24HOUR | FORMAT_SHOW_DATE;
@@ -305,7 +308,7 @@ public class DateIntervalFormatTest extends junit.framework.TestCase {
// http://b/10209343 - even if the caller didn't explicitly ask us to include the year,
// we should do so for years other than the current year.
public void test10209343_when_not_this_year() {
- Locale l = Locale.US;
+ ULocale l = ULocale.US;
TimeZone utc = TimeZone.getTimeZone("UTC");
int flags = FORMAT_SHOW_DATE | FORMAT_SHOW_WEEKDAY | FORMAT_SHOW_TIME | FORMAT_24HOUR;
@@ -328,7 +331,7 @@ public class DateIntervalFormatTest extends junit.framework.TestCase {
// http://b/10209343 - for the current year, we should honor the FORMAT_SHOW_YEAR flags.
public void test10209343_when_this_year() {
// Construct a date in the current year (whenever the test happens to be run).
- Locale l = Locale.US;
+ ULocale l = ULocale.US;
TimeZone utc = TimeZone.getTimeZone("UTC");
Calendar c = Calendar.getInstance(utc, l);
c.set(Calendar.MONTH, Calendar.FEBRUARY);
@@ -363,7 +366,7 @@ public class DateIntervalFormatTest extends junit.framework.TestCase {
// http://b/8467515 - yet another y2k38 bug report.
public void test8467515() throws Exception {
- Locale l = Locale.US;
+ ULocale l = ULocale.US;
TimeZone utc = TimeZone.getTimeZone("UTC");
int flags = FORMAT_SHOW_DATE | FORMAT_SHOW_WEEKDAY | FORMAT_SHOW_YEAR | FORMAT_ABBREV_MONTH | FORMAT_ABBREV_WEEKDAY;
long t;
@@ -383,7 +386,7 @@ public class DateIntervalFormatTest extends junit.framework.TestCase {
// http://b/12004664
public void test12004664() throws Exception {
TimeZone utc = TimeZone.getTimeZone("UTC");
- Calendar c = Calendar.getInstance(utc, Locale.US);
+ Calendar c = Calendar.getInstance(utc, ULocale.US);
c.clear();
c.set(Calendar.YEAR, 1980);
c.set(Calendar.MONTH, Calendar.FEBRUARY);
@@ -392,26 +395,26 @@ public class DateIntervalFormatTest extends junit.framework.TestCase {
long thisYear = c.getTimeInMillis();
int flags = FORMAT_SHOW_DATE | FORMAT_SHOW_WEEKDAY | FORMAT_SHOW_YEAR;
- assertEquals("Sunday, February 10, 1980", formatDateRange(new Locale("en", "US"), utc, thisYear, thisYear, flags));
+ assertEquals("Sunday, February 10, 1980", formatDateRange(new ULocale("en", "US"), utc, thisYear, thisYear, flags));
- // If we supported non-Gregorian calendars, this is what that we'd expect for these locales.
+ // If we supported non-Gregorian calendars, this is what that we'd expect for these ULocales.
// This is really the correct behavior, but since java.util.Calendar currently only supports
// the Gregorian calendar, we want to deliberately force icu4c to agree, otherwise we'd have
// a mix of calendars throughout an app's UI depending on whether Java or native code formatted
// the date.
- // assertEquals("یکشنبه ۲۱ بهمن ۱۳۵۸ ه‍.ش.", formatDateRange(new Locale("fa"), utc, thisYear, thisYear, flags));
- // assertEquals("AP ۱۳۵۸ سلواغه ۲۱, یکشنبه", formatDateRange(new Locale("ps"), utc, thisYear, thisYear, flags));
- // assertEquals("วันอาทิตย์ 10 กุมภาพันธ์ 2523", formatDateRange(new Locale("th"), utc, thisYear, thisYear, flags));
+ // assertEquals("یکشنبه ۲۱ بهمن ۱۳۵۸ ه‍.ش.", formatDateRange(new ULocale("fa"), utc, thisYear, thisYear, flags));
+ // assertEquals("AP ۱۳۵۸ سلواغه ۲۱, یکشنبه", formatDateRange(new ULocale("ps"), utc, thisYear, thisYear, flags));
+ // assertEquals("วันอาทิตย์ 10 กุมภาพันธ์ 2523", formatDateRange(new ULocale("th"), utc, thisYear, thisYear, flags));
// For now, here are the localized Gregorian strings instead...
- assertEquals("یکشنبه ۱۰ فوریهٔ ۱۹۸۰", formatDateRange(new Locale("fa"), utc, thisYear, thisYear, flags));
- assertEquals("یکشنبه د ۱۹۸۰ د فبروري ۱۰", formatDateRange(new Locale("ps"), utc, thisYear, thisYear, flags));
- assertEquals("วันอาทิตย์ 10 กุมภาพันธ์ 1980", formatDateRange(new Locale("th"), utc, thisYear, thisYear, flags));
+ assertEquals("یکشنبه ۱۰ فوریهٔ ۱۹۸۰", formatDateRange(new ULocale("fa"), utc, thisYear, thisYear, flags));
+ assertEquals("یکشنبه د ۱۹۸۰ د فبروري ۱۰", formatDateRange(new ULocale("ps"), utc, thisYear, thisYear, flags));
+ assertEquals("วันอาทิตย์ที่ 10 กุมภาพันธ์ ค.ศ. 1980", formatDateRange(new ULocale("th"), utc, thisYear, thisYear, flags));
}
// http://b/13234532
public void test13234532() throws Exception {
- Locale l = Locale.US;
+ ULocale l = ULocale.US;
TimeZone utc = TimeZone.getTimeZone("UTC");
int flags = FORMAT_SHOW_TIME | FORMAT_ABBREV_ALL | FORMAT_12HOUR;
diff --git a/luni/src/test/java/libcore/icu/ICUTest.java b/luni/src/test/java/libcore/icu/ICUTest.java
index a7cc7a0..99679a7 100644
--- a/luni/src/test/java/libcore/icu/ICUTest.java
+++ b/luni/src/test/java/libcore/icu/ICUTest.java
@@ -20,6 +20,7 @@ import java.text.BreakIterator;
import java.text.Collator;
import java.util.Arrays;
import java.util.Locale;
+import libcore.util.ZoneInfoDB;
public class ICUTest extends junit.framework.TestCase {
public void test_getISOLanguages() throws Exception {
@@ -152,24 +153,24 @@ public class ICUTest extends junit.framework.TestCase {
assertEquals("sr_ME_#Latn", sr_Latn_ME.toString());
assertEquals("Latn", sr_Latn_ME.getScript());
- assertEquals("Српски", sr_Cyrl_BA.getDisplayLanguage(sr_Cyrl_BA));
+ assertEquals("српски", sr_Cyrl_BA.getDisplayLanguage(sr_Cyrl_BA));
assertEquals("Босна и Херцеговина", sr_Cyrl_BA.getDisplayCountry(sr_Cyrl_BA));
- assertEquals("Ћирилица", sr_Cyrl_BA.getDisplayScript(sr_Cyrl_BA));
+ assertEquals("ћирилица", sr_Cyrl_BA.getDisplayScript(sr_Cyrl_BA));
assertEquals("", sr_Cyrl_BA.getDisplayVariant(sr_Cyrl_BA));
- assertEquals("Српски", sr_Cyrl_ME.getDisplayLanguage(sr_Cyrl_ME));
+ assertEquals("српски", sr_Cyrl_ME.getDisplayLanguage(sr_Cyrl_ME));
assertEquals("Црна Гора", sr_Cyrl_ME.getDisplayCountry(sr_Cyrl_ME));
- assertEquals("Ћирилица", sr_Cyrl_ME.getDisplayScript(sr_Cyrl_ME));
+ assertEquals("ћирилица", sr_Cyrl_ME.getDisplayScript(sr_Cyrl_ME));
assertEquals("", sr_Cyrl_ME.getDisplayVariant(sr_Cyrl_ME));
- assertEquals("Srpski", sr_Latn_BA.getDisplayLanguage(sr_Latn_BA));
+ assertEquals("srpski", sr_Latn_BA.getDisplayLanguage(sr_Latn_BA));
assertEquals("Bosna i Hercegovina", sr_Latn_BA.getDisplayCountry(sr_Latn_BA));
- assertEquals("Latinica", sr_Latn_BA.getDisplayScript(sr_Latn_BA));
+ assertEquals("latinica", sr_Latn_BA.getDisplayScript(sr_Latn_BA));
assertEquals("", sr_Latn_BA.getDisplayVariant(sr_Latn_BA));
- assertEquals("Srpski", sr_Latn_ME.getDisplayLanguage(sr_Latn_ME));
+ assertEquals("srpski", sr_Latn_ME.getDisplayLanguage(sr_Latn_ME));
assertEquals("Crna Gora", sr_Latn_ME.getDisplayCountry(sr_Latn_ME));
- assertEquals("Latinica", sr_Latn_ME.getDisplayScript(sr_Latn_ME));
+ assertEquals("latinica", sr_Latn_ME.getDisplayScript(sr_Latn_ME));
assertEquals("", sr_Latn_ME.getDisplayVariant(sr_Latn_ME));
assertEquals("BIH", sr_Cyrl_BA.getISO3Country());
@@ -253,4 +254,11 @@ public class ICUTest extends junit.framework.TestCase {
ICU.setDefaultLocale(initialDefaultLocale);
}
}
+
+ /** Confirms that ICU agrees with the rest of libcore about the version of the TZ data in use. */
+ public void testTimeZoneDataVersion() {
+ String icu4cTzVersion = ICU.getTZDataVersion();
+ String zoneInfoTzVersion = ZoneInfoDB.getInstance().getVersion();
+ assertEquals(icu4cTzVersion, zoneInfoTzVersion);
+ }
}
diff --git a/luni/src/test/java/libcore/icu/LocaleDataTest.java b/luni/src/test/java/libcore/icu/LocaleDataTest.java
index 0a83c53..09c3f0f 100644
--- a/luni/src/test/java/libcore/icu/LocaleDataTest.java
+++ b/luni/src/test/java/libcore/icu/LocaleDataTest.java
@@ -24,7 +24,7 @@ public class LocaleDataTest extends junit.framework.TestCase {
for (Locale l : Locale.getAvailableLocales()) {
LocaleData d = LocaleData.get(l);
// System.err.format("%20s %s %s %s\n", l, d.yesterday, d.today, d.tomorrow);
- // System.err.format("%20s %10s %10s\n", l, d.timeFormat12, d.timeFormat24);
+ // System.err.format("%20s %10s %10s\n", l, d.timeFormat_hm, d.timeFormat_Hm);
}
}
@@ -73,7 +73,7 @@ public class LocaleDataTest extends junit.framework.TestCase {
assertEquals("leden", l.longStandAloneMonthNames[0]);
assertEquals("led", l.shortStandAloneMonthNames[0]);
- assertEquals("l", l.tinyStandAloneMonthNames[0]);
+ assertEquals("1", l.tinyStandAloneMonthNames[0]);
}
public void test_ko_KR() throws Exception {
@@ -124,11 +124,11 @@ public class LocaleDataTest extends junit.framework.TestCase {
// http://b/7924970
public void testTimeFormat12And24() throws Exception {
LocaleData en_US = LocaleData.get(Locale.US);
- assertEquals("h:mm a", en_US.timeFormat12);
- assertEquals("HH:mm", en_US.timeFormat24);
+ assertEquals("h:mm a", en_US.timeFormat_hm);
+ assertEquals("HH:mm", en_US.timeFormat_Hm);
LocaleData ja_JP = LocaleData.get(Locale.JAPAN);
- assertEquals("aK:mm", ja_JP.timeFormat12);
- assertEquals("H:mm", ja_JP.timeFormat24);
+ assertEquals("aK:mm", ja_JP.timeFormat_hm);
+ assertEquals("H:mm", ja_JP.timeFormat_Hm);
}
}
diff --git a/luni/src/test/java/libcore/icu/RelativeDateTimeFormatterTest.java b/luni/src/test/java/libcore/icu/RelativeDateTimeFormatterTest.java
new file mode 100644
index 0000000..101896f
--- /dev/null
+++ b/luni/src/test/java/libcore/icu/RelativeDateTimeFormatterTest.java
@@ -0,0 +1,667 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package libcore.icu;
+
+import android.icu.util.ULocale;
+
+import java.util.Calendar;
+import java.util.Locale;
+import java.util.TimeZone;
+
+import static libcore.icu.DateUtilsBridge.FORMAT_ABBREV_ALL;
+import static libcore.icu.DateUtilsBridge.FORMAT_ABBREV_RELATIVE;
+import static libcore.icu.DateUtilsBridge.FORMAT_NO_YEAR;
+import static libcore.icu.DateUtilsBridge.FORMAT_NUMERIC_DATE;
+import static libcore.icu.DateUtilsBridge.FORMAT_SHOW_YEAR;
+import static libcore.icu.RelativeDateTimeFormatter.DAY_IN_MILLIS;
+import static libcore.icu.RelativeDateTimeFormatter.HOUR_IN_MILLIS;
+import static libcore.icu.RelativeDateTimeFormatter.MINUTE_IN_MILLIS;
+import static libcore.icu.RelativeDateTimeFormatter.SECOND_IN_MILLIS;
+import static libcore.icu.RelativeDateTimeFormatter.WEEK_IN_MILLIS;
+import static libcore.icu.RelativeDateTimeFormatter.YEAR_IN_MILLIS;
+import static libcore.icu.RelativeDateTimeFormatter.getRelativeDateTimeString;
+import static libcore.icu.RelativeDateTimeFormatter.getRelativeTimeSpanString;
+
+public class RelativeDateTimeFormatterTest extends junit.framework.TestCase {
+
+ // Tests adopted from CTS tests for DateUtils.getRelativeTimeSpanString.
+ public void test_getRelativeTimeSpanStringCTS() throws Exception {
+ Locale en_US = new Locale("en", "US");
+ TimeZone tz = TimeZone.getTimeZone("GMT");
+ Calendar cal = Calendar.getInstance(tz, en_US);
+ // Feb 5, 2015 at 10:50 GMT
+ cal.set(2015, Calendar.FEBRUARY, 5, 10, 50, 0);
+ final long baseTime = cal.getTimeInMillis();
+
+ assertEquals("0 minutes ago",
+ getRelativeTimeSpanString(en_US, tz, baseTime - SECOND_IN_MILLIS, baseTime,
+ MINUTE_IN_MILLIS, 0));
+ assertEquals("In 0 minutes",
+ getRelativeTimeSpanString(en_US, tz, baseTime + SECOND_IN_MILLIS, baseTime,
+ MINUTE_IN_MILLIS, 0));
+
+ assertEquals("1 minute ago",
+ getRelativeTimeSpanString(en_US, tz, 0, MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, 0));
+ assertEquals("In 1 minute",
+ getRelativeTimeSpanString(en_US, tz, MINUTE_IN_MILLIS, 0, MINUTE_IN_MILLIS, 0));
+
+ assertEquals("42 minutes ago",
+ getRelativeTimeSpanString(en_US, tz, baseTime - 42 * MINUTE_IN_MILLIS, baseTime,
+ MINUTE_IN_MILLIS, 0));
+ assertEquals("In 42 minutes",
+ getRelativeTimeSpanString(en_US, tz, baseTime + 42 * MINUTE_IN_MILLIS, baseTime,
+ MINUTE_IN_MILLIS, 0));
+
+ final long TWO_HOURS_IN_MS = 2 * HOUR_IN_MILLIS;
+ assertEquals("2 hours ago",
+ getRelativeTimeSpanString(en_US, tz, baseTime - TWO_HOURS_IN_MS, baseTime,
+ MINUTE_IN_MILLIS, FORMAT_NUMERIC_DATE));
+ assertEquals("In 2 hours",
+ getRelativeTimeSpanString(en_US, tz, baseTime + TWO_HOURS_IN_MS, baseTime,
+ MINUTE_IN_MILLIS, FORMAT_NUMERIC_DATE));
+
+ assertEquals("In 42 min.",
+ getRelativeTimeSpanString(en_US, tz, baseTime + (42 * MINUTE_IN_MILLIS), baseTime,
+ MINUTE_IN_MILLIS, FORMAT_ABBREV_RELATIVE));
+
+ assertEquals("Tomorrow",
+ getRelativeTimeSpanString(en_US, tz, DAY_IN_MILLIS, 0, DAY_IN_MILLIS, 0));
+ assertEquals("In 2 days",
+ getRelativeTimeSpanString(en_US, tz, 2 * DAY_IN_MILLIS, 0, DAY_IN_MILLIS, 0));
+ assertEquals("Yesterday",
+ getRelativeTimeSpanString(en_US, tz, 0, DAY_IN_MILLIS, DAY_IN_MILLIS, 0));
+ assertEquals("2 days ago",
+ getRelativeTimeSpanString(en_US, tz, 0, 2 * DAY_IN_MILLIS, DAY_IN_MILLIS, 0));
+
+ final long DAY_DURATION = 5 * 24 * 60 * 60 * 1000;
+ assertEquals("5 days ago",
+ getRelativeTimeSpanString(en_US, tz, baseTime - DAY_DURATION, baseTime,
+ DAY_IN_MILLIS, 0));
+ }
+
+ private void test_getRelativeTimeSpanString_helper(long delta, long minResolution, int flags,
+ String expectedInPast,
+ String expectedInFuture) throws Exception {
+ Locale en_US = new Locale("en", "US");
+ TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles");
+ Calendar cal = Calendar.getInstance(tz, en_US);
+ // Feb 5, 2015 at 10:50 PST
+ cal.set(2015, Calendar.FEBRUARY, 5, 10, 50, 0);
+ final long base = cal.getTimeInMillis();
+
+ assertEquals(expectedInPast,
+ getRelativeTimeSpanString(en_US, tz, base - delta, base, minResolution, flags));
+ assertEquals(expectedInFuture,
+ getRelativeTimeSpanString(en_US, tz, base + delta, base, minResolution, flags));
+ }
+
+ private void test_getRelativeTimeSpanString_helper(long delta, long minResolution,
+ String expectedInPast,
+ String expectedInFuture) throws Exception {
+ test_getRelativeTimeSpanString_helper(delta, minResolution, 0, expectedInPast, expectedInFuture);
+ }
+
+ public void test_getRelativeTimeSpanString() throws Exception {
+
+ test_getRelativeTimeSpanString_helper(0 * SECOND_IN_MILLIS, 0, "0 seconds ago", "0 seconds ago");
+ test_getRelativeTimeSpanString_helper(1 * MINUTE_IN_MILLIS, 0, "1 minute ago", "In 1 minute");
+ test_getRelativeTimeSpanString_helper(1 * MINUTE_IN_MILLIS, 0, "1 minute ago", "In 1 minute");
+ test_getRelativeTimeSpanString_helper(5 * DAY_IN_MILLIS, 0, "5 days ago", "In 5 days");
+
+ test_getRelativeTimeSpanString_helper(0 * SECOND_IN_MILLIS, SECOND_IN_MILLIS, "0 seconds ago",
+ "0 seconds ago");
+ test_getRelativeTimeSpanString_helper(1 * SECOND_IN_MILLIS, SECOND_IN_MILLIS, "1 second ago",
+ "In 1 second");
+ test_getRelativeTimeSpanString_helper(2 * SECOND_IN_MILLIS, SECOND_IN_MILLIS, "2 seconds ago",
+ "In 2 seconds");
+ test_getRelativeTimeSpanString_helper(25 * SECOND_IN_MILLIS, SECOND_IN_MILLIS, "25 seconds ago",
+ "In 25 seconds");
+ test_getRelativeTimeSpanString_helper(75 * SECOND_IN_MILLIS, SECOND_IN_MILLIS, "1 minute ago",
+ "In 1 minute");
+ test_getRelativeTimeSpanString_helper(5000 * SECOND_IN_MILLIS, SECOND_IN_MILLIS, "1 hour ago",
+ "In 1 hour");
+
+ test_getRelativeTimeSpanString_helper(0 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, "0 minutes ago",
+ "0 minutes ago");
+ test_getRelativeTimeSpanString_helper(1 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, "1 minute ago",
+ "In 1 minute");
+ test_getRelativeTimeSpanString_helper(2 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, "2 minutes ago",
+ "In 2 minutes");
+ test_getRelativeTimeSpanString_helper(25 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, "25 minutes ago",
+ "In 25 minutes");
+ test_getRelativeTimeSpanString_helper(75 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, "1 hour ago",
+ "In 1 hour");
+ test_getRelativeTimeSpanString_helper(720 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, "12 hours ago",
+ "In 12 hours");
+
+ test_getRelativeTimeSpanString_helper(0 * HOUR_IN_MILLIS, HOUR_IN_MILLIS, "0 hours ago",
+ "0 hours ago");
+ test_getRelativeTimeSpanString_helper(1 * HOUR_IN_MILLIS, HOUR_IN_MILLIS, "1 hour ago",
+ "In 1 hour");
+ test_getRelativeTimeSpanString_helper(2 * HOUR_IN_MILLIS, HOUR_IN_MILLIS, "2 hours ago",
+ "In 2 hours");
+ test_getRelativeTimeSpanString_helper(5 * HOUR_IN_MILLIS, HOUR_IN_MILLIS, "5 hours ago",
+ "In 5 hours");
+ test_getRelativeTimeSpanString_helper(20 * HOUR_IN_MILLIS, HOUR_IN_MILLIS, "20 hours ago",
+ "In 20 hours");
+
+ test_getRelativeTimeSpanString_helper(0 * DAY_IN_MILLIS, DAY_IN_MILLIS, "Today", "Today");
+ test_getRelativeTimeSpanString_helper(20 * HOUR_IN_MILLIS, DAY_IN_MILLIS, "Yesterday",
+ "Tomorrow");
+ test_getRelativeTimeSpanString_helper(24 * HOUR_IN_MILLIS, DAY_IN_MILLIS, "Yesterday",
+ "Tomorrow");
+ test_getRelativeTimeSpanString_helper(2 * DAY_IN_MILLIS, DAY_IN_MILLIS, "2 days ago",
+ "In 2 days");
+ test_getRelativeTimeSpanString_helper(25 * DAY_IN_MILLIS, DAY_IN_MILLIS, "January 11",
+ "March 2");
+
+ test_getRelativeTimeSpanString_helper(0 * WEEK_IN_MILLIS, WEEK_IN_MILLIS, "0 weeks ago",
+ "0 weeks ago");
+ test_getRelativeTimeSpanString_helper(1 * WEEK_IN_MILLIS, WEEK_IN_MILLIS, "1 week ago",
+ "In 1 week");
+ test_getRelativeTimeSpanString_helper(2 * WEEK_IN_MILLIS, WEEK_IN_MILLIS, "2 weeks ago",
+ "In 2 weeks");
+ test_getRelativeTimeSpanString_helper(25 * WEEK_IN_MILLIS, WEEK_IN_MILLIS, "25 weeks ago",
+ "In 25 weeks");
+
+ // duration >= minResolution
+ test_getRelativeTimeSpanString_helper(30 * SECOND_IN_MILLIS, 0, "30 seconds ago",
+ "In 30 seconds");
+ test_getRelativeTimeSpanString_helper(30 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS,
+ "30 minutes ago", "In 30 minutes");
+ test_getRelativeTimeSpanString_helper(30 * HOUR_IN_MILLIS, MINUTE_IN_MILLIS, "Yesterday",
+ "Tomorrow");
+ test_getRelativeTimeSpanString_helper(5 * DAY_IN_MILLIS, MINUTE_IN_MILLIS, "5 days ago",
+ "In 5 days");
+ test_getRelativeTimeSpanString_helper(30 * WEEK_IN_MILLIS, MINUTE_IN_MILLIS, "July 10, 2014",
+ "September 3");
+ test_getRelativeTimeSpanString_helper(5 * 365 * DAY_IN_MILLIS, MINUTE_IN_MILLIS,
+ "February 6, 2010", "February 4, 2020");
+
+ test_getRelativeTimeSpanString_helper(60 * SECOND_IN_MILLIS, MINUTE_IN_MILLIS, "1 minute ago",
+ "In 1 minute");
+ test_getRelativeTimeSpanString_helper(120 * SECOND_IN_MILLIS - 1, MINUTE_IN_MILLIS,
+ "1 minute ago", "In 1 minute");
+ test_getRelativeTimeSpanString_helper(60 * MINUTE_IN_MILLIS, HOUR_IN_MILLIS, "1 hour ago",
+ "In 1 hour");
+ test_getRelativeTimeSpanString_helper(120 * MINUTE_IN_MILLIS - 1, HOUR_IN_MILLIS, "1 hour ago",
+ "In 1 hour");
+ test_getRelativeTimeSpanString_helper(2 * HOUR_IN_MILLIS, DAY_IN_MILLIS, "Today", "Today");
+ test_getRelativeTimeSpanString_helper(12 * HOUR_IN_MILLIS, DAY_IN_MILLIS, "Yesterday",
+ "Today");
+ test_getRelativeTimeSpanString_helper(24 * HOUR_IN_MILLIS, DAY_IN_MILLIS, "Yesterday",
+ "Tomorrow");
+ test_getRelativeTimeSpanString_helper(48 * HOUR_IN_MILLIS, DAY_IN_MILLIS, "2 days ago",
+ "In 2 days");
+ test_getRelativeTimeSpanString_helper(45 * HOUR_IN_MILLIS, DAY_IN_MILLIS, "2 days ago",
+ "In 2 days");
+ test_getRelativeTimeSpanString_helper(7 * DAY_IN_MILLIS, WEEK_IN_MILLIS, "1 week ago",
+ "In 1 week");
+ test_getRelativeTimeSpanString_helper(14 * DAY_IN_MILLIS - 1, WEEK_IN_MILLIS, "1 week ago",
+ "In 1 week");
+
+ // duration < minResolution
+ test_getRelativeTimeSpanString_helper(59 * SECOND_IN_MILLIS, MINUTE_IN_MILLIS, "0 minutes ago",
+ "In 0 minutes");
+ test_getRelativeTimeSpanString_helper(59 * MINUTE_IN_MILLIS, HOUR_IN_MILLIS, "0 hours ago",
+ "In 0 hours");
+ test_getRelativeTimeSpanString_helper(HOUR_IN_MILLIS - 1, HOUR_IN_MILLIS, "0 hours ago",
+ "In 0 hours");
+ test_getRelativeTimeSpanString_helper(DAY_IN_MILLIS - 1, DAY_IN_MILLIS, "Yesterday",
+ "Tomorrow");
+ test_getRelativeTimeSpanString_helper(20 * SECOND_IN_MILLIS, WEEK_IN_MILLIS, "0 weeks ago",
+ "In 0 weeks");
+ test_getRelativeTimeSpanString_helper(WEEK_IN_MILLIS - 1, WEEK_IN_MILLIS, "0 weeks ago",
+ "In 0 weeks");
+ }
+
+ public void test_getRelativeTimeSpanStringAbbrev() throws Exception {
+ int flags = FORMAT_ABBREV_RELATIVE;
+
+ test_getRelativeTimeSpanString_helper(0 * SECOND_IN_MILLIS, 0, flags, "0 sec. ago",
+ "0 sec. ago");
+ test_getRelativeTimeSpanString_helper(1 * MINUTE_IN_MILLIS, 0, flags, "1 min. ago",
+ "In 1 min.");
+ test_getRelativeTimeSpanString_helper(5 * DAY_IN_MILLIS, 0, flags, "5 days ago", "In 5 days");
+
+ test_getRelativeTimeSpanString_helper(0 * SECOND_IN_MILLIS, SECOND_IN_MILLIS, flags,
+ "0 sec. ago", "0 sec. ago");
+ test_getRelativeTimeSpanString_helper(1 * SECOND_IN_MILLIS, SECOND_IN_MILLIS, flags,
+ "1 sec. ago", "In 1 sec.");
+ test_getRelativeTimeSpanString_helper(2 * SECOND_IN_MILLIS, SECOND_IN_MILLIS, flags,
+ "2 sec. ago", "In 2 sec.");
+ test_getRelativeTimeSpanString_helper(25 * SECOND_IN_MILLIS, SECOND_IN_MILLIS, flags,
+ "25 sec. ago", "In 25 sec.");
+ test_getRelativeTimeSpanString_helper(75 * SECOND_IN_MILLIS, SECOND_IN_MILLIS, flags,
+ "1 min. ago", "In 1 min.");
+ test_getRelativeTimeSpanString_helper(5000 * SECOND_IN_MILLIS, SECOND_IN_MILLIS, flags,
+ "1 hr. ago", "In 1 hr.");
+
+ test_getRelativeTimeSpanString_helper(0 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, flags,
+ "0 min. ago", "0 min. ago");
+ test_getRelativeTimeSpanString_helper(1 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, flags,
+ "1 min. ago", "In 1 min.");
+ test_getRelativeTimeSpanString_helper(2 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, flags,
+ "2 min. ago", "In 2 min.");
+ test_getRelativeTimeSpanString_helper(25 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, flags,
+ "25 min. ago", "In 25 min.");
+ test_getRelativeTimeSpanString_helper(75 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, flags,
+ "1 hr. ago", "In 1 hr.");
+ test_getRelativeTimeSpanString_helper(720 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, flags,
+ "12 hr. ago", "In 12 hr.");
+
+ test_getRelativeTimeSpanString_helper(0 * HOUR_IN_MILLIS, HOUR_IN_MILLIS, flags,
+ "0 hr. ago", "0 hr. ago");
+ test_getRelativeTimeSpanString_helper(1 * HOUR_IN_MILLIS, HOUR_IN_MILLIS, flags,
+ "1 hr. ago", "In 1 hr.");
+ test_getRelativeTimeSpanString_helper(2 * HOUR_IN_MILLIS, HOUR_IN_MILLIS, flags,
+ "2 hr. ago", "In 2 hr.");
+ test_getRelativeTimeSpanString_helper(5 * HOUR_IN_MILLIS, HOUR_IN_MILLIS, flags,
+ "5 hr. ago", "In 5 hr.");
+ test_getRelativeTimeSpanString_helper(20 * HOUR_IN_MILLIS, HOUR_IN_MILLIS, flags,
+ "20 hr. ago", "In 20 hr.");
+
+ test_getRelativeTimeSpanString_helper(0 * DAY_IN_MILLIS, DAY_IN_MILLIS, flags, "Today",
+ "Today");
+ test_getRelativeTimeSpanString_helper(20 * HOUR_IN_MILLIS, DAY_IN_MILLIS, flags,
+ "Yesterday", "Tomorrow");
+ test_getRelativeTimeSpanString_helper(24 * HOUR_IN_MILLIS, DAY_IN_MILLIS, flags,
+ "Yesterday", "Tomorrow");
+ test_getRelativeTimeSpanString_helper(2 * DAY_IN_MILLIS, DAY_IN_MILLIS, flags,
+ "2 days ago", "In 2 days");
+ test_getRelativeTimeSpanString_helper(25 * DAY_IN_MILLIS, DAY_IN_MILLIS, flags,
+ "January 11", "March 2");
+
+ test_getRelativeTimeSpanString_helper(0 * WEEK_IN_MILLIS, WEEK_IN_MILLIS, flags,
+ "0 wk. ago", "0 wk. ago");
+ test_getRelativeTimeSpanString_helper(1 * WEEK_IN_MILLIS, WEEK_IN_MILLIS, flags,
+ "1 wk. ago", "In 1 wk.");
+ test_getRelativeTimeSpanString_helper(2 * WEEK_IN_MILLIS, WEEK_IN_MILLIS, flags,
+ "2 wk. ago", "In 2 wk.");
+ test_getRelativeTimeSpanString_helper(25 * WEEK_IN_MILLIS, WEEK_IN_MILLIS, flags,
+ "25 wk. ago", "In 25 wk.");
+
+ // duration >= minResolution
+ test_getRelativeTimeSpanString_helper(30 * SECOND_IN_MILLIS, 0, flags, "30 sec. ago",
+ "In 30 sec.");
+ test_getRelativeTimeSpanString_helper(30 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, flags,
+ "30 min. ago", "In 30 min.");
+ test_getRelativeTimeSpanString_helper(30 * HOUR_IN_MILLIS, MINUTE_IN_MILLIS, flags,
+ "Yesterday", "Tomorrow");
+ test_getRelativeTimeSpanString_helper(5 * DAY_IN_MILLIS, MINUTE_IN_MILLIS, flags,
+ "5 days ago", "In 5 days");
+ test_getRelativeTimeSpanString_helper(30 * WEEK_IN_MILLIS, MINUTE_IN_MILLIS, flags,
+ "July 10, 2014", "September 3");
+ test_getRelativeTimeSpanString_helper(5 * 365 * DAY_IN_MILLIS, MINUTE_IN_MILLIS, flags,
+ "February 6, 2010", "February 4, 2020");
+
+ test_getRelativeTimeSpanString_helper(60 * SECOND_IN_MILLIS, MINUTE_IN_MILLIS, flags,
+ "1 min. ago", "In 1 min.");
+ test_getRelativeTimeSpanString_helper(120 * SECOND_IN_MILLIS - 1, MINUTE_IN_MILLIS, flags,
+ "1 min. ago", "In 1 min.");
+ test_getRelativeTimeSpanString_helper(60 * MINUTE_IN_MILLIS, HOUR_IN_MILLIS, flags,
+ "1 hr. ago", "In 1 hr.");
+ test_getRelativeTimeSpanString_helper(120 * MINUTE_IN_MILLIS - 1, HOUR_IN_MILLIS, flags,
+ "1 hr. ago", "In 1 hr.");
+ test_getRelativeTimeSpanString_helper(2 * HOUR_IN_MILLIS, DAY_IN_MILLIS, flags, "Today",
+ "Today");
+ test_getRelativeTimeSpanString_helper(12 * HOUR_IN_MILLIS, DAY_IN_MILLIS, flags,
+ "Yesterday", "Today");
+ test_getRelativeTimeSpanString_helper(24 * HOUR_IN_MILLIS, DAY_IN_MILLIS, flags,
+ "Yesterday", "Tomorrow");
+ test_getRelativeTimeSpanString_helper(48 * HOUR_IN_MILLIS, DAY_IN_MILLIS, flags,
+ "2 days ago", "In 2 days");
+ test_getRelativeTimeSpanString_helper(45 * HOUR_IN_MILLIS, DAY_IN_MILLIS, flags,
+ "2 days ago", "In 2 days");
+ test_getRelativeTimeSpanString_helper(7 * DAY_IN_MILLIS, WEEK_IN_MILLIS, flags,
+ "1 wk. ago", "In 1 wk.");
+ test_getRelativeTimeSpanString_helper(14 * DAY_IN_MILLIS - 1, WEEK_IN_MILLIS, flags,
+ "1 wk. ago", "In 1 wk.");
+
+ // duration < minResolution
+ test_getRelativeTimeSpanString_helper(59 * SECOND_IN_MILLIS, MINUTE_IN_MILLIS, flags,
+ "0 min. ago", "In 0 min.");
+ test_getRelativeTimeSpanString_helper(59 * MINUTE_IN_MILLIS, HOUR_IN_MILLIS, flags,
+ "0 hr. ago", "In 0 hr.");
+ test_getRelativeTimeSpanString_helper(HOUR_IN_MILLIS - 1, HOUR_IN_MILLIS, flags,
+ "0 hr. ago", "In 0 hr.");
+ test_getRelativeTimeSpanString_helper(DAY_IN_MILLIS - 1, DAY_IN_MILLIS, flags,
+ "Yesterday", "Tomorrow");
+ test_getRelativeTimeSpanString_helper(20 * SECOND_IN_MILLIS, WEEK_IN_MILLIS, flags,
+ "0 wk. ago", "In 0 wk.");
+ test_getRelativeTimeSpanString_helper(WEEK_IN_MILLIS - 1, WEEK_IN_MILLIS, flags,
+ "0 wk. ago", "In 0 wk.");
+
+ }
+
+ public void test_getRelativeTimeSpanStringGerman() throws Exception {
+ // Bug: 19744876
+ // We need to specify the timezone and the time explicitly. Otherwise it
+ // may not always give a correct answer of "tomorrow" by using
+ // (now + DAY_IN_MILLIS).
+ Locale de_DE = new Locale("de", "DE");
+ TimeZone tz = TimeZone.getTimeZone("Europe/Berlin");
+ Calendar cal = Calendar.getInstance(tz, de_DE);
+ // Feb 5, 2015 at 10:50 CET
+ cal.set(2015, Calendar.FEBRUARY, 5, 10, 50, 0);
+ final long now = cal.getTimeInMillis();
+
+ // 42 minutes ago
+ assertEquals("Vor 42 Minuten", getRelativeTimeSpanString(de_DE, tz,
+ now - 42 * MINUTE_IN_MILLIS, now, MINUTE_IN_MILLIS, 0));
+ // In 42 minutes
+ assertEquals("In 42 Minuten", getRelativeTimeSpanString(de_DE, tz,
+ now + 42 * MINUTE_IN_MILLIS, now, MINUTE_IN_MILLIS, 0));
+ // Yesterday
+ assertEquals("Gestern", getRelativeTimeSpanString(de_DE, tz,
+ now - DAY_IN_MILLIS, now, DAY_IN_MILLIS, 0));
+ // The day before yesterday
+ assertEquals("Vorgestern", getRelativeTimeSpanString(de_DE, tz,
+ now - 2 * DAY_IN_MILLIS, now, DAY_IN_MILLIS, 0));
+ // Tomorrow
+ assertEquals("Morgen", getRelativeTimeSpanString(de_DE, tz,
+ now + DAY_IN_MILLIS, now, DAY_IN_MILLIS, 0));
+ // The day after tomorrow
+ assertEquals("Übermorgen", getRelativeTimeSpanString(de_DE, tz,
+ now + 2 * DAY_IN_MILLIS, now, DAY_IN_MILLIS, 0));
+ }
+
+ public void test_getRelativeTimeSpanStringFrench() throws Exception {
+ Locale fr_FR = new Locale("fr", "FR");
+ TimeZone tz = TimeZone.getTimeZone("Europe/Paris");
+ Calendar cal = Calendar.getInstance(tz, fr_FR);
+ // Feb 5, 2015 at 10:50 CET
+ cal.set(2015, Calendar.FEBRUARY, 5, 10, 50, 0);
+ final long now = cal.getTimeInMillis();
+
+ // 42 minutes ago
+ assertEquals("Il y a 42 minutes", getRelativeTimeSpanString(fr_FR, tz,
+ now - (42 * MINUTE_IN_MILLIS), now, MINUTE_IN_MILLIS, 0));
+ // In 42 minutes
+ assertEquals("Dans 42 minutes", getRelativeTimeSpanString(fr_FR, tz,
+ now + (42 * MINUTE_IN_MILLIS), now, MINUTE_IN_MILLIS, 0));
+ // Yesterday
+ assertEquals("Hier", getRelativeTimeSpanString(fr_FR, tz,
+ now - DAY_IN_MILLIS, now, DAY_IN_MILLIS, 0));
+ // The day before yesterday
+ assertEquals("Avant-hier", getRelativeTimeSpanString(fr_FR, tz,
+ now - 2 * DAY_IN_MILLIS, now, DAY_IN_MILLIS, 0));
+ // Tomorrow
+ assertEquals("Demain", getRelativeTimeSpanString(fr_FR, tz,
+ now + DAY_IN_MILLIS, now, DAY_IN_MILLIS, 0));
+ // The day after tomorrow
+ assertEquals("Après-demain", getRelativeTimeSpanString(fr_FR, tz,
+ now + 2 * DAY_IN_MILLIS, now, DAY_IN_MILLIS, 0));
+ }
+
+ // Tests adopted from CTS tests for DateUtils.getRelativeDateTimeString.
+ public void test_getRelativeDateTimeStringCTS() throws Exception {
+ Locale en_US = Locale.getDefault();
+ TimeZone tz = TimeZone.getDefault();
+ final long baseTime = System.currentTimeMillis();
+
+ final long DAY_DURATION = 5 * 24 * 60 * 60 * 1000;
+ assertNotNull(getRelativeDateTimeString(en_US, tz, baseTime - DAY_DURATION, baseTime,
+ MINUTE_IN_MILLIS, DAY_IN_MILLIS,
+ FORMAT_NUMERIC_DATE));
+ }
+
+ public void test_getRelativeDateTimeString() throws Exception {
+ Locale en_US = new Locale("en", "US");
+ TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles");
+ Calendar cal = Calendar.getInstance(tz, en_US);
+ // Feb 5, 2015 at 10:50 PST
+ cal.set(2015, Calendar.FEBRUARY, 5, 10, 50, 0);
+ final long base = cal.getTimeInMillis();
+
+ assertEquals("5 seconds ago, 10:49 AM",
+ getRelativeDateTimeString(en_US, tz, base - 5 * SECOND_IN_MILLIS, base, 0,
+ MINUTE_IN_MILLIS, 0));
+ assertEquals("5 min. ago, 10:45 AM",
+ getRelativeDateTimeString(en_US, tz, base - 5 * MINUTE_IN_MILLIS, base, 0,
+ HOUR_IN_MILLIS, FORMAT_ABBREV_RELATIVE));
+ assertEquals("0 hr. ago, 10:45 AM",
+ getRelativeDateTimeString(en_US, tz, base - 5 * MINUTE_IN_MILLIS, base,
+ HOUR_IN_MILLIS, DAY_IN_MILLIS, FORMAT_ABBREV_RELATIVE));
+ assertEquals("5 hours ago, 5:50 AM",
+ getRelativeDateTimeString(en_US, tz, base - 5 * HOUR_IN_MILLIS, base,
+ HOUR_IN_MILLIS, DAY_IN_MILLIS, 0));
+ assertEquals("Yesterday, 7:50 PM",
+ getRelativeDateTimeString(en_US, tz, base - 15 * HOUR_IN_MILLIS, base, 0,
+ WEEK_IN_MILLIS, FORMAT_ABBREV_RELATIVE));
+ assertEquals("5 days ago, 10:50 AM",
+ getRelativeDateTimeString(en_US, tz, base - 5 * DAY_IN_MILLIS, base, 0,
+ WEEK_IN_MILLIS, 0));
+ assertEquals("Jan 29, 10:50 AM",
+ getRelativeDateTimeString(en_US, tz, base - 7 * DAY_IN_MILLIS, base, 0,
+ WEEK_IN_MILLIS, 0));
+ assertEquals("11/27/2014, 10:50 AM",
+ getRelativeDateTimeString(en_US, tz, base - 10 * WEEK_IN_MILLIS, base, 0,
+ WEEK_IN_MILLIS, 0));
+ assertEquals("11/27/2014, 10:50 AM",
+ getRelativeDateTimeString(en_US, tz, base - 10 * WEEK_IN_MILLIS, base, 0,
+ YEAR_IN_MILLIS, 0));
+
+ // User-supplied flags should be ignored when formatting the date clause.
+ final int FORMAT_SHOW_WEEKDAY = 0x00002;
+ assertEquals("11/27/2014, 10:50 AM",
+ getRelativeDateTimeString(en_US, tz, base - 10 * WEEK_IN_MILLIS, base, 0,
+ WEEK_IN_MILLIS,
+ FORMAT_ABBREV_ALL | FORMAT_SHOW_WEEKDAY));
+ }
+
+ public void test_getRelativeDateTimeStringDST() throws Exception {
+ Locale en_US = new Locale("en", "US");
+ TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles");
+ Calendar cal = Calendar.getInstance(tz, en_US);
+
+ // DST starts on Mar 9, 2014 at 2:00 AM.
+ // So 5 hours before 3:15 AM should be formatted as 'Yesterday, 9:15 PM'.
+ cal.set(2014, Calendar.MARCH, 9, 3, 15, 0);
+ long base = cal.getTimeInMillis();
+ assertEquals("Yesterday, 9:15 PM",
+ getRelativeDateTimeString(en_US, tz, base - 5 * HOUR_IN_MILLIS, base, 0,
+ WEEK_IN_MILLIS, 0));
+
+ // 1 hour after 2:00 AM should be formatted as 'In 1 hour, 4:00 AM'.
+ cal.set(2014, Calendar.MARCH, 9, 2, 0, 0);
+ base = cal.getTimeInMillis();
+ assertEquals("In 1 hour, 4:00 AM",
+ getRelativeDateTimeString(en_US, tz, base + 1 * HOUR_IN_MILLIS, base, 0,
+ WEEK_IN_MILLIS, 0));
+
+ // DST ends on Nov 2, 2014 at 2:00 AM. Clocks are turned backward 1 hour to
+ // 1:00 AM. 8 hours before 5:20 AM should be 'Yesterday, 10:20 PM'.
+ cal.set(2014, Calendar.NOVEMBER, 2, 5, 20, 0);
+ base = cal.getTimeInMillis();
+ assertEquals("Yesterday, 10:20 PM",
+ getRelativeDateTimeString(en_US, tz, base - 8 * HOUR_IN_MILLIS, base, 0,
+ WEEK_IN_MILLIS, 0));
+
+ cal.set(2014, Calendar.NOVEMBER, 2, 0, 45, 0);
+ base = cal.getTimeInMillis();
+ // 45 minutes after 0:45 AM should be 'In 45 minutes, 1:30 AM'.
+ assertEquals("In 45 minutes, 1:30 AM",
+ getRelativeDateTimeString(en_US, tz, base + 45 * MINUTE_IN_MILLIS, base, 0,
+ WEEK_IN_MILLIS, 0));
+ // 45 minutes later, it should be 'In 45 minutes, 1:15 AM'.
+ assertEquals("In 45 minutes, 1:15 AM",
+ getRelativeDateTimeString(en_US, tz, base + 90 * MINUTE_IN_MILLIS,
+ base + 45 * MINUTE_IN_MILLIS, 0, WEEK_IN_MILLIS, 0));
+ // Another 45 minutes later, it should be 'In 45 minutes, 2:00 AM'.
+ assertEquals("In 45 minutes, 2:00 AM",
+ getRelativeDateTimeString(en_US, tz, base + 135 * MINUTE_IN_MILLIS,
+ base + 90 * MINUTE_IN_MILLIS, 0, WEEK_IN_MILLIS, 0));
+ }
+
+
+ public void test_getRelativeDateTimeStringItalian() throws Exception {
+ Locale it_IT = new Locale("it", "IT");
+ TimeZone tz = TimeZone.getTimeZone("Europe/Rome");
+ Calendar cal = Calendar.getInstance(tz, it_IT);
+ // 05 febbraio 2015 20:15
+ cal.set(2015, Calendar.FEBRUARY, 5, 20, 15, 0);
+ final long base = cal.getTimeInMillis();
+
+ assertEquals("5 secondi fa, 20:14",
+ getRelativeDateTimeString(it_IT, tz, base - 5 * SECOND_IN_MILLIS, base, 0,
+ MINUTE_IN_MILLIS, 0));
+ assertEquals("5 min. fa, 20:10",
+ getRelativeDateTimeString(it_IT, tz, base - 5 * MINUTE_IN_MILLIS, base, 0,
+ HOUR_IN_MILLIS, FORMAT_ABBREV_RELATIVE));
+ assertEquals("0 h. fa, 20:10",
+ getRelativeDateTimeString(it_IT, tz, base - 5 * MINUTE_IN_MILLIS, base,
+ HOUR_IN_MILLIS, DAY_IN_MILLIS, FORMAT_ABBREV_RELATIVE));
+ assertEquals("Ieri, 22:15",
+ getRelativeDateTimeString(it_IT, tz, base - 22 * HOUR_IN_MILLIS, base, 0,
+ WEEK_IN_MILLIS, FORMAT_ABBREV_RELATIVE));
+ assertEquals("5 giorni fa, 20:15",
+ getRelativeDateTimeString(it_IT, tz, base - 5 * DAY_IN_MILLIS, base, 0,
+ WEEK_IN_MILLIS, 0));
+ assertEquals("27/11/2014, 20:15",
+ getRelativeDateTimeString(it_IT, tz, base - 10 * WEEK_IN_MILLIS, base, 0,
+ WEEK_IN_MILLIS, 0));
+ }
+
+ // http://b/5252772: detect the actual date difference
+ public void test5252772() throws Exception {
+ Locale en_US = new Locale("en", "US");
+ TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles");
+
+ // Now is Sep 2, 2011, 10:23 AM PDT.
+ Calendar nowCalendar = Calendar.getInstance(tz, en_US);
+ nowCalendar.set(2011, Calendar.SEPTEMBER, 2, 10, 23, 0);
+ final long now = nowCalendar.getTimeInMillis();
+
+ // Sep 1, 2011, 10:24 AM
+ Calendar yesterdayCalendar1 = Calendar.getInstance(tz, en_US);
+ yesterdayCalendar1.set(2011, Calendar.SEPTEMBER, 1, 10, 24, 0);
+ long yesterday1 = yesterdayCalendar1.getTimeInMillis();
+ assertEquals("Yesterday, 10:24 AM",
+ getRelativeDateTimeString(en_US, tz, yesterday1, now, MINUTE_IN_MILLIS,
+ WEEK_IN_MILLIS, 0));
+
+ // Sep 1, 2011, 10:22 AM
+ Calendar yesterdayCalendar2 = Calendar.getInstance(tz, en_US);
+ yesterdayCalendar2.set(2011, Calendar.SEPTEMBER, 1, 10, 22, 0);
+ long yesterday2 = yesterdayCalendar2.getTimeInMillis();
+ assertEquals("Yesterday, 10:22 AM",
+ getRelativeDateTimeString(en_US, tz, yesterday2, now, MINUTE_IN_MILLIS,
+ WEEK_IN_MILLIS, 0));
+
+ // Aug 31, 2011, 10:24 AM
+ Calendar twoDaysAgoCalendar1 = Calendar.getInstance(tz, en_US);
+ twoDaysAgoCalendar1.set(2011, Calendar.AUGUST, 31, 10, 24, 0);
+ long twoDaysAgo1 = twoDaysAgoCalendar1.getTimeInMillis();
+ assertEquals("2 days ago, 10:24 AM",
+ getRelativeDateTimeString(en_US, tz, twoDaysAgo1, now, MINUTE_IN_MILLIS,
+ WEEK_IN_MILLIS, 0));
+
+ // Aug 31, 2011, 10:22 AM
+ Calendar twoDaysAgoCalendar2 = Calendar.getInstance(tz, en_US);
+ twoDaysAgoCalendar2.set(2011, Calendar.AUGUST, 31, 10, 22, 0);
+ long twoDaysAgo2 = twoDaysAgoCalendar2.getTimeInMillis();
+ assertEquals("2 days ago, 10:22 AM",
+ getRelativeDateTimeString(en_US, tz, twoDaysAgo2, now, MINUTE_IN_MILLIS,
+ WEEK_IN_MILLIS, 0));
+
+ // Sep 3, 2011, 10:22 AM
+ Calendar tomorrowCalendar1 = Calendar.getInstance(tz, en_US);
+ tomorrowCalendar1.set(2011, Calendar.SEPTEMBER, 3, 10, 22, 0);
+ long tomorrow1 = tomorrowCalendar1.getTimeInMillis();
+ assertEquals("Tomorrow, 10:22 AM",
+ getRelativeDateTimeString(en_US, tz, tomorrow1, now, MINUTE_IN_MILLIS,
+ WEEK_IN_MILLIS, 0));
+
+ // Sep 3, 2011, 10:24 AM
+ Calendar tomorrowCalendar2 = Calendar.getInstance(tz, en_US);
+ tomorrowCalendar2.set(2011, Calendar.SEPTEMBER, 3, 10, 24, 0);
+ long tomorrow2 = tomorrowCalendar2.getTimeInMillis();
+ assertEquals("Tomorrow, 10:24 AM",
+ getRelativeDateTimeString(en_US, tz, tomorrow2, now, MINUTE_IN_MILLIS,
+ WEEK_IN_MILLIS, 0));
+
+ // Sep 4, 2011, 10:22 AM
+ Calendar twoDaysLaterCalendar1 = Calendar.getInstance(tz, en_US);
+ twoDaysLaterCalendar1.set(2011, Calendar.SEPTEMBER, 4, 10, 22, 0);
+ long twoDaysLater1 = twoDaysLaterCalendar1.getTimeInMillis();
+ assertEquals("In 2 days, 10:22 AM",
+ getRelativeDateTimeString(en_US, tz, twoDaysLater1, now, MINUTE_IN_MILLIS,
+ WEEK_IN_MILLIS, 0));
+
+ // Sep 4, 2011, 10:24 AM
+ Calendar twoDaysLaterCalendar2 = Calendar.getInstance(tz, en_US);
+ twoDaysLaterCalendar2.set(2011, Calendar.SEPTEMBER, 4, 10, 24, 0);
+ long twoDaysLater2 = twoDaysLaterCalendar2.getTimeInMillis();
+ assertEquals("In 2 days, 10:24 AM",
+ getRelativeDateTimeString(en_US, tz, twoDaysLater2, now, MINUTE_IN_MILLIS,
+ WEEK_IN_MILLIS, 0));
+ }
+
+ // b/19822016: show / hide the year based on the dates in the arguments.
+ public void test_bug19822016() throws Exception {
+ Locale en_US = new Locale("en", "US");
+ TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles");
+ Calendar cal = Calendar.getInstance(tz, en_US);
+ // Feb 5, 2012 at 10:50 PST
+ cal.set(2012, Calendar.FEBRUARY, 5, 10, 50, 0);
+ long base = cal.getTimeInMillis();
+
+ assertEquals("Feb 5, 5:50 AM", getRelativeDateTimeString(en_US, tz,
+ base - 5 * HOUR_IN_MILLIS, base, 0, MINUTE_IN_MILLIS, 0));
+ assertEquals("Jan 29, 10:50 AM", getRelativeDateTimeString(en_US, tz,
+ base - 7 * DAY_IN_MILLIS, base, 0, WEEK_IN_MILLIS, 0));
+ assertEquals("11/27/2011, 10:50 AM", getRelativeDateTimeString(en_US, tz,
+ base - 10 * WEEK_IN_MILLIS, base, 0, WEEK_IN_MILLIS, 0));
+
+ assertEquals("January 6", getRelativeTimeSpanString(en_US, tz,
+ base - 30 * DAY_IN_MILLIS, base, DAY_IN_MILLIS, 0));
+ assertEquals("January 6", getRelativeTimeSpanString(en_US, tz,
+ base - 30 * DAY_IN_MILLIS, base, DAY_IN_MILLIS, FORMAT_NO_YEAR));
+ assertEquals("January 6, 2012", getRelativeTimeSpanString(en_US, tz,
+ base - 30 * DAY_IN_MILLIS, base, DAY_IN_MILLIS, FORMAT_SHOW_YEAR));
+ assertEquals("December 7, 2011", getRelativeTimeSpanString(en_US, tz,
+ base - 60 * DAY_IN_MILLIS, base, DAY_IN_MILLIS, 0));
+ assertEquals("December 7, 2011", getRelativeTimeSpanString(en_US, tz,
+ base - 60 * DAY_IN_MILLIS, base, DAY_IN_MILLIS, FORMAT_SHOW_YEAR));
+ assertEquals("December 7", getRelativeTimeSpanString(en_US, tz,
+ base - 60 * DAY_IN_MILLIS, base, DAY_IN_MILLIS, FORMAT_NO_YEAR));
+
+ // Feb 5, 2018 at 10:50 PST
+ cal.set(2018, Calendar.FEBRUARY, 5, 10, 50, 0);
+ base = cal.getTimeInMillis();
+ assertEquals("Feb 5, 5:50 AM", getRelativeDateTimeString(en_US, tz,
+ base - 5 * HOUR_IN_MILLIS, base, 0, MINUTE_IN_MILLIS, 0));
+ assertEquals("Jan 29, 10:50 AM", getRelativeDateTimeString(en_US, tz,
+ base - 7 * DAY_IN_MILLIS, base, 0, WEEK_IN_MILLIS, 0));
+ assertEquals("11/27/2017, 10:50 AM", getRelativeDateTimeString(en_US, tz,
+ base - 10 * WEEK_IN_MILLIS, base, 0, WEEK_IN_MILLIS, 0));
+
+ assertEquals("January 6", getRelativeTimeSpanString(en_US, tz,
+ base - 30 * DAY_IN_MILLIS, base, DAY_IN_MILLIS, 0));
+ assertEquals("January 6", getRelativeTimeSpanString(en_US, tz,
+ base - 30 * DAY_IN_MILLIS, base, DAY_IN_MILLIS, FORMAT_NO_YEAR));
+ assertEquals("January 6, 2018", getRelativeTimeSpanString(en_US, tz,
+ base - 30 * DAY_IN_MILLIS, base, DAY_IN_MILLIS, FORMAT_SHOW_YEAR));
+ assertEquals("December 7, 2017", getRelativeTimeSpanString(en_US, tz,
+ base - 60 * DAY_IN_MILLIS, base, DAY_IN_MILLIS, 0));
+ assertEquals("December 7, 2017", getRelativeTimeSpanString(en_US, tz,
+ base - 60 * DAY_IN_MILLIS, base, DAY_IN_MILLIS, FORMAT_SHOW_YEAR));
+ assertEquals("December 7", getRelativeTimeSpanString(en_US, tz,
+ base - 60 * DAY_IN_MILLIS, base, DAY_IN_MILLIS, FORMAT_NO_YEAR));
+ }
+}
diff --git a/luni/src/test/java/libcore/io/OsTest.java b/luni/src/test/java/libcore/io/OsTest.java
index a0d1e5a..e648e8a 100644
--- a/luni/src/test/java/libcore/io/OsTest.java
+++ b/luni/src/test/java/libcore/io/OsTest.java
@@ -16,18 +16,26 @@
package libcore.io;
+import android.system.ErrnoException;
+import android.system.NetlinkSocketAddress;
+import android.system.PacketSocketAddress;
+import android.system.StructTimeval;
import android.system.StructUcred;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.InetUnixAddress;
+import java.net.NetworkInterface;
import java.net.ServerSocket;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
import java.util.Locale;
import junit.framework.TestCase;
import static android.system.OsConstants.*;
@@ -44,6 +52,20 @@ public class OsTest extends TestCase {
s.close();
}
+ public void testFcntlInt() throws Exception {
+ File f = File.createTempFile("OsTest", "tst");
+ FileInputStream fis = null;
+ try {
+ fis = new FileInputStream(f);
+ Libcore.os.fcntlInt(fis.getFD(), F_SETFD, FD_CLOEXEC);
+ int flags = Libcore.os.fcntlVoid(fis.getFD(), F_GETFD);
+ assertTrue((flags & FD_CLOEXEC) != 0);
+ } finally {
+ IoUtils.closeQuietly(fis);
+ f.delete();
+ }
+ }
+
public void testUnixDomainSockets_in_file_system() throws Exception {
String path = System.getProperty("java.io.tmpdir") + "/test_unix_socket";
new File(path).delete();
@@ -196,9 +218,10 @@ public class OsTest extends TestCase {
fis.close();
}
- public void test_byteBufferPositions_sendto_recvfrom() throws Exception {
- final FileDescriptor serverFd = Libcore.os.socket(AF_INET6, SOCK_STREAM, 0);
- Libcore.os.bind(serverFd, InetAddress.getLoopbackAddress(), 0);
+ static void checkByteBufferPositions_sendto_recvfrom(
+ int family, InetAddress loopback) throws Exception {
+ final FileDescriptor serverFd = Libcore.os.socket(family, SOCK_STREAM, 0);
+ Libcore.os.bind(serverFd, loopback, 0);
Libcore.os.listen(serverFd, 5);
InetSocketAddress address = (InetSocketAddress) Libcore.os.getsockname(serverFd);
@@ -232,7 +255,7 @@ public class OsTest extends TestCase {
server.start();
- FileDescriptor clientFd = Libcore.os.socket(AF_INET6, SOCK_STREAM, 0);
+ FileDescriptor clientFd = Libcore.os.socket(family, SOCK_STREAM, 0);
Libcore.os.connect(clientFd, address.getAddress(), address.getPort());
final byte[] bytes = "good bye, cruel black hole with fancy distortion".getBytes(StandardCharsets.US_ASCII);
@@ -254,4 +277,146 @@ public class OsTest extends TestCase {
Libcore.os.close(clientFd);
}
+
+ public void test_NetlinkSocket() throws Exception {
+ FileDescriptor nlSocket = Libcore.os.socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
+ Libcore.os.bind(nlSocket, new NetlinkSocketAddress());
+ NetlinkSocketAddress address = (NetlinkSocketAddress) Libcore.os.getsockname(nlSocket);
+ assertTrue(address.getPortId() > 0);
+ assertEquals(0, address.getGroupsMask());
+
+ NetlinkSocketAddress nlKernel = new NetlinkSocketAddress();
+ Libcore.os.connect(nlSocket, nlKernel);
+ NetlinkSocketAddress nlPeer = (NetlinkSocketAddress) Libcore.os.getpeername(nlSocket);
+ assertEquals(0, nlPeer.getPortId());
+ assertEquals(0, nlPeer.getGroupsMask());
+ Libcore.os.close(nlSocket);
+ }
+
+ public void test_PacketSocketAddress() throws Exception {
+ NetworkInterface lo = NetworkInterface.getByName("lo");
+ FileDescriptor fd = Libcore.os.socket(AF_PACKET, SOCK_DGRAM, ETH_P_IPV6);
+ PacketSocketAddress addr = new PacketSocketAddress((short) ETH_P_IPV6, lo.getIndex());
+ Libcore.os.bind(fd, addr);
+
+ PacketSocketAddress bound = (PacketSocketAddress) Libcore.os.getsockname(fd);
+ assertEquals((short) ETH_P_IPV6, bound.sll_protocol); // ETH_P_IPV6 is an int.
+ assertEquals(lo.getIndex(), bound.sll_ifindex);
+ assertEquals(ARPHRD_LOOPBACK, bound.sll_hatype);
+ assertEquals(0, bound.sll_pkttype);
+
+ // The loopback address is ETH_ALEN bytes long and is all zeros.
+ // http://lxr.free-electrons.com/source/drivers/net/loopback.c?v=3.10#L167
+ assertEquals(6, bound.sll_addr.length);
+ for (int i = 0; i < 6; i++) {
+ assertEquals(0, bound.sll_addr[i]);
+ }
+ }
+
+ public void test_byteBufferPositions_sendto_recvfrom_af_inet() throws Exception {
+ checkByteBufferPositions_sendto_recvfrom(AF_INET, InetAddress.getByName("127.0.0.1"));
+ }
+
+ public void test_byteBufferPositions_sendto_recvfrom_af_inet6() throws Exception {
+ checkByteBufferPositions_sendto_recvfrom(AF_INET6, InetAddress.getByName("::1"));
+ }
+
+ private void checkSendToSocketAddress(int family, InetAddress loopback) throws Exception {
+ FileDescriptor recvFd = Libcore.os.socket(family, SOCK_DGRAM, 0);
+ Libcore.os.bind(recvFd, loopback, 0);
+ StructTimeval tv = StructTimeval.fromMillis(20);
+ Libcore.os.setsockoptTimeval(recvFd, SOL_SOCKET, SO_RCVTIMEO, tv);
+
+ InetSocketAddress to = ((InetSocketAddress) Libcore.os.getsockname(recvFd));
+ FileDescriptor sendFd = Libcore.os.socket(family, SOCK_DGRAM, 0);
+ byte[] msg = ("Hello, I'm going to a socket address: " + to.toString()).getBytes("UTF-8");
+ int len = msg.length;
+
+ assertEquals(len, Libcore.os.sendto(sendFd, msg, 0, len, 0, to));
+ byte[] received = new byte[msg.length + 42];
+ InetSocketAddress from = new InetSocketAddress();
+ assertEquals(len, Libcore.os.recvfrom(recvFd, received, 0, received.length, 0, from));
+ assertEquals(loopback, from.getAddress());
+ }
+
+ public void test_sendtoSocketAddress_af_inet() throws Exception {
+ checkSendToSocketAddress(AF_INET, InetAddress.getByName("127.0.0.1"));
+ }
+
+ public void test_sendtoSocketAddress_af_inet6() throws Exception {
+ checkSendToSocketAddress(AF_INET6, InetAddress.getByName("::1"));
+ }
+
+ public void test_socketFamilies() throws Exception {
+ FileDescriptor fd = Libcore.os.socket(AF_INET6, SOCK_STREAM, 0);
+ Libcore.os.bind(fd, InetAddress.getByName("::"), 0);
+ InetSocketAddress localSocketAddress = (InetSocketAddress) Libcore.os.getsockname(fd);
+ assertEquals(Inet6Address.ANY, localSocketAddress.getAddress());
+
+ fd = Libcore.os.socket(AF_INET6, SOCK_STREAM, 0);
+ Libcore.os.bind(fd, InetAddress.getByName("0.0.0.0"), 0);
+ localSocketAddress = (InetSocketAddress) Libcore.os.getsockname(fd);
+ assertEquals(Inet6Address.ANY, localSocketAddress.getAddress());
+
+ fd = Libcore.os.socket(AF_INET, SOCK_STREAM, 0);
+ Libcore.os.bind(fd, InetAddress.getByName("0.0.0.0"), 0);
+ localSocketAddress = (InetSocketAddress) Libcore.os.getsockname(fd);
+ assertEquals(Inet4Address.ANY, localSocketAddress.getAddress());
+ try {
+ Libcore.os.bind(fd, InetAddress.getByName("::"), 0);
+ fail("Expected ErrnoException binding IPv4 socket to ::");
+ } catch (ErrnoException expected) {
+ assertEquals("Expected EAFNOSUPPORT binding IPv4 socket to ::", EAFNOSUPPORT, expected.errno);
+ }
+ }
+
+ private static void assertArrayEquals(byte[] expected, byte[] actual) {
+ assertTrue("Expected=" + Arrays.toString(expected) + ", actual=" + Arrays.toString(actual),
+ Arrays.equals(expected, actual));
+ }
+
+ private static void checkSocketPing(FileDescriptor fd, InetAddress to, byte[] packet,
+ byte type, byte responseType, boolean useSendto) throws Exception {
+ int len = packet.length;
+ packet[0] = type;
+ if (useSendto) {
+ assertEquals(len, Libcore.os.sendto(fd, packet, 0, len, 0, to, 0));
+ } else {
+ Libcore.os.connect(fd, to, 0);
+ assertEquals(len, Libcore.os.sendto(fd, packet, 0, len, 0, null, 0));
+ }
+
+ int icmpId = ((InetSocketAddress) Libcore.os.getsockname(fd)).getPort();
+ byte[] received = new byte[4096];
+ InetSocketAddress srcAddress = new InetSocketAddress();
+ assertEquals(len, Libcore.os.recvfrom(fd, received, 0, received.length, 0, srcAddress));
+ assertEquals(to, srcAddress.getAddress());
+ assertEquals(responseType, received[0]);
+ assertEquals(received[4], (byte) (icmpId >> 8));
+ assertEquals(received[5], (byte) (icmpId & 0xff));
+
+ received = Arrays.copyOf(received, len);
+ received[0] = (byte) type;
+ received[2] = received[3] = 0; // Checksum.
+ received[4] = received[5] = 0; // ICMP ID.
+ assertArrayEquals(packet, received);
+ }
+
+ public void test_socketPing() throws Exception {
+ final byte ICMP_ECHO = 8, ICMP_ECHOREPLY = 0;
+ final byte ICMPV6_ECHO_REQUEST = (byte) 128, ICMPV6_ECHO_REPLY = (byte) 129;
+ final byte[] packet = ("\000\000\000\000" + // ICMP type, code.
+ "\000\000\000\003" + // ICMP ID (== port), sequence number.
+ "Hello myself").getBytes(StandardCharsets.US_ASCII);
+
+ FileDescriptor fd = Libcore.os.socket(AF_INET6, SOCK_DGRAM, IPPROTO_ICMPV6);
+ InetAddress ipv6Loopback = InetAddress.getByName("::1");
+ checkSocketPing(fd, ipv6Loopback, packet, ICMPV6_ECHO_REQUEST, ICMPV6_ECHO_REPLY, true);
+ checkSocketPing(fd, ipv6Loopback, packet, ICMPV6_ECHO_REQUEST, ICMPV6_ECHO_REPLY, false);
+
+ fd = Libcore.os.socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
+ InetAddress ipv4Loopback = InetAddress.getByName("127.0.0.1");
+ checkSocketPing(fd, ipv4Loopback, packet, ICMP_ECHO, ICMP_ECHOREPLY, true);
+ checkSocketPing(fd, ipv4Loopback, packet, ICMP_ECHO, ICMP_ECHOREPLY, false);
+ }
}
diff --git a/luni/src/test/java/libcore/java/io/FileDescriptorTest.java b/luni/src/test/java/libcore/java/io/FileDescriptorTest.java
index 39472df..e2780c9 100644
--- a/luni/src/test/java/libcore/java/io/FileDescriptorTest.java
+++ b/luni/src/test/java/libcore/java/io/FileDescriptorTest.java
@@ -30,14 +30,14 @@ public class FileDescriptorTest extends TestCase {
new RandomAccessFile(f, "r").getFD().sync();
}
- public void test_isSocket() throws Exception {
+ public void test_isSocket$() throws Exception {
File f = new File("/dev/null");
FileInputStream fis = new FileInputStream(f);
- assertFalse(fis.getFD().isSocket());
+ assertFalse(fis.getFD().isSocket$());
fis.close();
ServerSocket s = new ServerSocket();
- assertTrue(s.getImpl$().getFD$().isSocket());
+ assertTrue(s.getImpl$().getFD$().isSocket$());
s.close();
}
}
diff --git a/luni/src/test/java/libcore/java/io/FileInputStreamTest.java b/luni/src/test/java/libcore/java/io/FileInputStreamTest.java
index 14950ee..26de11a 100644
--- a/luni/src/test/java/libcore/java/io/FileInputStreamTest.java
+++ b/luni/src/test/java/libcore/java/io/FileInputStreamTest.java
@@ -67,7 +67,7 @@ public final class FileInputStreamTest extends TestCase {
}
public void testSkipInPipes() throws Exception {
- FileDescriptor[] pipe = Libcore.os.pipe();
+ FileDescriptor[] pipe = Libcore.os.pipe2(0);
DataFeeder feeder = new DataFeeder(pipe[1]);
try {
feeder.start();
diff --git a/luni/src/test/java/libcore/java/io/RandomAccessFileTest.java b/luni/src/test/java/libcore/java/io/RandomAccessFileTest.java
index afe49b7..8d99457 100644
--- a/luni/src/test/java/libcore/java/io/RandomAccessFileTest.java
+++ b/luni/src/test/java/libcore/java/io/RandomAccessFileTest.java
@@ -20,6 +20,8 @@ import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
+import java.nio.channels.FileChannel;
+
import junit.framework.TestCase;
import libcore.java.lang.ref.FinalizationTester;
@@ -73,6 +75,61 @@ public final class RandomAccessFileTest extends TestCase {
FinalizationTester.induceFinalization();
}
}
+
+ // http://b/19892782
+ public void testCloseRaf_sameChannelReturned() throws Exception {
+ RandomAccessFile raf = new RandomAccessFile(file, "rw");
+
+ FileChannel fileChannelBeforeClosing = raf.getChannel();
+ raf.close();
+ FileChannel fileChannelAfterClosing = raf.getChannel();
+ assertSame(fileChannelBeforeClosing, fileChannelAfterClosing);
+ }
+
+ // http://b/19892782
+ public void testCloseRaf_channelIsClosed() throws Exception {
+ RandomAccessFile raf = new RandomAccessFile(file, "rw");
+
+ FileChannel fileChannelBeforeClosing = raf.getChannel();
+ raf.close();
+ FileChannel fileChannelAfterClosing = raf.getChannel();
+ assertFalse(fileChannelBeforeClosing.isOpen());
+ }
+
+ // http://b/19892782
+ public void testCloseFileChannel_sameChannelReturned() throws Exception {
+ RandomAccessFile raf = new RandomAccessFile(file, "rw");
+
+ FileChannel fileChannelBeforeClosing = raf.getChannel();
+ fileChannelBeforeClosing.close();
+
+ FileChannel fileChannelAfterClosing = raf.getChannel();
+ assertSame(fileChannelBeforeClosing, fileChannelAfterClosing);
+ }
+
+ // http://b/19892782
+ public void testCloseFileChannel_returnedFileChannelIsClosed() throws Exception {
+ RandomAccessFile raf = new RandomAccessFile(file, "rw");
+
+ FileChannel fileChannelBeforeClosing = raf.getChannel();
+ // This should close the Raf, and previous implementations wrongly returned a new
+ // open (but useless) channel in this case.
+ fileChannelBeforeClosing.close();
+ FileChannel fileChannelAfterClosing = raf.getChannel();
+ assertFalse(fileChannelBeforeClosing.isOpen());
+ }
+
+ // http://b/19892782
+ public void testCloseRafBeforeGetChannel_returnChannelWithCloseFdAfterClose() throws Exception {
+ RandomAccessFile raf = new RandomAccessFile(file, "rw");
+ raf.close();
+ try {
+ raf.getChannel().size();
+ fail();
+ } catch (IOException expected) {
+ }
+ }
+
private void createRandomAccessFile(File file) throws Exception {
// TODO: fix our register maps and remove this otherwise unnecessary
// indirection! (http://b/5412580)
diff --git a/luni/src/test/java/libcore/java/lang/FloatTest.java b/luni/src/test/java/libcore/java/lang/FloatTest.java
index 92e7ae4..c25bd5c 100644
--- a/luni/src/test/java/libcore/java/lang/FloatTest.java
+++ b/luni/src/test/java/libcore/java/lang/FloatTest.java
@@ -121,4 +121,20 @@ public class FloatTest extends junit.framework.TestCase {
}
assertEquals(f1, 0f);
}
+
+ // Float equivalent of testParseLargestSubnormalDoublePrecision. http://b/18087920.
+ public void testParseLargestSubnormalFloatPrecision() {
+ // These are different ways of saying MIN_NORMAL.
+ assertEquals(1.1754943508222875e-38f, Float.parseFloat("1.1754943508222875e-38"));
+ assertEquals(1.1754943508222875e-38f, Float.parseFloat("0.00011754943508222875e-34f"));
+ assertEquals(1.1754943508222875e-38f, Float.parseFloat("00000001.1754943508222875e-38f"));
+ assertEquals(1.1754943508222875e-38f, Float.parseFloat("1.17549435082228750000e-38f"));
+ assertEquals(1.1754943508222875e-38f, Float.parseFloat("1.1754943508222875e-0038f"));
+ assertEquals(-1.1754943508222875e-38f, Float.parseFloat("-1.1754943508222875e-38f"));
+
+ // Extra interesting values suggested as part of http://b/18087920.
+ assertEquals(1.1754944e-38f, Float.parseFloat("11754942807573643E-54"));
+ assertEquals(1.1754944e-38f, Float.parseFloat("11754942807573644E-54"));
+ assertEquals(1.1754944e-38f, Float.parseFloat("11754942807573645E-54"));
+ }
}
diff --git a/luni/src/test/java/libcore/java/lang/OldAndroidMonitorTest.java b/luni/src/test/java/libcore/java/lang/OldAndroidMonitorTest.java
index d1704fb..4760c6d 100644..100755
--- a/luni/src/test/java/libcore/java/lang/OldAndroidMonitorTest.java
+++ b/luni/src/test/java/libcore/java/lang/OldAndroidMonitorTest.java
@@ -103,7 +103,7 @@ public class OldAndroidMonitorTest extends TestCase {
}
private class Interrupter extends Thread {
- Waiter waiter;
+ private final Waiter waiter;
Interrupter(String name, Waiter waiter) {
super(name);
@@ -119,8 +119,7 @@ public class OldAndroidMonitorTest extends TestCase {
}
}
- void run_inner() {
- waiter.spin = true;
+ private void run_inner() {
// System.out.println("InterruptTest: starting waiter");
waiter.start();
@@ -168,7 +167,7 @@ public class OldAndroidMonitorTest extends TestCase {
private class Waiter extends Thread {
Object interrupterLock = new Object();
- Boolean spin = false;
+ volatile boolean spin = true;
Waiter(String name) {
super(name);
@@ -188,6 +187,7 @@ public class OldAndroidMonitorTest extends TestCase {
while (spin) {
// We're going to get interrupted while we spin.
}
+
if (interrupted()) {
// System.out.println("Waiter done spinning; interrupted.");
} else {
@@ -196,7 +196,7 @@ public class OldAndroidMonitorTest extends TestCase {
}
synchronized (this) {
- Boolean sawEx = false;
+ boolean sawEx = false;
try {
synchronized (interrupterLock) {
@@ -216,7 +216,7 @@ public class OldAndroidMonitorTest extends TestCase {
}
}
synchronized (this) {
- Boolean sawEx = false;
+ boolean sawEx = false;
try {
synchronized (interrupterLock) {
@@ -236,7 +236,7 @@ public class OldAndroidMonitorTest extends TestCase {
}
}
synchronized (this) {
- Boolean sawEx = false;
+ boolean sawEx = false;
try {
synchronized (interrupterLock) {
diff --git a/luni/src/test/java/libcore/java/lang/OldClassTest.java b/luni/src/test/java/libcore/java/lang/OldClassTest.java
index 23a42bd..f5bc787 100644
--- a/luni/src/test/java/libcore/java/lang/OldClassTest.java
+++ b/luni/src/test/java/libcore/java/lang/OldClassTest.java
@@ -40,11 +40,6 @@ import tests.support.resource.Support_Resources;
@SuppressWarnings("deprecation")
public class OldClassTest extends junit.framework.TestCase {
-
- public static final String FILENAME =
- OldClassTest.class.getPackage().getName().replace('.', '/') +
- "/test#.properties";
-
final String packageName = getClass().getPackage().getName();
final String classNameInitError1 = packageName + ".TestClass1";
final String classNameInitError2 = packageName + ".TestClass1B";
diff --git a/luni/src/test/java/libcore/java/lang/PackageTest.java b/luni/src/test/java/libcore/java/lang/PackageTest.java
index 6e274a0..c004e23 100644
--- a/luni/src/test/java/libcore/java/lang/PackageTest.java
+++ b/luni/src/test/java/libcore/java/lang/PackageTest.java
@@ -25,9 +25,10 @@ public final class PackageTest extends TestCase {
private static final List<Package> packages = Arrays.asList(Package.getPackages());
public void test_getAnnotations() throws Exception {
- // Package annotations aren't supported, but pre-ICS we crashed.
- assertEquals(0, getClass().getPackage().getAnnotations().length);
- assertEquals(0, getClass().getPackage().getDeclaredAnnotations().length);
+ // Pre-ICS we crashed. To pass, the package-info and TestPackageAnnotation classes must be
+ // on the classpath.
+ assertEquals(1, getClass().getPackage().getAnnotations().length);
+ assertEquals(1, getClass().getPackage().getDeclaredAnnotations().length);
}
public void testGetPackage() {
diff --git a/luni/src/test/java/libcore/java/lang/ProcessBuilderTest.java b/luni/src/test/java/libcore/java/lang/ProcessBuilderTest.java
index 9766cef..51aed38 100644
--- a/luni/src/test/java/libcore/java/lang/ProcessBuilderTest.java
+++ b/luni/src/test/java/libcore/java/lang/ProcessBuilderTest.java
@@ -28,7 +28,7 @@ import static tests.support.Support_Exec.execAndCheckOutput;
public class ProcessBuilderTest extends AbstractResourceLeakageDetectorTestCase {
private static String shell() {
- String deviceSh = "/system/bin/sh";
+ String deviceSh = System.getenv("ANDROID_ROOT") + "/bin/sh";
String desktopSh = "/bin/sh";
return new File(deviceSh).exists() ? deviceSh : desktopSh;
}
diff --git a/luni/src/test/java/libcore/java/lang/TestPackageAnnotation.java b/luni/src/test/java/libcore/java/lang/TestPackageAnnotation.java
new file mode 100644
index 0000000..7626206
--- /dev/null
+++ b/luni/src/test/java/libcore/java/lang/TestPackageAnnotation.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package libcore.java.lang;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+// Used by PackageTest
+@Target(ElementType.PACKAGE)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface TestPackageAnnotation {}
diff --git a/luni/src/test/java/libcore/java/lang/package-info.java b/luni/src/test/java/libcore/java/lang/package-info.java
new file mode 100644
index 0000000..d916e9a
--- /dev/null
+++ b/luni/src/test/java/libcore/java/lang/package-info.java
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+// Used by PackageTest
+@TestPackageAnnotation
+package libcore.java.lang; \ No newline at end of file
diff --git a/luni/src/test/java/libcore/java/lang/reflect/FieldTest.java b/luni/src/test/java/libcore/java/lang/reflect/FieldTest.java
index b60d984..75665db 100644
--- a/luni/src/test/java/libcore/java/lang/reflect/FieldTest.java
+++ b/luni/src/test/java/libcore/java/lang/reflect/FieldTest.java
@@ -17,6 +17,8 @@
package libcore.java.lang.reflect;
import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+
import junit.framework.TestCase;
public final class FieldTest extends TestCase {
@@ -46,6 +48,56 @@ public final class FieldTest extends TestCase {
assertFalse(f1.equals(f2));
}
+ // Tests that the "synthetic" modifier is handled correctly.
+ // It's supposed to be present but not shown in toString.
+ public void testSyntheticModifier() throws NoSuchFieldException {
+ Field valuesField = Thread.State.class.getDeclaredField("$VALUES");
+ // Check that this test makes sense.
+ assertTrue(valuesField.isSynthetic());
+ assertEquals(Modifier.SYNTHETIC, valuesField.getModifiers() & Modifier.SYNTHETIC);
+ assertEquals("private static final java.lang.Thread$State[] java.lang.Thread$State.$VALUES",
+ valuesField.toString());
+ }
+
+ // Ensure that the "enum constant" bit is not returned in toString.
+ public void testEnumValueField() throws NoSuchFieldException {
+ Field blockedField = Thread.State.class.getDeclaredField("BLOCKED");
+ assertTrue(Thread.State.class.getDeclaredField("BLOCKED").isEnumConstant());
+ assertEquals("public static final", Modifier.toString(blockedField.getModifiers()));
+ assertEquals(
+ "public static final java.lang.Thread$State java.lang.Thread$State.BLOCKED",
+ blockedField.toString());
+ }
+
+ class ClassWithATransientField {
+ private transient Class<String> transientField = String.class;
+ }
+
+ // Tests that the "transient" modifier is handled correctly.
+ // The underlying constant value for it is the same as for the "varargs" method modifier.
+ // http://b/18488857
+ public void testTransientModifier() throws NoSuchFieldException {
+ Field transientField = ClassWithATransientField.class.getDeclaredField("transientField");
+ // Check that this test makes sense.
+ assertEquals(Modifier.TRANSIENT, transientField.getModifiers() & Modifier.TRANSIENT);
+ assertEquals(
+ "private transient java.lang.Class "
+ + "libcore.java.lang.reflect.FieldTest$ClassWithATransientField"
+ + ".transientField",
+ transientField.toString());
+ }
+
+ public void testToGenericString() throws NoSuchFieldException {
+ Field transientField = ClassWithATransientField.class.getDeclaredField("transientField");
+ // Check that this test makes sense.
+ assertEquals(Modifier.TRANSIENT, transientField.getModifiers() & Modifier.TRANSIENT);
+ assertEquals(
+ "private transient java.lang.Class<java.lang.String> "
+ + "libcore.java.lang.reflect.FieldTest$ClassWithATransientField"
+ + ".transientField",
+ transientField.toGenericString());
+ }
+
static class FieldTestHelper {
public String a;
public Object b;
diff --git a/luni/src/test/java/libcore/java/lang/reflect/MethodTest.java b/luni/src/test/java/libcore/java/lang/reflect/MethodTest.java
index c3a436c..a3f9065 100644
--- a/luni/src/test/java/libcore/java/lang/reflect/MethodTest.java
+++ b/luni/src/test/java/libcore/java/lang/reflect/MethodTest.java
@@ -17,6 +17,7 @@
package libcore.java.lang.reflect;
import java.lang.reflect.Method;
+
import junit.framework.TestCase;
public final class MethodTest extends TestCase {
@@ -197,6 +198,23 @@ public final class MethodTest extends TestCase {
assertEquals( "public java.lang.Process java.lang.Runtime.exec(java.lang.String[])"
+ " throws java.io.IOException",
Runtime.class.getMethod("exec", new Class[] { String[].class }).toString());
+ // http://b/18488857
+ assertEquals(
+ "public int java.lang.String.compareTo(java.lang.Object)",
+ String.class.getMethod("compareTo", Object.class).toString());
+ }
+
+ // Tests that the "varargs" modifier is handled correctly.
+ // The underlying constant value for it is the same as for the "transient" field modifier.
+ // http://b/18488857
+ public void testVarargsModifier() throws NoSuchMethodException {
+ Method stringFormatMethod = String.class.getMethod(
+ "format", new Class[] { String.class, Object[].class });
+ assertTrue(stringFormatMethod.isVarArgs());
+ assertEquals(
+ "public static java.lang.String java.lang.String.format("
+ + "java.lang.String,java.lang.Object[])",
+ stringFormatMethod.toString());
}
public static class MethodTestHelper {
diff --git a/luni/src/test/java/libcore/java/lang/reflect/ModifierTest.java b/luni/src/test/java/libcore/java/lang/reflect/ModifierTest.java
index 1bde157..0505f2f 100644
--- a/luni/src/test/java/libcore/java/lang/reflect/ModifierTest.java
+++ b/luni/src/test/java/libcore/java/lang/reflect/ModifierTest.java
@@ -100,6 +100,9 @@ public class ModifierTest extends junit.framework.TestCase {
}
public void test_toStringI() {
- assertEquals("public abstract", Modifier.toString(Modifier.PUBLIC | Modifier.ABSTRACT));
+ // Note that it checks that "STRICT" is rendered as "strictfp" (for other modifiers,
+ // the displayed name is the same as the lowercase constant name).
+ assertEquals("public abstract strictfp",
+ Modifier.toString(Modifier.PUBLIC | Modifier.ABSTRACT | Modifier.STRICT));
}
}
diff --git a/luni/src/test/java/libcore/java/net/InetAddressTest.java b/luni/src/test/java/libcore/java/net/InetAddressTest.java
index 4b656cc..8bdcf64 100644
--- a/luni/src/test/java/libcore/java/net/InetAddressTest.java
+++ b/luni/src/test/java/libcore/java/net/InetAddressTest.java
@@ -21,10 +21,14 @@ import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.UnknownHostException;
+import java.util.Arrays;
import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
import libcore.util.SerializationTester;
public class InetAddressTest extends junit.framework.TestCase {
+ private static final byte[] LOOPBACK4_BYTES = new byte[] { 127, 0, 0, 1 };
private static final byte[] LOOPBACK6_BYTES = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
private static final String[] INVALID_IPv4_NUMERIC_ADDRESSES = new String[] {
@@ -72,7 +76,7 @@ public class InetAddressTest extends junit.framework.TestCase {
}
private static Inet6Address localhost6() throws Exception {
- return (Inet6Address) InetAddress.getByAddress("localhost", LOOPBACK6_BYTES);
+ return (Inet6Address) InetAddress.getByAddress("ip6-localhost", LOOPBACK6_BYTES);
}
public void test_parseNumericAddress() throws Exception {
@@ -311,4 +315,84 @@ public class InetAddressTest extends junit.framework.TestCase {
assertEquals(resultStrings[i], result);
}
}
+
+ public void test_getHostNameCaches() throws Exception {
+ InetAddress inetAddress = InetAddress.getByAddress(LOOPBACK6_BYTES);
+ assertEquals("::1", inetAddress.getHostString());
+ assertEquals("ip6-localhost", inetAddress.getHostName());
+ // getHostString() should now be different.
+ assertEquals("ip6-localhost", inetAddress.getHostString());
+ }
+
+ public void test_getByAddress_loopbackIpv4() throws Exception {
+ InetAddress inetAddress = InetAddress.getByAddress(LOOPBACK4_BYTES);
+ assertEquals(LOOPBACK4_BYTES, "localhost", inetAddress);
+ assertTrue(inetAddress.isLoopbackAddress());
+ }
+
+ public void test_getByAddress_loopbackIpv6() throws Exception {
+ InetAddress inetAddress = InetAddress.getByAddress(LOOPBACK6_BYTES);
+ assertEquals(LOOPBACK6_BYTES, "ip6-localhost", inetAddress);
+ assertTrue(inetAddress.isLoopbackAddress());
+ }
+
+ public void test_getByName_loopbackIpv4() throws Exception {
+ InetAddress inetAddress = InetAddress.getByName("127.0.0.1");
+ assertEquals(LOOPBACK4_BYTES, "localhost", inetAddress);
+ assertTrue(inetAddress.isLoopbackAddress());
+ }
+
+ public void test_getByName_loopbackIpv6() throws Exception {
+ InetAddress inetAddress = InetAddress.getByName("::1");
+ assertEquals(LOOPBACK6_BYTES, "ip6-localhost", inetAddress);
+ assertTrue(inetAddress.isLoopbackAddress());
+ }
+
+ public void test_getAllByName_localhost() throws Exception {
+ InetAddress[] inetAddresses = InetAddress.getAllByName("localhost");
+ assertEquals(1, inetAddresses.length);
+ InetAddress inetAddress = inetAddresses[0];
+ assertEquals(LOOPBACK4_BYTES, "localhost", inetAddress);
+ assertTrue(inetAddress.isLoopbackAddress());
+ }
+
+ public void test_getAllByName_ip6_localhost() throws Exception {
+ InetAddress[] inetAddresses = InetAddress.getAllByName("ip6-localhost");
+ assertEquals(1, inetAddresses.length);
+ InetAddress inetAddress = inetAddresses[0];
+ assertEquals(LOOPBACK6_BYTES, "ip6-localhost", inetAddress);
+ assertTrue(inetAddress.isLoopbackAddress());
+ }
+
+ public void test_getByName_null() throws Exception {
+ InetAddress inetAddress = InetAddress.getByName("::1");
+
+ Set<InetAddress> expectedLoopbackAddresses =
+ createSet(Inet4Address.LOOPBACK, Inet6Address.LOOPBACK);
+ assertTrue(expectedLoopbackAddresses.contains(inetAddress));
+ }
+
+ public void test_getAllByName_null() throws Exception {
+ InetAddress[] inetAddresses = InetAddress.getAllByName(null);
+ assertEquals(2, inetAddresses.length);
+ Set<InetAddress> expectedLoopbackAddresses =
+ createSet(Inet4Address.LOOPBACK, Inet6Address.LOOPBACK);
+ assertEquals(expectedLoopbackAddresses, createSet(inetAddresses));
+ }
+
+ private static void assertEquals(
+ byte[] expectedAddressBytes, String expectedHostname, InetAddress actual) {
+ assertArrayEquals(expectedAddressBytes, actual.getAddress());
+ assertEquals(expectedHostname, actual.getHostName());
+
+ }
+
+ private static void assertArrayEquals(byte[] expected, byte[] actual) {
+ assertTrue("Expected=" + Arrays.toString(expected) + ", actual=" + Arrays.toString(actual),
+ Arrays.equals(expected, actual));
+ }
+
+ private static Set<InetAddress> createSet(InetAddress... members) {
+ return new HashSet<InetAddress>(Arrays.asList(members));
+ }
}
diff --git a/luni/src/test/java/libcore/java/net/InetSocketAddressTest.java b/luni/src/test/java/libcore/java/net/InetSocketAddressTest.java
index 3bca8dc..d97c48a 100644
--- a/luni/src/test/java/libcore/java/net/InetSocketAddressTest.java
+++ b/luni/src/test/java/libcore/java/net/InetSocketAddressTest.java
@@ -63,7 +63,7 @@ public class InetSocketAddressTest extends TestCase {
}
InetSocketAddress isa = new InetSocketAddress((InetAddress)null, 80);
- assertEquals("0.0.0.0", isa.getHostName());
+ assertEquals("::", isa.getHostName());
try {
new InetSocketAddress(InetAddress.getByName("localhost"), 65536);
@@ -80,7 +80,7 @@ public class InetSocketAddressTest extends TestCase {
public void test_ConstructorI() {
InetSocketAddress isa = new InetSocketAddress(65535);
- assertEquals("0.0.0.0", isa.getHostName());
+ assertEquals("::", isa.getHostName());
assertEquals(65535, isa.getPort());
try {
@@ -150,6 +150,20 @@ public class InetSocketAddressTest extends TestCase {
assertTrue(hasHostname.isUnresolved());
assertEquals("some host", hasHostname.getHostString());
assertEquals("some host", hasHostname.getHostName());
+
+ InetSocketAddress hasHostnameAndAddress = new InetSocketAddress(
+ InetAddress.getByAddress("some host", new byte[] { 127, 0, 0, 1 }),
+ 1234);
+ assertFalse(hasHostnameAndAddress.isUnresolved());
+ assertEquals("some host", hasHostnameAndAddress.getHostString());
+ assertEquals("some host", hasHostnameAndAddress.getHostName());
+
+ // Using a host name that is actually an IP.
+ InetSocketAddress hostnameIsIp = InetSocketAddress.createUnresolved("127.0.0.1", 1234);
+ assertTrue(hostnameIsIp.isUnresolved());
+ assertEquals("127.0.0.1", hostnameIsIp.getHostString());
+ assertEquals("127.0.0.1", hostnameIsIp.getHostName());
+
// When we don't have a hostname, whether or not we do the reverse lookup is the difference
// between getHostString and getHostName...
InetAddress address = InetAddress.getByAddress(new byte[] { 127, 0, 0, 1 });
@@ -157,4 +171,18 @@ public class InetSocketAddressTest extends TestCase {
assertEquals("127.0.0.1", noHostname.getHostString());
assertEquals("localhost", noHostname.getHostName());
}
+
+ public void test_getHostString_cachingBehavior() throws Exception {
+ InetAddress inetAddress = InetAddress.getByAddress(new byte[] { 127, 0, 0, 1 });
+ InetSocketAddress socketAddress = new InetSocketAddress(inetAddress, 1234);
+ assertEquals("127.0.0.1", socketAddress.getHostString());
+ assertEquals("localhost", socketAddress.getHostName());
+ assertEquals("localhost", socketAddress.getHostString());
+
+ inetAddress = InetAddress.getByName("127.0.0.1");
+ socketAddress = new InetSocketAddress(inetAddress, 1234);
+ assertEquals("127.0.0.1", socketAddress.getHostString());
+ assertEquals("localhost", socketAddress.getHostName());
+ assertEquals("localhost", socketAddress.getHostString());
+ }
}
diff --git a/luni/src/test/java/libcore/java/net/OldSocketTest.java b/luni/src/test/java/libcore/java/net/OldSocketTest.java
index 7973965..ded5802 100644
--- a/luni/src/test/java/libcore/java/net/OldSocketTest.java
+++ b/luni/src/test/java/libcore/java/net/OldSocketTest.java
@@ -37,6 +37,7 @@ import java.net.UnknownHostException;
import java.nio.channels.IllegalBlockingModeException;
import java.nio.channels.SocketChannel;
import java.security.Permission;
+import tests.net.StuckServer;
import tests.support.Support_Configuration;
public class OldSocketTest extends OldSocketTestCase {
@@ -932,25 +933,15 @@ public class OldSocketTest extends OldSocketTestCase {
}
// start by validating the error checks
- int portNumber = 0;
- Socket theSocket = null;
- ServerSocket serverSocket = null;
- SocketAddress theAddress = null;
- SocketAddress nonConnectableAddress = null;
- SocketAddress nonReachableAddress = null;
- SocketAddress invalidType = null;
- // byte[] theBytes = {-1,-1,-1,-1};
- byte[] theBytes = { 0, 0, 0, 0 };
- theAddress = new InetSocketAddress(InetAddress.getLocalHost(),
- portNumber);
- nonConnectableAddress = new InetSocketAddress(InetAddress
- .getByAddress(theBytes), portNumber);
- nonReachableAddress = new InetSocketAddress(InetAddress
- .getByName(Support_Configuration.ResolvedNotExistingHost),
- portNumber);
- invalidType = new mySocketAddress();
+ byte[] theBytes = { 0, 0, 0, 0 };
+ SocketAddress theAddress = new InetSocketAddress(InetAddress.getLocalHost(), 0);
+ SocketAddress nonConnectableAddress = new InetSocketAddress(InetAddress.getByAddress(theBytes), 0);
+ SocketAddress nonReachableAddress = new InetSocketAddress(StuckServer.UNREACHABLE_ADDRESS, 0);
+ SocketAddress invalidType = new mySocketAddress();
+ Socket theSocket = null;
+ ServerSocket serverSocket = null;
try {
theSocket = new Socket();
theSocket.connect(null);
@@ -1165,7 +1156,7 @@ public class OldSocketTest extends OldSocketTestCase {
byte[] theBytes = { 0, 0, 0, 0 };
SocketAddress theAddress = new InetSocketAddress(InetAddress.getLocalHost(), 0);
SocketAddress nonConnectableAddress = new InetSocketAddress(InetAddress.getByAddress(theBytes), 0);
- SocketAddress nonReachableAddress = new InetSocketAddress(InetAddress.getByName(Support_Configuration.ResolvedNotExistingHost), 0);
+ SocketAddress nonReachableAddress = new InetSocketAddress(StuckServer.UNREACHABLE_ADDRESS, 0);
SocketAddress invalidType = new mySocketAddress();
Socket theSocket = null;
diff --git a/luni/src/test/java/libcore/java/net/SocketTest.java b/luni/src/test/java/libcore/java/net/SocketTest.java
index fb09be0..9765a45 100644
--- a/luni/src/test/java/libcore/java/net/SocketTest.java
+++ b/luni/src/test/java/libcore/java/net/SocketTest.java
@@ -31,9 +31,11 @@ import java.net.SocketImpl;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.concurrent.Callable;
+import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
public class SocketTest extends junit.framework.TestCase {
// See http://b/2980559.
@@ -353,6 +355,37 @@ public class SocketTest extends junit.framework.TestCase {
assertEquals(boundAddress.getPort(), localAddressAfterClose.getPort());
}
+ public void testCloseDuringConnect() throws Exception {
+ final CountDownLatch signal = new CountDownLatch(1);
+
+ final Socket s = new Socket();
+ new Thread() {
+ @Override
+ public void run() {
+ try {
+ // This address is reserved for documentation: should never be reachable.
+ InetSocketAddress unreachableIp = new InetSocketAddress("192.0.2.0", 80);
+ // This should never return.
+ s.connect(unreachableIp, 0 /* infinite */);
+ fail("Connect returned unexpectedly for: " + unreachableIp);
+ } catch (SocketException expected) {
+ assertTrue(expected.getMessage().contains("Socket closed"));
+ signal.countDown();
+ } catch (IOException e) {
+ fail("Unexpected exception: " + e);
+ }
+ }
+ }.start();
+
+ // Wait for the connect() thread to run and start connect()
+ Thread.sleep(2000);
+
+ s.close();
+
+ boolean connectUnblocked = signal.await(2000, TimeUnit.MILLISECONDS);
+ assertTrue(connectUnblocked);
+ }
+
static class MockServer {
private ExecutorService executor;
private ServerSocket serverSocket;
diff --git a/luni/src/test/java/libcore/java/net/URLConnectionTest.java b/luni/src/test/java/libcore/java/net/URLConnectionTest.java
index c09939f..3f831e0 100644
--- a/luni/src/test/java/libcore/java/net/URLConnectionTest.java
+++ b/luni/src/test/java/libcore/java/net/URLConnectionTest.java
@@ -16,7 +16,8 @@
package libcore.java.net;
-import com.android.okhttp.HttpResponseCache;
+import com.android.okhttp.AndroidShimResponseCache;
+
import com.google.mockwebserver.MockResponse;
import com.google.mockwebserver.MockWebServer;
import com.google.mockwebserver.RecordedRequest;
@@ -37,11 +38,14 @@ import java.net.ProtocolException;
import java.net.Proxy;
import java.net.ResponseCache;
import java.net.Socket;
+import java.net.SocketAddress;
+import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.net.URI;
import java.net.URL;
import java.net.URLConnection;
import java.net.UnknownHostException;
+import java.nio.channels.SocketChannel;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
@@ -58,18 +62,18 @@ import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
-import javax.net.SocketFactory;
+import javax.net.ssl.HandshakeCompletedListener;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLHandshakeException;
+import javax.net.ssl.SSLParameters;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
-import libcore.java.security.StandardNames;
import libcore.java.security.TestKeyStore;
import libcore.java.util.AbstractResourceLeakageDetectorTestCase;
import libcore.javax.net.ssl.TestSSLContext;
@@ -84,7 +88,7 @@ import static com.google.mockwebserver.SocketPolicy.SHUTDOWN_OUTPUT_AT_END;
public final class URLConnectionTest extends AbstractResourceLeakageDetectorTestCase {
private MockWebServer server;
- private HttpResponseCache cache;
+ private AndroidShimResponseCache cache;
private String hostName;
@Override protected void setUp() throws Exception {
@@ -674,11 +678,144 @@ public final class URLConnectionTest extends AbstractResourceLeakageDetectorTest
private void initResponseCache() throws IOException {
String tmp = System.getProperty("java.io.tmpdir");
File cacheDir = new File(tmp, "HttpCache-" + UUID.randomUUID());
- cache = new HttpResponseCache(cacheDir, Integer.MAX_VALUE);
+ cache = AndroidShimResponseCache.create(cacheDir, Integer.MAX_VALUE);
ResponseCache.setDefault(cache);
}
/**
+ * Test Etag headers are returned correctly when a client-side cache is not installed.
+ * https://code.google.com/p/android/issues/detail?id=108949
+ */
+ public void testEtagHeaders_uncached() throws Exception {
+ final String etagValue1 = "686897696a7c876b7e";
+ final String body1 = "Response with etag 1";
+ final String etagValue2 = "686897696a7c876b7f";
+ final String body2 = "Response with etag 2";
+
+ server.enqueue(
+ new MockResponse()
+ .setBody(body1)
+ .setHeader("Content-Type", "text/plain")
+ .setHeader("Etag", etagValue1));
+ server.enqueue(
+ new MockResponse()
+ .setBody(body2)
+ .setHeader("Content-Type", "text/plain")
+ .setHeader("Etag", etagValue2));
+ server.play();
+
+ URL url = server.getUrl("/");
+ HttpURLConnection connection1 = (HttpURLConnection) url.openConnection();
+ assertEquals(etagValue1, connection1.getHeaderField("Etag"));
+ assertContent(body1, connection1);
+ connection1.disconnect();
+
+ // Discard the server-side record of the request made.
+ server.takeRequest();
+
+ HttpURLConnection connection2 = (HttpURLConnection) url.openConnection();
+ assertEquals(etagValue2, connection2.getHeaderField("Etag"));
+ assertContent(body2, connection2);
+ connection2.disconnect();
+
+ // Check the client did not cache.
+ RecordedRequest request = server.takeRequest();
+ assertNull(request.getHeader("If-None-Match"));
+ }
+
+ /**
+ * Test Etag headers are returned correctly when a client-side cache is installed and the server
+ * data is unchanged.
+ * https://code.google.com/p/android/issues/detail?id=108949
+ */
+ public void testEtagHeaders_cachedWithServerHit() throws Exception {
+ final String etagValue = "686897696a7c876b7e";
+ final String body = "Response with etag";
+
+ server.enqueue(
+ new MockResponse()
+ .setBody(body)
+ .setResponseCode(HttpURLConnection.HTTP_OK)
+ .setHeader("Content-Type", "text/plain")
+ .setHeader("Etag", etagValue));
+
+ server.enqueue(
+ new MockResponse()
+ .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED));
+ server.play();
+
+ initResponseCache();
+
+ URL url = server.getUrl("/");
+ HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+ assertEquals(etagValue, connection.getHeaderField("Etag"));
+ assertContent(body, connection);
+ connection.disconnect();
+
+ // Discard the server-side record of the request made.
+ server.takeRequest();
+
+ // Confirm the cached body is returned along with the original etag header.
+ HttpURLConnection cachedConnection = (HttpURLConnection) url.openConnection();
+ assertEquals(etagValue, cachedConnection.getHeaderField("Etag"));
+ assertContent(body, cachedConnection);
+ cachedConnection.disconnect();
+
+ // Check the client formatted the request correctly.
+ RecordedRequest request = server.takeRequest();
+ assertEquals(etagValue, request.getHeader("If-None-Match"));
+ }
+
+ /**
+ * Test Etag headers are returned correctly when a client-side cache is installed and the server
+ * data has changed.
+ * https://code.google.com/p/android/issues/detail?id=108949
+ */
+ public void testEtagHeaders_cachedWithServerMiss() throws Exception {
+ final String etagValue1 = "686897696a7c876b7e";
+ final String body1 = "Response with etag 1";
+ final String etagValue2 = "686897696a7c876b7f";
+ final String body2 = "Response with etag 2";
+
+ server.enqueue(
+ new MockResponse()
+ .setBody(body1)
+ .setResponseCode(HttpURLConnection.HTTP_OK)
+ .setHeader("Content-Type", "text/plain")
+ .setHeader("Etag", etagValue1));
+
+ server.enqueue(
+ new MockResponse()
+ .setBody(body2)
+ .setResponseCode(HttpURLConnection.HTTP_OK)
+ .setHeader("Content-Type", "text/plain")
+ .setHeader("Etag", etagValue2));
+
+ server.play();
+
+ initResponseCache();
+
+ URL url = server.getUrl("/");
+ HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+ assertEquals(etagValue1, connection.getHeaderField("Etag"));
+ assertContent(body1, connection);
+ connection.disconnect();
+
+ // Discard the server-side record of the request made.
+ server.takeRequest();
+
+ // Confirm the new body is returned along with the new etag header.
+ HttpURLConnection cachedConnection = (HttpURLConnection) url.openConnection();
+ assertEquals(etagValue2, cachedConnection.getHeaderField("Etag"));
+ assertContent(body2, cachedConnection);
+ cachedConnection.disconnect();
+
+ // Check the client formatted the request correctly.
+ RecordedRequest request = server.takeRequest();
+ assertEquals(etagValue1, request.getHeader("If-None-Match"));
+ }
+
+ /**
* Test which headers are sent unencrypted to the HTTP proxy.
*/
public void testProxyConnectIncludesProxyHeadersOnly()
@@ -2074,6 +2211,19 @@ public final class URLConnectionTest extends AbstractResourceLeakageDetectorTest
connection.disconnect();
}
+ public void testLastModified() throws Exception {
+ server.enqueue(new MockResponse()
+ .addHeader("Last-Modified", "Wed, 27 Nov 2013 11:26:00 GMT")
+ .setBody("Hello"));
+ server.play();
+
+ HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection();
+ connection.connect();
+
+ assertEquals(1385551560000L, connection.getLastModified());
+ assertEquals(1385551560000L, connection.getHeaderFieldDate("Last-Modified", -1));
+ }
+
public void testClientSendsContentLength() throws Exception {
server.enqueue(new MockResponse().setBody("A"));
server.play();
@@ -2185,52 +2335,107 @@ public final class URLConnectionTest extends AbstractResourceLeakageDetectorTest
urlConnection.getInputStream();
}
- public void testSslFallback() throws Exception {
+ public void testSslFallback_allSupportedProtocols() throws Exception {
TestSSLContext testSSLContext = TestSSLContext.create();
- // This server socket factory only supports SSLv3. This is to avoid issues due to SCSV
- // checks. See https://tools.ietf.org/html/draft-ietf-tls-downgrade-scsv-00
+ String[] allSupportedProtocols = { "TLSv1.2", "TLSv1.1", "TLSv1", "SSLv3" };
SSLSocketFactory serverSocketFactory =
new LimitedProtocolsSocketFactory(
testSSLContext.serverContext.getSocketFactory(),
- "SSLv3");
-
+ allSupportedProtocols);
server.useHttps(serverSocketFactory, false);
server.enqueue(new MockResponse().setSocketPolicy(FAIL_HANDSHAKE));
- server.enqueue(new MockResponse().setBody("This required a 2nd handshake"));
+ server.enqueue(new MockResponse().setSocketPolicy(FAIL_HANDSHAKE));
+ server.enqueue(new MockResponse().setSocketPolicy(FAIL_HANDSHAKE));
+ server.enqueue(new MockResponse().setBody("This required fallbacks"));
server.play();
HttpsURLConnection connection = (HttpsURLConnection) server.getUrl("/").openConnection();
- // Keep track of the client sockets created so that we can interrogate them.
- RecordingSocketFactory clientSocketFactory =
- new RecordingSocketFactory(testSSLContext.clientContext.getSocketFactory());
+ // Keeps track of the client sockets created so that we can interrogate them.
+ final boolean disableFallbackScsv = true;
+ FallbackTestClientSocketFactory clientSocketFactory = new FallbackTestClientSocketFactory(
+ new LimitedProtocolsSocketFactory(
+ testSSLContext.clientContext.getSocketFactory(), allSupportedProtocols),
+ disableFallbackScsv);
connection.setSSLSocketFactory(clientSocketFactory);
- assertEquals("This required a 2nd handshake",
+ assertEquals("This required fallbacks",
readAscii(connection.getInputStream(), Integer.MAX_VALUE));
+ // Confirm the server accepted a single connection.
RecordedRequest retry = server.takeRequest();
assertEquals(0, retry.getSequenceNumber());
assertEquals("SSLv3", retry.getSslProtocol());
// Confirm the client fallback looks ok.
List<SSLSocket> createdSockets = clientSocketFactory.getCreatedSockets();
- assertEquals(2, createdSockets.size());
- SSLSocket clientSocket1 = createdSockets.get(0);
- List<String> clientSocket1EnabledProtocols = Arrays.asList(
- clientSocket1.getEnabledProtocols());
- assertContains(clientSocket1EnabledProtocols, "TLSv1.2");
- List<String> clientSocket1EnabledCiphers =
- Arrays.asList(clientSocket1.getEnabledCipherSuites());
- assertContainsNoneMatching(
- clientSocket1EnabledCiphers, StandardNames.CIPHER_SUITE_FALLBACK);
-
- SSLSocket clientSocket2 = createdSockets.get(1);
- List<String> clientSocket2EnabledProtocols =
- Arrays.asList(clientSocket2.getEnabledProtocols());
- assertContainsNoneMatching(clientSocket2EnabledProtocols, "TLSv1.2");
- List<String> clientSocket2EnabledCiphers =
- Arrays.asList(clientSocket2.getEnabledCipherSuites());
- assertContains(clientSocket2EnabledCiphers, StandardNames.CIPHER_SUITE_FALLBACK);
+ assertEquals(4, createdSockets.size());
+ TlsFallbackDisabledScsvSSLSocket clientSocket1 =
+ (TlsFallbackDisabledScsvSSLSocket) createdSockets.get(0);
+ assertSslSocket(clientSocket1,
+ false /* expectedWasFallbackScsvSet */, "TLSv1.2", "TLSv1.1", "TLSv1", "SSLv3");
+
+ TlsFallbackDisabledScsvSSLSocket clientSocket2 =
+ (TlsFallbackDisabledScsvSSLSocket) createdSockets.get(1);
+ assertSslSocket(clientSocket2,
+ true /* expectedWasFallbackScsvSet */, "TLSv1.1", "TLSv1", "SSLv3");
+
+ TlsFallbackDisabledScsvSSLSocket clientSocket3 =
+ (TlsFallbackDisabledScsvSSLSocket) createdSockets.get(2);
+ assertSslSocket(clientSocket3, true /* expectedWasFallbackScsvSet */, "TLSv1", "SSLv3");
+
+ TlsFallbackDisabledScsvSSLSocket clientSocket4 =
+ (TlsFallbackDisabledScsvSSLSocket) createdSockets.get(3);
+ assertSslSocket(clientSocket4, true /* expectedWasFallbackScsvSet */, "SSLv3");
+ }
+
+ public void testSslFallback_defaultProtocols() throws Exception {
+ TestSSLContext testSSLContext = TestSSLContext.create();
+
+ server.useHttps(testSSLContext.serverContext.getSocketFactory(), false);
+ server.enqueue(new MockResponse().setSocketPolicy(FAIL_HANDSHAKE));
+ server.enqueue(new MockResponse().setSocketPolicy(FAIL_HANDSHAKE));
+ server.enqueue(new MockResponse().setBody("This required fallbacks"));
+ server.play();
+
+ HttpsURLConnection connection = (HttpsURLConnection) server.getUrl("/").openConnection();
+ // Keeps track of the client sockets created so that we can interrogate them.
+ final boolean disableFallbackScsv = true;
+ FallbackTestClientSocketFactory clientSocketFactory = new FallbackTestClientSocketFactory(
+ testSSLContext.clientContext.getSocketFactory(),
+ disableFallbackScsv);
+ connection.setSSLSocketFactory(clientSocketFactory);
+ assertEquals("This required fallbacks",
+ readAscii(connection.getInputStream(), Integer.MAX_VALUE));
+
+ // Confirm the server accepted a single connection.
+ RecordedRequest retry = server.takeRequest();
+ assertEquals(0, retry.getSequenceNumber());
+ assertEquals("TLSv1", retry.getSslProtocol());
+
+ // Confirm the client fallback looks ok.
+ List<SSLSocket> createdSockets = clientSocketFactory.getCreatedSockets();
+ assertEquals(3, createdSockets.size());
+ TlsFallbackDisabledScsvSSLSocket clientSocket1 =
+ (TlsFallbackDisabledScsvSSLSocket) createdSockets.get(0);
+ assertSslSocket(clientSocket1,
+ false /* expectedWasFallbackScsvSet */, "TLSv1.2", "TLSv1.1", "TLSv1");
+
+ TlsFallbackDisabledScsvSSLSocket clientSocket2 =
+ (TlsFallbackDisabledScsvSSLSocket) createdSockets.get(1);
+ assertSslSocket(clientSocket2, true /* expectedWasFallbackScsvSet */, "TLSv1.1", "TLSv1");
+
+ TlsFallbackDisabledScsvSSLSocket clientSocket3 =
+ (TlsFallbackDisabledScsvSSLSocket) createdSockets.get(2);
+ assertSslSocket(clientSocket3, true /* expectedWasFallbackScsvSet */, "TLSv1");
+ }
+
+ private static void assertSslSocket(TlsFallbackDisabledScsvSSLSocket socket,
+ boolean expectedWasFallbackScsvSet, String... expectedEnabledProtocols) {
+ Set<String> enabledProtocols =
+ new HashSet<String>(Arrays.asList(socket.getEnabledProtocols()));
+ Set<String> expectedProtocolsSet = new HashSet<String>(Arrays.asList(expectedEnabledProtocols));
+ assertEquals(expectedProtocolsSet, enabledProtocols);
+ assertEquals(expectedWasFallbackScsvSet, socket.wasTlsFallbackScsvSet());
}
public void testInspectSslBeforeConnect() throws Exception {
@@ -2491,36 +2696,37 @@ public final class URLConnectionTest extends AbstractResourceLeakageDetectorTest
}
@Override
- public Socket createSocket(Socket s, String host, int port, boolean autoClose)
+ public SSLSocket createSocket(Socket s, String host, int port, boolean autoClose)
throws IOException {
- return delegate.createSocket(s, host, port, autoClose);
+ return (SSLSocket) delegate.createSocket(s, host, port, autoClose);
}
@Override
- public Socket createSocket() throws IOException {
- return delegate.createSocket();
+ public SSLSocket createSocket() throws IOException {
+ return (SSLSocket) delegate.createSocket();
}
@Override
- public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
- return delegate.createSocket(host, port);
+ public SSLSocket createSocket(String host, int port)
+ throws IOException, UnknownHostException {
+ return (SSLSocket) delegate.createSocket(host, port);
}
@Override
- public Socket createSocket(String host, int port, InetAddress localHost,
+ public SSLSocket createSocket(String host, int port, InetAddress localHost,
int localPort) throws IOException, UnknownHostException {
- return delegate.createSocket(host, port, localHost, localPort);
+ return (SSLSocket) delegate.createSocket(host, port, localHost, localPort);
}
@Override
- public Socket createSocket(InetAddress host, int port) throws IOException {
- return delegate.createSocket(host, port);
+ public SSLSocket createSocket(InetAddress host, int port) throws IOException {
+ return (SSLSocket) delegate.createSocket(host, port);
}
@Override
- public Socket createSocket(InetAddress address, int port,
+ public SSLSocket createSocket(InetAddress address, int port,
InetAddress localAddress, int localPort) throws IOException {
- return delegate.createSocket(address, port, localAddress, localPort);
+ return (SSLSocket) delegate.createSocket(address, port, localAddress, localPort);
}
}
@@ -2539,7 +2745,7 @@ public final class URLConnectionTest extends AbstractResourceLeakageDetectorTest
}
@Override
- public Socket createSocket(Socket s, String host, int port, boolean autoClose)
+ public SSLSocket createSocket(Socket s, String host, int port, boolean autoClose)
throws IOException {
SSLSocket socket = (SSLSocket) delegate.createSocket(s, host, port, autoClose);
socket.setEnabledProtocols(protocols);
@@ -2547,21 +2753,22 @@ public final class URLConnectionTest extends AbstractResourceLeakageDetectorTest
}
@Override
- public Socket createSocket() throws IOException {
+ public SSLSocket createSocket() throws IOException {
SSLSocket socket = (SSLSocket) delegate.createSocket();
socket.setEnabledProtocols(protocols);
return socket;
}
@Override
- public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
+ public SSLSocket createSocket(String host, int port)
+ throws IOException, UnknownHostException {
SSLSocket socket = (SSLSocket) delegate.createSocket(host, port);
socket.setEnabledProtocols(protocols);
return socket;
}
@Override
- public Socket createSocket(String host, int port, InetAddress localHost,
+ public SSLSocket createSocket(String host, int port, InetAddress localHost,
int localPort) throws IOException, UnknownHostException {
SSLSocket socket = (SSLSocket) delegate.createSocket(host, port, localHost, localPort);
socket.setEnabledProtocols(protocols);
@@ -2569,14 +2776,14 @@ public final class URLConnectionTest extends AbstractResourceLeakageDetectorTest
}
@Override
- public Socket createSocket(InetAddress host, int port) throws IOException {
+ public SSLSocket createSocket(InetAddress host, int port) throws IOException {
SSLSocket socket = (SSLSocket) delegate.createSocket(host, port);
socket.setEnabledProtocols(protocols);
return socket;
}
@Override
- public Socket createSocket(InetAddress address, int port,
+ public SSLSocket createSocket(InetAddress address, int port,
InetAddress localAddress, int localPort) throws IOException {
SSLSocket socket =
(SSLSocket) delegate.createSocket(address, port, localAddress, localPort);
@@ -2586,58 +2793,337 @@ public final class URLConnectionTest extends AbstractResourceLeakageDetectorTest
}
/**
- * An SSLSocketFactory that delegates calls and keeps a record of any sockets created.
+ * An {@link javax.net.ssl.SSLSocket} that delegates all calls.
*/
- private static class RecordingSocketFactory extends DelegatingSSLSocketFactory {
+ private static abstract class DelegatingSSLSocket extends SSLSocket {
+ protected final SSLSocket delegate;
+
+ public DelegatingSSLSocket(SSLSocket delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override public void shutdownInput() throws IOException {
+ delegate.shutdownInput();
+ }
+
+ @Override public void shutdownOutput() throws IOException {
+ delegate.shutdownOutput();
+ }
+
+ @Override public String[] getSupportedCipherSuites() {
+ return delegate.getSupportedCipherSuites();
+ }
+
+ @Override public String[] getEnabledCipherSuites() {
+ return delegate.getEnabledCipherSuites();
+ }
+
+ @Override public void setEnabledCipherSuites(String[] suites) {
+ delegate.setEnabledCipherSuites(suites);
+ }
+
+ @Override public String[] getSupportedProtocols() {
+ return delegate.getSupportedProtocols();
+ }
+
+ @Override public String[] getEnabledProtocols() {
+ return delegate.getEnabledProtocols();
+ }
+
+ @Override public void setEnabledProtocols(String[] protocols) {
+ delegate.setEnabledProtocols(protocols);
+ }
+
+ @Override public SSLSession getSession() {
+ return delegate.getSession();
+ }
+
+ @Override public void addHandshakeCompletedListener(HandshakeCompletedListener listener) {
+ delegate.addHandshakeCompletedListener(listener);
+ }
+
+ @Override public void removeHandshakeCompletedListener(HandshakeCompletedListener listener) {
+ delegate.removeHandshakeCompletedListener(listener);
+ }
+
+ @Override public void startHandshake() throws IOException {
+ delegate.startHandshake();
+ }
+
+ @Override public void setUseClientMode(boolean mode) {
+ delegate.setUseClientMode(mode);
+ }
+
+ @Override public boolean getUseClientMode() {
+ return delegate.getUseClientMode();
+ }
+
+ @Override public void setNeedClientAuth(boolean need) {
+ delegate.setNeedClientAuth(need);
+ }
+
+ @Override public void setWantClientAuth(boolean want) {
+ delegate.setWantClientAuth(want);
+ }
+
+ @Override public boolean getNeedClientAuth() {
+ return delegate.getNeedClientAuth();
+ }
+
+ @Override public boolean getWantClientAuth() {
+ return delegate.getWantClientAuth();
+ }
+ @Override public void setEnableSessionCreation(boolean flag) {
+ delegate.setEnableSessionCreation(flag);
+ }
+
+ @Override public boolean getEnableSessionCreation() {
+ return delegate.getEnableSessionCreation();
+ }
+
+ @Override public SSLParameters getSSLParameters() {
+ return delegate.getSSLParameters();
+ }
+
+ @Override public void setSSLParameters(SSLParameters p) {
+ delegate.setSSLParameters(p);
+ }
+
+ @Override public void close() throws IOException {
+ delegate.close();
+ }
+
+ @Override public InetAddress getInetAddress() {
+ return delegate.getInetAddress();
+ }
+
+ @Override public InputStream getInputStream() throws IOException {
+ return delegate.getInputStream();
+ }
+
+ @Override public boolean getKeepAlive() throws SocketException {
+ return delegate.getKeepAlive();
+ }
+
+ @Override public InetAddress getLocalAddress() {
+ return delegate.getLocalAddress();
+ }
+
+ @Override public int getLocalPort() {
+ return delegate.getLocalPort();
+ }
+
+ @Override public OutputStream getOutputStream() throws IOException {
+ return delegate.getOutputStream();
+ }
+
+ @Override public int getPort() {
+ return delegate.getPort();
+ }
+
+ @Override public int getSoLinger() throws SocketException {
+ return delegate.getSoLinger();
+ }
+
+ @Override public int getReceiveBufferSize() throws SocketException {
+ return delegate.getReceiveBufferSize();
+ }
+
+ @Override public int getSendBufferSize() throws SocketException {
+ return delegate.getSendBufferSize();
+ }
+
+ @Override public int getSoTimeout() throws SocketException {
+ return delegate.getSoTimeout();
+ }
+
+ @Override public boolean getTcpNoDelay() throws SocketException {
+ return delegate.getTcpNoDelay();
+ }
+
+ @Override public void setKeepAlive(boolean keepAlive) throws SocketException {
+ delegate.setKeepAlive(keepAlive);
+ }
+
+ @Override public void setSendBufferSize(int size) throws SocketException {
+ delegate.setSendBufferSize(size);
+ }
+
+ @Override public void setReceiveBufferSize(int size) throws SocketException {
+ delegate.setReceiveBufferSize(size);
+ }
+
+ @Override public void setSoLinger(boolean on, int timeout) throws SocketException {
+ delegate.setSoLinger(on, timeout);
+ }
+
+ @Override public void setSoTimeout(int timeout) throws SocketException {
+ delegate.setSoTimeout(timeout);
+ }
+
+ @Override public void setTcpNoDelay(boolean on) throws SocketException {
+ delegate.setTcpNoDelay(on);
+ }
+
+ @Override public String toString() {
+ return delegate.toString();
+ }
+
+ @Override public SocketAddress getLocalSocketAddress() {
+ return delegate.getLocalSocketAddress();
+ }
+
+ @Override public SocketAddress getRemoteSocketAddress() {
+ return delegate.getRemoteSocketAddress();
+ }
+
+ @Override public boolean isBound() {
+ return delegate.isBound();
+ }
+
+ @Override public boolean isConnected() {
+ return delegate.isConnected();
+ }
+
+ @Override public boolean isClosed() {
+ return delegate.isClosed();
+ }
+
+ @Override public void bind(SocketAddress localAddr) throws IOException {
+ delegate.bind(localAddr);
+ }
+
+ @Override public void connect(SocketAddress remoteAddr) throws IOException {
+ delegate.connect(remoteAddr);
+ }
+
+ @Override public void connect(SocketAddress remoteAddr, int timeout) throws IOException {
+ delegate.connect(remoteAddr, timeout);
+ }
+
+ @Override public boolean isInputShutdown() {
+ return delegate.isInputShutdown();
+ }
+
+ @Override public boolean isOutputShutdown() {
+ return delegate.isOutputShutdown();
+ }
+
+ @Override public void setReuseAddress(boolean reuse) throws SocketException {
+ delegate.setReuseAddress(reuse);
+ }
+
+ @Override public boolean getReuseAddress() throws SocketException {
+ return delegate.getReuseAddress();
+ }
+
+ @Override public void setOOBInline(boolean oobinline) throws SocketException {
+ delegate.setOOBInline(oobinline);
+ }
+
+ @Override public boolean getOOBInline() throws SocketException {
+ return delegate.getOOBInline();
+ }
+
+ @Override public void setTrafficClass(int value) throws SocketException {
+ delegate.setTrafficClass(value);
+ }
+
+ @Override public int getTrafficClass() throws SocketException {
+ return delegate.getTrafficClass();
+ }
+
+ @Override public void sendUrgentData(int value) throws IOException {
+ delegate.sendUrgentData(value);
+ }
+
+ @Override public SocketChannel getChannel() {
+ return delegate.getChannel();
+ }
+
+ @Override public void setPerformancePreferences(int connectionTime, int latency,
+ int bandwidth) {
+ delegate.setPerformancePreferences(connectionTime, latency, bandwidth);
+ }
+ }
+
+ /**
+ * An SSLSocketFactory that delegates calls. It keeps a record of any sockets created.
+ * If {@link #disableTlsFallbackScsv} is set to {@code true} then sockets created by the
+ * delegate are wrapped with ones that will not accept the {@link #TLS_FALLBACK_SCSV} cipher,
+ * thus bypassing server-side fallback checks on platforms that support it. Unfortunately this
+ * wrapping will disable any reflection-based calls to SSLSocket from Platform.
+ */
+ private static class FallbackTestClientSocketFactory extends DelegatingSSLSocketFactory {
+ /**
+ * The cipher suite used during TLS connection fallback to indicate a fallback.
+ * See https://tools.ietf.org/html/draft-ietf-tls-downgrade-scsv-00
+ */
+ public static final String TLS_FALLBACK_SCSV = "TLS_FALLBACK_SCSV";
+
+ private final boolean disableTlsFallbackScsv;
private final List<SSLSocket> createdSockets = new ArrayList<SSLSocket>();
- private RecordingSocketFactory(SSLSocketFactory delegate) {
+ public FallbackTestClientSocketFactory(SSLSocketFactory delegate,
+ boolean disableTlsFallbackScsv) {
super(delegate);
+ this.disableTlsFallbackScsv = disableTlsFallbackScsv;
}
- @Override
- public Socket createSocket(Socket s, String host, int port, boolean autoClose)
+ @Override public SSLSocket createSocket(Socket s, String host, int port, boolean autoClose)
throws IOException {
- SSLSocket socket = (SSLSocket) delegate.createSocket(s, host, port, autoClose);
+ SSLSocket socket = super.createSocket(s, host, port, autoClose);
+ if (disableTlsFallbackScsv) {
+ socket = new TlsFallbackDisabledScsvSSLSocket(socket);
+ }
createdSockets.add(socket);
return socket;
}
- @Override
- public Socket createSocket() throws IOException {
- SSLSocket socket = (SSLSocket) delegate.createSocket();
+ @Override public SSLSocket createSocket() throws IOException {
+ SSLSocket socket = super.createSocket();
+ if (disableTlsFallbackScsv) {
+ socket = new TlsFallbackDisabledScsvSSLSocket(socket);
+ }
createdSockets.add(socket);
return socket;
}
- @Override
- public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
- SSLSocket socket = (SSLSocket) delegate.createSocket(host, port);
+ @Override public SSLSocket createSocket(String host,int port) throws IOException {
+ SSLSocket socket = super.createSocket(host, port);
+ if (disableTlsFallbackScsv) {
+ socket = new TlsFallbackDisabledScsvSSLSocket(socket);
+ }
createdSockets.add(socket);
return socket;
}
- @Override
- public Socket createSocket(String host, int port, InetAddress localHost,
- int localPort) throws IOException, UnknownHostException {
- SSLSocket socket = (SSLSocket) delegate.createSocket(host, port, localHost, localPort);
+ @Override public SSLSocket createSocket(String host,int port, InetAddress localHost,
+ int localPort) throws IOException {
+ SSLSocket socket = super.createSocket(host, port, localHost, localPort);
+ if (disableTlsFallbackScsv) {
+ socket = new TlsFallbackDisabledScsvSSLSocket(socket);
+ }
createdSockets.add(socket);
return socket;
}
- @Override
- public Socket createSocket(InetAddress host, int port) throws IOException {
- SSLSocket socket = (SSLSocket) delegate.createSocket(host, port);
+ @Override public SSLSocket createSocket(InetAddress host,int port) throws IOException {
+ SSLSocket socket = super.createSocket(host, port);
+ if (disableTlsFallbackScsv) {
+ socket = new TlsFallbackDisabledScsvSSLSocket(socket);
+ }
createdSockets.add(socket);
return socket;
}
- @Override
- public Socket createSocket(InetAddress address, int port,
+ @Override public SSLSocket createSocket(InetAddress address,int port,
InetAddress localAddress, int localPort) throws IOException {
- SSLSocket socket =
- (SSLSocket) delegate.createSocket(address, port, localAddress, localPort);
+ SSLSocket socket = super.createSocket(address, port, localAddress, localPort);
+ if (disableTlsFallbackScsv) {
+ socket = new TlsFallbackDisabledScsvSSLSocket(socket);
+ }
createdSockets.add(socket);
return socket;
}
@@ -2647,4 +3133,31 @@ public final class URLConnectionTest extends AbstractResourceLeakageDetectorTest
}
}
+ private static class TlsFallbackDisabledScsvSSLSocket extends DelegatingSSLSocket {
+
+ private boolean tlsFallbackScsvSet;
+
+ public TlsFallbackDisabledScsvSSLSocket(SSLSocket socket) {
+ super(socket);
+ }
+
+ @Override public void setEnabledCipherSuites(String[] suites) {
+ List<String> enabledCipherSuites = new ArrayList<String>(suites.length);
+ for (String suite : suites) {
+ if (suite.equals(FallbackTestClientSocketFactory.TLS_FALLBACK_SCSV)) {
+ // Record that an attempt was made to set TLS_FALLBACK_SCSV, but don't actually
+ // set it.
+ tlsFallbackScsvSet = true;
+ } else {
+ enabledCipherSuites.add(suite);
+ }
+ }
+ delegate.setEnabledCipherSuites(
+ enabledCipherSuites.toArray(new String[enabledCipherSuites.size()]));
+ }
+
+ public boolean wasTlsFallbackScsvSet() {
+ return tlsFallbackScsvSet;
+ }
+ }
}
diff --git a/luni/src/test/java/libcore/java/nio/channels/SelectorTest.java b/luni/src/test/java/libcore/java/nio/channels/SelectorTest.java
index 9789197..41b434d 100644
--- a/luni/src/test/java/libcore/java/nio/channels/SelectorTest.java
+++ b/luni/src/test/java/libcore/java/nio/channels/SelectorTest.java
@@ -15,7 +15,6 @@
*/
package libcore.java.nio.channels;
-import android.system.OsConstants;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
@@ -28,7 +27,6 @@ import java.nio.channels.SocketChannel;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import junit.framework.TestCase;
-import libcore.io.Libcore;
import tests.net.StuckServer;
public class SelectorTest extends TestCase {
@@ -71,25 +69,6 @@ public class SelectorTest extends TestCase {
}
}
- // http://b/6453247
- // This test won't work on the host until/unless we start using libcorkscrew there.
- // The runtime itself blocks SIGQUIT, so that doesn't cause poll(2) to EINTR directly.
- // The EINTR is caused by the way libcorkscrew works.
- public void testEINTR() throws Exception {
- Selector selector = Selector.open();
- new Thread(new Runnable() {
- @Override public void run() {
- try {
- Thread.sleep(2000);
- Libcore.os.kill(Libcore.os.getpid(), OsConstants.SIGQUIT);
- } catch (Exception ex) {
- fail();
- }
- }
- }).start();
- assertEquals(0, selector.select());
- }
-
// http://code.google.com/p/android/issues/detail?id=15388
public void testInterrupted() throws IOException {
Selector selector = Selector.open();
diff --git a/luni/src/test/java/libcore/java/nio/charset/CharsetEncoderTest.java b/luni/src/test/java/libcore/java/nio/charset/CharsetEncoderTest.java
index ff510e0..e9ab8ae 100644
--- a/luni/src/test/java/libcore/java/nio/charset/CharsetEncoderTest.java
+++ b/luni/src/test/java/libcore/java/nio/charset/CharsetEncoderTest.java
@@ -20,8 +20,10 @@ import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder;
+import java.nio.charset.CharsetDecoder;
import java.nio.charset.CoderResult;
import java.nio.charset.CodingErrorAction;
+import java.nio.charset.StandardCharsets;
import java.util.Arrays;
public class CharsetEncoderTest extends junit.framework.TestCase {
@@ -161,4 +163,71 @@ public class CharsetEncoderTest extends junit.framework.TestCase {
assertEquals(CoderResult.UNDERFLOW, cr);
assertEquals(8, bb.position());
}
+
+ // Discards all input. Outputs a single byte 'X' on flush.
+ private static final class MockCharset extends Charset {
+ static final Charset INSTANCE = new MockCharset();
+
+ private MockCharset() {
+ super("MockCharset", new String[0]);
+ }
+
+ public boolean contains(Charset charset) {
+ return false;
+ }
+
+ public CharsetEncoder newEncoder() {
+ return new CharsetEncoder(INSTANCE, 1.f, 1.f) {
+ protected CoderResult encodeLoop(CharBuffer in, ByteBuffer out) {
+ in.position(in.limit());
+ return CoderResult.UNDERFLOW;
+ }
+
+ protected CoderResult implFlush(ByteBuffer out) {
+ out.put((byte) 'X');
+ return CoderResult.UNDERFLOW;
+ }
+ };
+ }
+
+ public CharsetDecoder newDecoder() {
+ return new CharsetDecoder(INSTANCE, 1.f, 1.f) {
+ protected CoderResult decodeLoop(ByteBuffer in, CharBuffer out) {
+ in.position(in.limit());
+ return CoderResult.UNDERFLOW;
+ }
+ };
+ }
+ }
+
+ // Repeated calls to flush() should not result in repeated calls to implFlush().
+ public void testFlushNotCallingImplFlushRepeatedly() {
+ CharsetEncoder e = MockCharset.INSTANCE.newEncoder();
+ ByteBuffer bb = ByteBuffer.allocate(4);
+ CoderResult cr = e.encode(CharBuffer.allocate(0), bb, true);
+ assertEquals(CoderResult.UNDERFLOW, cr);
+ cr = e.flush(bb);
+ assertEquals(CoderResult.UNDERFLOW, cr);
+ cr = e.flush(bb);
+ assertEquals(CoderResult.UNDERFLOW, cr);
+ assertEquals(1, bb.position());
+ assertEquals((byte) 'X', bb.get(0));
+ assertEquals(0x00, bb.get(1));
+ assertEquals(0x00, bb.get(2));
+ assertEquals(0x00, bb.get(3));
+ }
+
+ // http://b/19185235
+ public void testFlushWithIncompleteInput() {
+ CharsetEncoder encoder = StandardCharsets.UTF_8.newEncoder();
+ ByteBuffer output = ByteBuffer.allocate(10);
+ CoderResult result = encoder.encode(CharBuffer.wrap("\ud800"), output,
+ true /* endOfInput */);
+ assertTrue(result.isUnderflow());
+
+ result = encoder.flush(output);
+ assertTrue(result.isMalformed());
+ assertEquals(1, result.length());
+ assertEquals(0, output.position());
+ }
}
diff --git a/luni/src/test/java/libcore/java/nio/charset/SettableCharsetProvider.java b/luni/src/test/java/libcore/java/nio/charset/SettableCharsetProvider.java
new file mode 100644
index 0000000..b4886d2
--- /dev/null
+++ b/luni/src/test/java/libcore/java/nio/charset/SettableCharsetProvider.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package libcore.java.nio.charset;
+
+import java.nio.charset.Charset;
+import java.nio.charset.spi.CharsetProvider;
+import java.util.Collections;
+import java.util.Iterator;
+
+/**
+ * This class is registered as a charset provider by the META-INF in the libcore
+ * tests jar. Since there isn't any convenient API to dynamically register and de-register
+ * charset-providers, this class allows tests to plug in a delegate that lives for the
+ * duration of the test.
+ */
+public final class SettableCharsetProvider extends CharsetProvider {
+ private static CharsetProvider delegate;
+
+ public static void setDelegate(CharsetProvider cp) {
+ delegate = cp;
+ }
+
+ public static void clearDelegate() {
+ delegate = null;
+ }
+
+ @Override
+ public Iterator<Charset> charsets() {
+ if (delegate != null) {
+ return delegate.charsets();
+ }
+
+ return Collections.emptyIterator();
+ }
+
+ @Override
+ public Charset charsetForName(String charsetName) {
+ if (delegate != null) {
+ return delegate.charsetForName(charsetName);
+ }
+
+ return null;
+ }
+}
diff --git a/luni/src/test/java/libcore/java/security/KeyPairGeneratorTest.java b/luni/src/test/java/libcore/java/security/KeyPairGeneratorTest.java
index e7fdb1f..7e08b5f 100644
--- a/luni/src/test/java/libcore/java/security/KeyPairGeneratorTest.java
+++ b/luni/src/test/java/libcore/java/security/KeyPairGeneratorTest.java
@@ -121,7 +121,10 @@ public class KeyPairGeneratorTest extends TestCase {
}
String algorithm = service.getAlgorithm();
- // AndroidKeyStore is tested in CTS.
+ // Do not test AndroidKeyStore's KeyPairGenerator. It cannot be initialized without
+ // providing AndroidKeyStore-specific algorithm parameters.
+ // It's OKish not to test AndroidKeyStore's KeyPairGenerator here because it's tested
+ // by cts/tests/test/keystore.
if ("AndroidKeyStore".equals(provider.getName())) {
continue;
}
diff --git a/luni/src/test/java/libcore/java/security/ProviderTest.java b/luni/src/test/java/libcore/java/security/ProviderTest.java
index 994214b..0be558e 100644
--- a/luni/src/test/java/libcore/java/security/ProviderTest.java
+++ b/luni/src/test/java/libcore/java/security/ProviderTest.java
@@ -160,7 +160,7 @@ public class ProviderTest extends TestCase {
public void test_Provider_Properties() throws Exception {
/*
* A useful reference on Provider properties
- * <a href="http://java.sun.com/javase/6/docs/technotes/guides/security/crypto/HowToImplAProvider.html>
+ * <a href="http://java.sun.com/javase/6/docs/technotes/guides/security/crypto/HowToImplAProvider.html">
* How to Implement a Provider in the Java &trade; Cryptography Architecture
* </a>
*/
diff --git a/luni/src/test/java/libcore/java/security/SignatureTest.java b/luni/src/test/java/libcore/java/security/SignatureTest.java
index 5e02f10..e546f4f 100644
--- a/luni/src/test/java/libcore/java/security/SignatureTest.java
+++ b/luni/src/test/java/libcore/java/security/SignatureTest.java
@@ -71,6 +71,24 @@ public class SignatureTest extends TestCase {
}
}
+ public void testSignature_getInstance_DoesNotSupportKeyClass_Success() throws Exception {
+ Provider mockProvider = new MockProvider("MockProvider") {
+ public void setup() {
+ put("Signature.FOO", MockSignatureSpi.AllKeyTypes.class.getName());
+ put("Signature.FOO SupportedKeyClasses", "None");
+ }
+ };
+
+ Security.addProvider(mockProvider);
+ try {
+ Signature s = Signature.getInstance("FOO", mockProvider);
+ s.initSign(new MockPrivateKey());
+ assertEquals(mockProvider, s.getProvider());
+ } finally {
+ Security.removeProvider(mockProvider.getName());
+ }
+ }
+
public void testSignature_getInstance_OnlyUsesSpecifiedProvider_SameNameAndClass_Success()
throws Exception {
Provider mockProvider = new MockProvider("MockProvider") {
diff --git a/luni/src/test/java/libcore/java/security/cert/CertificateFactoryTest.java b/luni/src/test/java/libcore/java/security/cert/CertificateFactoryTest.java
index e2f21e8..a3a721a 100644
--- a/luni/src/test/java/libcore/java/security/cert/CertificateFactoryTest.java
+++ b/luni/src/test/java/libcore/java/security/cert/CertificateFactoryTest.java
@@ -16,11 +16,13 @@
package libcore.java.security.cert;
+import com.android.org.bouncycastle.asn1.x509.AuthorityKeyIdentifier;
import com.android.org.bouncycastle.asn1.x509.BasicConstraints;
-import com.android.org.bouncycastle.asn1.x509.X509Extensions;
+import com.android.org.bouncycastle.asn1.x509.Extension;
+import com.android.org.bouncycastle.asn1.x509.SubjectKeyIdentifier;
+import com.android.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import com.android.org.bouncycastle.x509.X509V3CertificateGenerator;
import com.android.org.bouncycastle.x509.extension.AuthorityKeyIdentifierStructure;
-import com.android.org.bouncycastle.x509.extension.SubjectKeyIdentifierStructure;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
@@ -28,13 +30,14 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
-import java.io.OptionalDataException;
-import java.io.StreamCorruptedException;
import java.math.BigInteger;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.Provider;
+import java.security.PublicKey;
import java.security.Security;
import java.security.cert.CertPath;
import java.security.cert.Certificate;
@@ -554,25 +557,26 @@ public class CertificateFactoryTest extends TestCase {
X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
+ PublicKey pubKey = keyPair.getPublic();
certGen.setSerialNumber(serial);
certGen.setIssuerDN(issuerPrincipal);
certGen.setNotBefore(startDate);
certGen.setNotAfter(expiryDate);
certGen.setSubjectDN(subjectPrincipal);
- certGen.setPublicKey(keyPair.getPublic());
+ certGen.setPublicKey(pubKey);
certGen.setSignatureAlgorithm("SHA1withRSA");
if (issuer != null) {
- certGen.addExtension(X509Extensions.AuthorityKeyIdentifier, false,
+ certGen.addExtension(Extension.authorityKeyIdentifier, false,
new AuthorityKeyIdentifierStructure(issuer.certificate));
} else {
- certGen.addExtension(X509Extensions.AuthorityKeyIdentifier, false,
- new AuthorityKeyIdentifierStructure(keyPair.getPublic()));
+ certGen.addExtension(Extension.authorityKeyIdentifier, false,
+ new AuthorityKeyIdentifier(generatePublicKeyDigest(pubKey)));
}
- certGen.addExtension(X509Extensions.SubjectKeyIdentifier, false,
- new SubjectKeyIdentifierStructure(keyPair.getPublic()));
- certGen.addExtension(X509Extensions.BasicConstraints, true, basicConstraints);
+ certGen.addExtension(Extension.subjectKeyIdentifier, false,
+ new SubjectKeyIdentifier(generatePublicKeyDigest(pubKey)));
+ certGen.addExtension(Extension.basicConstraints, true, basicConstraints);
X509Certificate cert = certGen.generate(caKey);
@@ -582,4 +586,18 @@ public class CertificateFactoryTest extends TestCase {
return holder;
}
+
+ /**
+ * Generates a type 1 key identifier according to RFC 3280 4.2.1.2.
+ */
+ private static byte[] generatePublicKeyDigest(PublicKey pubKey) {
+ SubjectPublicKeyInfo spki = SubjectPublicKeyInfo.getInstance(pubKey.getEncoded());
+ MessageDigest sha1digest;
+ try {
+ sha1digest = MessageDigest.getInstance("SHA-1");
+ } catch (NoSuchAlgorithmException e) {
+ throw new RuntimeException("SHA-1 not available");
+ }
+ return sha1digest.digest(spki.getPublicKeyData().getBytes());
+ }
}
diff --git a/luni/src/test/java/libcore/java/security/cert/X509CRLTest.java b/luni/src/test/java/libcore/java/security/cert/X509CRLTest.java
index 42de50a..1611120 100644
--- a/luni/src/test/java/libcore/java/security/cert/X509CRLTest.java
+++ b/luni/src/test/java/libcore/java/security/cert/X509CRLTest.java
@@ -256,15 +256,7 @@ public class X509CRLTest extends TestCase {
private void getSigAlgName(CertificateFactory f) throws Exception {
X509CRL crlRsa = getCRL(f, CRL_RSA);
-
- String actual = crlRsa.getSigAlgName().toUpperCase(Locale.US);
-
- // Bouncycastle is broken
- if ("BC".equals(f.getProvider().getName())) {
- assertEquals("1.2.840.113549.1.1.5", actual);
- } else {
- assertEquals("SHA1WITHRSA", actual);
- }
+ assertEquals("SHA1WITHRSA", getCRL(f, CRL_RSA).getSigAlgName().toUpperCase(Locale.ROOT));
}
private void getSigAlgOID(CertificateFactory f) throws Exception {
diff --git a/luni/src/test/java/libcore/java/sql/TimestampTest.java b/luni/src/test/java/libcore/java/sql/TimestampTest.java
index 2985848..71ac8c8 100644
--- a/luni/src/test/java/libcore/java/sql/TimestampTest.java
+++ b/luni/src/test/java/libcore/java/sql/TimestampTest.java
@@ -144,4 +144,12 @@ public final class TimestampTest extends TestCase {
} catch (IllegalArgumentException expected) { }
}
+ // http://b/19756610
+ public void testAsymmetricEquals() {
+ Timestamp timestamp = new Timestamp(0);
+ java.util.Date date = new java.util.Date(0);
+
+ assertTrue(date.equals(timestamp));
+ assertFalse(timestamp.equals(date));
+ }
}
diff --git a/luni/src/test/java/libcore/java/text/BreakIteratorTest.java b/luni/src/test/java/libcore/java/text/BreakIteratorTest.java
index 47701c8..de2ae52 100644
--- a/luni/src/test/java/libcore/java/text/BreakIteratorTest.java
+++ b/luni/src/test/java/libcore/java/text/BreakIteratorTest.java
@@ -172,32 +172,4 @@ public class BreakIteratorTest extends junit.framework.TestCase {
// Expected exception
}
}
-
- // http://code.google.com/p/android/issues/detail?id=41143
- // This code is inherently unsafe and crazy;
- // we're just trying to provoke native crashes!
- public void testConcurrentBreakIteratorAccess() throws Exception {
- final BreakIterator it = BreakIterator.getCharacterInstance();
-
- ArrayList<Thread> threads = new ArrayList<Thread>();
- for (int i = 0; i < 10; ++i) {
- Thread t = new Thread(new Runnable() {
- public void run() {
- for (int i = 0; i < 4096; ++i) {
- it.setText("some example text");
- for (int index = it.first(); index != BreakIterator.DONE; index = it.next()) {
- }
- }
- }
- });
- threads.add(t);
- }
-
- for (Thread t : threads) {
- t.start();
- }
- for (Thread t : threads) {
- t.join();
- }
- }
}
diff --git a/luni/src/test/java/libcore/java/text/DateFormatSymbolsTest.java b/luni/src/test/java/libcore/java/text/DateFormatSymbolsTest.java
index e6933e6..0c97f34 100644
--- a/luni/src/test/java/libcore/java/text/DateFormatSymbolsTest.java
+++ b/luni/src/test/java/libcore/java/text/DateFormatSymbolsTest.java
@@ -147,17 +147,17 @@ public class DateFormatSymbolsTest extends junit.framework.TestCase {
}
// http://b/7955614
- public void test_getZoneStrings_GMT_short_names() throws Exception {
+ public void test_getZoneStrings_Apia() throws Exception {
String[][] array = DateFormatSymbols.getInstance(Locale.US).getZoneStrings();
for (int i = 0; i < array.length; ++i) {
String[] row = array[i];
- // America/Santiago is somewhat arbitrary; we just want a zone we have to generate
+ // Pacific/Apia is somewhat arbitrary; we just want a zone we have to generate
// "GMT" strings for the short names.
- if (row[0].equals("America/Santiago")) {
- assertEquals("Chile Standard Time", row[1]);
- assertEquals("GMT-03:00", row[2]);
- assertEquals("Chile Summer Time", row[3]);
- assertEquals("GMT-03:00", row[4]);
+ if (row[0].equals("Pacific/Apia")) {
+ assertEquals("Apia Standard Time", row[1]);
+ assertEquals("GMT+13:00", row[2]);
+ assertEquals("Apia Daylight Time", row[3]);
+ assertEquals("GMT+14:00", row[4]);
}
}
}
diff --git a/luni/src/test/java/libcore/java/text/NumberFormatTest.java b/luni/src/test/java/libcore/java/text/NumberFormatTest.java
index 0678e96..87fe96d 100644
--- a/luni/src/test/java/libcore/java/text/NumberFormatTest.java
+++ b/luni/src/test/java/libcore/java/text/NumberFormatTest.java
@@ -17,6 +17,7 @@
package libcore.java.text;
import java.math.BigInteger;
+import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.FieldPosition;
@@ -93,6 +94,21 @@ public class NumberFormatTest extends junit.framework.TestCase {
}
}
+ public void testPercentageRounding() throws Exception {
+ NumberFormat nf = NumberFormat.getPercentInstance(Locale.US);
+ assertEquals("15%", nf.format(0.149));
+ assertEquals("14%", nf.format(0.142));
+
+ nf.setRoundingMode(RoundingMode.UP);
+ assertEquals("15%", nf.format(0.142));
+
+ nf.setRoundingMode(RoundingMode.DOWN);
+ assertEquals("14%", nf.format(0.149));
+
+ nf.setMaximumFractionDigits(1);
+ assertEquals("14.9%", nf.format(0.149));
+ }
+
// https://code.google.com/p/android/issues/detail?id=62269
public void test_62269() throws Exception {
NumberFormat nf = NumberFormat.getNumberInstance(Locale.US);
diff --git a/luni/src/test/java/libcore/java/util/CalendarTest.java b/luni/src/test/java/libcore/java/util/CalendarTest.java
index e0e1a35..2e13ad8 100644
--- a/luni/src/test/java/libcore/java/util/CalendarTest.java
+++ b/luni/src/test/java/libcore/java/util/CalendarTest.java
@@ -263,4 +263,76 @@ public class CalendarTest extends junit.framework.TestCase {
b.setTime(d);
assertEquals(a, b);
}
+
+ public void testCloneMakesDeepCopyOfCalendarFields() {
+ FakeCalendar c = new FakeCalendar();
+ FakeCalendar c2 = (FakeCalendar) c.clone();
+
+ assertFalse(c.getTimeZone() == c2.getTimeZone());
+ assertEquals(c.getTimeZone(), c2.getTimeZone());
+
+ // The default clone() implementation makes a deep copy of calendar
+ // fields...
+ assertFalse(c.getCalenderFields() == c2.getCalenderFields());
+ // ,,, and a shallow copy of subclass fields.
+ assertSame(c.getSubclassFields(), c2.getSubclassFields());
+ }
+
+ public static class FakeCalendar extends Calendar {
+
+ private int[] subclassFields;
+
+ public FakeCalendar() {
+ super(TimeZone.getDefault(), Locale.getDefault());
+ subclassFields = new int[12];
+ }
+
+ public int[] getCalenderFields() {
+ return fields;
+ }
+
+ public int[] getSubclassFields() {
+ return subclassFields;
+ }
+
+ @Override
+ public void add(int field, int value) {
+
+ }
+
+ @Override
+ protected void computeFields() {
+
+ }
+
+ @Override
+ protected void computeTime() {
+
+ }
+
+ @Override
+ public int getGreatestMinimum(int field) {
+ return 0;
+ }
+
+ @Override
+ public int getLeastMaximum(int field) {
+ return 0;
+ }
+
+ @Override
+ public int getMaximum(int field) {
+ return 0;
+ }
+
+ @Override
+ public int getMinimum(int field) {
+ return 0;
+ }
+
+ @Override
+ public void roll(int field, boolean increment) {
+
+ }
+ }
}
diff --git a/luni/src/test/java/libcore/java/util/CollectionsTest.java b/luni/src/test/java/libcore/java/util/CollectionsTest.java
index 80c769e..bc73817 100644
--- a/luni/src/test/java/libcore/java/util/CollectionsTest.java
+++ b/luni/src/test/java/libcore/java/util/CollectionsTest.java
@@ -17,7 +17,10 @@
package libcore.java.util;
import java.io.Serializable;
+import java.util.ArrayList;
import java.util.Collections;
+import java.util.Comparator;
+import java.util.ConcurrentModificationException;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.ListIterator;
@@ -94,4 +97,92 @@ public final class CollectionsTest extends TestCase {
} catch (IllegalStateException expected) {
}
}
+
+ public void testSortFastPath_incrementsModcount() {
+ ArrayList<String> list = new ArrayList<String>(16);
+ list.add("coven");
+ list.add("asylum");
+ list.add("murder house");
+ list.add("freak show");
+
+ Iterator<String> it = list.iterator();
+ it.next();
+ Collections.sort(list);
+ try {
+ it.next();
+ fail();
+ } catch (ConcurrentModificationException expected) {
+ }
+ }
+
+ /**
+ * A value type whose {@code compareTo} method returns one of {@code 0},
+ * {@code Integer.MIN_VALUE} and {@code Integer.MAX_VALUE}.
+ */
+ static final class IntegerWithExtremeComparator
+ implements Comparable<IntegerWithExtremeComparator> {
+ private final int value;
+
+ public IntegerWithExtremeComparator(int value) {
+ this.value = value;
+ }
+
+ @Override
+ public int compareTo(IntegerWithExtremeComparator another) {
+ if (another.value == this.value) {
+ return 0;
+ } else if (another.value > this.value) {
+ return Integer.MIN_VALUE;
+ } else {
+ return Integer.MAX_VALUE;
+ }
+ }
+ }
+
+ // http://b/19749094
+ public void testBinarySearch_comparatorThatReturnsMinAndMaxValue() {
+ ArrayList<Integer> list = new ArrayList<Integer>(16);
+ list.add(4);
+ list.add(9);
+ list.add(11);
+ list.add(14);
+ list.add(16);
+
+ int index = Collections.binarySearch(list, 9, new Comparator<Integer>() {
+ @Override
+ public int compare(Integer lhs, Integer rhs) {
+ final int compare = lhs.compareTo(rhs);
+ if (compare == 0) {
+ return 0;
+ } else if (compare < 0) {
+ return Integer.MIN_VALUE;
+ } else {
+ return Integer.MAX_VALUE;
+ }
+ }
+ });
+ assertEquals(1, index);
+
+ ArrayList<IntegerWithExtremeComparator> list2 =
+ new ArrayList<IntegerWithExtremeComparator>();
+ list2.add(new IntegerWithExtremeComparator(4));
+ list2.add(new IntegerWithExtremeComparator(9));
+ list2.add(new IntegerWithExtremeComparator(11));
+ list2.add(new IntegerWithExtremeComparator(14));
+ list2.add(new IntegerWithExtremeComparator(16));
+
+ assertEquals(1, Collections.binarySearch(list2, new IntegerWithExtremeComparator(9)));
+ }
+
+ public void testBinarySearch_emptyCollection() {
+ assertEquals(-1, Collections.binarySearch(new ArrayList<Integer>(), 9));
+
+ assertEquals(-1, Collections.binarySearch(new ArrayList<Integer>(), 9,
+ new Comparator<Integer>() {
+ @Override
+ public int compare(Integer lhs, Integer rhs) {
+ return lhs.compareTo(rhs);
+ }
+ }));
+ }
}
diff --git a/luni/src/test/java/libcore/java/util/CurrencyTest.java b/luni/src/test/java/libcore/java/util/CurrencyTest.java
index cf2a1b6..e4c56e5 100644
--- a/luni/src/test/java/libcore/java/util/CurrencyTest.java
+++ b/luni/src/test/java/libcore/java/util/CurrencyTest.java
@@ -58,7 +58,7 @@ public class CurrencyTest extends junit.framework.TestCase {
assertEquals("Swiss Franc", Currency.getInstance("CHF").getDisplayName(Locale.US));
assertEquals("Schweizer Franken", Currency.getInstance("CHF").getDisplayName(new Locale("de", "CH")));
assertEquals("franc suisse", Currency.getInstance("CHF").getDisplayName(new Locale("fr", "CH")));
- assertEquals("Franco Svizzero", Currency.getInstance("CHF").getDisplayName(new Locale("it", "CH")));
+ assertEquals("franco svizzero", Currency.getInstance("CHF").getDisplayName(new Locale("it", "CH")));
}
public void test_getDefaultFractionDigits() throws Exception {
diff --git a/luni/src/test/java/libcore/java/util/LocaleTest.java b/luni/src/test/java/libcore/java/util/LocaleTest.java
index c72ecd7..e1e84ab 100644
--- a/luni/src/test/java/libcore/java/util/LocaleTest.java
+++ b/luni/src/test/java/libcore/java/util/LocaleTest.java
@@ -20,6 +20,7 @@ import java.text.BreakIterator;
import java.text.Collator;
import java.text.DateFormat;
import java.text.DateFormatSymbols;
+import java.text.DecimalFormatSymbols;
import java.text.NumberFormat;
import java.util.Calendar;
import java.util.IllformedLocaleException;
@@ -1146,4 +1147,60 @@ public class LocaleTest extends junit.framework.TestCase {
assertEquals("variant", locale.getVariant());
assertEquals(locale, Locale.forLanguageTag(locale.toLanguageTag()));
}
+
+ public void testArabicDigits() throws Exception {
+ // ar-DZ uses latn digits by default, but we can override that.
+ Locale ar_DZ = Locale.forLanguageTag("ar-DZ");
+ Locale ar_DZ_arab = Locale.forLanguageTag("ar-DZ-u-nu-arab");
+ Locale ar_DZ_latn = Locale.forLanguageTag("ar-DZ-u-nu-latn");
+ assertEquals('0', new DecimalFormatSymbols(ar_DZ).getZeroDigit());
+ assertEquals('\u0660', new DecimalFormatSymbols(ar_DZ_arab).getZeroDigit());
+ assertEquals('0', new DecimalFormatSymbols(ar_DZ_latn).getZeroDigit());
+
+ // ar-EG uses arab digits by default, but we can override that.
+ Locale ar_EG = Locale.forLanguageTag("ar-EG");
+ Locale ar_EG_arab = Locale.forLanguageTag("ar-EG-u-nu-arab");
+ Locale ar_EG_latn = Locale.forLanguageTag("ar-EG-u-nu-latn");
+ assertEquals('\u0660', new DecimalFormatSymbols(ar_EG).getZeroDigit());
+ assertEquals('\u0660', new DecimalFormatSymbols(ar_EG_arab).getZeroDigit());
+ assertEquals('0', new DecimalFormatSymbols(ar_EG_latn).getZeroDigit());
+ }
+
+ public void testDefaultLocale() throws Exception {
+ final String userLanguage = System.getProperty("user.language", "");
+ final String userRegion = System.getProperty("user.region", "");
+ final String userLocale = System.getProperty("user.locale", "");
+ try {
+ // Assert that user.locale gets priority.
+ System.setUnchangeableSystemProperty("user.locale", "de-DE");
+ System.setUnchangeableSystemProperty("user.language", "en");
+ System.setUnchangeableSystemProperty("user.region", "US");
+
+ Locale l = Locale.getDefaultLocaleFromSystemProperties();
+ assertEquals("de", l.getLanguage());
+ assertEquals("DE", l.getCountry());
+
+ // Assert that it's parsed as a full language tag.
+ System.setUnchangeableSystemProperty("user.locale", "de-Latn-DE");
+ System.setUnchangeableSystemProperty("user.language", "en");
+ System.setUnchangeableSystemProperty("user.region", "US");
+
+ l = Locale.getDefaultLocaleFromSystemProperties();
+ assertEquals("de", l.getLanguage());
+ assertEquals("DE", l.getCountry());
+ assertEquals("Latn", l.getScript());
+
+ // Assert that we use "und" if we're faced with a bad language tag, and
+ // that we don't end up with a null default locale or an exception.
+ System.setUnchangeableSystemProperty("user.locale", "dexx-Latn-DE");
+
+ l = Locale.getDefaultLocaleFromSystemProperties();
+ assertEquals("und", l.getLanguage());
+ assertEquals("DE", l.getCountry());
+ } finally {
+ System.setUnchangeableSystemProperty("user.language", userLanguage);
+ System.setUnchangeableSystemProperty("user.region", userRegion);
+ System.setUnchangeableSystemProperty("user.locale", userLocale);
+ }
+ }
}
diff --git a/luni/src/test/java/libcore/java/util/OldTimeZoneTest.java b/luni/src/test/java/libcore/java/util/OldTimeZoneTest.java
index ecf2e5f..7a5fc4a 100644
--- a/luni/src/test/java/libcore/java/util/OldTimeZoneTest.java
+++ b/luni/src/test/java/libcore/java/util/OldTimeZoneTest.java
@@ -108,7 +108,7 @@ public class OldTimeZoneTest extends TestCase {
TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles");
assertEquals("Pacific Daylight Time", tz.getDisplayName(true, TimeZone.LONG, Locale.US));
assertEquals("Pacific Standard Time", tz.getDisplayName(false, TimeZone.LONG, Locale.UK));
- assertEquals("heure avanc\u00e9e du Pacifique",
+ assertEquals("heure d’été du Pacifique",
tz.getDisplayName(true, TimeZone.LONG, Locale.FRANCE));
assertEquals("heure normale du Pacifique nord-américain",
tz.getDisplayName(false, TimeZone.LONG, Locale.FRANCE));
@@ -123,18 +123,6 @@ public class OldTimeZoneTest extends TestCase {
assertEquals("GMT-07:00", tz.getDisplayName(true, TimeZone.SHORT, Locale.FRANCE));
assertEquals("GMT-08:00", tz.getDisplayName(false, TimeZone.SHORT, Locale.UK));
assertEquals("GMT-07:00", tz.getDisplayName(true, TimeZone.SHORT, Locale.UK));
-
- // The RI behavior mentioned above does not appear to be because "PST" is a legacy
- // three-character timezone supported by the RI: it happens for "Asia/Tehran"/"IRST" too
- // (IRST is not a legacy code). The RI may just use a different dataset that has "PST" /
- // "IRST" as valid translations (even for scripts like Chinese).
- TimeZone iranTz = TimeZone.getTimeZone("Asia/Tehran");
- assertEquals("Iran Summer Time", iranTz.getDisplayName(true, TimeZone.LONG, Locale.UK));
- assertEquals("Iran Daylight Time", iranTz.getDisplayName(true, TimeZone.LONG, Locale.US));
- assertEquals("Iran Standard Time", iranTz.getDisplayName(false, TimeZone.LONG, Locale.UK));
- assertEquals("Iran Standard Time", iranTz.getDisplayName(false, TimeZone.LONG, Locale.US));
- assertEquals("GMT+03:30", iranTz.getDisplayName(false, TimeZone.SHORT, Locale.UK));
- assertEquals("GMT+04:30", iranTz.getDisplayName(true, TimeZone.SHORT, Locale.UK));
}
public void test_getID() {
diff --git a/luni/src/test/java/libcore/java/util/TimeZoneTest.java b/luni/src/test/java/libcore/java/util/TimeZoneTest.java
index 1ca950c..68e9109 100644
--- a/luni/src/test/java/libcore/java/util/TimeZoneTest.java
+++ b/luni/src/test/java/libcore/java/util/TimeZoneTest.java
@@ -73,6 +73,12 @@ public class TimeZoneTest extends TestCase {
assertFalse(tz.inDaylightTime(date));
}
+ public void testGetDisplayNameShort_nonHourOffsets() {
+ TimeZone iranTz = TimeZone.getTimeZone("Asia/Tehran");
+ assertEquals("GMT+03:30", iranTz.getDisplayName(false, TimeZone.SHORT, Locale.UK));
+ assertEquals("GMT+04:30", iranTz.getDisplayName(true, TimeZone.SHORT, Locale.UK));
+ }
+
public void testPreHistoricOffsets() throws Exception {
// "Africa/Bissau" has just a few transitions and hasn't changed in a long time.
// 1912-01-01 00:02:19-0100 ... 1912-01-01 00:02:20-0100
@@ -256,12 +262,12 @@ public class TimeZoneTest extends TestCase {
}
// http://b/7955614
- public void test_getDisplayName_GMT_short_names() throws Exception {
- TimeZone tz = TimeZone.getTimeZone("America/Santiago");
- assertEquals("Chile Summer Time", tz.getDisplayName(true, TimeZone.LONG, Locale.US));
- assertEquals("Chile Standard Time", tz.getDisplayName(false, TimeZone.LONG, Locale.US));
- assertEquals("GMT-03:00", tz.getDisplayName(true, TimeZone.SHORT, Locale.US));
- assertEquals("GMT-03:00", tz.getDisplayName(false, TimeZone.SHORT, Locale.US));
+ public void testApia() throws Exception {
+ TimeZone tz = TimeZone.getTimeZone("Pacific/Apia");
+ assertEquals("Apia Daylight Time", tz.getDisplayName(true, TimeZone.LONG, Locale.US));
+ assertEquals("Apia Standard Time", tz.getDisplayName(false, TimeZone.LONG, Locale.US));
+ assertEquals("GMT+14:00", tz.getDisplayName(true, TimeZone.SHORT, Locale.US));
+ assertEquals("GMT+13:00", tz.getDisplayName(false, TimeZone.SHORT, Locale.US));
}
private static boolean isGmtString(String s) {
@@ -290,4 +296,32 @@ public class TimeZoneTest extends TestCase {
}
}
}
+
+ // http://b/18839557
+ public void testOverflowing32BitUnixDates() {
+ final TimeZone tz = TimeZone.getTimeZone("America/New_York");
+
+ // This timezone didn't have any daylight savings prior to 1917 and this
+ // date is sometime in 1901.
+ assertFalse(tz.inDaylightTime(new Date(-2206292400000L)));
+ assertEquals(-18000000, tz.getOffset(-2206292400000L));
+
+ // Nov 30th 2039, no daylight savings as per current rules.
+ assertFalse(tz.inDaylightTime(new Date(2206292400000L)));
+ assertEquals(-18000000, tz.getOffset(2206292400000L));
+ }
+
+ public void testTimeZoneIDLocalization() {
+ Locale defaultLocale = Locale.getDefault();
+ try {
+ Locale.setDefault(new Locale("en"));
+ TimeZone en_timezone = TimeZone.getTimeZone("GMT+09:00");
+ Locale.setDefault(new Locale("ar"));
+ TimeZone ar_timezone = TimeZone.getTimeZone("GMT+09:00");
+
+ assertEquals(en_timezone.getID(), ar_timezone.getID());
+ } finally {
+ Locale.setDefault(defaultLocale);
+ }
+ }
}
diff --git a/luni/src/test/java/libcore/java/util/jar/StrictJarFileTest.java b/luni/src/test/java/libcore/java/util/jar/StrictJarFileTest.java
index e5a6cd8..9496ad0 100644
--- a/luni/src/test/java/libcore/java/util/jar/StrictJarFileTest.java
+++ b/luni/src/test/java/libcore/java/util/jar/StrictJarFileTest.java
@@ -169,6 +169,10 @@ public class StrictJarFileTest extends TestCase {
assertThrowsOnInit("Modified_SF_EntryAttributes.jar");
}
+ public void testJarSigning_removedEntry() throws Exception {
+ assertThrowsOnInit("removed.jar");
+ }
+
private void assertThrowsOnInit(String name) throws Exception {
Support_Resources.copyFile(resources, null, name);
try {
diff --git a/luni/src/test/java/libcore/java/util/zip/AbstractZipFileTest.java b/luni/src/test/java/libcore/java/util/zip/AbstractZipFileTest.java
new file mode 100644
index 0000000..9e049c0
--- /dev/null
+++ b/luni/src/test/java/libcore/java/util/zip/AbstractZipFileTest.java
@@ -0,0 +1,548 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package libcore.java.util.zip;
+
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Random;
+import java.util.Set;
+import java.util.zip.CRC32;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipException;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipInputStream;
+import java.util.zip.ZipOutputStream;
+import junit.framework.TestCase;
+
+import tests.support.resource.Support_Resources;
+
+public abstract class AbstractZipFileTest extends TestCase {
+ /**
+ * Exercise Inflater's ability to refill the zlib's input buffer. As of this
+ * writing, this buffer's max size is 64KiB compressed bytes. We'll write a
+ * full megabyte of uncompressed data, which should be sufficient to exhaust
+ * the buffer. http://b/issue?id=2734751
+ */
+ public void testInflatingFilesRequiringZipRefill() throws IOException {
+ int originalSize = 1024 * 1024;
+ byte[] readBuffer = new byte[8192];
+ final File f = createTemporaryZipFile();
+ writeEntries(createZipOutputStream(f), 1, originalSize, false /* setEntrySize */);
+ ZipFile zipFile = new ZipFile(f);
+ for (Enumeration<? extends ZipEntry> e = zipFile.entries(); e.hasMoreElements(); ) {
+ ZipEntry zipEntry = e.nextElement();
+ assertTrue("This test needs >64 KiB of compressed data to exercise Inflater",
+ zipEntry.getCompressedSize() > (64 * 1024));
+ InputStream is = zipFile.getInputStream(zipEntry);
+ while (is.read(readBuffer, 0, readBuffer.length) != -1) {}
+ is.close();
+ }
+ zipFile.close();
+ }
+
+ private static void replaceBytes(byte[] buffer, byte[] original, byte[] replacement) {
+ // Gotcha here: original and replacement must be the same length
+ assertEquals(original.length, replacement.length);
+ boolean found;
+ for(int i=0; i < buffer.length - original.length; i++) {
+ found = false;
+ if (buffer[i] == original[0]) {
+ found = true;
+ for (int j=0; j < original.length; j++) {
+ if (buffer[i+j] != original[j]) {
+ found = false;
+ break;
+ }
+ }
+ }
+ if (found) {
+ for (int j=0; j < original.length; j++) {
+ buffer[i+j] = replacement[j];
+ }
+ }
+ }
+ }
+
+ private static void writeBytes(File f, byte[] bytes) throws IOException {
+ FileOutputStream out = new FileOutputStream(f);
+ out.write(bytes);
+ out.close();
+ }
+
+ /**
+ * Make sure we don't fail silently for duplicate entries.
+ * b/8219321
+ */
+ public void testDuplicateEntries() throws Exception {
+ String name1 = "test_file_name1";
+ String name2 = "test_file_name2";
+
+ // Create the good zip file.
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ ZipOutputStream out = createZipOutputStream(baos);
+ out.putNextEntry(new ZipEntry(name2));
+ out.closeEntry();
+ out.putNextEntry(new ZipEntry(name1));
+ out.closeEntry();
+ out.close();
+
+ // Rewrite one of the filenames.
+ byte[] buffer = baos.toByteArray();
+ replaceBytes(buffer, name2.getBytes(), name1.getBytes());
+
+ // Write the result to a file.
+ File badZip = createTemporaryZipFile();
+ writeBytes(badZip, buffer);
+
+ // Check that we refuse to load the modified file.
+ try {
+ ZipFile bad = new ZipFile(badZip);
+ fail();
+ } catch (ZipException expected) {
+ }
+ }
+
+ /**
+ * Make sure the size used for stored zip entires is the uncompressed size.
+ * b/10227498
+ */
+ public void testStoredEntrySize() throws Exception {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ ZipOutputStream out = createZipOutputStream(baos);
+
+ // Set up a single stored entry.
+ String name = "test_file";
+ int expectedLength = 5;
+ ZipEntry outEntry = new ZipEntry(name);
+ byte[] buffer = new byte[expectedLength];
+ outEntry.setMethod(ZipEntry.STORED);
+ CRC32 crc = new CRC32();
+ crc.update(buffer);
+ outEntry.setCrc(crc.getValue());
+ outEntry.setSize(buffer.length);
+
+ out.putNextEntry(outEntry);
+ out.write(buffer);
+ out.closeEntry();
+ out.close();
+
+ // Write the result to a file.
+ byte[] outBuffer = baos.toByteArray();
+ File zipFile = createTemporaryZipFile();
+ writeBytes(zipFile, outBuffer);
+
+ ZipFile zip = new ZipFile(zipFile);
+ // Set up the zip entry to have different compressed/uncompressed sizes.
+ ZipEntry ze = zip.getEntry(name);
+ ze.setCompressedSize(expectedLength - 1);
+ // Read the contents of the stream and verify uncompressed size was used.
+ InputStream stream = zip.getInputStream(ze);
+ int count = 0;
+ int read;
+ while ((read = stream.read(buffer)) != -1) {
+ count += read;
+ }
+
+ assertEquals(expectedLength, count);
+ zip.close();
+ }
+
+ public void testInflatingStreamsRequiringZipRefill() throws IOException {
+ int originalSize = 1024 * 1024;
+ byte[] readBuffer = new byte[8192];
+ final File f = createTemporaryZipFile();
+ writeEntries(createZipOutputStream(f), 1, originalSize, false /* setEntrySize */);
+
+ ZipInputStream in = new ZipInputStream(new FileInputStream(f));
+ while (in.getNextEntry() != null) {
+ while (in.read(readBuffer, 0, readBuffer.length) != -1) {}
+ }
+ in.close();
+ }
+
+ public void testZipFileWithLotsOfEntries() throws IOException {
+ int expectedEntryCount = 64*1024 - 1;
+ final File f = createTemporaryZipFile();
+ writeEntries(createZipOutputStream(f), expectedEntryCount, 0, false /* setEntrySize */);
+ ZipFile zipFile = new ZipFile(f);
+ int entryCount = 0;
+ for (Enumeration<? extends ZipEntry> e = zipFile.entries(); e.hasMoreElements(); ) {
+ ZipEntry zipEntry = e.nextElement();
+ ++entryCount;
+ }
+ assertEquals(expectedEntryCount, entryCount);
+ zipFile.close();
+ }
+
+ // http://code.google.com/p/android/issues/detail?id=36187
+ public void testZipFileLargerThan2GiB() throws IOException {
+ if (false) { // TODO: this test requires too much time and too much disk space!
+ final File f = createTemporaryZipFile();
+ writeEntries(createZipOutputStream(f), 1024, 3*1024*1024, false /* setEntrySize */);
+ ZipFile zipFile = new ZipFile(f);
+ int entryCount = 0;
+ for (Enumeration<? extends ZipEntry> e = zipFile.entries(); e.hasMoreElements(); ) {
+ e.nextElement();
+ ++entryCount;
+ }
+ assertEquals(1024, entryCount);
+ zipFile.close();
+ }
+ }
+
+ /**
+ * Compresses the given number of files, each of the given size, into a .zip archive.
+ */
+ protected void writeEntries(ZipOutputStream out, int entryCount, long entrySize,
+ boolean setEntrySize)
+ throws IOException {
+ byte[] writeBuffer = new byte[8192];
+ Random random = new Random();
+ try {
+ for (int entry = 0; entry < entryCount; ++entry) {
+ ZipEntry ze = new ZipEntry(Integer.toHexString(entry));
+ if (setEntrySize) {
+ ze.setSize(entrySize);
+ }
+ out.putNextEntry(ze);
+
+ for (long i = 0; i < entrySize; i += writeBuffer.length) {
+ random.nextBytes(writeBuffer);
+ int byteCount = (int) Math.min(writeBuffer.length, entrySize - i);
+ out.write(writeBuffer, 0, byteCount);
+ }
+
+ out.closeEntry();
+ }
+ } finally {
+ out.close();
+ }
+ }
+
+ static File createTemporaryZipFile() throws IOException {
+ File result = File.createTempFile("ZipFileTest", ".zip");
+ result.deleteOnExit();
+ return result;
+ }
+
+ private ZipOutputStream createZipOutputStream(File f) throws IOException {
+ return createZipOutputStream(new BufferedOutputStream(new FileOutputStream(f)));
+ }
+
+ protected abstract ZipOutputStream createZipOutputStream(OutputStream wrapped);
+
+ public void testSTORED() throws IOException {
+ ZipOutputStream out = createZipOutputStream(createTemporaryZipFile());
+ CRC32 crc = new CRC32();
+
+ // Missing CRC, size, and compressed size => failure.
+ try {
+ ZipEntry ze = new ZipEntry("a");
+ ze.setMethod(ZipEntry.STORED);
+ out.putNextEntry(ze);
+ fail();
+ } catch (ZipException expected) {
+ }
+
+ // Missing CRC and compressed size => failure.
+ try {
+ ZipEntry ze = new ZipEntry("a");
+ ze.setMethod(ZipEntry.STORED);
+ ze.setSize(0);
+ out.putNextEntry(ze);
+ fail();
+ } catch (ZipException expected) {
+ }
+
+ // Missing CRC and size => failure.
+ try {
+ ZipEntry ze = new ZipEntry("a");
+ ze.setMethod(ZipEntry.STORED);
+ ze.setSize(0);
+ ze.setCompressedSize(0);
+ out.putNextEntry(ze);
+ fail();
+ } catch (ZipException expected) {
+ }
+
+ // Missing size and compressed size => failure.
+ try {
+ ZipEntry ze = new ZipEntry("a");
+ ze.setMethod(ZipEntry.STORED);
+ ze.setCrc(crc.getValue());
+ out.putNextEntry(ze);
+ fail();
+ } catch (ZipException expected) {
+ }
+
+ // Missing size is copied from compressed size.
+ {
+ ZipEntry ze = new ZipEntry("okay1");
+ ze.setMethod(ZipEntry.STORED);
+ ze.setCrc(crc.getValue());
+
+ assertEquals(-1, ze.getSize());
+ assertEquals(-1, ze.getCompressedSize());
+
+ ze.setCompressedSize(0);
+
+ assertEquals(-1, ze.getSize());
+ assertEquals(0, ze.getCompressedSize());
+
+ out.putNextEntry(ze);
+
+ assertEquals(0, ze.getSize());
+ assertEquals(0, ze.getCompressedSize());
+ }
+
+ // Missing compressed size is copied from size.
+ {
+ ZipEntry ze = new ZipEntry("okay2");
+ ze.setMethod(ZipEntry.STORED);
+ ze.setCrc(crc.getValue());
+
+ assertEquals(-1, ze.getSize());
+ assertEquals(-1, ze.getCompressedSize());
+
+ ze.setSize(0);
+
+ assertEquals(0, ze.getSize());
+ assertEquals(-1, ze.getCompressedSize());
+
+ out.putNextEntry(ze);
+
+ assertEquals(0, ze.getSize());
+ assertEquals(0, ze.getCompressedSize());
+ }
+
+ // Mismatched size and compressed size => failure.
+ try {
+ ZipEntry ze = new ZipEntry("a");
+ ze.setMethod(ZipEntry.STORED);
+ ze.setCrc(crc.getValue());
+ ze.setCompressedSize(1);
+ ze.setSize(0);
+ out.putNextEntry(ze);
+ fail();
+ } catch (ZipException expected) {
+ }
+
+ // Everything present => success.
+ ZipEntry ze = new ZipEntry("okay");
+ ze.setMethod(ZipEntry.STORED);
+ ze.setCrc(crc.getValue());
+ ze.setSize(0);
+ ze.setCompressedSize(0);
+ out.putNextEntry(ze);
+
+ out.close();
+ }
+
+ private String makeString(int count, String ch) {
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < count; ++i) {
+ sb.append(ch);
+ }
+ return sb.toString();
+ }
+
+ public void testComments() throws Exception {
+ String expectedFileComment = "1 \u0666 2";
+ String expectedEntryComment = "a \u0666 b";
+
+ File file = createTemporaryZipFile();
+ ZipOutputStream out = createZipOutputStream(file);
+
+ // Is file comment length checking done on bytes or characters? (Should be bytes.)
+ out.setComment(null);
+ out.setComment(makeString(0xffff, "a"));
+ try {
+ out.setComment(makeString(0xffff + 1, "a"));
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+ try {
+ out.setComment(makeString(0xffff, "\u0666"));
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+
+ ZipEntry ze = new ZipEntry("a");
+
+ // Is entry comment length checking done on bytes or characters? (Should be bytes.)
+ ze.setComment(null);
+ ze.setComment(makeString(0xffff, "a"));
+ try {
+ ze.setComment(makeString(0xffff + 1, "a"));
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+ try {
+ ze.setComment(makeString(0xffff, "\u0666"));
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+
+ ze.setComment(expectedEntryComment);
+ out.putNextEntry(ze);
+ out.closeEntry();
+
+ out.setComment(expectedFileComment);
+ out.close();
+
+ ZipFile zipFile = new ZipFile(file);
+ assertEquals(expectedFileComment, zipFile.getComment());
+ assertEquals(expectedEntryComment, zipFile.getEntry("a").getComment());
+ zipFile.close();
+ }
+
+ public void test_getComment_unset() throws Exception {
+ File file = createTemporaryZipFile();
+ ZipOutputStream out = createZipOutputStream(file);
+ ZipEntry ze = new ZipEntry("test entry");
+ ze.setComment("per-entry comment");
+ out.putNextEntry(ze);
+ out.close();
+
+ ZipFile zipFile = new ZipFile(file);
+ assertEquals(null, zipFile.getComment());
+ }
+
+ // https://code.google.com/p/android/issues/detail?id=58465
+ public void test_NUL_in_filename() throws Exception {
+ File file = createTemporaryZipFile();
+
+ // We allow creation of a ZipEntry whose name contains a NUL byte,
+ // mainly because it's not likely to happen by accident and it's useful for testing.
+ ZipOutputStream out = createZipOutputStream(file);
+ out.putNextEntry(new ZipEntry("hello"));
+ out.putNextEntry(new ZipEntry("hello\u0000"));
+ out.close();
+
+ // But you can't open a ZIP file containing such an entry, because we reject it
+ // when we find it in the central directory.
+ try {
+ ZipFile zipFile = new ZipFile(file);
+ fail();
+ } catch (ZipException expected) {
+ }
+ }
+
+ public void testCrc() throws IOException {
+ ZipEntry ze = new ZipEntry("test");
+ ze.setMethod(ZipEntry.STORED);
+ ze.setSize(4);
+
+ // setCrc takes a long, not an int, so -1 isn't a valid CRC32 (because it's 64 bits).
+ try {
+ ze.setCrc(-1);
+ } catch (IllegalArgumentException expected) {
+ }
+
+ // You can set the CRC32 to 0xffffffff if you're slightly more careful though...
+ ze.setCrc(0xffffffffL);
+ assertEquals(0xffffffffL, ze.getCrc());
+
+ // And it actually works, even though we use -1L to mean "no CRC set"...
+ ZipOutputStream out = createZipOutputStream(createTemporaryZipFile());
+ out.putNextEntry(ze);
+ out.write(-1);
+ out.write(-1);
+ out.write(-1);
+ out.write(-1);
+ out.closeEntry();
+ out.close();
+ }
+
+ /**
+ * RI does not allow reading of an empty zip using a {@link ZipFile}.
+ */
+ public void testConstructorFailsWhenReadingEmptyZipArchive() throws IOException {
+
+ File resources = Support_Resources.createTempFolder();
+ File emptyZip = Support_Resources.copyFile(
+ resources, "java/util/zip", "EmptyArchive.zip");
+
+ try {
+ // The following should fail with an exception but if it doesn't then we need to clean
+ // up the resource so we need a reference to it.
+ ZipFile zipFile = new ZipFile(emptyZip);
+
+ // Clean up the resource.
+ try {
+ zipFile.close();
+ } catch (Exception e) {
+ // Ignore
+ }
+ fail();
+ } catch (ZipException expected) {
+ // expected
+ }
+ }
+
+ // Demonstrates http://b/18644314 : Zip entry names are relative to the point of
+ // extraction and can contain relative paths "../" and "./".
+ //
+ // It is left to callers of the API to perform any validation / santization to
+ // ensure that files are not written outside of the destination directory, where that
+ // is a concern.
+ public void testArchivesWithRelativePaths() throws IOException {
+ String[] entryNames = {
+ "../",
+ "../foo.bar",
+ "foo/../../",
+ "foo/../../bar.baz"
+ };
+
+ File zip = createTemporaryZipFile();
+ ZipOutputStream out = createZipOutputStream(zip);
+
+ try {
+ byte[] entryData = new byte[1024];
+ for (String entryName : entryNames) {
+ ZipEntry ze = new ZipEntry(entryName);
+ out.putNextEntry(ze);
+ out.write(entryData);
+ out.closeEntry();
+ }
+ } finally {
+ out.close();
+ }
+
+ ZipFile zf = new ZipFile(zip, ZipFile.OPEN_READ);
+ Enumeration<? extends ZipEntry> entries = zf.entries();
+ Set<String> entryNamesFromFile = new HashSet<>();
+ while (entries.hasMoreElements()) {
+ ZipEntry ze = entries.nextElement();
+ entryNamesFromFile.add(ze.getName());
+ }
+
+ zf.close();
+
+ for (String entryName : entryNames) {
+ assertTrue(entryNamesFromFile.contains(entryName));
+ }
+ }
+}
diff --git a/luni/src/test/java/libcore/java/util/zip/DeflaterTest.java b/luni/src/test/java/libcore/java/util/zip/DeflaterTest.java
index 30aa7f3..1dfa775 100644
--- a/luni/src/test/java/libcore/java/util/zip/DeflaterTest.java
+++ b/luni/src/test/java/libcore/java/util/zip/DeflaterTest.java
@@ -82,4 +82,26 @@ public class DeflaterTest extends TestCase {
assertTrue(totalDeflated > 0); // the deflated form should be non-empty
assertEquals(0, totalInflated);
}
+
+ public void testDeflaterCounts() throws Exception {
+ deflater.setInput(new byte[] { 1, 2, 3 });
+ assertEquals(11, deflater.deflate(compressed, 0, compressed.length, Deflater.FULL_FLUSH));
+ assertEquals(3, deflater.getBytesRead());
+ assertEquals(3, deflater.getTotalIn());
+ assertEquals(11, deflater.getBytesWritten());
+ assertEquals(11, deflater.getTotalOut());
+
+ deflater.setInput(new byte[] { 1, 2, 3 });
+ assertEquals(9, deflater.deflate(compressed, 0, compressed.length, Deflater.FULL_FLUSH));
+ assertEquals(6, deflater.getBytesRead());
+ assertEquals(6, deflater.getTotalIn());
+ assertEquals(20, deflater.getBytesWritten());
+
+
+ deflater.reset();
+ assertEquals(0, deflater.getBytesRead());
+ assertEquals(0, deflater.getBytesWritten());
+ assertEquals(0, deflater.getTotalIn());
+ assertEquals(0, deflater.getTotalOut());
+ }
}
diff --git a/luni/src/test/java/libcore/java/util/zip/GZIPInputStreamTest.java b/luni/src/test/java/libcore/java/util/zip/GZIPInputStreamTest.java
index 494520a..5813753 100644
--- a/luni/src/test/java/libcore/java/util/zip/GZIPInputStreamTest.java
+++ b/luni/src/test/java/libcore/java/util/zip/GZIPInputStreamTest.java
@@ -35,14 +35,46 @@ import libcore.io.Streams;
public final class GZIPInputStreamTest extends TestCase {
private static final byte[] HELLO_WORLD_GZIPPED = new byte[] {
- 31, -117, 8, 0, 0, 0, 0, 0, 0, 0, -13, 72, -51, -55, -55, 87, 8, -49,
- 47, -54, 73, 1, 0, 86, -79, 23, 74, 11, 0, 0, 0
+ 31, -117, 8, 0, 0, 0, 0, 0, 0, 0, // 10 byte header
+ -13, 72, -51, -55, -55, 87, 8, -49, 47, -54, 73, 1, 0, 86, -79, 23, 74, 11, 0, 0, 0 // data
+ };
+
+ /**
+ * This is the same as the above, except that the 4th header byte is 2 (FHCRC flag)
+ * and the 2 bytes after the header make up the CRC.
+ *
+ * Constructed manually because none of the commonly used tools appear to emit header CRCs.
+ */
+ private static final byte[] HELLO_WORLD_GZIPPED_WITH_HEADER_CRC = new byte[] {
+ 31, -117, 8, 2, 0, 0, 0, 0, 0, 0, // 10 byte header
+ 29, 38, // 2 byte CRC.
+ -13, 72, -51, -55, -55, 87, 8, -49, 47, -54, 73, 1, 0, 86, -79, 23, 74, 11, 0, 0, 0 // data
+ };
+
+ /*(
+ * This is the same as {@code HELLO_WORLD_GZIPPED} except that the 4th header byte is 4
+ * (FEXTRA flag) and that the 8 bytes after the header make up the extra.
+ *
+ * Constructed manually because none of the commonly used tools appear to emit header CRCs.
+ */
+ private static final byte[] HELLO_WORLD_GZIPPED_WITH_EXTRA = new byte[] {
+ 31, -117, 8, 4, 0, 0, 0, 0, 0, 0, // 10 byte header
+ 6, 0, 4, 2, 4, 2, 4, 2, // 2 byte extra length + 6 byte extra.
+ -13, 72, -51, -55, -55, 87, 8, -49, 47, -54, 73, 1, 0, 86, -79, 23, 74, 11, 0, 0, 0 // data
};
public void testShortMessage() throws IOException {
assertEquals("Hello World", new String(gunzip(HELLO_WORLD_GZIPPED), "UTF-8"));
}
+ public void testShortMessageWithCrc() throws IOException {
+ assertEquals("Hello World", new String(gunzip(HELLO_WORLD_GZIPPED_WITH_HEADER_CRC), "UTF-8"));
+ }
+
+ public void testShortMessageWithHeaderExtra() throws IOException {
+ assertEquals("Hello World", new String(gunzip(HELLO_WORLD_GZIPPED_WITH_EXTRA), "UTF-8"));
+ }
+
public void testLongMessage() throws IOException {
byte[] data = new byte[1024 * 1024];
new Random().nextBytes(data);
diff --git a/luni/src/test/java/libcore/java/util/zip/InflaterTest.java b/luni/src/test/java/libcore/java/util/zip/InflaterTest.java
index 158b3e9..cce08f3 100644
--- a/luni/src/test/java/libcore/java/util/zip/InflaterTest.java
+++ b/luni/src/test/java/libcore/java/util/zip/InflaterTest.java
@@ -122,4 +122,35 @@ public class InflaterTest extends TestCase {
adler32.update(bytes);
return (int) adler32.getValue();
}
+
+ public void testInflaterCounts() throws Exception {
+ Inflater inflater = new Inflater();
+
+ byte[] decompressed = new byte[32];
+ byte[] compressed = deflate(new byte[] { 1, 2, 3}, null);
+ assertEquals(11, compressed.length);
+
+ // Feed in bytes [0, 5) to the first iteration.
+ inflater.setInput(compressed, 0, 5);
+ inflater.inflate(decompressed, 0, decompressed.length);
+ assertEquals(5, inflater.getBytesRead());
+ assertEquals(5, inflater.getTotalIn());
+ assertEquals(2, inflater.getBytesWritten());
+ assertEquals(2, inflater.getTotalOut());
+
+ // Feed in bytes [5, 11) to the second iteration.
+ assertEquals(true, inflater.needsInput());
+ inflater.setInput(compressed, 5, 6);
+ assertEquals(1, inflater.inflate(decompressed, 0, decompressed.length));
+ assertEquals(11, inflater.getBytesRead());
+ assertEquals(11, inflater.getTotalIn());
+ assertEquals(3, inflater.getBytesWritten());
+ assertEquals(3, inflater.getTotalOut());
+
+ inflater.reset();
+ assertEquals(0, inflater.getBytesRead());
+ assertEquals(0, inflater.getTotalIn());
+ assertEquals(0, inflater.getBytesWritten());
+ assertEquals(0, inflater.getTotalOut());
+ }
}
diff --git a/luni/src/test/java/libcore/java/util/zip/Zip64FileTest.java b/luni/src/test/java/libcore/java/util/zip/Zip64FileTest.java
new file mode 100644
index 0000000..1b733f9
--- /dev/null
+++ b/luni/src/test/java/libcore/java/util/zip/Zip64FileTest.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package libcore.java.util.zip;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Enumeration;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipOutputStream;
+
+public final class Zip64FileTest extends AbstractZipFileTest {
+ @Override
+ protected ZipOutputStream createZipOutputStream(OutputStream wrapped) {
+ return new ZipOutputStream(wrapped, true /* forceZip64 */);
+ }
+
+ public void testZip64Support_largeNumberOfEntries() throws IOException {
+ final File file = createZipFile(65550, 2, false /* setEntrySize */);
+ ZipFile zf = null;
+ try {
+ zf = new ZipFile(file);
+ assertEquals(65550, zf.size());
+
+ Enumeration<? extends ZipEntry> entries = zf.entries();
+ assertTrue(entries.hasMoreElements());
+ ZipEntry ze = entries.nextElement();
+ assertEquals(2, ze.getSize());
+ } finally {
+ if (zf != null) {
+ zf.close();
+ }
+ }
+ }
+
+ public void testZip64Support_totalLargerThan4G() throws IOException {
+ final File file = createZipFile(5, 1073741824L, false /* setEntrySize */);
+ ZipFile zf = null;
+ try {
+ zf = new ZipFile(file);
+ assertEquals(5, zf.size());
+ Enumeration<? extends ZipEntry> entries = zf.entries();
+ assertTrue(entries.hasMoreElements());
+ ZipEntry ze = entries.nextElement();
+ assertEquals(1073741824L, ze.getSize());
+ } finally {
+ if (zf != null) {
+ zf.close();
+ }
+ }
+ }
+
+ public void testZip64Support_hugeEntry() throws IOException {
+ try {
+ createZipFile(1, 4294967410L, false /* setEntrySize */);
+ fail();
+ } catch (IOException expected) {
+ }
+
+ final File file = createZipFile(1, 4294967410L, true /* setEntrySize */);
+ ZipFile zf = null;
+ try {
+ zf = new ZipFile(file);
+ assertEquals(1, zf.size());
+ Enumeration<? extends ZipEntry> entries = zf.entries();
+ assertTrue(entries.hasMoreElements());
+ ZipEntry ze = entries.nextElement();
+ assertEquals(4294967410L, ze.getSize());
+ } finally {
+ if (zf != null) {
+ zf.close();
+ }
+ }
+ }
+
+ private File createZipFile(int numEntries, long entrySize, boolean setEntrySize)
+ throws IOException {
+ File file = createTemporaryZipFile();
+ // Don't force a 64 bit zip file to test that our heuristics work.
+ ZipOutputStream os = new ZipOutputStream(
+ new BufferedOutputStream(new FileOutputStream(file)));
+ writeEntries(os, numEntries, entrySize, setEntrySize);
+ return file;
+ }
+}
diff --git a/luni/src/test/java/libcore/java/util/zip/ZipEntryTest.java b/luni/src/test/java/libcore/java/util/zip/ZipEntryTest.java
index 550ddfb..c7667b9 100644
--- a/luni/src/test/java/libcore/java/util/zip/ZipEntryTest.java
+++ b/luni/src/test/java/libcore/java/util/zip/ZipEntryTest.java
@@ -25,6 +25,7 @@ import java.util.Arrays;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.zip.ZipEntry;
+import java.util.zip.ZipException;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
@@ -132,6 +133,7 @@ public class ZipEntryTest extends junit.framework.TestCase {
File f = createTemporaryZipFile();
ZipOutputStream out = createZipOutputStream(f);
ZipEntry ze = new ZipEntry("x");
+ ze.setSize(0);
ze.setExtra(maxLengthExtra);
out.putNextEntry(ze);
out.closeEntry();
@@ -143,6 +145,25 @@ public class ZipEntryTest extends junit.framework.TestCase {
zipFile.close();
}
+ public void testMaxLengthExtra_zip64() throws Exception {
+ // Not quite the max length (65535), but large enough that there's no space
+ // for the zip64 extended info header.
+ byte[] maxLengthExtra = new byte[65530];
+
+ File f = createTemporaryZipFile();
+ ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(f)),
+ true /* forceZip64 */);
+ ZipEntry ze = new ZipEntry("x");
+
+ ze.setExtra(maxLengthExtra);
+ try {
+ out.putNextEntry(ze);
+ fail();
+ } catch (ZipException expected) {
+ }
+ }
+
+
public void testTooLongComment() throws Exception {
String tooLongComment = makeString(65536, "z");
ZipEntry ze = new ZipEntry("x");
@@ -176,7 +197,17 @@ public class ZipEntryTest extends junit.framework.TestCase {
File f = createTemporaryZipFile();
ZipOutputStream out = createZipOutputStream(f);
+
+ // Regular (non zip64) format.
ZipEntry ze = new ZipEntry("x");
+ ze.setSize(0);
+ ze.setExtra(extra);
+ ze.setComment(comment);
+ out.putNextEntry(ze);
+ out.closeEntry();
+
+ // An entry without a length is assumed to be zip64.
+ ze = new ZipEntry("y");
ze.setExtra(extra);
ze.setComment(comment);
out.putNextEntry(ze);
@@ -188,6 +219,9 @@ public class ZipEntryTest extends junit.framework.TestCase {
try {
assertEquals(comment, zipFile.getEntry("x").getComment());
assertTrue(Arrays.equals(extra, zipFile.getEntry("x").getExtra()));
+
+ assertEquals(comment, zipFile.getEntry("y").getComment());
+ assertTrue(Arrays.equals(extra, zipFile.getEntry("y").getExtra()));
} finally {
zipFile.close();
}
diff --git a/luni/src/test/java/libcore/java/util/zip/ZipFileTest.java b/luni/src/test/java/libcore/java/util/zip/ZipFileTest.java
index a9ff56f..02210ac 100644
--- a/luni/src/test/java/libcore/java/util/zip/ZipFileTest.java
+++ b/luni/src/test/java/libcore/java/util/zip/ZipFileTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -11,497 +11,18 @@
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
- * limitations under the License.
+ * limitations under the License
*/
package libcore.java.util.zip;
-import java.io.BufferedOutputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
import java.io.OutputStream;
-import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.Enumeration;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Random;
-import java.util.Set;
-import java.util.zip.CRC32;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipException;
-import java.util.zip.ZipFile;
-import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
-import junit.framework.TestCase;
-import tests.support.resource.Support_Resources;
+public final class ZipFileTest extends AbstractZipFileTest {
-public final class ZipFileTest extends TestCase {
- /**
- * Exercise Inflater's ability to refill the zlib's input buffer. As of this
- * writing, this buffer's max size is 64KiB compressed bytes. We'll write a
- * full megabyte of uncompressed data, which should be sufficient to exhaust
- * the buffer. http://b/issue?id=2734751
- */
- public void testInflatingFilesRequiringZipRefill() throws IOException {
- int originalSize = 1024 * 1024;
- byte[] readBuffer = new byte[8192];
- ZipFile zipFile = new ZipFile(createZipFile(1, originalSize));
- for (Enumeration<? extends ZipEntry> e = zipFile.entries(); e.hasMoreElements(); ) {
- ZipEntry zipEntry = e.nextElement();
- assertTrue("This test needs >64 KiB of compressed data to exercise Inflater",
- zipEntry.getCompressedSize() > (64 * 1024));
- InputStream is = zipFile.getInputStream(zipEntry);
- while (is.read(readBuffer, 0, readBuffer.length) != -1) {}
- is.close();
- }
- zipFile.close();
- }
-
- private static void replaceBytes(byte[] buffer, byte[] original, byte[] replacement) {
- // Gotcha here: original and replacement must be the same length
- assertEquals(original.length, replacement.length);
- boolean found;
- for(int i=0; i < buffer.length - original.length; i++) {
- found = false;
- if (buffer[i] == original[0]) {
- found = true;
- for (int j=0; j < original.length; j++) {
- if (buffer[i+j] != original[j]) {
- found = false;
- break;
- }
- }
- }
- if (found) {
- for (int j=0; j < original.length; j++) {
- buffer[i+j] = replacement[j];
- }
- }
- }
- }
-
- private static void writeBytes(File f, byte[] bytes) throws IOException {
- FileOutputStream out = new FileOutputStream(f);
- out.write(bytes);
- out.close();
- }
-
- /**
- * Make sure we don't fail silently for duplicate entries.
- * b/8219321
- */
- public void testDuplicateEntries() throws Exception {
- String name1 = "test_file_name1";
- String name2 = "test_file_name2";
-
- // Create the good zip file.
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- ZipOutputStream out = new ZipOutputStream(baos);
- out.putNextEntry(new ZipEntry(name2));
- out.closeEntry();
- out.putNextEntry(new ZipEntry(name1));
- out.closeEntry();
- out.close();
-
- // Rewrite one of the filenames.
- byte[] buffer = baos.toByteArray();
- replaceBytes(buffer, name2.getBytes(), name1.getBytes());
-
- // Write the result to a file.
- File badZip = createTemporaryZipFile();
- writeBytes(badZip, buffer);
-
- // Check that we refuse to load the modified file.
- try {
- ZipFile bad = new ZipFile(badZip);
- fail();
- } catch (ZipException expected) {
- }
- }
-
- /**
- * Make sure the size used for stored zip entires is the uncompressed size.
- * b/10227498
- */
- public void testStoredEntrySize() throws Exception {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- ZipOutputStream out = new ZipOutputStream(baos);
-
- // Set up a single stored entry.
- String name = "test_file";
- int expectedLength = 5;
- ZipEntry outEntry = new ZipEntry(name);
- byte[] buffer = new byte[expectedLength];
- outEntry.setMethod(ZipEntry.STORED);
- CRC32 crc = new CRC32();
- crc.update(buffer);
- outEntry.setCrc(crc.getValue());
- outEntry.setSize(buffer.length);
-
- out.putNextEntry(outEntry);
- out.write(buffer);
- out.closeEntry();
- out.close();
-
- // Write the result to a file.
- byte[] outBuffer = baos.toByteArray();
- File zipFile = createTemporaryZipFile();
- writeBytes(zipFile, outBuffer);
-
- ZipFile zip = new ZipFile(zipFile);
- // Set up the zip entry to have different compressed/uncompressed sizes.
- ZipEntry ze = zip.getEntry(name);
- ze.setCompressedSize(expectedLength - 1);
- // Read the contents of the stream and verify uncompressed size was used.
- InputStream stream = zip.getInputStream(ze);
- int count = 0;
- int read;
- while ((read = stream.read(buffer)) != -1) {
- count += read;
- }
-
- assertEquals(expectedLength, count);
- zip.close();
- }
-
- public void testInflatingStreamsRequiringZipRefill() throws IOException {
- int originalSize = 1024 * 1024;
- byte[] readBuffer = new byte[8192];
- ZipInputStream in = new ZipInputStream(new FileInputStream(createZipFile(1, originalSize)));
- while (in.getNextEntry() != null) {
- while (in.read(readBuffer, 0, readBuffer.length) != -1) {}
- }
- in.close();
- }
-
- public void testZipFileWithLotsOfEntries() throws IOException {
- int expectedEntryCount = 64*1024 - 1;
- File f = createZipFile(expectedEntryCount, 0);
- ZipFile zipFile = new ZipFile(f);
- int entryCount = 0;
- for (Enumeration<? extends ZipEntry> e = zipFile.entries(); e.hasMoreElements(); ) {
- ZipEntry zipEntry = e.nextElement();
- ++entryCount;
- }
- assertEquals(expectedEntryCount, entryCount);
- zipFile.close();
- }
-
- // http://code.google.com/p/android/issues/detail?id=36187
- public void testZipFileLargerThan2GiB() throws IOException {
- if (false) { // TODO: this test requires too much time and too much disk space!
- File f = createZipFile(1024, 3*1024*1024);
- ZipFile zipFile = new ZipFile(f);
- int entryCount = 0;
- for (Enumeration<? extends ZipEntry> e = zipFile.entries(); e.hasMoreElements(); ) {
- ZipEntry zipEntry = e.nextElement();
- ++entryCount;
- }
- assertEquals(1024, entryCount);
- zipFile.close();
- }
- }
-
- public void testZip64Support() throws IOException {
- try {
- createZipFile(64*1024, 0);
- fail(); // Make this test more like testHugeZipFile when we have Zip64 support.
- } catch (ZipException expected) {
- }
- }
-
- /**
- * Compresses the given number of files, each of the given size, into a .zip archive.
- */
- private File createZipFile(int entryCount, int entrySize) throws IOException {
- File result = createTemporaryZipFile();
-
- byte[] writeBuffer = new byte[8192];
- Random random = new Random();
-
- ZipOutputStream out = createZipOutputStream(result);
- try {
- for (int entry = 0; entry < entryCount; ++entry) {
- ZipEntry ze = new ZipEntry(Integer.toHexString(entry));
- out.putNextEntry(ze);
-
- for (int i = 0; i < entrySize; i += writeBuffer.length) {
- random.nextBytes(writeBuffer);
- int byteCount = Math.min(writeBuffer.length, entrySize - i);
- out.write(writeBuffer, 0, byteCount);
- }
-
- out.closeEntry();
- }
- } finally {
- out.close();
- }
- return result;
- }
-
- private File createTemporaryZipFile() throws IOException {
- File result = File.createTempFile("ZipFileTest", "zip");
- result.deleteOnExit();
- return result;
- }
-
- private ZipOutputStream createZipOutputStream(File f) throws IOException {
- return new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(f)));
- }
-
- public void testSTORED() throws IOException {
- ZipOutputStream out = createZipOutputStream(createTemporaryZipFile());
- CRC32 crc = new CRC32();
-
- // Missing CRC, size, and compressed size => failure.
- try {
- ZipEntry ze = new ZipEntry("a");
- ze.setMethod(ZipEntry.STORED);
- out.putNextEntry(ze);
- fail();
- } catch (ZipException expected) {
- }
-
- // Missing CRC and compressed size => failure.
- try {
- ZipEntry ze = new ZipEntry("a");
- ze.setMethod(ZipEntry.STORED);
- ze.setSize(0);
- out.putNextEntry(ze);
- fail();
- } catch (ZipException expected) {
- }
-
- // Missing CRC and size => failure.
- try {
- ZipEntry ze = new ZipEntry("a");
- ze.setMethod(ZipEntry.STORED);
- ze.setSize(0);
- ze.setCompressedSize(0);
- out.putNextEntry(ze);
- fail();
- } catch (ZipException expected) {
- }
-
- // Missing size and compressed size => failure.
- try {
- ZipEntry ze = new ZipEntry("a");
- ze.setMethod(ZipEntry.STORED);
- ze.setCrc(crc.getValue());
- out.putNextEntry(ze);
- fail();
- } catch (ZipException expected) {
- }
-
- // Missing size is copied from compressed size.
- {
- ZipEntry ze = new ZipEntry("okay1");
- ze.setMethod(ZipEntry.STORED);
- ze.setCrc(crc.getValue());
-
- assertEquals(-1, ze.getSize());
- assertEquals(-1, ze.getCompressedSize());
-
- ze.setCompressedSize(0);
-
- assertEquals(-1, ze.getSize());
- assertEquals(0, ze.getCompressedSize());
-
- out.putNextEntry(ze);
-
- assertEquals(0, ze.getSize());
- assertEquals(0, ze.getCompressedSize());
- }
-
- // Missing compressed size is copied from size.
- {
- ZipEntry ze = new ZipEntry("okay2");
- ze.setMethod(ZipEntry.STORED);
- ze.setCrc(crc.getValue());
-
- assertEquals(-1, ze.getSize());
- assertEquals(-1, ze.getCompressedSize());
-
- ze.setSize(0);
-
- assertEquals(0, ze.getSize());
- assertEquals(-1, ze.getCompressedSize());
-
- out.putNextEntry(ze);
-
- assertEquals(0, ze.getSize());
- assertEquals(0, ze.getCompressedSize());
- }
-
- // Mismatched size and compressed size => failure.
- try {
- ZipEntry ze = new ZipEntry("a");
- ze.setMethod(ZipEntry.STORED);
- ze.setCrc(crc.getValue());
- ze.setCompressedSize(1);
- ze.setSize(0);
- out.putNextEntry(ze);
- fail();
- } catch (ZipException expected) {
- }
-
- // Everything present => success.
- ZipEntry ze = new ZipEntry("okay");
- ze.setMethod(ZipEntry.STORED);
- ze.setCrc(crc.getValue());
- ze.setSize(0);
- ze.setCompressedSize(0);
- out.putNextEntry(ze);
-
- out.close();
- }
-
- private String makeString(int count, String ch) {
- StringBuilder sb = new StringBuilder();
- for (int i = 0; i < count; ++i) {
- sb.append(ch);
- }
- return sb.toString();
- }
-
- public void testComments() throws Exception {
- String expectedFileComment = "1 \u0666 2";
- String expectedEntryComment = "a \u0666 b";
-
- File file = createTemporaryZipFile();
- ZipOutputStream out = createZipOutputStream(file);
-
- // Is file comment length checking done on bytes or characters? (Should be bytes.)
- out.setComment(null);
- out.setComment(makeString(0xffff, "a"));
- try {
- out.setComment(makeString(0xffff + 1, "a"));
- fail();
- } catch (IllegalArgumentException expected) {
- }
- try {
- out.setComment(makeString(0xffff, "\u0666"));
- fail();
- } catch (IllegalArgumentException expected) {
- }
-
- ZipEntry ze = new ZipEntry("a");
-
- // Is entry comment length checking done on bytes or characters? (Should be bytes.)
- ze.setComment(null);
- ze.setComment(makeString(0xffff, "a"));
- try {
- ze.setComment(makeString(0xffff + 1, "a"));
- fail();
- } catch (IllegalArgumentException expected) {
- }
- try {
- ze.setComment(makeString(0xffff, "\u0666"));
- fail();
- } catch (IllegalArgumentException expected) {
- }
-
- ze.setComment(expectedEntryComment);
- out.putNextEntry(ze);
- out.closeEntry();
-
- out.setComment(expectedFileComment);
- out.close();
-
- ZipFile zipFile = new ZipFile(file);
- assertEquals(expectedFileComment, zipFile.getComment());
- assertEquals(expectedEntryComment, zipFile.getEntry("a").getComment());
- zipFile.close();
- }
-
- public void test_getComment_unset() throws Exception {
- File file = createTemporaryZipFile();
- ZipOutputStream out = createZipOutputStream(file);
- ZipEntry ze = new ZipEntry("test entry");
- ze.setComment("per-entry comment");
- out.putNextEntry(ze);
- out.close();
-
- ZipFile zipFile = new ZipFile(file);
- assertEquals(null, zipFile.getComment());
- }
-
- // https://code.google.com/p/android/issues/detail?id=58465
- public void test_NUL_in_filename() throws Exception {
- File file = createTemporaryZipFile();
-
- // We allow creation of a ZipEntry whose name contains a NUL byte,
- // mainly because it's not likely to happen by accident and it's useful for testing.
- ZipOutputStream out = createZipOutputStream(file);
- out.putNextEntry(new ZipEntry("hello"));
- out.putNextEntry(new ZipEntry("hello\u0000"));
- out.close();
-
- // But you can't open a ZIP file containing such an entry, because we reject it
- // when we find it in the central directory.
- try {
- ZipFile zipFile = new ZipFile(file);
- fail();
- } catch (ZipException expected) {
- }
- }
-
- public void testCrc() throws IOException {
- ZipEntry ze = new ZipEntry("test");
- ze.setMethod(ZipEntry.STORED);
- ze.setSize(4);
-
- // setCrc takes a long, not an int, so -1 isn't a valid CRC32 (because it's 64 bits).
- try {
- ze.setCrc(-1);
- } catch (IllegalArgumentException expected) {
- }
-
- // You can set the CRC32 to 0xffffffff if you're slightly more careful though...
- ze.setCrc(0xffffffffL);
- assertEquals(0xffffffffL, ze.getCrc());
-
- // And it actually works, even though we use -1L to mean "no CRC set"...
- ZipOutputStream out = createZipOutputStream(createTemporaryZipFile());
- out.putNextEntry(ze);
- out.write(-1);
- out.write(-1);
- out.write(-1);
- out.write(-1);
- out.closeEntry();
- out.close();
- }
-
- /**
- * RI does not allow reading of an empty zip using a {@link ZipFile}.
- */
- public void testConstructorFailsWhenReadingEmptyZipArchive() throws IOException {
-
- File resources = Support_Resources.createTempFolder();
- File emptyZip = Support_Resources.copyFile(
- resources, "java/util/zip", "EmptyArchive.zip");
-
- try {
- // The following should fail with an exception but if it doesn't then we need to clean
- // up the resource so we need a reference to it.
- ZipFile zipFile = new ZipFile(emptyZip);
-
- // Clean up the resource.
- try {
- zipFile.close();
- } catch (Exception e) {
- // Ignore
- }
- fail();
- } catch (ZipException expected) {
- // expected
- }
+ @Override
+ protected ZipOutputStream createZipOutputStream(OutputStream wrapped) {
+ return new ZipOutputStream(wrapped);
}
}
diff --git a/luni/src/test/java/libcore/java/util/zip/ZipOutputStreamTest.java b/luni/src/test/java/libcore/java/util/zip/ZipOutputStreamTest.java
index e69f010..15600de 100644
--- a/luni/src/test/java/libcore/java/util/zip/ZipOutputStreamTest.java
+++ b/luni/src/test/java/libcore/java/util/zip/ZipOutputStreamTest.java
@@ -21,7 +21,6 @@ import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
-import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Random;
import java.util.zip.ZipEntry;
diff --git a/luni/src/test/java/libcore/javax/crypto/CipherTest.java b/luni/src/test/java/libcore/javax/crypto/CipherTest.java
index c89886c..494d15e 100644
--- a/luni/src/test/java/libcore/javax/crypto/CipherTest.java
+++ b/luni/src/test/java/libcore/javax/crypto/CipherTest.java
@@ -847,6 +847,24 @@ public final class CipherTest extends TestCase {
}
}
+ public void testCipher_getInstance_DoesNotSupportKeyClass_Success() throws Exception {
+ Provider mockProvider = new MockProvider("MockProvider") {
+ public void setup() {
+ put("Cipher.FOO", MockCipherSpi.AllKeyTypes.class.getName());
+ put("Cipher.FOO SupportedKeyClasses", "None");
+ }
+ };
+
+ Security.addProvider(mockProvider);
+ try {
+ Cipher c = Cipher.getInstance("FOO", mockProvider);
+ c.init(Cipher.ENCRYPT_MODE, new MockKey());
+ assertEquals(mockProvider, c.getProvider());
+ } finally {
+ Security.removeProvider(mockProvider.getName());
+ }
+ }
+
public void testCipher_getInstance_SuppliedProviderNotRegistered_MultipartTransform_Success()
throws Exception {
Provider mockProvider = new MockProvider("MockProvider") {
@@ -1136,6 +1154,9 @@ public final class CipherTest extends TestCase {
final AlgorithmParameterSpec decryptSpec = getDecryptAlgorithmParameterSpec(encryptSpec, c);
int decryptMode = getDecryptMode(algorithm);
+
+ test_Cipher_init_Decrypt_NullParameters(c, decryptMode, encryptKey, decryptSpec != null);
+
c.init(decryptMode, encryptKey, decryptSpec);
assertEquals(cipherID + " getBlockSize() decryptMode",
getExpectedBlockSize(algorithm, decryptMode, providerName), c.getBlockSize());
@@ -1268,6 +1289,53 @@ public final class CipherTest extends TestCase {
}
}
+ private void test_Cipher_init_Decrypt_NullParameters(Cipher c, int decryptMode, Key encryptKey,
+ boolean needsParameters) throws Exception {
+ try {
+ c.init(decryptMode, encryptKey, (AlgorithmParameterSpec) null);
+ if (needsParameters) {
+ fail("Should throw InvalidAlgorithmParameterException with null parameters");
+ }
+ } catch (InvalidAlgorithmParameterException e) {
+ if (!needsParameters) {
+ throw e;
+ }
+ }
+
+ try {
+ c.init(decryptMode, encryptKey, (AlgorithmParameterSpec) null, (SecureRandom) null);
+ if (needsParameters) {
+ fail("Should throw InvalidAlgorithmParameterException with null parameters");
+ }
+ } catch (InvalidAlgorithmParameterException e) {
+ if (!needsParameters) {
+ throw e;
+ }
+ }
+
+ try {
+ c.init(decryptMode, encryptKey, (AlgorithmParameters) null);
+ if (needsParameters) {
+ fail("Should throw InvalidAlgorithmParameterException with null parameters");
+ }
+ } catch (InvalidAlgorithmParameterException e) {
+ if (!needsParameters) {
+ throw e;
+ }
+ }
+
+ try {
+ c.init(decryptMode, encryptKey, (AlgorithmParameters) null, (SecureRandom) null);
+ if (needsParameters) {
+ fail("Should throw InvalidAlgorithmParameterException with null parameters");
+ }
+ } catch (InvalidAlgorithmParameterException e) {
+ if (!needsParameters) {
+ throw e;
+ }
+ }
+ }
+
public void testInputPKCS1Padding() throws Exception {
for (String provider : RSA_PROVIDERS) {
testInputPKCS1Padding(provider);
@@ -2797,6 +2865,17 @@ public final class CipherTest extends TestCase {
}
}
+ public void testCipher_Update_WithZeroLengthInput_ReturnsNull() throws Exception {
+ SecretKey key = new SecretKeySpec(AES_128_KEY, "AES");
+ Cipher c = Cipher.getInstance("AES/ECB/NoPadding");
+ c.init(Cipher.ENCRYPT_MODE, key);
+ assertNull(c.update(new byte[0]));
+ assertNull(c.update(new byte[c.getBlockSize() * 2], 0, 0));
+
+ // Try with non-zero offset just in case the implementation mixes up offset and inputLen
+ assertNull(c.update(new byte[c.getBlockSize() * 2], 16, 0));
+ }
+
private void checkCipher_ShortBlock_Failure(CipherTestParam p, String provider) throws Exception {
SecretKey key = new SecretKeySpec(p.key, "AES");
Cipher c = Cipher.getInstance(
diff --git a/luni/src/test/java/libcore/javax/crypto/KeyAgreementTest.java b/luni/src/test/java/libcore/javax/crypto/KeyAgreementTest.java
new file mode 100644
index 0000000..ba03f75
--- /dev/null
+++ b/luni/src/test/java/libcore/javax/crypto/KeyAgreementTest.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package libcore.javax.crypto;
+
+import java.security.Provider;
+import java.security.Security;
+
+import javax.crypto.KeyAgreement;
+
+import junit.framework.TestCase;
+
+public class KeyAgreementTest extends TestCase {
+ private static abstract class MockProvider extends Provider {
+ public MockProvider(String name) {
+ super(name, 1.0, "Mock provider used for testing");
+ setup();
+ }
+
+ public abstract void setup();
+ }
+
+ public void testKeyAgreement_getInstance_SuppliedProviderNotRegistered_Success()
+ throws Exception {
+ Provider mockProvider = new MockProvider("MockProvider") {
+ public void setup() {
+ put("KeyAgreement.FOO", MockKeyAgreementSpi.AllKeyTypes.class.getName());
+ }
+ };
+
+ {
+ KeyAgreement c = KeyAgreement.getInstance("FOO", mockProvider);
+ c.init(new MockKey());
+ assertEquals(mockProvider, c.getProvider());
+ }
+ }
+
+ public void testKeyAgreement_getInstance_DoesNotSupportKeyClass_Success()
+ throws Exception {
+ Provider mockProvider = new MockProvider("MockProvider") {
+ public void setup() {
+ put("KeyAgreement.FOO", MockKeyAgreementSpi.AllKeyTypes.class.getName());
+ put("KeyAgreement.FOO SupportedKeyClasses", "none");
+
+ }
+ };
+
+ Security.addProvider(mockProvider);
+ try {
+ KeyAgreement c = KeyAgreement.getInstance("FOO", mockProvider);
+ c.init(new MockKey());
+ assertEquals(mockProvider, c.getProvider());
+ } finally {
+ Security.removeProvider(mockProvider.getName());
+ }
+ }
+}
diff --git a/luni/src/test/java/libcore/javax/crypto/KeyGeneratorTest.java b/luni/src/test/java/libcore/javax/crypto/KeyGeneratorTest.java
index 8bbd548..5763562 100644
--- a/luni/src/test/java/libcore/javax/crypto/KeyGeneratorTest.java
+++ b/luni/src/test/java/libcore/javax/crypto/KeyGeneratorTest.java
@@ -44,6 +44,15 @@ public class KeyGeneratorTest extends TestCase {
if (!type.equals("KeyGenerator")) {
continue;
}
+
+ // Do not test AndroidKeyStore's KeyGenerator. It cannot be initialized without
+ // providing AndroidKeyStore-specific algorithm parameters.
+ // It's OKish not to test AndroidKeyStore's KeyGenerator here because it's tested
+ // by cts/tests/test/keystore.
+ if ("AndroidKeyStore".equals(provider.getName())) {
+ continue;
+ }
+
String algorithm = service.getAlgorithm();
try {
// KeyGenerator.getInstance(String)
diff --git a/luni/src/test/java/libcore/javax/crypto/MockKeyAgreementSpi.java b/luni/src/test/java/libcore/javax/crypto/MockKeyAgreementSpi.java
new file mode 100644
index 0000000..574dbeb
--- /dev/null
+++ b/luni/src/test/java/libcore/javax/crypto/MockKeyAgreementSpi.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package libcore.javax.crypto;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import javax.crypto.KeyAgreementSpi;
+import javax.crypto.SecretKey;
+import javax.crypto.ShortBufferException;
+
+/**
+ * Mock KeyAgreementSpi used by {@link KeyAgreementTest}.
+ */
+public class MockKeyAgreementSpi extends KeyAgreementSpi {
+ public static class SpecificKeyTypes extends MockKeyAgreementSpi {
+ @Override
+ public void checkKeyType(Key key) throws InvalidKeyException {
+ if (!(key instanceof MockKey)) {
+ throw new InvalidKeyException("Must be MockKey!");
+ }
+ }
+ }
+
+ public static class SpecificKeyTypes2 extends MockKeyAgreementSpi {
+ @Override
+ public void checkKeyType(Key key) throws InvalidKeyException {
+ System.err.println("Checking key of type " + key.getClass().getName());
+ if (!(key instanceof MockKey2)) {
+ throw new InvalidKeyException("Must be MockKey2!");
+ }
+ }
+ }
+
+ public static class AllKeyTypes extends MockKeyAgreementSpi {
+ }
+
+ public void checkKeyType(Key key) throws InvalidKeyException {
+ }
+
+ @Override
+ protected Key engineDoPhase(Key key, boolean lastPhase) throws InvalidKeyException,
+ IllegalStateException {
+ throw new UnsupportedOperationException("not implemented");
+ }
+
+ @Override
+ protected byte[] engineGenerateSecret() throws IllegalStateException {
+ throw new UnsupportedOperationException("not implemented");
+ }
+
+ @Override
+ protected int engineGenerateSecret(byte[] sharedSecret, int offset)
+ throws IllegalStateException, ShortBufferException {
+ throw new UnsupportedOperationException("not implemented");
+ }
+
+ @Override
+ protected SecretKey engineGenerateSecret(String algorithm) throws IllegalStateException,
+ NoSuchAlgorithmException, InvalidKeyException {
+ throw new UnsupportedOperationException("not implemented");
+ }
+
+ @Override
+ protected void engineInit(Key key, SecureRandom random) throws InvalidKeyException {
+ checkKeyType(key);
+ }
+
+ @Override
+ protected void engineInit(Key key, AlgorithmParameterSpec params, SecureRandom random)
+ throws InvalidKeyException, InvalidAlgorithmParameterException {
+ checkKeyType(key);
+ }
+}
diff --git a/luni/src/test/java/libcore/javax/net/ssl/DefaultHostnameVerifierTest.java b/luni/src/test/java/libcore/javax/net/ssl/DefaultHostnameVerifierTest.java
index feecebe..07ecd12 100644
--- a/luni/src/test/java/libcore/javax/net/ssl/DefaultHostnameVerifierTest.java
+++ b/luni/src/test/java/libcore/javax/net/ssl/DefaultHostnameVerifierTest.java
@@ -22,6 +22,7 @@ import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.Principal;
import java.security.PublicKey;
+import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
@@ -30,21 +31,32 @@ import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
-import javax.net.ssl.DefaultHostnameVerifier;
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLPeerUnverifiedException;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSessionContext;
import javax.security.auth.x500.X500Principal;
import junit.framework.TestCase;
+/**
+ * Tests for the platform-default {@link HostnameVerifier} as provided by
+ * {@link HttpsURLConnection#getDefaultHostnameVerifier()}.
+ */
public final class DefaultHostnameVerifierTest extends TestCase {
private static final int ALT_UNKNOWN = 0;
private static final int ALT_DNS_NAME = 2;
private static final int ALT_IPA_NAME = 7;
- private final DefaultHostnameVerifier verifier = new DefaultHostnameVerifier();
+ private final HostnameVerifier verifier = HttpsURLConnection.getDefaultHostnameVerifier();
public void testVerify() {
- assertTrue(verifier.verify("imap.g.com", new StubX509Certificate("cn=imap.g.com")));
- assertFalse(verifier.verify("imap.g.com", new StubX509Certificate("cn=imap2.g.com")));
- assertFalse(verifier.verify("imap.g.com", new StubX509Certificate("cn=sub.imap.g.com")));
+ assertTrue(verifyWithServerCertificate(
+ "imap.g.com", new StubX509Certificate("cn=imap.g.com")));
+ assertFalse(verifyWithServerCertificate(
+ "imap.g.com", new StubX509Certificate("cn=imap2.g.com")));
+ assertFalse(verifyWithServerCertificate(
+ "imap.g.com", new StubX509Certificate("cn=sub.imap.g.com")));
}
/**
@@ -52,32 +64,33 @@ public final class DefaultHostnameVerifierTest extends TestCase {
* be used as the identity and the CN should be ignored.
*/
public void testSubjectAltNameAndCn() {
- assertFalse(verifier.verify("imap.g.com", new StubX509Certificate("")
- .addSubjectAlternativeName(ALT_DNS_NAME, "a.y.com")));
- assertFalse(verifier.verify("imap.g.com", new StubX509Certificate("cn=imap.g.com")
+ assertFalse(verifyWithServerCertificate("imap.g.com", new StubX509Certificate("")
.addSubjectAlternativeName(ALT_DNS_NAME, "a.y.com")));
- assertTrue(verifier.verify("imap.g.com", new StubX509Certificate("")
+ assertFalse(
+ verifyWithServerCertificate("imap.g.com", new StubX509Certificate("cn=imap.g.com")
+ .addSubjectAlternativeName(ALT_DNS_NAME, "a.y.com")));
+ assertTrue(verifyWithServerCertificate("imap.g.com", new StubX509Certificate("")
.addSubjectAlternativeName(ALT_DNS_NAME, "imap.g.com")));
}
public void testSubjectAltNameWithWildcard() {
- assertTrue(verifier.verify("imap.g.com", new StubX509Certificate("")
+ assertTrue(verifyWithServerCertificate("imap.g.com", new StubX509Certificate("")
.addSubjectAlternativeName(ALT_DNS_NAME, "*.g.com")));
}
public void testSubjectAltNameWithIpAddress() {
- assertTrue(verifier.verify("1.2.3.4", new StubX509Certificate("")
+ assertTrue(verifyWithServerCertificate("1.2.3.4", new StubX509Certificate("")
.addSubjectAlternativeName(ALT_IPA_NAME, "1.2.3.4")));
- assertFalse(verifier.verify("1.2.3.5", new StubX509Certificate("")
+ assertFalse(verifyWithServerCertificate("1.2.3.5", new StubX509Certificate("")
.addSubjectAlternativeName(ALT_IPA_NAME, "1.2.3.4")));
- assertTrue(verifier.verify("192.168.100.1", new StubX509Certificate("")
+ assertTrue(verifyWithServerCertificate("192.168.100.1", new StubX509Certificate("")
.addSubjectAlternativeName(ALT_IPA_NAME, "1.2.3.4")
.addSubjectAlternativeName(ALT_IPA_NAME, "192.168.100.1")));
}
public void testUnknownSubjectAltName() {
// Has unknown subject alternative names
- assertTrue(verifier.verify("imap.g.com", new StubX509Certificate("")
+ assertTrue(verifyWithServerCertificate("imap.g.com", new StubX509Certificate("")
.addSubjectAlternativeName(ALT_UNKNOWN, "random string 1")
.addSubjectAlternativeName(ALT_UNKNOWN, "random string 2")
.addSubjectAlternativeName(ALT_DNS_NAME, "a.b.c.d")
@@ -85,7 +98,7 @@ public final class DefaultHostnameVerifierTest extends TestCase {
.addSubjectAlternativeName(ALT_DNS_NAME, "imap.g.com")
.addSubjectAlternativeName(ALT_IPA_NAME, "2.33.44.55")
.addSubjectAlternativeName(ALT_UNKNOWN, "random string 3")));
- assertTrue(verifier.verify("2.33.44.55", new StubX509Certificate("")
+ assertTrue(verifyWithServerCertificate("2.33.44.55", new StubX509Certificate("")
.addSubjectAlternativeName(ALT_UNKNOWN, "random string 1")
.addSubjectAlternativeName(ALT_UNKNOWN, "random string 2")
.addSubjectAlternativeName(ALT_DNS_NAME, "a.b.c.d")
@@ -93,7 +106,7 @@ public final class DefaultHostnameVerifierTest extends TestCase {
.addSubjectAlternativeName(ALT_DNS_NAME, "imap.g.com")
.addSubjectAlternativeName(ALT_IPA_NAME, "2.33.44.55")
.addSubjectAlternativeName(ALT_UNKNOWN, "random string 3")));
- assertFalse(verifier.verify("g.com", new StubX509Certificate("")
+ assertFalse(verifyWithServerCertificate("g.com", new StubX509Certificate("")
.addSubjectAlternativeName(ALT_UNKNOWN, "random string 1")
.addSubjectAlternativeName(ALT_UNKNOWN, "random string 2")
.addSubjectAlternativeName(ALT_DNS_NAME, "a.b.c.d")
@@ -101,7 +114,7 @@ public final class DefaultHostnameVerifierTest extends TestCase {
.addSubjectAlternativeName(ALT_DNS_NAME, "imap.g.com")
.addSubjectAlternativeName(ALT_IPA_NAME, "2.33.44.55")
.addSubjectAlternativeName(ALT_UNKNOWN, "random string 3")));
- assertFalse(verifier.verify("2.33.44.1", new StubX509Certificate("")
+ assertFalse(verifyWithServerCertificate("2.33.44.1", new StubX509Certificate("")
.addSubjectAlternativeName(ALT_UNKNOWN, "random string 1")
.addSubjectAlternativeName(ALT_UNKNOWN, "random string 2")
.addSubjectAlternativeName(ALT_DNS_NAME, "a.b.c.d")
@@ -111,40 +124,129 @@ public final class DefaultHostnameVerifierTest extends TestCase {
.addSubjectAlternativeName(ALT_UNKNOWN, "random string 3")));
}
- public void testWildcardMatchesWildcardSuffix() {
- assertTrue(verifier.verifyHostName("b.c.d", "*.b.c.d"));
- assertTrue(verifier.verifyHostName("imap.google.com", "*.imap.google.com"));
- assertFalse(verifier.verifyHostName("imap.google.com.au", "*.imap.google.com"));
+ public void testWildcardsRejectedForIpAddress() {
+ assertFalse(verifyWithServerCertificate("1.2.3.4", new StubX509Certificate("cn=*.2.3.4")));
+ assertFalse(verifyWithServerCertificate("1.2.3.4", new StubX509Certificate("cn=*.2.3.4")
+ .addSubjectAlternativeName(ALT_IPA_NAME, "*.2.3.4")
+ .addSubjectAlternativeName(ALT_DNS_NAME, "*.2.3.4")));
+ assertFalse(verifyWithServerCertificate(
+ "2001:1234::1", new StubX509Certificate("cn=*:1234::1")));
+ assertFalse(verifyWithServerCertificate(
+ "2001:1234::1", new StubX509Certificate("cn=*:1234::1")
+ .addSubjectAlternativeName(ALT_IPA_NAME, "*:1234::1")
+ .addSubjectAlternativeName(ALT_DNS_NAME, "*:1234::1")));
+ }
+
+ public void testNullParameters() {
+ // Confirm that neither of the parameters used later in the test cause the verifier to blow
+ // up
+ String hostname = "www.example.com";
+ StubSSLSession session = new StubSSLSession();
+ session.peerCertificates =
+ new Certificate[] {new StubX509Certificate("cn=www.example.com")};
+ verifier.verify(hostname, session);
+
+ try {
+ verifier.verify(hostname, null);
+ fail();
+ } catch (NullPointerException expected) {
+ }
+
+ try {
+ verifier.verify(null, session);
+ fail();
+ } catch (NullPointerException expected) {
+ }
+ }
+
+ public void testInvalidDomainNames() {
+ assertFalse(verifyWithDomainNamePattern("", ""));
+ assertFalse(verifyWithDomainNamePattern(".test.example.com", ".test.example.com"));
+ assertFalse(verifyWithDomainNamePattern("ex*ample.com", "ex*ample.com"));
+ assertFalse(verifyWithDomainNamePattern("example.com..", "example.com."));
+ assertFalse(verifyWithDomainNamePattern("example.com.", "example.com.."));
+ }
+
+ public void testWildcardCharacterMustBeLeftMostLabelOnly() {
+ assertFalse(verifyWithDomainNamePattern("test.www.example.com", "test.*.example.com"));
+ assertFalse(verifyWithDomainNamePattern("www.example.com", "www.*.com"));
+ assertFalse(verifyWithDomainNamePattern("www.example.com", "www.example.*"));
+ assertFalse(verifyWithDomainNamePattern("www.example.com", "*www.example.com"));
+ assertFalse(verifyWithDomainNamePattern("www.example.com", "*w.example.com"));
+ assertFalse(verifyWithDomainNamePattern("www.example.com", "w*w.example.com"));
+ assertFalse(verifyWithDomainNamePattern("www.example.com", "w*.example.com"));
+ assertFalse(verifyWithDomainNamePattern("www.example.com", "www*.example.com"));
}
- public void testWildcardMatchingSubstring() {
- assertTrue(verifier.verifyHostName("b.c.d", "b*.c.d"));
- assertTrue(verifier.verifyHostName("imap.google.com", "ima*.google.com"));
- assertFalse(verifier.verifyHostName("imap.google.com.au", "ima*.google.com"));
+ public void testWildcardCannotMatchEmptyLabel() {
+ assertFalse(verifyWithDomainNamePattern("example.com", "*.example.com"));
+ assertFalse(verifyWithDomainNamePattern(".example.com", "*.example.com"));
}
- public void testWildcardMatchingEmptySubstring() {
- assertTrue(verifier.verifyHostName("imap.google.com", "imap*.google.com"));
- assertFalse(verifier.verifyHostName("imap.google.com.au", "imap*.google.com"));
+ public void testWildcardCannotMatchChildDomain() {
+ assertFalse(verifyWithDomainNamePattern("sub.www.example.com", "*.example.com"));
}
- public void testWildcardMatchesChildDomain() {
- assertFalse(verifier.verifyHostName("a.b.c.d", "*.c.d"));
+ public void testWildcardRejectedForSingleLabelPatterns() {
+ assertFalse(verifyWithDomainNamePattern("d", "*"));
+ assertFalse(verifyWithDomainNamePattern("d.", "*."));
+ assertFalse(verifyWithDomainNamePattern("d", "d*"));
+ assertFalse(verifyWithDomainNamePattern("d.", "d*."));
+ assertFalse(verifyWithDomainNamePattern("d", "*d"));
+ assertFalse(verifyWithDomainNamePattern("d.", "*d."));
+ assertFalse(verifyWithDomainNamePattern("ddd", "d*d"));
+ assertFalse(verifyWithDomainNamePattern("ddd.", "d*d."));
+ }
+
+ public void testNoPrefixMatch() {
+ assertFalse(verifyWithDomainNamePattern("imap.google.com.au", "imap.google.com"));
+ assertFalse(verifyWithDomainNamePattern("imap.google.com.au", "*.google.com"));
}
public void testVerifyHostName() {
- assertTrue(verifier.verifyHostName("a.b.c.d", "a.b.c.d"));
- assertTrue(verifier.verifyHostName("a.b.c.d", "*.b.c.d"));
- assertFalse(verifier.verifyHostName("a.b.c.d", "*.*.c.d"));
- assertTrue(verifier.verifyHostName("imap.google.com", "imap.google.com"));
- assertFalse(verifier.verifyHostName("imap2.google.com", "imap.google.com"));
- assertTrue(verifier.verifyHostName("imap.google.com", "*.google.com"));
- assertTrue(verifier.verifyHostName("imap2.google.com", "*.google.com"));
- assertFalse(verifier.verifyHostName("imap.google.com", "*.googl.com"));
- assertFalse(verifier.verifyHostName("imap2.google2.com", "*.google3.com"));
- assertFalse(verifier.verifyHostName("imap.google.com", "a*.google.com"));
- assertFalse(verifier.verifyHostName("imap.google.com", "ix*.google.com"));
- assertTrue(verifier.verifyHostName("imap.google.com", "iMap.Google.Com"));
+ assertTrue(verifyWithDomainNamePattern("a.b.c.d", "a.b.c.d"));
+ assertTrue(verifyWithDomainNamePattern("a.b.c.d", "*.b.c.d"));
+ assertFalse(verifyWithDomainNamePattern("a.b.c.d", "*.*.c.d"));
+ assertTrue(verifyWithDomainNamePattern("imap.google.com", "imap.google.com"));
+ assertFalse(verifyWithDomainNamePattern("imap2.google.com", "imap.google.com"));
+ assertTrue(verifyWithDomainNamePattern("imap.google.com", "*.google.com"));
+ assertTrue(verifyWithDomainNamePattern("imap2.google.com", "*.google.com"));
+ assertFalse(verifyWithDomainNamePattern("imap.google.com", "*.googl.com"));
+ assertFalse(verifyWithDomainNamePattern("imap2.google2.com", "*.google3.com"));
+ assertFalse(verifyWithDomainNamePattern("imap.google.com", "a*.google.com"));
+ assertFalse(verifyWithDomainNamePattern("imap.google.com", "ix*.google.com"));
+ assertTrue(verifyWithDomainNamePattern("imap.google.com", "iMap.Google.Com"));
+ assertTrue(verifyWithDomainNamePattern("weird", "weird"));
+ assertTrue(verifyWithDomainNamePattern("weird", "weird."));
+
+ // Wildcards rejected for domain names consisting of fewer than two labels (excluding root).
+ assertFalse(verifyWithDomainNamePattern("weird", "weird*"));
+ assertFalse(verifyWithDomainNamePattern("weird", "*weird"));
+ assertFalse(verifyWithDomainNamePattern("weird", "weird*."));
+ assertFalse(verifyWithDomainNamePattern("weird", "weird.*"));
+ }
+
+ public void testVerifyAbsoluteHostName() {
+ assertTrue(verifyWithDomainNamePattern("a.b.c.d.", "a.b.c.d"));
+ assertTrue(verifyWithDomainNamePattern("a.b.c.d.", "*.b.c.d"));
+ assertFalse(verifyWithDomainNamePattern("a.b.c.d.", "*.*.c.d"));
+ assertTrue(verifyWithDomainNamePattern("imap.google.com.", "imap.google.com"));
+ assertFalse(verifyWithDomainNamePattern("imap2.google.com.", "imap.google.com"));
+ assertTrue(verifyWithDomainNamePattern("imap.google.com.", "*.google.com"));
+ assertTrue(verifyWithDomainNamePattern("imap2.google.com.", "*.google.com"));
+ assertFalse(verifyWithDomainNamePattern("imap.google.com.", "*.googl.com"));
+ assertFalse(verifyWithDomainNamePattern("imap2.google2.com.", "*.google3.com"));
+ assertFalse(verifyWithDomainNamePattern("imap.google.com.", "a*.google.com"));
+ assertFalse(verifyWithDomainNamePattern("imap.google.com.", "ix*.google.com"));
+ assertTrue(verifyWithDomainNamePattern("imap.google.com.", "iMap.Google.Com"));
+ assertTrue(verifyWithDomainNamePattern("weird.", "weird"));
+ assertTrue(verifyWithDomainNamePattern("weird.", "weird."));
+
+ // Wildcards rejected for domain names consisting of fewer than two labels (excluding root).
+ assertFalse(verifyWithDomainNamePattern("weird.", "*weird"));
+ assertFalse(verifyWithDomainNamePattern("weird.", "weird*"));
+ assertFalse(verifyWithDomainNamePattern("weird.", "weird*."));
+ assertFalse(verifyWithDomainNamePattern("weird.", "weird.*"));
}
public void testSubjectOnlyCert() throws Exception {
@@ -168,8 +270,8 @@ public final class DefaultHostnameVerifierTest extends TestCase {
+ "rs2oQLwOLnuifH52ey9+tJguabo+brlYYigAuWWFEzJfBzikDkIwnE/L7wlrypIk\n"
+ "taXDWI4=\n"
+ "-----END CERTIFICATE-----");
- assertTrue(verifier.verify("www.example.com", cert));
- assertFalse(verifier.verify("www2.example.com", cert));
+ assertTrue(verifyWithServerCertificate("www.example.com", cert));
+ assertFalse(verifyWithServerCertificate("www2.example.com", cert));
}
public void testSubjectAltOnlyCert() throws Exception {
@@ -192,8 +294,8 @@ public final class DefaultHostnameVerifierTest extends TestCase {
+ "JPRynf9244Pn0Sr/wsnmdsTRFIFYynrc51hQ7DkwbUxpcaewkZzilru/SwZ3+pPT\n"
+ "9JSqm5hJ1pg5WDlPkW7c/1VA0/141N52Q8MIU+2ZpuOj\n"
+ "-----END CERTIFICATE-----");
- assertTrue(verifier.verify("www.example.com", cert));
- assertFalse(verifier.verify("www2.example.com", cert));
+ assertTrue(verifyWithServerCertificate("www.example.com", cert));
+ assertFalse(verifyWithServerCertificate("www2.example.com", cert));
}
public void testSubjectWithAltNamesCert() throws Exception {
@@ -219,10 +321,10 @@ public final class DefaultHostnameVerifierTest extends TestCase {
+ "hrTVypLSoRXuTB2aWilu4p6aNh84xTdyqo2avtNr2MiQMZIcdamBq8LdBIAShFXI\n"
+ "h5G2eVGXH/Y=\n"
+ "-----END CERTIFICATE-----");
- assertFalse(verifier.verify("www.example.com", cert));
- assertTrue(verifier.verify("www2.example.com", cert));
- assertTrue(verifier.verify("www3.example.com", cert));
- assertFalse(verifier.verify("www4.example.com", cert));
+ assertFalse(verifyWithServerCertificate("www.example.com", cert));
+ assertTrue(verifyWithServerCertificate("www2.example.com", cert));
+ assertTrue(verifyWithServerCertificate("www3.example.com", cert));
+ assertFalse(verifyWithServerCertificate("www4.example.com", cert));
}
public void testSubjectWithWildAltNamesCert() throws Exception {
@@ -247,11 +349,11 @@ public final class DefaultHostnameVerifierTest extends TestCase {
+ "Y3R0HZvKzNIU3pwAm69HCJoG+/9MZEIDJb0WJc5UygxDT45XE9zQMQe4dBOTaNXT\n"
+ "+ntgaB62kE10HzrzpqXAgoAWxWK4RzFcUpBWw9qYq9xOCewJ\n"
+ "-----END CERTIFICATE-----");
- assertFalse(verifier.verify("www.example.com", cert));
- assertFalse(verifier.verify("www2.example.com", cert));
- assertTrue(verifier.verify("www.example2.com", cert));
- assertTrue(verifier.verify("abc.example2.com", cert));
- assertFalse(verifier.verify("www.example3.com", cert));
+ assertFalse(verifyWithServerCertificate("www.example.com", cert));
+ assertFalse(verifyWithServerCertificate("www2.example.com", cert));
+ assertTrue(verifyWithServerCertificate("www.example2.com", cert));
+ assertTrue(verifyWithServerCertificate("abc.example2.com", cert));
+ assertFalse(verifyWithServerCertificate("www.example3.com", cert));
}
public void testWildAltNameOnlyCert() throws Exception {
@@ -274,9 +376,9 @@ public final class DefaultHostnameVerifierTest extends TestCase {
+ "va++ow5r1VxQXFJc0ZPzsDo+6TlktoDHaRQJGMqQomqHWT4i7F5UZgf6BHGfEUPU\n"
+ "qep+GsF3QRHSBtpObWkVDZNFvky3a1iZ2q25+hFIqQ==\n"
+ "-----END CERTIFICATE-----");
- assertTrue(verifier.verify("www.example.com", cert));
- assertTrue(verifier.verify("www2.example.com", cert));
- assertFalse(verifier.verify("www.example2.com", cert));
+ assertTrue(verifyWithServerCertificate("www.example.com", cert));
+ assertTrue(verifyWithServerCertificate("www2.example.com", cert));
+ assertFalse(verifyWithServerCertificate("www.example2.com", cert));
}
public void testAltIpOnlyCert() throws Exception {
@@ -299,8 +401,48 @@ public final class DefaultHostnameVerifierTest extends TestCase {
+ "WPjHQcWfpkFzAF5wyOq0kveVfx0g5xPhOVDd+U+q7WastbXICpCoHp9FxISmZVik\n"
+ "sAyifp8agkYdzaSh55fFmKXlFnRsQw==\n"
+ "-----END CERTIFICATE-----");
- assertTrue(verifier.verify("192.168.10.1", cert));
- assertFalse(verifier.verify("192.168.10.2", cert));
+ assertTrue(verifyWithServerCertificate("192.168.10.1", cert));
+ assertFalse(verifyWithServerCertificate("192.168.10.2", cert));
+ }
+
+ /**
+ * Verifies the provided hostname against the provided domain name pattern from server
+ * certificate.
+ */
+ private boolean verifyWithDomainNamePattern(String hostname, String pattern) {
+ StubSSLSession session = new StubSSLSession();
+
+ // Verify using a certificate where the pattern is in the CN
+ session.peerCertificates = new Certificate[] {
+ new StubX509Certificate("cn=\"" + pattern + "\"")
+ };
+ boolean resultWhenPatternInCn = verifier.verify(hostname, session);
+
+ // Verify using a certificate where the pattern is in a DNS SubjectAltName
+ session.peerCertificates = new Certificate[] {
+ new StubX509Certificate("ou=test")
+ .addSubjectAlternativeName(ALT_DNS_NAME, pattern)
+ };
+ boolean resultWhenPatternInSubjectAltName = verifier.verify(hostname, session);
+
+ // Assert that in both cases the verifier gives the same result
+ if (resultWhenPatternInCn != resultWhenPatternInSubjectAltName) {
+ fail("Different results between pattern in CN and SubjectAltName."
+ + " hostname : " + hostname + ", pattern: " + pattern
+ + ", when pattern in CN: " + resultWhenPatternInCn
+ + ", when pattern in SubjectAltName: " + resultWhenPatternInSubjectAltName);
+ }
+ return resultWhenPatternInCn;
+ }
+
+ /**
+ * Verifies the provided hostname against the provided server certificate.
+ */
+ private boolean verifyWithServerCertificate(String hostname, X509Certificate certificate) {
+ StubSSLSession session = new StubSSLSession();
+ session.peerCertificates =
+ (certificate != null) ? new Certificate[] {certificate} : new Certificate[0];
+ return verifier.verify(hostname, session);
}
X509Certificate parseCertificate(String encoded) throws Exception {
@@ -308,6 +450,117 @@ public final class DefaultHostnameVerifierTest extends TestCase {
return (X509Certificate) CertificateFactory.getInstance("X509").generateCertificate(in);
}
+ private static class StubSSLSession implements SSLSession {
+
+ public Certificate[] peerCertificates = new Certificate[0];
+
+ @Override
+ public int getApplicationBufferSize() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getCipherSuite() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public long getCreationTime() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public byte[] getId() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public long getLastAccessedTime() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Certificate[] getLocalCertificates() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Principal getLocalPrincipal() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int getPacketBufferSize() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public javax.security.cert.X509Certificate[] getPeerCertificateChain()
+ throws SSLPeerUnverifiedException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException {
+ return peerCertificates;
+ }
+
+ @Override
+ public String getPeerHost() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int getPeerPort() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Principal getPeerPrincipal() throws SSLPeerUnverifiedException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getProtocol() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public SSLSessionContext getSessionContext() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Object getValue(String name) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String[] getValueNames() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void invalidate() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isValid() {
+ return true;
+ }
+
+ @Override
+ public void putValue(String name, Object value) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void removeValue(String name) {
+ throw new UnsupportedOperationException();
+ }
+ }
+
private static class StubX509Certificate extends X509Certificate {
private final X500Principal subjectX500Principal;
private Collection<List<?>> subjectAlternativeNames;
diff --git a/luni/src/test/java/libcore/javax/net/ssl/HttpsURLConnectionTest.java b/luni/src/test/java/libcore/javax/net/ssl/HttpsURLConnectionTest.java
new file mode 100644
index 0000000..cbaea20
--- /dev/null
+++ b/luni/src/test/java/libcore/javax/net/ssl/HttpsURLConnectionTest.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package libcore.javax.net.ssl;
+
+import junit.framework.TestCase;
+
+import java.io.IOException;
+import java.net.URL;
+
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocketFactory;
+
+public class HttpsURLConnectionTest extends TestCase {
+
+ /**
+ * HTTPS URL which cannot be resolved and is thus safe to use in tests where network traffic
+ * should be avoided.
+ */
+ private static final String UNRESOLVABLE_HTTPS_URL = "https:///";
+
+ public void testDefaultHostnameVerifierNotNull() {
+ assertNotNull(HttpsURLConnection.getDefaultHostnameVerifier());
+ }
+
+ public void testDefaultHostnameVerifierUsedForNewConnectionsByDefault() throws IOException {
+ HostnameVerifier originalHostnameVerifier = HttpsURLConnection.getDefaultHostnameVerifier();
+ HttpsURLConnection connection =
+ (HttpsURLConnection) new URL(UNRESOLVABLE_HTTPS_URL).openConnection();
+ try {
+ assertSame(originalHostnameVerifier, connection.getHostnameVerifier());
+ } finally {
+ connection.disconnect();
+ }
+
+ HostnameVerifier anotherVerifier = new FakeHostnameVerifier();
+ try {
+ HttpsURLConnection.setDefaultHostnameVerifier(anotherVerifier);
+ connection = (HttpsURLConnection) new URL(UNRESOLVABLE_HTTPS_URL).openConnection();
+ try {
+ assertSame(anotherVerifier, connection.getHostnameVerifier());
+ } finally {
+ connection.disconnect();
+ }
+
+ HttpsURLConnection.setDefaultHostnameVerifier(originalHostnameVerifier);
+ connection = (HttpsURLConnection) new URL(UNRESOLVABLE_HTTPS_URL).openConnection();
+ try {
+ assertSame(originalHostnameVerifier, connection.getHostnameVerifier());
+ } finally {
+ connection.disconnect();
+ }
+ } finally {
+ HttpsURLConnection.setDefaultHostnameVerifier(originalHostnameVerifier);
+ }
+ }
+
+ public void testDefaultSSLSocketFactoryNotNull() {
+ assertNotNull(HttpsURLConnection.getDefaultSSLSocketFactory());
+ }
+
+ public void testDefaultSSLSocketFactoryUsedForNewConnectionsByDefault() throws IOException {
+ SSLSocketFactory originalFactory = HttpsURLConnection.getDefaultSSLSocketFactory();
+ HttpsURLConnection connection =
+ (HttpsURLConnection) new URL(UNRESOLVABLE_HTTPS_URL).openConnection();
+ try {
+ assertSame(originalFactory, connection.getSSLSocketFactory());
+ } finally {
+ connection.disconnect();
+ }
+
+ SSLSocketFactory anotherFactory = new SSLSocketFactoryTest.FakeSSLSocketFactory();
+ try {
+ HttpsURLConnection.setDefaultSSLSocketFactory(anotherFactory);
+ connection = (HttpsURLConnection) new URL(UNRESOLVABLE_HTTPS_URL).openConnection();
+ try {
+ assertSame(anotherFactory, connection.getSSLSocketFactory());
+ } finally {
+ connection.disconnect();
+ }
+
+ HttpsURLConnection.setDefaultSSLSocketFactory(originalFactory);
+ connection = (HttpsURLConnection) new URL(UNRESOLVABLE_HTTPS_URL).openConnection();
+ try {
+ assertSame(originalFactory, connection.getSSLSocketFactory());
+ } finally {
+ connection.disconnect();
+ }
+ } finally {
+ HttpsURLConnection.setDefaultSSLSocketFactory(originalFactory);
+ }
+ }
+
+ private static class FakeHostnameVerifier implements HostnameVerifier {
+ @Override
+ public boolean verify(String hostname, SSLSession session) {
+ return true;
+ }
+ }
+}
diff --git a/luni/src/test/java/libcore/javax/net/ssl/SSLContextTest.java b/luni/src/test/java/libcore/javax/net/ssl/SSLContextTest.java
index dccadbd..533849c 100644
--- a/luni/src/test/java/libcore/javax/net/ssl/SSLContextTest.java
+++ b/luni/src/test/java/libcore/javax/net/ssl/SSLContextTest.java
@@ -26,7 +26,6 @@ import java.security.Security;
import java.security.UnrecoverableKeyException;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collections;
import java.util.List;
import java.util.concurrent.Callable;
import libcore.io.IoUtils;
@@ -82,14 +81,14 @@ public class SSLContextTest extends TestCase {
}
public void test_SSLContext_defaultConfiguration() throws Exception {
- SSLDefaultConfigurationAsserts.assertSSLContext(SSLContext.getDefault());
+ SSLConfigurationAsserts.assertSSLContextDefaultConfiguration(SSLContext.getDefault());
for (String protocol : StandardNames.SSL_CONTEXT_PROTOCOLS) {
SSLContext sslContext = SSLContext.getInstance(protocol);
if (!protocol.equals(StandardNames.SSL_CONTEXT_PROTOCOLS_DEFAULT)) {
sslContext.init(null, null, null);
}
- SSLDefaultConfigurationAsserts.assertSSLContext(sslContext);
+ SSLConfigurationAsserts.assertSSLContextDefaultConfiguration(sslContext);
}
}
@@ -149,6 +148,27 @@ public class SSLContextTest extends TestCase {
sslContext);
}
+ public void test_SSLContext_init_correctProtocolVersionsEnabled() throws Exception {
+ for (String tlsVersion : StandardNames.SSL_CONTEXT_PROTOCOLS) {
+ // Don't test the "Default" instance.
+ if (StandardNames.SSL_CONTEXT_PROTOCOLS_DEFAULT.equals(tlsVersion)) {
+ continue;
+ }
+
+ SSLContext context = SSLContext.getInstance(tlsVersion);
+ context.init(null, null, null);
+
+ StandardNames.assertSSLContextEnabledProtocols(tlsVersion, ((SSLSocket) (context.getSocketFactory()
+ .createSocket())).getEnabledProtocols());
+ StandardNames.assertSSLContextEnabledProtocols(tlsVersion, ((SSLServerSocket) (context
+ .getServerSocketFactory().createServerSocket())).getEnabledProtocols());
+ StandardNames.assertSSLContextEnabledProtocols(tlsVersion, context.getDefaultSSLParameters()
+ .getProtocols());
+ StandardNames.assertSSLContextEnabledProtocols(tlsVersion, context.createSSLEngine()
+ .getEnabledProtocols());
+ }
+ }
+
private static void assertEnabledCipherSuites(
List<String> expectedCipherSuites, SSLContext sslContext) throws Exception {
assertContentsInOrder(
diff --git a/luni/src/test/java/libcore/javax/net/ssl/SSLEngineTest.java b/luni/src/test/java/libcore/javax/net/ssl/SSLEngineTest.java
index df4585f..5e3a3d5 100644
--- a/luni/src/test/java/libcore/javax/net/ssl/SSLEngineTest.java
+++ b/luni/src/test/java/libcore/javax/net/ssl/SSLEngineTest.java
@@ -65,7 +65,7 @@ public class SSLEngineTest extends TestCase {
}
public void test_SSLEngine_defaultConfiguration() throws Exception {
- SSLDefaultConfigurationAsserts.assertSSLEngine(
+ SSLConfigurationAsserts.assertSSLEngineDefaultConfiguration(
TestSSLContext.create().clientContext.createSSLEngine());
}
@@ -203,24 +203,31 @@ public class SSLEngineTest extends TestCase {
: new String[] { cipherSuite });
// Check that handshake succeeds.
- TestSSLEnginePair pair = TestSSLEnginePair.create(c, new TestSSLEnginePair.Hooks() {
- @Override
- void beforeBeginHandshake(SSLEngine client, SSLEngine server) {
- client.setEnabledCipherSuites(cipherSuiteArray);
- server.setEnabledCipherSuites(cipherSuiteArray);
+ TestSSLEnginePair pair = null;
+ try {
+ pair = TestSSLEnginePair.create(c, new TestSSLEnginePair.Hooks() {
+ @Override
+ void beforeBeginHandshake(SSLEngine client, SSLEngine server) {
+ client.setEnabledCipherSuites(cipherSuiteArray);
+ server.setEnabledCipherSuites(cipherSuiteArray);
+ }
+ });
+ assertConnected(pair);
+
+ boolean needsRecordSplit =
+ ("TLS".equalsIgnoreCase(c.clientContext.getProtocol())
+ || "SSLv3".equalsIgnoreCase(c.clientContext.getProtocol()))
+ && cipherSuite.contains("_CBC_");
+
+ assertSendsCorrectly("This is the client. Hello!".getBytes(),
+ pair.client, pair.server, needsRecordSplit);
+ assertSendsCorrectly("This is the server. Hi!".getBytes(),
+ pair.server, pair.client, needsRecordSplit);
+ } finally {
+ if (pair != null) {
+ pair.close();
}
- });
- assertConnected(pair);
-
- boolean needsRecordSplit =
- ("TLS".equalsIgnoreCase(c.clientContext.getProtocol())
- || "SSLv3".equalsIgnoreCase(c.clientContext.getProtocol()))
- && cipherSuite.contains("_CBC_");
-
- assertSendsCorrectly("This is the client. Hello!".getBytes(),
- pair.client, pair.server, needsRecordSplit);
- assertSendsCorrectly("This is the server. Hi!".getBytes(),
- pair.server, pair.client, needsRecordSplit);
+ }
// Check that handshake fails when the server does not possess the private key
// corresponding to the server's certificate. This is achieved by using SSLContext
@@ -234,17 +241,23 @@ public class SSLEngineTest extends TestCase {
serverAuthenticatedUsingPublicKey = false;
}
if (serverAuthenticatedUsingPublicKey) {
+ TestSSLEnginePair p = null;
try {
- TestSSLEnginePair p = TestSSLEnginePair.create(
+ p = TestSSLEnginePair.create(
cWithWrongPrivateKeys, new TestSSLEnginePair.Hooks() {
- @Override
+ @Override
void beforeBeginHandshake(SSLEngine client, SSLEngine server) {
- client.setEnabledCipherSuites(cipherSuiteArray);
- server.setEnabledCipherSuites(cipherSuiteArray);
- }
- });
+ client.setEnabledCipherSuites(cipherSuiteArray);
+ server.setEnabledCipherSuites(cipherSuiteArray);
+ }
+ });
assertNotConnected(p);
- } catch (IOException expected) {}
+ } catch (IOException expected) {
+ } finally {
+ if (p != null) {
+ p.close();
+ }
+ }
}
} catch (Exception e) {
String message = ("Problem trying to connect cipher suite " + cipherSuite);
@@ -432,21 +445,28 @@ public class SSLEngineTest extends TestCase {
fail();
} catch (IllegalStateException expected) {
}
+ c.close();
- assertConnected(TestSSLEnginePair.create(null));
+ TestSSLEnginePair p = TestSSLEnginePair.create(null);
+ assertConnected(p);
+ p.close();
- c.close();
}
public void test_SSLEngine_beginHandshake_noKeyStore() throws Exception {
TestSSLContext c = TestSSLContext.create(null, null, null, null, null, null, null, null,
SSLContext.getDefault(), SSLContext.getDefault());
+ SSLEngine[] p = null;
try {
// TODO Fix KnownFailure AlertException "NO SERVER CERTIFICATE FOUND"
// ServerHandshakeImpl.selectSuite should not select a suite without a required cert
- TestSSLEnginePair.connect(c, null);
+ p = TestSSLEnginePair.connect(c, null);
fail();
} catch (SSLHandshakeException expected) {
+ } finally {
+ if (p != null) {
+ TestSSLEnginePair.close(p);
+ }
}
c.close();
}
@@ -456,6 +476,7 @@ public class SSLEngineTest extends TestCase {
SSLEngine[] engines = TestSSLEnginePair.connect(c, null);
assertConnected(engines[0], engines[1]);
c.close();
+ TestSSLEnginePair.close(engines);
}
public void test_SSLEngine_getUseClientMode() throws Exception {
@@ -467,33 +488,47 @@ public class SSLEngineTest extends TestCase {
public void test_SSLEngine_setUseClientMode() throws Exception {
boolean[] finished;
+ TestSSLEnginePair p = null;
// client is client, server is server
finished = new boolean[2];
- assertConnected(test_SSLEngine_setUseClientMode(true, false, finished));
+ p = test_SSLEngine_setUseClientMode(true, false, finished);
+ assertConnected(p);
assertTrue(finished[0]);
assertTrue(finished[1]);
+ p.close();
// client is server, server is client
finished = new boolean[2];
- assertConnected(test_SSLEngine_setUseClientMode(false, true, finished));
+ p = test_SSLEngine_setUseClientMode(false, true, finished);
+ assertConnected(p);
assertTrue(finished[0]);
assertTrue(finished[1]);
+ p.close();
// both are client
/*
* Our implementation throws an SSLHandshakeException, but RI just
* stalls forever
*/
+ p = null;
try {
- assertNotConnected(test_SSLEngine_setUseClientMode(true, true, null));
+ p = test_SSLEngine_setUseClientMode(true, true, null);
+ assertNotConnected(p);
assertTrue(StandardNames.IS_RI);
} catch (SSLHandshakeException maybeExpected) {
assertFalse(StandardNames.IS_RI);
+ } finally {
+ if (p != null) {
+ p.close();
+ }
+
}
+ p = test_SSLEngine_setUseClientMode(false, false, null);
// both are server
- assertNotConnected(test_SSLEngine_setUseClientMode(false, false, null));
+ assertNotConnected(p);
+ p.close();
}
public void test_SSLEngine_setUseClientMode_afterHandshake() throws Exception {
@@ -510,6 +545,7 @@ public class SSLEngineTest extends TestCase {
fail();
} catch (IllegalArgumentException expected) {
}
+ pair.close();
}
private TestSSLEnginePair test_SSLEngine_setUseClientMode(final boolean clientClientMode,
@@ -572,6 +608,7 @@ public class SSLEngineTest extends TestCase {
p.client.getSession().getLocalCertificates());
clientAuthContext.close();
c.close();
+ p.close();
}
/**
@@ -591,6 +628,7 @@ public class SSLEngineTest extends TestCase {
});
assertConnected(p);
clientAuthContext.close();
+ p.close();
}
/**
@@ -604,8 +642,9 @@ public class SSLEngineTest extends TestCase {
TestSSLContext clientAuthContext
= TestSSLContext.create(TestKeyStore.getClient(),
TestKeyStore.getServer());
+ TestSSLEnginePair p = null;
try {
- TestSSLEnginePair.create(clientAuthContext,
+ p = TestSSLEnginePair.create(clientAuthContext,
new TestSSLEnginePair.Hooks() {
@Override
void beforeBeginHandshake(SSLEngine client, SSLEngine server) {
@@ -616,6 +655,9 @@ public class SSLEngineTest extends TestCase {
} catch (SSLHandshakeException expected) {
} finally {
clientAuthContext.close();
+ if (p != null) {
+ p.close();
+ }
}
}
@@ -624,11 +666,13 @@ public class SSLEngineTest extends TestCase {
SSLEngine e = c.clientContext.createSSLEngine();
assertTrue(e.getEnableSessionCreation());
c.close();
+ TestSSLEnginePair.close(new SSLEngine[] { e });
}
public void test_SSLEngine_setEnableSessionCreation_server() throws Exception {
+ TestSSLEnginePair p = null;
try {
- TestSSLEnginePair p = TestSSLEnginePair.create(new TestSSLEnginePair.Hooks() {
+ p = TestSSLEnginePair.create(new TestSSLEnginePair.Hooks() {
@Override
void beforeBeginHandshake(SSLEngine client, SSLEngine server) {
server.setEnableSessionCreation(false);
@@ -639,12 +683,17 @@ public class SSLEngineTest extends TestCase {
assertNotConnected(p);
} catch (SSLException maybeExpected) {
assertFalse(StandardNames.IS_RI);
+ } finally {
+ if (p != null) {
+ p.close();
+ }
}
}
public void test_SSLEngine_setEnableSessionCreation_client() throws Exception {
+ TestSSLEnginePair p = null;
try {
- TestSSLEnginePair.create(new TestSSLEnginePair.Hooks() {
+ p = TestSSLEnginePair.create(new TestSSLEnginePair.Hooks() {
@Override
void beforeBeginHandshake(SSLEngine client, SSLEngine server) {
client.setEnableSessionCreation(false);
@@ -652,6 +701,10 @@ public class SSLEngineTest extends TestCase {
});
fail();
} catch (SSLException expected) {
+ } finally {
+ if (p != null) {
+ p.close();
+ }
}
}
@@ -735,5 +788,6 @@ public class SSLEngineTest extends TestCase {
assertNotNull(test.server);
assertNotNull(test.client);
assertConnected(test);
+ test.close();
}
}
diff --git a/luni/src/test/java/libcore/javax/net/ssl/SSLServerSocketFactoryTest.java b/luni/src/test/java/libcore/javax/net/ssl/SSLServerSocketFactoryTest.java
index ea9c3f0..cda1fb8 100644
--- a/luni/src/test/java/libcore/javax/net/ssl/SSLServerSocketFactoryTest.java
+++ b/luni/src/test/java/libcore/javax/net/ssl/SSLServerSocketFactoryTest.java
@@ -22,7 +22,7 @@ import junit.framework.TestCase;
public class SSLServerSocketFactoryTest extends TestCase {
public void testDefaultConfiguration() throws Exception {
- SSLDefaultConfigurationAsserts.assertSSLServerSocketFactory(
+ SSLConfigurationAsserts.assertSSLServerSocketFactoryDefaultConfiguration(
(SSLServerSocketFactory) SSLServerSocketFactory.getDefault());
}
}
diff --git a/luni/src/test/java/libcore/javax/net/ssl/SSLServerSocketTest.java b/luni/src/test/java/libcore/javax/net/ssl/SSLServerSocketTest.java
index 59c44c1..d2c0f48 100644
--- a/luni/src/test/java/libcore/javax/net/ssl/SSLServerSocketTest.java
+++ b/luni/src/test/java/libcore/javax/net/ssl/SSLServerSocketTest.java
@@ -24,7 +24,7 @@ import java.util.Arrays;
public class SSLServerSocketTest extends TestCase {
public void testDefaultConfiguration() throws Exception {
- SSLDefaultConfigurationAsserts.assertSSLServerSocket(
+ SSLConfigurationAsserts.assertSSLServerSocketDefaultConfiguration(
(SSLServerSocket) SSLServerSocketFactory.getDefault().createServerSocket());
}
diff --git a/luni/src/test/java/libcore/javax/net/ssl/SSLSocketFactoryTest.java b/luni/src/test/java/libcore/javax/net/ssl/SSLSocketFactoryTest.java
index acf69c0..83b690b 100644
--- a/luni/src/test/java/libcore/javax/net/ssl/SSLSocketFactoryTest.java
+++ b/luni/src/test/java/libcore/javax/net/ssl/SSLSocketFactoryTest.java
@@ -210,7 +210,7 @@ public class SSLSocketFactoryTest extends TestCase {
}
public void test_SSLSocketFactory_defaultConfiguration() throws Exception {
- SSLDefaultConfigurationAsserts.assertSSLSocketFactory(
+ SSLConfigurationAsserts.assertSSLSocketFactoryDefaultConfiguration(
(SSLSocketFactory) SSLSocketFactory.getDefault());
}
diff --git a/luni/src/test/java/libcore/javax/net/ssl/SSLSocketTest.java b/luni/src/test/java/libcore/javax/net/ssl/SSLSocketTest.java
index 4af7f5a..8e4519d 100644
--- a/luni/src/test/java/libcore/javax/net/ssl/SSLSocketTest.java
+++ b/luni/src/test/java/libcore/javax/net/ssl/SSLSocketTest.java
@@ -16,6 +16,8 @@
package libcore.javax.net.ssl;
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
@@ -26,15 +28,18 @@ import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
-import java.net.SocketAddress;
import java.net.SocketException;
import java.net.SocketTimeoutException;
+import java.security.KeyManagementException;
+import java.security.NoSuchAlgorithmException;
import java.security.Principal;
import java.security.PrivateKey;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@@ -66,11 +71,23 @@ import libcore.io.IoUtils;
import libcore.io.Streams;
import libcore.java.security.StandardNames;
import libcore.java.security.TestKeyStore;
+import libcore.tlswire.handshake.CipherSuite;
+import libcore.tlswire.handshake.ClientHello;
+import libcore.tlswire.handshake.CompressionMethod;
+import libcore.tlswire.handshake.HandshakeMessage;
+import libcore.tlswire.handshake.HelloExtension;
+import libcore.tlswire.handshake.ServerNameHelloExtension;
+import libcore.tlswire.record.TlsProtocols;
+import libcore.tlswire.record.TlsRecord;
+import libcore.tlswire.util.TlsProtocolVersion;
+import tests.util.ForEachRunner;
+import tests.util.DelegatingSSLSocketFactory;
+import tests.util.Pair;
public class SSLSocketTest extends TestCase {
public void test_SSLSocket_defaultConfiguration() throws Exception {
- SSLDefaultConfigurationAsserts.assertSSLSocket(
+ SSLConfigurationAsserts.assertSSLSocketDefaultConfiguration(
(SSLSocket) SSLSocketFactory.getDefault().createSocket());
}
@@ -1458,11 +1475,147 @@ public class SSLSocketTest extends TestCase {
test.close();
}
- public void test_SSLSocket_ClientHello_size() throws Exception {
+ public void test_SSLSocket_ClientHello_record_size() throws Exception {
// This test checks the size of ClientHello of the default SSLSocket. TLS/SSL handshakes
// with older/unpatched F5/BIG-IP appliances are known to stall and time out when
// the fragment containing ClientHello is between 256 and 511 (inclusive) bytes long.
- //
+ SSLContext sslContext = SSLContext.getInstance("TLS");
+ sslContext.init(null, null, null);
+ SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
+ sslSocketFactory = new DelegatingSSLSocketFactory(sslSocketFactory) {
+ @Override
+ protected void configureSocket(SSLSocket socket) {
+ // Enable SNI extension on the socket (this is typically enabled by default)
+ // to increase the size of ClientHello.
+ try {
+ Method setHostname =
+ socket.getClass().getMethod("setHostname", String.class);
+ setHostname.invoke(socket, "sslsockettest.androidcts.google.com");
+ } catch (NoSuchMethodException ignored) {
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to enable SNI", e);
+ }
+
+ // Enable Session Tickets extension on the socket (this is typically enabled
+ // by default) to increase the size of ClientHello.
+ try {
+ Method setUseSessionTickets =
+ socket.getClass().getMethod(
+ "setUseSessionTickets", boolean.class);
+ setUseSessionTickets.invoke(socket, true);
+ } catch (NoSuchMethodException ignored) {
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to enable Session Tickets", e);
+ }
+ }
+ };
+
+ TlsRecord firstReceivedTlsRecord = captureTlsHandshakeFirstTlsRecord(sslSocketFactory);
+ assertEquals("TLS record type", TlsProtocols.HANDSHAKE, firstReceivedTlsRecord.type);
+ HandshakeMessage handshakeMessage = HandshakeMessage.read(
+ new DataInputStream(new ByteArrayInputStream(firstReceivedTlsRecord.fragment)));
+ assertEquals("HandshakeMessage type",
+ HandshakeMessage.TYPE_CLIENT_HELLO, handshakeMessage.type);
+ int fragmentLength = firstReceivedTlsRecord.fragment.length;
+ if ((fragmentLength >= 256) && (fragmentLength <= 511)) {
+ fail("Fragment containing ClientHello is of dangerous length: "
+ + fragmentLength + " bytes");
+ }
+ }
+
+ public void test_SSLSocket_ClientHello_cipherSuites() throws Exception {
+ ForEachRunner.runNamed(new ForEachRunner.Callback<SSLSocketFactory>() {
+ @Override
+ public void run(SSLSocketFactory sslSocketFactory) throws Exception {
+ ClientHello clientHello = captureTlsHandshakeClientHello(sslSocketFactory);
+ String[] cipherSuites = new String[clientHello.cipherSuites.size()];
+ for (int i = 0; i < clientHello.cipherSuites.size(); i++) {
+ CipherSuite cipherSuite = clientHello.cipherSuites.get(i);
+ cipherSuites[i] = cipherSuite.getAndroidName();
+ }
+ StandardNames.assertDefaultCipherSuites(cipherSuites);
+ }
+ }, getSSLSocketFactoriesToTest());
+ }
+
+ public void test_SSLSocket_ClientHello_clientProtocolVersion() throws Exception {
+ ForEachRunner.runNamed(new ForEachRunner.Callback<SSLSocketFactory>() {
+ @Override
+ public void run(SSLSocketFactory sslSocketFactory) throws Exception {
+ ClientHello clientHello = captureTlsHandshakeClientHello(sslSocketFactory);
+ assertEquals(TlsProtocolVersion.TLSv1_2, clientHello.clientVersion);
+ }
+ }, getSSLSocketFactoriesToTest());
+ }
+
+ public void test_SSLSocket_ClientHello_compressionMethods() throws Exception {
+ ForEachRunner.runNamed(new ForEachRunner.Callback<SSLSocketFactory>() {
+ @Override
+ public void run(SSLSocketFactory sslSocketFactory) throws Exception {
+ ClientHello clientHello = captureTlsHandshakeClientHello(sslSocketFactory);
+ assertEquals(Arrays.asList(CompressionMethod.NULL), clientHello.compressionMethods);
+ }
+ }, getSSLSocketFactoriesToTest());
+ }
+
+ public void test_SSLSocket_ClientHello_SNI() throws Exception {
+ ForEachRunner.runNamed(new ForEachRunner.Callback<SSLSocketFactory>() {
+ @Override
+ public void run(SSLSocketFactory sslSocketFactory) throws Exception {
+ ClientHello clientHello = captureTlsHandshakeClientHello(sslSocketFactory);
+ ServerNameHelloExtension sniExtension = (ServerNameHelloExtension)
+ clientHello.findExtensionByType(HelloExtension.TYPE_SERVER_NAME);
+ assertNotNull(sniExtension);
+ assertEquals(Arrays.asList("localhost.localdomain"), sniExtension.hostnames);
+ }
+ }, getSSLSocketFactoriesToTest());
+ }
+
+ private List<Pair<String, SSLSocketFactory>> getSSLSocketFactoriesToTest()
+ throws NoSuchAlgorithmException, KeyManagementException {
+ List<Pair<String, SSLSocketFactory>> result =
+ new ArrayList<Pair<String, SSLSocketFactory>>();
+ result.add(Pair.of("default", (SSLSocketFactory) SSLSocketFactory.getDefault()));
+ for (String sslContextProtocol : StandardNames.SSL_CONTEXT_PROTOCOLS) {
+ SSLContext sslContext = SSLContext.getInstance(sslContextProtocol);
+ if (StandardNames.SSL_CONTEXT_PROTOCOLS_DEFAULT.equals(sslContextProtocol)) {
+ continue;
+ }
+ sslContext.init(null, null, null);
+ result.add(Pair.of(
+ "SSLContext(\"" + sslContext.getProtocol() + "\")",
+ sslContext.getSocketFactory()));
+ }
+ return result;
+ }
+
+ private ClientHello captureTlsHandshakeClientHello(SSLSocketFactory sslSocketFactory)
+ throws Exception {
+ TlsRecord record = captureTlsHandshakeFirstTlsRecord(sslSocketFactory);
+ assertEquals("TLS record type", TlsProtocols.HANDSHAKE, record.type);
+ ByteArrayInputStream fragmentIn = new ByteArrayInputStream(record.fragment);
+ HandshakeMessage handshakeMessage = HandshakeMessage.read(new DataInputStream(fragmentIn));
+ assertEquals("HandshakeMessage type",
+ HandshakeMessage.TYPE_CLIENT_HELLO, handshakeMessage.type);
+ // Assert that the fragment does not contain any more messages
+ assertEquals(0, fragmentIn.available());
+
+ return (ClientHello) handshakeMessage;
+ }
+
+ private TlsRecord captureTlsHandshakeFirstTlsRecord(SSLSocketFactory sslSocketFactory)
+ throws Exception {
+ byte[] firstReceivedChunk = captureTlsHandshakeFirstTransmittedChunkBytes(sslSocketFactory);
+ ByteArrayInputStream firstReceivedChunkIn = new ByteArrayInputStream(firstReceivedChunk);
+ TlsRecord record = TlsRecord.read(new DataInputStream(firstReceivedChunkIn));
+ // Assert that the chunk does not contain any more data
+ assertEquals(0, firstReceivedChunkIn.available());
+
+ return record;
+ }
+
+ private byte[] captureTlsHandshakeFirstTransmittedChunkBytes(
+ final SSLSocketFactory sslSocketFactory) throws Exception {
// Since there's no straightforward way to obtain a ClientHello from SSLSocket, this test
// does the following:
// 1. Creates a listening server socket (a plain one rather than a TLS/SSL one).
@@ -1506,33 +1659,19 @@ public class SSLSocketTest extends TestCase {
executorService.submit(new Callable<Void>() {
@Override
public Void call() throws Exception {
- SSLContext sslContext = SSLContext.getInstance("TLS");
- sslContext.init(null, null, null);
- SSLSocket client = (SSLSocket) sslContext.getSocketFactory().createSocket();
+ Socket client = new Socket();
sockets[0] = client;
try {
- // Enable SNI extension on the socket (this is typically enabled by default)
- // to increase the size of ClientHello.
- try {
- Method setHostname =
- client.getClass().getMethod("setHostname", String.class);
- setHostname.invoke(client, "sslsockettest.androidcts.google.com");
- } catch (NoSuchMethodException ignored) {}
-
- // Enable Session Tickets extension on the socket (this is typically enabled
- // by default) to increase the size of ClientHello.
- try {
- Method setUseSessionTickets =
- client.getClass().getMethod(
- "setUseSessionTickets", boolean.class);
- setUseSessionTickets.invoke(client, true);
- } catch (NoSuchMethodException ignored) {}
-
client.connect(finalListeningSocket.getLocalSocketAddress());
// Initiate the TLS/SSL handshake which is expected to fail as soon as the
// server socket receives a ClientHello.
try {
- client.startHandshake();
+ SSLSocket sslSocket = (SSLSocket) sslSocketFactory.createSocket(
+ client,
+ "localhost.localdomain",
+ finalListeningSocket.getLocalPort(),
+ true);
+ sslSocket.startHandshake();
fail();
return null;
} catch (IOException expected) {}
@@ -1551,16 +1690,7 @@ public class SSLSocketTest extends TestCase {
});
// Wait for the ClientHello to arrive
- byte[] clientHello = readFirstReceivedChunkFuture.get(10, TimeUnit.SECONDS);
-
- // Check for ClientHello length that may cause handshake to fail/time out with older
- // F5/BIG-IP appliances.
- assertEquals("TLS record type: handshake", 22, clientHello[0]);
- int fragmentLength = ((clientHello[3] & 0xff) << 8) | (clientHello[4] & 0xff);
- if ((fragmentLength >= 256) && (fragmentLength <= 511)) {
- fail("Fragment containing ClientHello is of dangerous length: "
- + fragmentLength + " bytes");
- }
+ return readFirstReceivedChunkFuture.get(10, TimeUnit.SECONDS);
} finally {
executorService.shutdownNow();
IoUtils.closeQuietly(listeningSocket);
diff --git a/luni/src/test/java/libcore/net/MimeUtilsTest.java b/luni/src/test/java/libcore/net/MimeUtilsTest.java
index 9bfb375..ff22632 100644
--- a/luni/src/test/java/libcore/net/MimeUtilsTest.java
+++ b/luni/src/test/java/libcore/net/MimeUtilsTest.java
@@ -27,6 +27,12 @@ public class MimeUtilsTest extends TestCase {
assertEquals("flac", MimeUtils.guessExtensionFromMimeType("application/x-flac"));
}
+ // https://code.google.com/p/android/issues/detail?id=78909
+ public void test_78909() {
+ assertEquals("mka", MimeUtils.guessExtensionFromMimeType("audio/x-matroska"));
+ assertEquals("mkv", MimeUtils.guessExtensionFromMimeType("video/x-matroska"));
+ }
+
public void test_16978217() {
assertEquals("image/x-ms-bmp", MimeUtils.guessMimeTypeFromExtension("bmp"));
assertEquals("image/x-icon", MimeUtils.guessMimeTypeFromExtension("ico"));
diff --git a/luni/src/test/java/libcore/net/NetworkSecurityPolicyTest.java b/luni/src/test/java/libcore/net/NetworkSecurityPolicyTest.java
new file mode 100644
index 0000000..d04e2ba
--- /dev/null
+++ b/luni/src/test/java/libcore/net/NetworkSecurityPolicyTest.java
@@ -0,0 +1,315 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package libcore.net;
+
+import junit.framework.TestCase;
+import libcore.io.IoUtils;
+import java.io.Closeable;
+import java.io.IOException;
+import java.net.JarURLConnection;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Future;
+import java.util.concurrent.FutureTask;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.logging.ErrorManager;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+import java.util.logging.SocketHandler;
+
+public class NetworkSecurityPolicyTest extends TestCase {
+
+ private boolean mCleartextTrafficPermittedOriginalState;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mCleartextTrafficPermittedOriginalState =
+ NetworkSecurityPolicy.isCleartextTrafficPermitted();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ try {
+ NetworkSecurityPolicy.setCleartextTrafficPermitted(
+ mCleartextTrafficPermittedOriginalState);
+ } finally {
+ super.tearDown();
+ }
+ }
+
+ public void testCleartextTrafficPolicySetterAndGetter() {
+ NetworkSecurityPolicy.setCleartextTrafficPermitted(false);
+ assertEquals(false, NetworkSecurityPolicy.isCleartextTrafficPermitted());
+
+ NetworkSecurityPolicy.setCleartextTrafficPermitted(true);
+ assertEquals(true, NetworkSecurityPolicy.isCleartextTrafficPermitted());
+
+ NetworkSecurityPolicy.setCleartextTrafficPermitted(false);
+ assertEquals(false, NetworkSecurityPolicy.isCleartextTrafficPermitted());
+
+ NetworkSecurityPolicy.setCleartextTrafficPermitted(true);
+ assertEquals(true, NetworkSecurityPolicy.isCleartextTrafficPermitted());
+ }
+
+ public void testCleartextTrafficPolicyWithHttpURLConnection() throws Exception {
+ // Assert that client transmits some data when cleartext traffic is permitted.
+ NetworkSecurityPolicy.setCleartextTrafficPermitted(true);
+ try (CapturingServerSocket server = new CapturingServerSocket()) {
+ URL url = new URL("http://localhost:" + server.getPort() + "/test.txt");
+ try {
+ url.openConnection().getContent();
+ fail();
+ } catch (IOException expected) {
+ }
+ server.assertDataTransmittedByClient();
+ }
+
+ // Assert that client does not transmit any data when cleartext traffic is not permitted and
+ // that URLConnection.openConnection or getContent fail with an IOException.
+ NetworkSecurityPolicy.setCleartextTrafficPermitted(false);
+ try (CapturingServerSocket server = new CapturingServerSocket()) {
+ URL url = new URL("http://localhost:" + server.getPort() + "/test.txt");
+ try {
+ url.openConnection().getContent();
+ fail();
+ } catch (IOException expected) {
+ }
+ server.assertNoDataTransmittedByClient();
+ }
+ }
+
+ public void testCleartextTrafficPolicyWithFtpURLConnection() throws Exception {
+ // Assert that client transmits some data when cleartext traffic is permitted.
+ NetworkSecurityPolicy.setCleartextTrafficPermitted(true);
+ byte[] serverReplyOnConnect = "220\r\n".getBytes("US-ASCII");
+ try (CapturingServerSocket server = new CapturingServerSocket(serverReplyOnConnect)) {
+ URL url = new URL("ftp://localhost:" + server.getPort() + "/test.txt");
+ try {
+ url.openConnection().getContent();
+ fail();
+ } catch (IOException expected) {
+ }
+ server.assertDataTransmittedByClient();
+ }
+
+ // Assert that client does not transmit any data when cleartext traffic is not permitted and
+ // that URLConnection.openConnection or getContent fail with an IOException.
+ NetworkSecurityPolicy.setCleartextTrafficPermitted(false);
+ try (CapturingServerSocket server = new CapturingServerSocket(serverReplyOnConnect)) {
+ URL url = new URL("ftp://localhost:" + server.getPort() + "/test.txt");
+ try {
+ url.openConnection().getContent();
+ fail();
+ } catch (IOException expected) {
+ }
+ server.assertNoDataTransmittedByClient();
+ }
+ }
+
+ public void testCleartextTrafficPolicyWithJarHttpURLConnection() throws Exception {
+ // Assert that client transmits some data when cleartext traffic is permitted.
+ NetworkSecurityPolicy.setCleartextTrafficPermitted(true);
+ try (CapturingServerSocket server = new CapturingServerSocket()) {
+ URL url = new URL("jar:http://localhost:" + server.getPort() + "/test.jar!/");
+ try {
+ ((JarURLConnection) url.openConnection()).getManifest();
+ fail();
+ } catch (IOException expected) {
+ }
+ server.assertDataTransmittedByClient();
+ }
+
+ // Assert that client does not transmit any data when cleartext traffic is not permitted and
+ // that JarURLConnection.openConnection or getManifest fail with an IOException.
+ NetworkSecurityPolicy.setCleartextTrafficPermitted(false);
+ try (CapturingServerSocket server = new CapturingServerSocket()) {
+ URL url = new URL("jar:http://localhost:" + server.getPort() + "/test.jar!/");
+ try {
+ ((JarURLConnection) url.openConnection()).getManifest();
+ fail();
+ } catch (IOException expected) {
+ }
+ server.assertNoDataTransmittedByClient();
+ }
+ }
+
+ public void testCleartextTrafficPolicyWithJarFtpURLConnection() throws Exception {
+ // Assert that client transmits some data when cleartext traffic is permitted.
+ NetworkSecurityPolicy.setCleartextTrafficPermitted(true);
+ byte[] serverReplyOnConnect = "220\r\n".getBytes("US-ASCII");
+ try (CapturingServerSocket server = new CapturingServerSocket(serverReplyOnConnect)) {
+ URL url = new URL("jar:ftp://localhost:" + server.getPort() + "/test.jar!/");
+ try {
+ ((JarURLConnection) url.openConnection()).getManifest();
+ fail();
+ } catch (IOException expected) {
+ }
+ server.assertDataTransmittedByClient();
+ }
+
+ // Assert that client does not transmit any data when cleartext traffic is not permitted and
+ // that JarURLConnection.openConnection or getManifest fail with an IOException.
+ NetworkSecurityPolicy.setCleartextTrafficPermitted(false);
+ try (CapturingServerSocket server = new CapturingServerSocket(serverReplyOnConnect)) {
+ URL url = new URL("jar:ftp://localhost:" + server.getPort() + "/test.jar!/");
+ try {
+ ((JarURLConnection) url.openConnection()).getManifest();
+ fail();
+ } catch (IOException expected) {
+ }
+ server.assertNoDataTransmittedByClient();
+ }
+ }
+
+ public void testCleartextTrafficPolicyWithLoggingSocketHandler() throws Exception {
+ // Assert that client transmits some data when cleartext traffic is permitted.
+ NetworkSecurityPolicy.setCleartextTrafficPermitted(true);
+ try (CapturingServerSocket server = new CapturingServerSocket()) {
+ SocketHandler logger = new SocketHandler("localhost", server.getPort());
+ MockErrorManager mockErrorManager = new MockErrorManager();
+ logger.setErrorManager(mockErrorManager);
+ logger.setLevel(Level.ALL);
+ LogRecord record = new LogRecord(Level.INFO, "A log record");
+ assertTrue(logger.isLoggable(record));
+ logger.publish(record);
+ assertNull(mockErrorManager.getMostRecentException());
+ server.assertDataTransmittedByClient();
+ }
+
+ // Assert that client does not transmit any data when cleartext traffic is not permitted.
+ NetworkSecurityPolicy.setCleartextTrafficPermitted(false);
+ try (CapturingServerSocket server = new CapturingServerSocket()) {
+ try {
+ new SocketHandler("localhost", server.getPort());
+ fail();
+ } catch (IOException expected) {
+ }
+ server.assertNoDataTransmittedByClient();
+ }
+ }
+
+ /**
+ * Server socket which listens on a local port and captures the first chunk of data transmitted
+ * by the client.
+ */
+ private static class CapturingServerSocket implements Closeable {
+ private final ServerSocket mSocket;
+ private final int mPort;
+ private final Thread mListeningThread;
+ private final FutureTask<byte[]> mFirstChunkReceivedFuture;
+
+ /**
+ * Constructs a new socket listening on a local port.
+ */
+ public CapturingServerSocket() throws IOException {
+ this(null);
+ }
+
+ /**
+ * Constructs a new socket listening on a local port, which sends the provided reply as
+ * soon as a client connects to it.
+ */
+ public CapturingServerSocket(final byte[] replyOnConnect) throws IOException {
+ mSocket = new ServerSocket(0);
+ mPort = mSocket.getLocalPort();
+ mFirstChunkReceivedFuture = new FutureTask<byte[]>(new Callable<byte[]>() {
+ @Override
+ public byte[] call() throws Exception {
+ try (Socket client = mSocket.accept()) {
+ // Reply (if requested)
+ if (replyOnConnect != null) {
+ client.getOutputStream().write(replyOnConnect);
+ client.getOutputStream().flush();
+ }
+
+ // Read request
+ byte[] buf = new byte[64 * 1024];
+ int chunkSize = client.getInputStream().read(buf);
+ if (chunkSize == -1) {
+ // Connection closed without any data received
+ return new byte[0];
+ }
+ // Received some data
+ return Arrays.copyOf(buf, chunkSize);
+ } finally {
+ IoUtils.closeQuietly(mSocket);
+ }
+ }
+ });
+ mListeningThread = new Thread(mFirstChunkReceivedFuture);
+ mListeningThread.start();
+ }
+
+ public int getPort() {
+ return mPort;
+ }
+
+ public Future<byte[]> getFirstReceivedChunkFuture() {
+ return mFirstChunkReceivedFuture;
+ }
+
+ @Override
+ public void close() {
+ IoUtils.closeQuietly(mSocket);
+ mListeningThread.interrupt();
+ }
+
+ private void assertDataTransmittedByClient()
+ throws Exception {
+ byte[] firstChunkFromClient = getFirstReceivedChunkFuture().get(2, TimeUnit.SECONDS);
+ if ((firstChunkFromClient == null) || (firstChunkFromClient.length == 0)) {
+ fail("Client did not transmit any data to server");
+ }
+ }
+
+ private void assertNoDataTransmittedByClient()
+ throws Exception {
+ byte[] firstChunkFromClient;
+ try {
+ firstChunkFromClient = getFirstReceivedChunkFuture().get(2, TimeUnit.SECONDS);
+ } catch (TimeoutException expected) {
+ return;
+ }
+ if ((firstChunkFromClient != null) && (firstChunkFromClient.length > 0)) {
+ fail("Client transmitted " + firstChunkFromClient.length+ " bytes: "
+ + new String(firstChunkFromClient, "US-ASCII"));
+ }
+ }
+ }
+
+ private static class MockErrorManager extends ErrorManager {
+ private Exception mMostRecentException;
+
+ public Exception getMostRecentException() {
+ synchronized (this) {
+ return mMostRecentException;
+ }
+ }
+
+ @Override
+ public void error(String message, Exception exception, int errorCode) {
+ synchronized (this) {
+ mMostRecentException = exception;
+ }
+ }
+ }
+}
diff --git a/luni/src/test/java/libcore/net/http/ResponseUtilsTest.java b/luni/src/test/java/libcore/net/http/ResponseUtilsTest.java
new file mode 100644
index 0000000..16745ee
--- /dev/null
+++ b/luni/src/test/java/libcore/net/http/ResponseUtilsTest.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package libcore.net.http;
+
+import java.nio.charset.StandardCharsets;
+import java.nio.charset.UnsupportedCharsetException;
+import junit.framework.TestCase;
+import static libcore.net.http.ResponseUtils.responseCharset;
+
+public class ResponseUtilsTest extends TestCase {
+ public void test_responseCharset_missing() {
+ assertEquals(StandardCharsets.UTF_8, responseCharset(null));
+ assertEquals(StandardCharsets.UTF_8, responseCharset("text/plain"));
+ assertEquals(StandardCharsets.UTF_8, responseCharset("text/plain;foo=bar;baz=bal"));
+ assertEquals(StandardCharsets.UTF_8, responseCharset("text/plain;charset="));
+ }
+
+ public void test_responseCharset_valid() {
+ assertEquals(StandardCharsets.ISO_8859_1,
+ responseCharset("text/plain;charset=ISO-8859-1"));
+ assertEquals(StandardCharsets.ISO_8859_1,
+ responseCharset("text/plain;CHARSET=ISO-8859-1"));
+ assertEquals(StandardCharsets.ISO_8859_1,
+ responseCharset("text/plain; charset = ISO-8859-1"));
+ assertEquals(StandardCharsets.ISO_8859_1,
+ responseCharset("text/plain; foo=bar;baz=bag;charset=ISO-8859-1"));
+ assertEquals(StandardCharsets.ISO_8859_1,
+ responseCharset("text/plain;charset=ISO-8859-1;;==,=="));
+ }
+
+ public void test_responseCharset_invalid() {
+ try {
+ responseCharset("text/plain;charset=unsupportedCharset");
+ fail();
+ } catch (UnsupportedCharsetException expected) {
+ }
+ }
+}
diff --git a/luni/src/test/java/libcore/util/HexEncodingTest.java b/luni/src/test/java/libcore/util/HexEncodingTest.java
new file mode 100644
index 0000000..ef79f5c
--- /dev/null
+++ b/luni/src/test/java/libcore/util/HexEncodingTest.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package libcore.util;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import junit.framework.TestCase;
+import static libcore.util.HexEncoding.decode;
+import static libcore.util.HexEncoding.encode;
+
+public class HexEncodingTest extends TestCase {
+ public void testEncode() {
+ final byte[] avocados = "avocados".getBytes(StandardCharsets.UTF_8);
+
+ assertArraysEqual("61766f6361646f73".toCharArray(), encode(avocados));
+ assertArraysEqual(avocados, decode(encode(avocados), false));
+ }
+
+ public void testDecode_allow4Bit() {
+ assertArraysEqual(new byte[] { 6 }, decode("6".toCharArray(), true));
+ assertArraysEqual(new byte[] { 6, 'v' }, decode("676".toCharArray(), true));
+ }
+
+ public void testDecode_disallow4Bit() {
+ try {
+ decode("676".toCharArray(), false);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ public void testDecode_invalid() {
+ try {
+ decode("deadbard".toCharArray(), false);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+
+ // This demonstrates a difference in behaviour from apache commons : apache
+ // commons uses Character.isDigit and would successfully decode a string with
+ // arabic and devanagari characters.
+ try {
+ decode("६१٧٥٥f6361646f73".toCharArray(), false);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+
+ try {
+ decode("#%6361646f73".toCharArray(), false);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ private static void assertArraysEqual(char[] lhs, char[] rhs) {
+ assertEquals(new String(lhs), new String(rhs));
+ }
+
+ private static void assertArraysEqual(byte[] lhs, byte[] rhs) {
+ assertEquals(Arrays.toString(lhs), Arrays.toString(rhs));
+ }
+}
diff --git a/luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/ExemptionMechanismTest.java b/luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/ExemptionMechanismTest.java
index 87b2913..17fb127 100644
--- a/luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/ExemptionMechanismTest.java
+++ b/luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/ExemptionMechanismTest.java
@@ -28,7 +28,6 @@ import java.security.Provider;
import java.security.SecureRandom;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.RSAKeyGenParameterSpec;
-import java.util.Vector;
import javax.crypto.ExemptionMechanism;
import javax.crypto.ExemptionMechanismException;
@@ -37,7 +36,6 @@ import javax.crypto.KeyGenerator;
import javax.crypto.ShortBufferException;
import org.apache.harmony.crypto.tests.support.MyExemptionMechanismSpi;
-import org.apache.harmony.crypto.tests.support.MyExemptionMechanismSpi.tmpKey;
import org.apache.harmony.security.tests.support.SpiEngUtils;
import junit.framework.TestCase;
@@ -170,45 +168,6 @@ public class ExemptionMechanismTest extends TestCase {
em.genExemptionBlob(new byte[10], -5);
}
- static boolean flag = false;
-
- class Mock_ExemptionMechanism extends ExemptionMechanism {
- protected Mock_ExemptionMechanism(ExemptionMechanismSpi exmechSpi, Provider provider, String mechanism) {
- super(exmechSpi, provider, mechanism);
- }
-
- @Override
- protected void finalize() {
- flag = true;
- super.finalize();
- }
- }
-
- // Side Effect: Causes OutOfMemoryError to test finalization
- public void test_finalize () {
- Mock_ExemptionMechanism mem = new Mock_ExemptionMechanism(null, null, "Name");
- assertNotNull(mem);
- mem = null;
- assertFalse(flag);
- Vector v = new Vector();
- int capacity;
- try {
- while(true) {
- v.add(this);
- }
- } catch (OutOfMemoryError e) {
- capacity = v.size();
- v = null;
- }
-
- v = new Vector();
- for (int i = 0; i < capacity/2; i++) {
- v.add(this);
- }
- v = null;
- assertTrue(flag);
- }
-
class Mock_ExemptionMechanismSpi extends MyExemptionMechanismSpi {
@Override
protected byte[] engineGenExemptionBlob()
diff --git a/luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/MacTest.java b/luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/MacTest.java
index ddd0695..e90452d 100644
--- a/luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/MacTest.java
+++ b/luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/MacTest.java
@@ -100,6 +100,12 @@ public class MacTest extends TestCase {
macList.add(Mac.getInstance(defaultAlgorithm, defaultProvider));
macList.add(Mac.getInstance(defaultAlgorithm, defaultProviderName));
for (Provider p : Security.getProviders("Mac." + defaultAlgorithm)) {
+ // Do not test AndroidKeyStore's Mac. It cannot be initialized without providing an
+ // AndroidKeyStore-backed SecretKey instance. It's OKish not to test here because it's
+ // tested by cts/tests/test/keystore.
+ if ("AndroidKeyStore".equals(p.getName())) {
+ continue;
+ }
macList.add(Mac.getInstance(defaultAlgorithm, p));
}
return macList.toArray(new Mac[macList.size()]);
@@ -845,6 +851,13 @@ public class MacTest extends TestCase {
byte[] output = null;
byte[] output2 = null;
for (int i = 0; i < providers.length; i++) {
+ // Do not test AndroidKeyStore's Mac. It cannot be initialized without providing an
+ // AndroidKeyStore-backed SecretKey instance. It's OKish not to test here because it's
+ // tested by cts/tests/test/keystore.
+ if ("AndroidKeyStore".equals(providers[i].getName())) {
+ continue;
+ }
+
System.out.println("provider = " + providers[i].getName());
Mac mac = Mac.getInstance("HmacMD5", providers[i]);
mac.init(key);
@@ -884,6 +897,24 @@ public class MacTest extends TestCase {
public abstract void setup();
}
+ public void testMac_getInstance_DoesNotSupportKeyClass_Success() throws Exception {
+ Provider mockProvider = new MockProvider("MockProvider") {
+ public void setup() {
+ put("Mac.FOO", MockMacSpi.AllKeyTypes.class.getName());
+ put("Mac.FOO SupportedKeyClasses", "None");
+ }
+ };
+
+ Security.addProvider(mockProvider);
+ try {
+ Mac s = Mac.getInstance("FOO", mockProvider);
+ s.init(new MockKey());
+ assertEquals(mockProvider, s.getProvider());
+ } finally {
+ Security.removeProvider(mockProvider.getName());
+ }
+ }
+
public void testMac_getInstance_SuppliedProviderNotRegistered_Success() throws Exception {
Provider mockProvider = new MockProvider("MockProvider") {
public void setup() {