/*
* This file is part of the Heritrix web crawler (crawler.archive.org).
*
* Licensed to the Internet Archive (IA) by one or more individual
* contributors.
*
* The IA licenses this file to You 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 org.archive.util;
import java.text.ParseException;
import java.util.Date;
import java.util.HashSet;
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicInteger;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
/**
* JUnit test suite for ArchiveUtils
*
* @author <a href="mailto:me@jamesc.net">James Casey</a>
* @version $Id$
*/
public class ArchiveUtilsTest extends TestCase {
/**
* Create a new ArchiveUtilsTest object
*
* @param testName the name of the test
*/
public ArchiveUtilsTest(final String testName) {
super(testName);
}
/**
* run all the tests for ArchiveUtilsTest
*
* @param argv the command line arguments
*/
public static void main(String argv[]) {
junit.textui.TestRunner.run(suite());
}
/**
* return the suite of tests for ArchiveUtilsTest
*
* @return the suite of test
*/
public static Test suite() {
return new TestSuite(ArchiveUtilsTest.class);
}
/** check the getXXDigitDate() methods produce valid dates*/
public void testGetXXDigitDate() {
// TODO - we only really test the date lengths here. How to test
// other stuff well ?
final String date12 = ArchiveUtils.get12DigitDate();
assertEquals("12 digits", 12, date12.length());
final String date14 = ArchiveUtils.get14DigitDate();
assertEquals("14 digits", 14, date14.length());
final String date17 = ArchiveUtils.get17DigitDate();
assertEquals("17 digits", 17, date17.length());
// now parse, and check they're all within 1 minute
try {
final long long12 = ArchiveUtils.parse12DigitDate(date12).getTime();
long long14 = ArchiveUtils.parse14DigitDate(date14).getTime();
long long17 = ArchiveUtils.parse17DigitDate(date17).getTime();
assertClose("12 and 14 close", long12, long14, 600000);
assertClose("12 and 17 close", long12, long17, 600000);
assertClose("14 and 17 close", long14, long17, 600000);
} catch (ParseException e) {
fail("Could not parse a date : " + e.getMessage());
}
}
/** check that getXXDigitDate(long) does the right thing */
public void testGetXXDigitDateLong() {
final long now = System.currentTimeMillis();
final String date12 = ArchiveUtils.get12DigitDate(now);
assertEquals("12 digits", 12, date12.length());
final String date14 = ArchiveUtils.get14DigitDate(now);
assertEquals("14 digits", 14, date14.length());
assertEquals("first twelve digits same as date12", date12, date14.substring(0, 12));
final String date17 = ArchiveUtils.get17DigitDate(now);
assertEquals("17 digits", 17, date17.length());
assertEquals("first twelve digits same as date12", date12, date17.substring(0, 12));
assertEquals("first fourteen digits same as date14", date14, date17.substring(0, 14));
}
/**
* Check that parseXXDigitDate() works
*
* @throws ParseException
*/
public void testParseXXDigitDate() throws ParseException {
// given a date, check it get resolved properly
// It's 02 Jan 2004, 12:40:02.111
final String date = "20040102124002111";
try {
final long long12 = ArchiveUtils.parse12DigitDate(date.substring(0, 12)).getTime();
final long long14 = ArchiveUtils.parse14DigitDate(date.substring(0, 14)).getTime();
final long long17 = ArchiveUtils.parse17DigitDate(date).getTime();
assertClose("12 and 14 close", long12, long14, 600000);
assertClose("12 and 17 close", long12, long17, 600000);
assertClose("14 and 17 close", long14, long17, 600000);
} catch (ParseException e) {
fail("Could not parse a date : " + e.getMessage());
}
}
public void testTooShortParseDigitDate() throws ParseException {
String d = "X";
boolean b = false;
try {
ArchiveUtils.getDate(d);
} catch (ParseException e) {
b = true;
}
assertTrue(b);
Date date = ArchiveUtils.getDate("1999");
assertTrue(date.getTime() == 915148800000L);
b = false;
try {
ArchiveUtils.getDate("19991");
} catch (ParseException e) {
b = true;
}
assertTrue(b);
ArchiveUtils.getDate("19990101");
ArchiveUtils.getDate("1999010101");
ArchiveUtils.getDate("19990101010101");
ArchiveUtils.getDate("1960");
}
/** check that parse12DigitDate doesn't accept a bad date */
public void testBad12Date() {
// now try a badly formed dates
assertBad12DigitDate("a-stringy-digit-date");
assertBad12DigitDate("20031201"); // too short
}
/**
* check that parse14DigitDate doesn't accept a bad date
*/
public void testBad14Date() {
// now try a badly formed dates
assertBad14DigitDate("a-stringy-digit-date");
assertBad14DigitDate("20031201"); // too short
assertBad14DigitDate("200401021240"); // 12 digit
}
/**
* check that parse12DigitDate doesn't accept a bad date
*/
public void testBad17Date() {
// now try a badly formed dates
assertBad17DigitDate("a-stringy-digit-date");
assertBad17DigitDate("20031201"); // too short
assertBad17DigitDate("200401021240"); // 12 digit
assertBad17DigitDate("20040102124002"); // 14 digit
}
/** check that padTo(String) works */
public void testPadToString() {
assertEquals("pad to one (smaller)", "foo", ArchiveUtils.padTo("foo", 1));
assertEquals("pad to 0 (no sense)", "foo", ArchiveUtils.padTo("foo", 0));
assertEquals("pad to neg (nonsense)", "foo", ArchiveUtils.padTo("foo", 0));
assertEquals("pad to 4", " foo", ArchiveUtils.padTo("foo", 4));
assertEquals("pad to 10", " foo", ArchiveUtils.padTo("foo", 10));
}
/**
* check that padTo(int) works
*/
public void testPadToInt() {
assertEquals("pad to one (smaller)", "123", ArchiveUtils.padTo(123, 1));
assertEquals("pad to 0 (no sense)", "123", ArchiveUtils.padTo(123, 0));
assertEquals("pad to neg (nonsense)", "123", ArchiveUtils.padTo(123, 0));
assertEquals("pad to 4", " 123", ArchiveUtils.padTo(123, 4));
assertEquals("pad to 10", " 123", ArchiveUtils.padTo(123, 10));
assertEquals("pad -123 to 10", " -123", ArchiveUtils.padTo(-123, 10));
}
/** check that byteArrayEquals() works */
public void testByteArrayEquals() {
// foo == foo2, foo != bar, foo != bar2
byte[] foo = new byte[10], bar = new byte[20];
byte[] foo2 = new byte[10], bar2 = new byte[10];
for (byte i = 0; i < 10 ; ++i) {
foo[i] = foo2[i] = bar[i] = i;
bar2[i] = (byte)(01 + i);
}
assertTrue("two nulls", ArchiveUtils.byteArrayEquals(null, null));
assertFalse("lhs null", ArchiveUtils.byteArrayEquals(null, foo));
assertFalse("rhs null", ArchiveUtils.byteArrayEquals(foo, null));
// now check with same length, with same (foo2) and different (bar2)
// contents
assertFalse("different lengths", ArchiveUtils.byteArrayEquals(foo, bar));
assertTrue("same to itself", ArchiveUtils.byteArrayEquals(foo, foo));
assertTrue("same contents", ArchiveUtils.byteArrayEquals(foo, foo2));
assertFalse("different contents", ArchiveUtils.byteArrayEquals(foo, bar2));
}
/** test doubleToString() */
public void testDoubleToString(){
double test = 12.345;
assertTrue(
"cecking zero precision",
ArchiveUtils.doubleToString(test, 0).equals("12"));
assertTrue(
"cecking 2 character precision",
ArchiveUtils.doubleToString(test, 2).equals("12.34"));
assertTrue(
"cecking precision higher then the double has",
ArchiveUtils.doubleToString(test, 65).equals("12.345"));
}
public void testFormatBytesForDisplayPrecise(){
assertEquals("formating negative number", "0 B", ArchiveUtils
.formatBytesForDisplay(-1));
assertEquals("0 bytes", "0 B", ArchiveUtils
.formatBytesForDisplay(0));
assertEquals("1023 bytes", "1,023 B", ArchiveUtils
.formatBytesForDisplay(1023));
assertEquals("1025 bytes", "1.0 KiB", ArchiveUtils
.formatBytesForDisplay(1025));
// expected display values taken from Google calculator
assertEquals("10,000 bytes", "9.8 KiB",
ArchiveUtils.formatBytesForDisplay(10000));
assertEquals("1,000,000 bytes", "977 KiB",
ArchiveUtils.formatBytesForDisplay(1000000));
assertEquals("100,000,000 bytes", "95 MiB",
ArchiveUtils.formatBytesForDisplay(100000000));
assertEquals("100,000,000,000 bytes", "93 GiB",
ArchiveUtils.formatBytesForDisplay(100000000000L));
assertEquals("100,000,000,000,000 bytes", "91 TiB",
ArchiveUtils.formatBytesForDisplay(100000000000000L));
assertEquals("100,000,000,000,000,000 bytes", "90,949 TiB",
ArchiveUtils.formatBytesForDisplay(100000000000000000L));
}
/*
* helper methods
*/
/** check that this is a bad date, and <code>fail()</code> if so.
*
* @param date the 12digit date to check
*/
private void assertBad12DigitDate(final String date) {
try {
ArchiveUtils.parse12DigitDate(date);
} catch (ParseException e) {
return;
}
fail("Expected exception on parse of : " + date);
}
/**
* check that this is a bad date, and <code>fail()</code> if so.
*
* @param date the 14digit date to check
*/
private void assertBad14DigitDate(final String date) {
try {
ArchiveUtils.parse14DigitDate(date);
} catch (ParseException e) {
return;
}
fail("Expected exception on parse of : " + date);
}
/**
* check that this is a bad date, and <code>fail()</code> if so.
*
* @param date the 17digit date to check
*/
private void assertBad17DigitDate(final String date) {
try {
ArchiveUtils.parse17DigitDate(date);
} catch (ParseException e) {
return;
}
fail("Expected exception on parse of : " + date);
}
/** check that two longs are within a given <code>delta</code> */
private void assertClose(String desc, long date1, long date2, long delta) {
assertTrue(desc, date1 == date2 ||
(date1 < date2 && date2 < (date1 + delta)) ||
(date2 < date1 && date1 < (date2 + delta)));
}
public void testArrayToLong() {
testOneArrayToLong(-1);
testOneArrayToLong(1);
testOneArrayToLong(1000);
testOneArrayToLong(Integer.MAX_VALUE);
}
private void testOneArrayToLong(final long testValue) {
byte [] a = new byte[8];
ArchiveUtils.longIntoByteArray(testValue, a, 0);
final long l = ArchiveUtils.byteArrayIntoLong(a, 0);
assertEquals(testValue, l);
}
public void testSecondsSinceEpochCalculation() throws ParseException {
assertEquals(ArchiveUtils.secondsSinceEpoch("20010909014640"),
"1000000000");
assertEquals(ArchiveUtils.secondsSinceEpoch("20010909014639"),
"0999999999");
assertEquals(ArchiveUtils.secondsSinceEpoch("19700101"),
"0000000000");
assertEquals(ArchiveUtils.secondsSinceEpoch("2005"), "1104537600");
assertEquals(ArchiveUtils.secondsSinceEpoch("200501"), "1104537600");
assertEquals(ArchiveUtils.secondsSinceEpoch("20050101"), "1104537600");
assertEquals(ArchiveUtils.secondsSinceEpoch("2005010100"),
"1104537600");
boolean eThrown = false;
try {
ArchiveUtils.secondsSinceEpoch("20050");
} catch (IllegalArgumentException e) {
eThrown = true;
}
assertTrue(eThrown);
}
public static void testZeroPadInteger() {
assertEquals(ArchiveUtils.zeroPadInteger(1), "0000000001");
assertEquals(ArchiveUtils.zeroPadInteger(1000000000), "1000000000");
}
/**
* Test stable behavior of date formatting under heavy concurrency.
*
* @throws InterruptedException
*/
public static void testDateFormatConcurrency() throws InterruptedException {
final int COUNT = 1000;
Thread [] ts = new Thread[COUNT];
final Semaphore allDone = new Semaphore(-COUNT+1);
final AtomicInteger failures = new AtomicInteger(0);
for (int i = 0; i < COUNT; i++) {
Thread t = new Thread() {
public void run() {
long n = System.currentTimeMillis();
final String d = ArchiveUtils.get17DigitDate(n);
for (int i = 0; i < 1000; i++) {
try {
sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
String d2 = ArchiveUtils.get17DigitDate(n);
if(!d.equals(d2)) {
failures.incrementAndGet();
break;
}
}
allDone.release();
}
};
ts[i] = t;
ts[i].setName(Integer.toString(i));
ts[i].start();
while(!ts[i].isAlive()) /* Wait for thread to spin up*/;
}
allDone.acquire(); // wait for all threads to finish
assertEquals(failures.get()+" format mismatches",0,failures.get());
}
public void testIsTld() {
assertTrue("TLD test problem", ArchiveUtils.isTld("com"));
assertTrue("TLD test problem", ArchiveUtils.isTld("COM"));
}
public void testUnique17() {
HashSet<String> uniqueTimestamps = new HashSet<String>();
for(int i = 0; i<10; i++) {
assertTrue("timestamp17 repeated",uniqueTimestamps.add(ArchiveUtils.getUnique17DigitDate()));
}
}
public void testUnique14() {
HashSet<String> uniqueTimestamps = new HashSet<String>();
for(int i = 0; i<10; i++) {
assertTrue("timestamp14 repeated",uniqueTimestamps.add(ArchiveUtils.getUnique14DigitDate()));
}
}
}