// Copyright (C) 2006 Google Inc. // // 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 com.google.enterprise.connector.spi; import com.google.common.base.Charsets; import com.google.enterprise.connector.common.StringUtils; import com.google.enterprise.connector.manager.Context; import com.google.enterprise.connector.spiimpl.BinaryValue; import com.google.enterprise.connector.spiimpl.BooleanValue; import com.google.enterprise.connector.util.InputStreamFactory; import junit.framework.Assert; import junit.framework.TestCase; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.text.ParseException; import java.util.Calendar; import java.util.Date; import java.util.Locale; import java.util.TimeZone; /** * Unit tests for the {@link Value} class. */ public class ValueTest extends TestCase { @Override public void setUp() { // RFC 822 is English-only, and ISO 8601 isn't locale-sensitive, // so change the locale but expect the same results. Locale.setDefault(Locale.FRENCH); } @Override public void tearDown() { // Reset the default time zone. Value.setFeedTimeZone(""); } public void testCalendarToIso8601() { // We're comparing date strings here, so we need a fixed time zone. Value.setFeedTimeZone("GMT"); Calendar c = Calendar.getInstance(); Date d = new Date(999); c.setTime(d); String s = Value.calendarToIso8601(c); Assert.assertEquals("1970-01-01T00:00:00.999Z", s); } public void testIso8601ToCalendar() throws ParseException { { String s = "1970-01-01T00:00:00.999Z"; Calendar c = Value.iso8601ToCalendar(s); Date d = c.getTime(); long millis = d.getTime(); Assert.assertEquals(999, millis); } { String s = "1970-01-01T00:00:50Z"; Calendar c = Value.iso8601ToCalendar(s); Date d = c.getTime(); long millis = d.getTime(); Assert.assertEquals(50000, millis); } } public void testCalendarToRfc822() { // We're comparing date strings here, so we need a fixed time zone. Value.setFeedTimeZone("GMT"); Calendar c = Calendar.getInstance(); Date d = new Date(999); c.setTime(d); String s = Value.calendarToRfc822(c); Assert.assertEquals("Thu, 01 Jan 1970 00:00:00 GMT", s); } /** * Represents the prefix and suffix of formatted timestamp strings * for a specific date in both the RFC 822 and ISO 8601 formats. */ private static class DateFragments { public final String rfc822Date; public final String rfc822TimeZone; public final String iso8601Date; public final String iso8601TimeZone; public DateFragments(String rfc822Date, String rfc822TimeZone, String iso8601Date, String iso8601TimeZone) { this.rfc822Date = rfc822Date; this.rfc822TimeZone = rfc822TimeZone; this.iso8601Date = iso8601Date; this.iso8601TimeZone = iso8601TimeZone; } } /** Tests the local time zone. */ public void testDefaultTimeZone() { Value.setFeedTimeZone(""); Calendar timestamp = Calendar.getInstance(); // We have to compute the offset in this case, because we do not // know the time zone. Due to Daylight Savings Time, which may // alter the UTC offset of any given time zone, we need to use the // date under test, rather than the current date, to get the right // offset. The date used here should match the dates in // testTimeZoneOFfset. // TODO(jlacey): Find a way to isolate this from test data changes. timestamp.set(2000, 11 /* zero-based */, 31); int offset = timestamp.get(Calendar.ZONE_OFFSET) + timestamp.get(Calendar.DST_OFFSET); int minutes = offset / 60 / 1000; String timezone = String.format("%+03d%02d", minutes / 60, Math.abs(minutes % 60)); testTimeZoneOffset(timestamp, offset, timezone); } /** * Tests the given time zone. * * @param offset the offset does not have to match the * <code>timezone</code> value, it just needs to have the right sign * @param timezone the UTC offset as a timezone string, e.g., "-0800" */ private void testFixedTimeZone(int offset, String timezone) { Value.setFeedTimeZone("GMT" + timezone); Calendar timestamp = Calendar.getInstance(); timestamp.setTimeZone(TimeZone.getTimeZone("GMT" + timezone)); testTimeZoneOffset(timestamp, offset, timezone); } /** Tests a time zone west of UTC. The details do not matter. */ public void testWestTimeZone() { testFixedTimeZone(-1, "-0500"); } /** Tests a time zone east of UTC. The details do not matter. */ public void testEastTimeZone() { testFixedTimeZone(+1, "+1100"); } /** Tests the UTC time zone. */ public void testUtcTimeZone() { testFixedTimeZone(0, "+0000"); } /** * Tests converting a timestamp with the default local time zone, * setting the time zone, and converting the same timestamp again. * * NOTE: We want all of the Value methods to be called in this same * test method, because the Java date-time classes do some strange * cloning behind the scenes, and we need to make sure that * Value.setFeedTimeZone correctly affects all of the SimpleDateFormat * instances in the Value class. * * @param timestamp a calendar with the time zone set as desired * @param offset the offset does not have to match the * <code>timezone</code> value, it just needs to have the right sign * @param timezone the UTC offset as a timezone string, e.g., "-0800" */ private void testTimeZoneOffset(Calendar timestamp, int offset, String timezone) { timestamp.clear(); DateFragments local; DateFragments other; String otherId; // The test and local dates here should be less than an hour from // midnight, so that the date in the other time zone is different. // If the dates used here change, especially across a DST bounday, // you need to change the date used in testDefaultTimeZone. if (offset < 0) { // West of prime meridian. timestamp.set(2000, 11 /* zero-based */, 31, 23, 59, 01); local = new DateFragments("Sun, 31 Dec 2000", timezone, "2000-12-31", timezone); other = new DateFragments("Mon, 01 Jan 2001", "GMT", "2001-01-01", "Z"); otherId = "GMT"; } else if (offset > 0) { // East of prime meridian. timestamp.set(2001, 0 /* zero-based */, 1, 00, 00, 59); local = new DateFragments("Mon, 01 Jan 2001", timezone, "2001-01-01", timezone); other = new DateFragments("Sun, 31 Dec 2000", "GMT", "2000-12-31", "Z"); otherId = "GMT"; } else { // UTC timestamp.set(2001, 0 /* zero-based */, 1, 00, 00, 59); local = new DateFragments("Mon, 01 Jan 2001", "GMT", "2001-01-01", "Z"); // Do not use timezone in this case, which is "+0000". other = new DateFragments("Sun, 31 Dec 2000", "-0800", "2000-12-31", "-0800"); otherId = "GMT-0800"; } testTimeZoneFragments(timestamp, local); Value.setFeedTimeZone(otherId); testTimeZoneFragments(timestamp, other); } /** * Calls all three formatting methods in <code>Value</code> and * compares the results to the given fragments. * * @param timestamp a calendar with the time and time zone set as desired * @param expected the expected date string fragments */ private void testTimeZoneFragments(Calendar timestamp, DateFragments expected) { String s; s = Value.calendarToRfc822(timestamp); assertTrue(s, s.startsWith(expected.rfc822Date)); assertTrue(s, s.endsWith(expected.rfc822TimeZone)); s = Value.calendarToIso8601(timestamp); assertTrue(s, s.startsWith(expected.iso8601Date)); assertTrue(s, s.endsWith(expected.iso8601TimeZone)); s = Value.calendarToFeedXml(timestamp); assertEquals(expected.iso8601Date, s); } private static final String TEST_DIR = "testdata/contextTests/value/"; /** Tests the default Spring configuration. */ public void testDefaultConfig() throws Exception { testConfig(TEST_DIR + "default.xml", TimeZone.getDefault().getID()); } /** * Tests the Spring configuration and an explicit time zone. This * test uses an offset, because those are unlikely to be the default * time zone, due to Daylight Savings Time. As an added but probably * unnecessary protection, we use GMT+0100, which is almost empty * during standard time or DST. */ public void testOffsetConfig() throws Exception { testConfig(TEST_DIR + "offset.xml", "GMT+01:00"); } private void testConfig(String applicationContext, String expectedId) { Context.refresh(); Context context = Context.getInstance(); context.setStandaloneContext(applicationContext, null); assertEquals(expectedId, Value.getFeedTimeZone()); } private static final String CONTENTS = "Test Content"; private static final byte[] CONTENTS_BYTES = CONTENTS.getBytes(Charsets.UTF_8); /** Tests BinaryValue constructors - byte array. */ public void testBinaryValueByteArray() throws Exception { testBinaryValue(Value.getBinaryValue(CONTENTS_BYTES)); } /** Tests BinaryValue constructors - InputStream. */ public void testBinaryValueInputStream() throws Exception { testBinaryValue(Value.getBinaryValue( new ByteArrayInputStream(CONTENTS_BYTES))); } /** Tests BinaryValue constructors - InputStreamFactory. */ public void testBinaryValueInputStreamFactory() throws Exception { testBinaryValue(Value.getBinaryValue( new InputStreamFactory() { public InputStream getInputStream() { return new ByteArrayInputStream(CONTENTS_BYTES); } })); } /** Tests BinaryValue constructors - InputStreamFactory. */ public void testBinaryValueInputStreamFactoryError() throws Exception { BinaryValue value = (BinaryValue) Value.getBinaryValue( new InputStreamFactory() { public InputStream getInputStream() throws IOException { throw new IOException("Test Exception"); } }); try { value.getInputStream(); fail("Expected RepositoryDocumentException, but got none."); } catch (RepositoryDocumentException expected) { // Expected. } } /** Tests reading a BinaryValue. */ public void testBinaryValue(Value value) throws Exception { assertTrue(value instanceof BinaryValue); InputStream is = ((BinaryValue) value).getInputStream(); assertNotNull(is); assertEquals(CONTENTS, StringUtils.streamToStringAndThrow(is)); } /** Asserts that the Value represents a boolean of the expected value. */ private void assertValueEquals(boolean expected, Value value) { assertEquals(value.toString(), BooleanValue.class, value.getClass()); assertEquals(value.toString(), expected, ((BooleanValue) value).toBoolean()); } public void testBooleanValue_f() { assertValueEquals(false, Value.getBooleanValue("f")); } public void testBooleanValue_false() { assertValueEquals(false, Value.getBooleanValue("false")); } public void testBooleanValue_FaLsE() { assertValueEquals(false, Value.getBooleanValue("FaLsE")); } public void testBooleanValue_t() { assertValueEquals(true, Value.getBooleanValue("t")); } public void testBooleanValue_true() { assertValueEquals(true, Value.getBooleanValue("true")); } public void testBooleanValue_TRUE() { assertValueEquals(true, Value.getBooleanValue("TRUE")); } public void testBooleanValue_helloworld() { assertValueEquals(true, Value.getBooleanValue("hello, world")); } public void testBooleanValue_empty() { assertValueEquals(true, Value.getBooleanValue("")); } public void testBooleanValue_null() { assertValueEquals(true, Value.getBooleanValue(null)); } }