package water.rapids.ast.prims.time; import org.junit.BeforeClass; import org.junit.Test; import water.Scope; import water.TestUtil; import water.fvec.Frame; import water.fvec.TestFrameBuilder; import water.fvec.Vec; import water.parser.ParseTime; import water.rapids.Rapids; import water.rapids.Session; import water.rapids.Val; import water.util.Log; import java.util.Random; import static org.junit.Assert.*; /** */ public class AstMomentTest extends TestUtil { @BeforeClass public static void setup() { stall_till_cloudsize(1); } @Test public void generalTest() { AstMoment am = new AstMoment(); assertEquals(am.nargs() - 1, am.args().length); } @Test public void time0Test() { Scope.enter(); try { Val result = Rapids.exec("(moment 1970 1 1 0 0 0 0)->$f1"); assertTrue(result.isFrame()); Frame fr = result.getFrame(); assertEquals(1, fr.numCols()); assertEquals(1, fr.numRows()); assertEquals(Vec.T_TIME, fr.vec(0).get_type()); assertEquals(0, fr.vec(0).at8(0)); } finally { Scope.exit(); } } @Test public void badtimeTest() { Scope.enter(); try { // Invalid time moment -- should be cast into NaN Val result = Rapids.exec("(moment 1970 0 0 0 0 0 0)->$f1"); assertTrue(result.isFrame()); Frame fr = result.getFrame(); assertEquals(1, fr.numCols()); assertEquals(1, fr.numRows()); assertEquals(Vec.T_TIME, fr.vec(0).get_type()); assertTrue(Double.isNaN(fr.vec(0).at(0))); result = Rapids.exec("(moment 2001 2 29 0 0 0 0)->$f2"); assertTrue(Double.isNaN(result.getFrame().vec(0).at(0))); } finally { Scope.exit(); } } @Test public void vectimeTest() { Scope.enter(); try { Session session = new Session(); new TestFrameBuilder() .withName("$fr", session) .withColNames("day", "hour", "min") .withDataForCol(0, ard(1, 1.1, 1.2, 2, 3)) .withDataForCol(1, ard(0, Double.NaN, 11, 13, 15)) .withDataForCol(2, ar(0, 0, 30, 0, 0)) .build(); Val result = Rapids.exec("(moment 2016 12 (cols $fr 'day') 0 0 0 0)->$res1", session); assertTrue(result.isFrame()); Frame fr = result.getFrame(); Scope.track(fr); assertEquals(1, fr.numCols()); assertEquals(5, fr.numRows()); assertEquals(Vec.T_TIME, fr.vec(0).get_type()); long t0 = (long) fr.vec(0).at(0); long t1 = (long) fr.vec(0).at(1); long t2 = (long) fr.vec(0).at(2); long t3 = (long) fr.vec(0).at(3); long t4 = (long) fr.vec(0).at(4); assertEquals(0, t0 - t1); assertEquals(0, t1 - t2); assertEquals(24 * 3600 * 1000, t3 - t2); assertEquals(24 * 3600 * 1000, t4 - t3); result = Rapids.exec("(moment 2016 12 1 (cols $fr 'hour') (cols $fr 'min') 0 0)->$res2", session); assertTrue(result.isFrame()); fr = result.getFrame(); Scope.track(fr); assertEquals(1, fr.numCols()); assertEquals(5, fr.numRows()); assertEquals(Vec.T_TIME, fr.vec(0).get_type()); double d0 = fr.vec(0).at(0); double d1 = fr.vec(0).at(1); double d2 = fr.vec(0).at(2); double d3 = fr.vec(0).at(3); double d4 = fr.vec(0).at(4); assertTrue("d1 should have been NaN, got " + d1 + " instead", Double.isNaN(d1)); assertEquals((11 * 60 + 30) * 60 * 1000, (long)(d2 - d0)); assertEquals((13 * 60) * 60 * 1000, (long)(d3 - d0)); assertEquals((15 * 60) * 60 * 1000, (long)(d4 - d0)); } finally { Scope.exit(); } } @Test public void naTest() { Scope.enter(); try { Val result = Rapids.exec("(moment 2000 1 1 0 0 0 NaN)->$f1"); assertTrue(result.isFrame()); Frame fr = result.getFrame(); Scope.track(fr); assertEquals(1, fr.numCols()); assertEquals(1, fr.numRows()); assertEquals(Vec.T_TIME, fr.vec(0).get_type()); assertTrue(Double.isNaN(fr.vec(0).at(0))); Session s = new Session(); new TestFrameBuilder() .withName("$year", s) .withColNames("year") .withDataForCol(0, ard(2000, 2004, 2008)) .build(); result = Rapids.exec("(moment $year 1 1 0 0 NaN 0)->$f2", s); assertTrue(result.isFrame()); fr = result.getFrame(); Scope.track(fr); assertEquals(1, fr.numCols()); assertEquals(3, fr.numRows()); assertEquals(Vec.T_TIME, fr.vec(0).get_type()); assertTrue(Double.isNaN(fr.vec(0).at(0))); assertTrue(Double.isNaN(fr.vec(0).at(1))); assertTrue(Double.isNaN(fr.vec(0).at(2))); new TestFrameBuilder() .withName("$day", s) .withColNames("day") .withDataForCol(0, ard(28, 29, 30)) .build(); result = Rapids.exec("(moment 2001 2 $day 0 0 0 0)->$f3", s); assertTrue(result.isFrame()); fr = result.getFrame(); Scope.track(fr); assertEquals(1, fr.numCols()); assertEquals(3, fr.numRows()); assertEquals(Vec.T_TIME, fr.vec(0).get_type()); assertTrue(!Double.isNaN(fr.vec(0).at(0))); assertTrue(Double.isNaN(fr.vec(0).at(1))); assertTrue(Double.isNaN(fr.vec(0).at(2))); } finally { Scope.exit(); } } @Test public void testBadArguments() { Scope.enter(); try { Session s = new Session(); try { Rapids.exec("(moment 2000 1 1 0 0 0)->$f1", s); fail("Expected error: Wrong number of arguments"); } catch (IllegalArgumentException ignored) {} try { Rapids.exec("(moment 2000 1 1 [0] 0 0 0)->$f2", s); fail("Expected error: A NumList is not allowed"); } catch (IllegalArgumentException ignored) {} try { Rapids.exec("(moment '2000' 1 1 0 0 0 0)->$f3", s); fail("Expected error: A string is not allowed"); } catch (IllegalArgumentException ignored) {} new TestFrameBuilder() .withName("$test", s) .withColNames("day", "month") .withVecTypes(Vec.T_NUM, Vec.T_CAT) .withDataForCol(0, ard(5, 10, 15)) .withDataForCol(1, ar("April", "May", "June")) .build(); try { Rapids.exec("(moment 2010 1 $test 0 0 0 0)->$f4", s); fail("Expected error: frame with >1 columns passed"); } catch (IllegalArgumentException ignored) {} try { Rapids.exec("(moment 2010 (cols $test 'month') 1 0 0 0 0)->$f5", s); fail("Expected error: non-numeric column used"); } catch (IllegalArgumentException ignored) {} new TestFrameBuilder() .withName("$frame0", s) .withColNames("a") .build(); try { Rapids.exec("(moment 2010 1 $frame0 0 0 0 0)->$f6", s); fail("Expected error: 0-rows frame used"); } catch (IllegalArgumentException ignored) {} new TestFrameBuilder() .withName("$test2", s) .withColNames("month") .withDataForCol(0, ard(1, 2)) .build(); try { Rapids.exec("(moment 2010 (cols $test2 'month') (cols $test 'day') 0 0 0 0)->$f7", s); fail("Expected error: Incompatible vecs: 2 rows and 3 rows"); } catch (IllegalArgumentException ignored) {} } finally { Scope.exit(); } } @Test public void testOneRowFrame() { Scope.enter(); try { Session s = new Session(); new TestFrameBuilder() .withName("$frame1", s) .withColNames("day", "hour") .withDataForCol(0, ar(1)) .withDataForCol(1, ard(Double.NaN)) .build(); new TestFrameBuilder() .withName("$month", s) .withColNames("month") .withDataForCol(0, ar(2, 3)) .build(); Val result = Rapids.exec("(moment 2010 $month (cols $frame1 'day') 0 0 0 0)->$res1", s); assertTrue(result.isFrame()); Frame fr = result.getFrame(); Scope.track(fr); assertEquals(1, fr.numCols()); assertEquals(2, fr.numRows()); assertEquals(Vec.T_TIME, fr.vec(0).get_type()); result = Rapids.exec("(moment 2010 $month 1 (cols $frame1 'hour') 0 0 0)->$res2", s); assertTrue(result.isFrame()); fr = result.getFrame(); Scope.track(fr); assertEquals(1, fr.numCols()); assertEquals(2, fr.numRows()); assertEquals(Vec.T_TIME, fr.vec(0).get_type()); assertTrue(Double.isNaN(fr.vec(0).at(0))); assertTrue(Double.isNaN(fr.vec(0).at(1))); } finally { Scope.exit(); } } /** * [PUBDEV-4044] Verify that {@code moment} function creates the same moments it's * supposed to create, even if the input frame has multiple chunks. */ @Test public void testMultiChunkedFrame() { long seed = new Random().nextLong(); Log.info("In testMultiChunkedFrame: using seed " + seed); Random rnd = new Random(seed); int N = 30000; long[] years = new long[N]; long[] months = new long[N]; long[] days = new long[N]; for (int i = 0; i < N; i++) { years[i] = 1980 + rnd.nextInt(50); months[i] = 1 + rnd.nextInt(12); days[i] = 1 + rnd.nextInt(28); } int nchunks = 30; long[] layout = new long[nchunks]; layout[0] = N; for (int i = 1; i < nchunks; i++) { layout[i] = N / nchunks; layout[0] -= layout[i]; } Scope.enter(); try { Session s = new Session(); Frame f0 = new TestFrameBuilder() .withName("$f0", s) .withColNames("year", "month", "day") .withDataForCol(0, years) .withDataForCol(1, months) .withDataForCol(2, days) .withChunkLayout(layout) .build(); Scope.track(f0); Frame f1 = Rapids.exec("(moment (cols $f0 0) (cols $f0 1) (cols $f0 2) 0 0 0 0)->$f1", s).getFrame(); Scope.track(f1); assertEquals(1, f1.numCols()); assertEquals(N, f1.numRows()); ParseTime.setTimezone("UTC"); // having a global timezone setting is evil... Frame f1y = Rapids.exec("(year $f1)->$fy", s).getFrame(); Frame f1m = Rapids.exec("(month $f1)->$fm", s).getFrame(); Frame f1d = Rapids.exec("(day $f1)->$fd", s).getFrame(); Scope.track(f1y, f1m, f1d); assertVecEquals(f0.vec(0), f1y.vec(0), 1e-10); assertVecEquals(f0.vec(1), f1m.vec(0), 1e-10); assertVecEquals(f0.vec(2), f1d.vec(0), 1e-10); } finally { Scope.exit(); } } }