/* See LICENSE for licensing and NOTICE for copyright. */ package org.ldaptive.io; import java.time.LocalDateTime; import java.time.ZoneId; import java.time.ZoneOffset; import java.time.ZonedDateTime; import java.time.temporal.ChronoUnit; import org.testng.Assert; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; /** * Unit test for {@link GeneralizedTimeValueTranscoder}. * * @author Middleware Services */ public class GeneralizedTimeValueTranscoderTest { /** Transcoder to test. */ private final GeneralizedTimeValueTranscoder transcoder = new GeneralizedTimeValueTranscoder(); /** * Date test data. * * @return dates * * @throws Exception if test data cannot be generated */ @DataProvider(name = "dates") public Object[][] createDates() throws Exception { return new Object[][] { // no fraction new Object[] { createDateTime("Z", 1990, 10, 23, 17), "1990102317Z", "19901023170000.000Z", }, new Object[] { createDateTime("GMT+04", 2007, 10, 27, 13), "2007102713+04", "20071027090000.000Z", }, new Object[] { createDateTime("GMT-1030", 1993, 12, 15, 14), "1993121514-1030", "19931216003000.000Z", }, // dot fraction new Object[] { createDateTime("Z", 2006, 8, 18, 23, 35, 9, 600), "2006081823.586Z", "20060818233509.600Z", }, new Object[] { createDateTime("GMT+0100", 2012, 2, 15, 2, 15, 0, 0), "2012021502.250+0100", "20120215011500.000Z", }, new Object[] { createDateTime("GMT-1030", 2005, 6, 4, 5, 52, 55, 200), "2005060405.882-1030", "20050604162255.200Z", }, // comma fraction new Object[] { createDateTime("Z", 1992, 3, 1, 7, 20, 38, 400), "1992030107,344Z", "19920301072038.400Z", }, new Object[] { createDateTime("GMT+0100", 2008, 3, 21, 23, 30, 14, 400), "2008032123,504+0100", "20080321223014.400Z", }, new Object[] { createDateTime("GMT-1030", 2018, 4, 8, 6, 45, 43, 200), "2018040806,762-1030", "20180408171543.200Z", }, // min, no fraction new Object[] { createDateTime("Z", 1994, 6, 7, 11, 50), "199406071150Z", "19940607115000.000Z", }, new Object[] { createDateTime("GMT+04", 2015, 8, 24, 12, 41), "201508241241+04", "20150824084100.000Z", }, new Object[] { createDateTime("GMT-1030", 2012, 12, 19, 7, 31), "201212190731-1030", "20121219180100.000Z", }, // min, dot fraction new Object[] { createDateTime("Z", 2019, 5, 27, 13, 57, 46, 800), "201905271357.780Z", "20190527135746.800Z", }, new Object[] { createDateTime("GMT+0100", 2001, 2, 23, 17, 32, 33, 180), "200102231732.553+0100", "20010223163233.180Z", }, new Object[] { createDateTime("GMT-1030", 1997, 10, 27, 19, 32, 31, 860), "199710271932.531-1030", "19971028060231.860Z", }, // min, comma fraction new Object[] { createDateTime("Z", 2005, 1, 6, 7, 5, 19, 260), "200501060705,321Z", "20050106070519.260Z", }, new Object[] { createDateTime("GMT+0100", 2019, 10, 1, 3, 53, 16, 260), "201910010353,271+0100", "20191001025316.260Z", }, new Object[] { createDateTime("GMT-1030", 2003, 2, 4, 10, 56, 49, 560), "200302041056,826-1030", "20030204212649.560Z", }, // min, sec, no fraction new Object[] { createDateTime("Z", 1993, 3, 4, 1, 6, 45), "19930304010645Z", "19930304010645.000Z", }, new Object[] { createDateTime("GMT+04", 1996, 11, 15, 2, 1, 33), "19961115020133+04", "19961114220133.000Z", }, new Object[] { createDateTime("GMT-1030", 2012, 11, 4, 10, 37, 40), "20121104103740-1030", "20121104210740.000Z", }, // min, sec, dot fraction new Object[] { createDateTime("Z", 2016, 5, 17, 5, 31, 50, 193), "20160517053150.193Z", "20160517053150.193Z", }, new Object[] { createDateTime("GMT+0100", 2006, 9, 28, 9, 50, 56, 142), "20060928095056.142+0100", "20060928085056.142Z", }, new Object[] { createDateTime("GMT-1030", 1997, 7, 15, 17, 41, 7, 418), "19970715174107.418-1030", "19970716041107.418Z", }, // min, sec, comma fraction new Object[] { createDateTime("Z", 2003, 5, 11, 3, 55, 24, 11), "20030511035524,011Z", "20030511035524.011Z", }, new Object[] { createDateTime("GMT+0100", 2000, 9, 8, 4, 38, 1, 536), "20000908043801,536+0100", "20000908033801.536Z", }, new Object[] { createDateTime("GMT-1030", 1999, 5, 12, 3, 34, 16, 307), "19990512033416.307-1030", "19990512140416.307Z", }, // feb 29 in leap year new Object[] { createDateTime("Z", 2012, 2, 29, 0), "2012022900Z", "20120229000000.000Z", }, }; } /** * Date test data. * * @return dates * * @throws Exception if test data cannot be generated */ @DataProvider(name = "invalid") public Object[][] createInvalidSyntax() throws Exception { return new Object[][] { // invalid month new Object[] {"20050003193252Z"}, new Object[] {"20011315121902Z"}, new Object[] {"20065205051238Z"}, new Object[] {"19989912035214Z"}, // invalid day new Object[] {"20130600153448Z"}, new Object[] {"19970132100613Z"}, new Object[] {"19990466184045Z"}, new Object[] {"20180299184327Z"}, // invalid hour new Object[] {"19991104604515Z"}, new Object[] {"19990611775328Z"}, new Object[] {"20161126993226Z"}, // invalid min new Object[] {"20150120036044Z"}, new Object[] {"19950801078428Z"}, new Object[] {"20141110059918Z"}, // invalid sec new Object[] {"19970507065463Z"}, new Object[] {"20010804024188Z"}, new Object[] {"20100401071599Z"}, // invalid timezone new Object[] {"20110118183832Z+"}, new Object[] {"20140828202734+2400"}, new Object[] {"20020505162928+9900"}, new Object[] {"20160404014028+1260"}, new Object[] {"20020522033010+1299"}, // leap second new Object[] {"19981126110460Z"}, // too short new Object[] {"200"}, new Object[] {"2009"}, new Object[] {"20091"}, new Object[] {"200912"}, new Object[] {"2009122"}, new Object[] {"20091220"}, new Object[] {"200912200"}, new Object[] {"2009122003"}, // invalid characters new Object[] {"2AA9122003Z"}, new Object[] {"2009122003Y"}, new Object[] {"2004072704BBZ"}, new Object[] {"200407270431CCZ"}, new Object[] {"20040727043108.DZ"}, new Object[] {"20040727043108.DDZ"}, new Object[] {"20040727043108.DDDZ"}, // missing timezone new Object[] {"2017092602"}, new Object[] {"201709260206"}, new Object[] {"20170926020649"}, new Object[] {"20170926020649.5"}, new Object[] {"20170926020649.56"}, new Object[] {"20170926020649.567"}, new Object[] {"20170926020649,2"}, new Object[] {"20170926020649,23"}, new Object[] {"20170926020649,234"}, // invalid timezone character new Object[] {"2010112415E"}, new Object[] {"201011241520E"}, new Object[] {"20101124152005E"}, new Object[] {"20101124152005.1E"}, new Object[] {"20101124152005.12E"}, new Object[] {"20101124152005.122E"}, new Object[] {"20130915044541ZF"}, new Object[] {"20101124152005+0630F"}, // missing fraction new Object[] {"20020511040917.Z"}, new Object[] {"20020511040917,Z"}, // feb 29 in non-leap year new Object[] {"2011022900Z"}, new Object[] {""}, new Object[] {null}, }; } /** * @param date to compare * @param generalizedTime ldap attribute string value * @param formatTime formatted ldap attribute string value * * @throws Exception On test failure. */ @Test(groups = {"io"}, dataProvider = "dates") public void decodeGeneralized(final ZonedDateTime date, final String generalizedTime, final String formatTime) throws Exception { Assert.assertEquals(transcoder.decodeStringValue(generalizedTime), date); } /** * @param date to compare * @param generalizedTime ldap attribute string value * @param formatTime formatted ldap attribute string value * * @throws Exception On test failure. */ @Test(groups = {"io"}, dataProvider = "dates") public void encodeFormat(final ZonedDateTime date, final String generalizedTime, final String formatTime) throws Exception { Assert.assertEquals(transcoder.encodeStringValue(date), formatTime); } /** * @param date to compare * @param generalizedTime ldap attribute string value * @param formatTime formatted ldap attribute string value * * @throws Exception On test failure. */ @Test(groups = {"io"}, dataProvider = "dates") public void decodeFormat(final ZonedDateTime date, final String generalizedTime, final String formatTime) throws Exception { Assert.assertEquals(transcoder.decodeStringValue(formatTime), date.withZoneSameInstant(ZoneOffset.UTC)); } /** * @param generalizedTime ldap attribute string value * * @throws Exception On test failure. */ @Test(groups = {"io"}, dataProvider = "invalid") public void testInvalid(final String generalizedTime) throws Exception { try { transcoder.decodeStringValue(generalizedTime); Assert.fail("Should have thrown exception"); } catch (Exception e) { Assert.assertEquals(e.getClass(), IllegalArgumentException.class); } } /** * Creates a date time for testing. * * @param timezone of the date time * @param values corresponding to date time fields * * @return date time */ protected ZonedDateTime createDateTime(final String timezone, final int... values) { return ZonedDateTime.of( LocalDateTime.of( values[0], values[1], values[2], values[3], values.length > 4 ? values[4] : 0, values.length > 5 ? values[5] : 0).plus(values.length > 6 ? values[6] : 0, ChronoUnit.MILLIS), ZoneId.of(timezone)); } }