text:
package org.kuali.hr.time.shiftdiff.rule;

import com.google.common.collect.ImmutableMap;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.LocalTime;
import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Test;
import org.kuali.hr.KPMEWebTestCase;
import org.kuali.kpme.core.FunctionalTest;
import org.kuali.kpme.core.api.assignment.Assignment;
import org.kuali.kpme.core.api.assignment.AssignmentDescriptionKey;
import org.kuali.kpme.core.api.calendar.entry.CalendarEntry;
import org.kuali.kpme.core.calendar.CalendarBo;
import org.kuali.kpme.core.service.HrServiceLocator;
import org.kuali.kpme.core.util.HrContext;
import org.kuali.kpme.core.util.TKUtils;
import org.kuali.kpme.tklm.api.leave.block.LeaveBlock;
import org.kuali.kpme.tklm.api.time.timeblock.TimeBlock;
import org.kuali.kpme.tklm.time.rules.shiftdifferential.ShiftDifferentialRule;
import org.kuali.kpme.tklm.time.rules.shiftdifferential.service.ShiftDifferentialRuleService;
import org.kuali.kpme.tklm.time.service.TkServiceLocator;
import org.kuali.kpme.tklm.time.timesheet.TimesheetDocument;
import org.kuali.kpme.tklm.time.timesheet.TimesheetUtils;
import org.kuali.kpme.tklm.time.util.TkTimeBlockAggregate;
import org.kuali.kpme.tklm.utils.TkTestUtils;

import java.math.BigDecimal;
import java.sql.Time;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

/**
 *
 * @author djunk
 *
 */
@FunctionalTest
public class ShiftDifferentialRuleServiceProcessTest extends KPMEWebTestCase {

	public static final String USER_PRINCIPAL_ID = "admin";
	private DateTime JAN_AS_OF_DATE = new DateTime(2010, 1, 1, 0, 0, 0, 0, TKUtils.getSystemDateTimeZone());

	/**
	 * Test with boundary carryover and overlapping rules.
	 *
	 * Rule 1:
	 *
	 * Runs on Tu, Wed, Th on the interval: [22:00, 4:00)
	 * Max Gap: 15 minutes
	 * Min Hours: 3
	 *
	 * Rule 2:
	 *
	 * Runs on Tu, Th on the interval: [23:00, 2:00)
	 * Max Gap: 2 hours
	 * Min Hours: 3
	 *
	 * Rule 3:
	 *
	 * Runs on W, Th on the interval: [5:00, 12:00)
	 * Max Gap: 15 minutes
	 * Min Hours: 7 hours
	 *
	 * Rule 4:
	 *
	 * Runs on W on the interval: [5:00, 12:00)
	 * Max Gap: 15 minutes
	 * Min Hours: 5
	 *
	 *
	 * |--------------+----+------------+------------|
	 * | Tu : 8/31/10 | XX | W : 9/1/10 | Th: 9/2/10 |
	 * |--------------+----+------------+------------|
	 * | 9:45p - 11:45| XX | Mid - 5a   | 5p - 11p   |
	 * |              | XX | 6a - Noon  |            |
	 * |--------------+----+------------+------------|
     *
     *
     * Aug 31: 2h  : 21:45 - 23:45 (Tue) **
     *                           [1: 5h 45m]  // [2: 2h 45m] - Not qualifying, min hours must be 3.
     * Sep  1: 5h  : 00:00 - 05:00 (Wed) **
     * Sep  1: 6h  : 06:00 - 12:00 (Wed) [4: 6h]
     *
     * Sep  1: 2h  : 22:00 - 24:00 (Wed)
     * Sep  2: 1h  : 00:00 - 01:00 (Thu) [1: 3h]
     *
     * Sep  2: 6h  : 17:00 - 22:00 (Thu)
     *
     * 1: [22:00,  4:00) (Tue/Wed/Thu) minimum: 3h gap: 15m
     * 2: [23:00,  2:00) (Tue/Thu)     minimum: 3h gap: 2h
     * 3: [05:00, 12:00) (Wed/Thu)     minimum: 7h gap: 15m
     * 4: [05:00, 12:00) (Wed)         minimum: 5h gap: 15m
     *
	 */
	@SuppressWarnings("serial")
	@Test
	public void testProcessTimesheetBoundaryCarryoverOverlapCase() throws Exception {
        DateTimeZone tz = HrServiceLocator.getTimezoneService().getUserTimezoneWithFallback();
		// Create the Rule    Sun,   Mon,   Tue,  Wed,   Thu,  Fri,  Sat
		boolean[] dayArray = {false, false, true, true, true, true, true};
		// Matches HR Job ID #1 (job # 30)
		Long jobNumber = 30L;
		Long workArea = 0L;
		this.createShiftDifferentialRule(
				"BWS-CAL", "REG", "PRM", "IN", "SD1", "SD1",// // changed from "SD1" to "IN" for changes of adding groupKeyCode to Job
				(new LocalTime(22, 0)),
				(new LocalTime(4, 0)),
				new BigDecimal(3), // minHours
				new BigDecimal("15.00"), // maxGap
				dayArray);

		// Timeblocks

		// August
		DateTime beginPeriodDate = new DateTime(2010, 8, 15, 0, 0, 0, 0, tz);
		CalendarEntry endOfAugust =  HrServiceLocator.getCalendarEntryService().getCalendarEntryByIdAndPeriodEndDate("2", new DateTime(2010, 9, 1, 0, 0, 0, 0));
		DateTime start = new DateTime(2010, 8, 31, 21, 45, 0, 0, tz);
		List<TimeBlock> blocks = new ArrayList<TimeBlock>();
		TimesheetDocument tdoc = TkServiceLocator.getTimesheetService().openTimesheetDocument("admin", endOfAugust);
        Assignment assignment = HrServiceLocator.getAssignmentService().getAssignment("admin", AssignmentDescriptionKey.get("IU-IN_30_30_30"), beginPeriodDate.toLocalDate());
		blocks.addAll(TkTestUtils.createUniformActualTimeBlocks(tdoc, assignment, "RGN", start, 1, new BigDecimal(2), BigDecimal.ZERO, "admin"));
		TkTimeBlockAggregate aggregate = new TkTimeBlockAggregate(blocks, endOfAugust, HrServiceLocator.getCalendarService().getCalendar(endOfAugust.getHrCalendarId()), true);
		tdoc.setTimeBlocks(blocks);
		TkServiceLocator.getShiftDifferentialRuleService().processShiftDifferentialRules(tdoc, aggregate);
		TkTestUtils.verifyAggregateHourSumsFlatList("August Pre-Check", new HashMap<String,BigDecimal>() {{put("PRM", BigDecimal.ZERO);put("RGN", new BigDecimal(2));}},aggregate);
		TkServiceLocator.getTimeBlockService().saveOrUpdateTimeBlocks(new ArrayList<TimeBlock>(), aggregate.getFlattenedTimeBlockList(), "admin");

		// September

		start = new DateTime(2010, 9, 1, 0, 0, 0, 0, tz);
		CalendarEntry payCalendarEntry =  HrServiceLocator.getCalendarEntryService().getCurrentCalendarDates("admin", start.toLocalDate().toDateTimeAtStartOfDay());
		tdoc = TkServiceLocator.getTimesheetService().openTimesheetDocument("admin", payCalendarEntry);
		blocks = new ArrayList<TimeBlock>();
		blocks.addAll(TkTestUtils.createUniformTimeBlocks(start, 1, new BigDecimal("5"), "RGN", jobNumber, workArea));
		blocks.addAll(TkTestUtils.createUniformTimeBlocks(start.plusHours(6), 1, new BigDecimal("6"), "RGN", jobNumber, workArea));
        blocks.addAll(TkTestUtils.createUniformTimeBlocks(start.plusHours(22), 1, new BigDecimal("2"), "RGN", jobNumber, workArea));
        blocks.addAll(TkTestUtils.createUniformTimeBlocks(start.plusDays(1), 1, new BigDecimal("1"), "RGN", jobNumber, workArea));
		blocks.addAll(TkTestUtils.createUniformTimeBlocks(start.plusDays(1).plusHours(17), 1, new BigDecimal("6"), "RGN", jobNumber, workArea));
		blocks = setDocumentIdOnBlocks(blocks, tdoc.getDocumentId());

		aggregate = new TkTimeBlockAggregate(blocks, payCalendarEntry, HrServiceLocator.getCalendarService().getCalendar(payCalendarEntry.getHrCalendarId()), true);

		TkTestUtils.verifyAggregateHourSumsFlatList("September Pre-Check", new HashMap<String,BigDecimal>() {{put("PRM", BigDecimal.ZERO);put("RGN", new BigDecimal(20));}},aggregate);

		// Verify carry over and applied PRM bucket
		TkServiceLocator.getShiftDifferentialRuleService().processShiftDifferentialRules(tdoc, aggregate);
		TkTestUtils.verifyAggregateHourSumsFlatList("September Post-Check", new HashMap<String,BigDecimal>() {{put("PRM", new BigDecimal("8.75"));put("RGN", new BigDecimal(22));}},aggregate);
	}

    private List<TimeBlock> setDocumentIdOnBlocks(List<TimeBlock> blocks, String id) {
        List<TimeBlock> updatedTimeBlocks = new ArrayList<TimeBlock>();
        for (TimeBlock b : blocks) {
            TimeBlock.Builder builder = TimeBlock.Builder.create(b);
            builder.setDocumentId(id);
            updatedTimeBlocks.add(builder.build());
        }
        return updatedTimeBlocks;
    }

	/**
	 * Test where previous time sheet contains hours that should be added to
	 * the next pay periods first day shift.
	 *
	 * Runs on Tu, Th on the interval: [22:00, 4:00)
	 * Max Gap: 15 minutes
	 * Min Hours: 3
	 *
	 * |--------------+----+------------+-------------|
	 * | Tu : 8/31/10 | XX | W : 9/1/10 | Th : 9/2/10 |
	 * |--------------+----+------------+-------------|
	 * | 10pm - Mid   | XX | Mid - 5am  | 5pm - 11pm  |
	 * |--------------+----+------------+-------------|
	 *
	 * @throws Exception
	 */
	@SuppressWarnings("serial")
	@Test
	public void testProcessShiftTimesheeetBoundaryCarryoverCase() throws Exception {
		// Create the Rule    Sun,   Mon,   Tue,  Wed,   Thu,  Fri,  Sat
		boolean[] dayArray = {false, false, true, false, true, true, true};
		// Matches HR Job ID #1 (job # 30)
		Long jobNumber = 30L;
		Long workArea = 0L;

        DateTimeZone tz = HrServiceLocator.getTimezoneService().getTargetUserTimezoneWithFallback();
		this.createShiftDifferentialRule(
				"BWS-CAL",
				"REG",
				"PRM",
				"IN",  // changed from "SD1" to "IN" for changes of adding groupKeyCode to Job
				"SD1",
				"SD1",
				(new LocalTime(22, 0)),
				(new LocalTime(5, 0)),
				new BigDecimal(3), // minHours
				new BigDecimal("0.25"), // maxGap
				dayArray);

		// August
		DateTime endPeriodDate = new DateTime(2010, 9, 1, 0, 0, 0, 0);
        CalendarEntry endOfAugust =  HrServiceLocator.getCalendarEntryService().getCalendarEntryByIdAndPeriodEndDate("2", endPeriodDate);
		DateTime start = new DateTime(2010, 8, 31, 22, 0, 0, 0, tz);
		List<TimeBlock> blocks = new ArrayList<TimeBlock>();
		TimesheetDocument tdoc = TkServiceLocator.getTimesheetService().openTimesheetDocument("admin", endOfAugust);
        Assignment assignment = HrServiceLocator.getAssignmentService().getAssignment("admin", AssignmentDescriptionKey.get("IU-IN_30_30_30"), endOfAugust.getBeginPeriodFullDateTime().toLocalDate());
		blocks.addAll(TkTestUtils.createUniformActualTimeBlocks(tdoc, assignment, "RGN", start, 1, new BigDecimal(2), BigDecimal.ZERO, "admin"));
		TkTimeBlockAggregate aggregate = new TkTimeBlockAggregate(blocks, endOfAugust, HrServiceLocator.getCalendarService().getCalendar(endOfAugust.getHrCalendarId()), true);

		tdoc.setTimeBlocks(blocks);
		TkServiceLocator.getShiftDifferentialRuleService().processShiftDifferentialRules(tdoc, aggregate);
		TkTestUtils.verifyAggregateHourSumsFlatList("August Pre-Check", new HashMap<String,BigDecimal>() {{put("PRM", BigDecimal.ZERO);put("RGN", new BigDecimal(2));}},aggregate);
		TkServiceLocator.getTimeBlockService().saveOrUpdateTimeBlocks(new ArrayList<TimeBlock>(), aggregate.getFlattenedTimeBlockList(), "admin");

		// September
		start = new DateTime(2010, 9, 1, 0, 0, 0, 0, tz);
		CalendarEntry payCalendarEntry =  HrServiceLocator.getCalendarEntryService().getCurrentCalendarDates("admin", start.toLocalDate().toDateTimeAtStartOfDay());
		tdoc = TkServiceLocator.getTimesheetService().openTimesheetDocument("admin", payCalendarEntry);
		blocks = new ArrayList<TimeBlock>();
		blocks.addAll(TkTestUtils.createUniformTimeBlocks(start, 1, new BigDecimal("5"), "RGN", jobNumber, workArea));
		aggregate = new TkTimeBlockAggregate(blocks, payCalendarEntry, HrServiceLocator.getCalendarService().getCalendar(payCalendarEntry.getHrCalendarId()), true);
		TkTestUtils.verifyAggregateHourSumsFlatList("September Pre-Check", new HashMap<String,BigDecimal>() {{put("PRM", BigDecimal.ZERO);put("RGN", new BigDecimal(5));}},aggregate);

		// Verify carry over and applied PRM bucket
		TkServiceLocator.getShiftDifferentialRuleService().processShiftDifferentialRules(tdoc, aggregate);
		TkTestUtils.verifyAggregateHourSumsFlatList("September Post-Check", new HashMap<String,BigDecimal>() {{put("PRM", new BigDecimal(7));put("RGN", new BigDecimal(7));}},aggregate);
	}

	@SuppressWarnings("serial")
	@Test
	/**
	 * Runs on every day on the interval: [16:00, 24:00)
	 * Max Gap: 15 minutes
	 * Min Hours: 4
	 *
	 * Added some extra time blocks that are not in the shift interval, but
	 * close to the time blocks that are.
	 *
	 * @throws Exception
	 */
	public void testProcessShiftSimpleNoisyCase() throws Exception {
		// Create the Rule
		boolean[] dayArray = {true, true, true, true, true, true, true};
		// Matches HR Job ID #1 (job # 30)
		Long jobNumber = 30L;
		Long workArea = 0L;
        DateTimeZone zone = HrServiceLocator.getTimezoneService().getTargetUserTimezoneWithFallback();
		this.createShiftDifferentialRule(
				"BWS-CAL",
				"REG",
				"PRM",
				"IN", // changed from "SD1" to "IN" for changes of adding groupKeyCode to Job
				"SD1",
				"SD1",
				(new LocalTime(16, 0)),
				(new LocalTime(0, 0)),
				new BigDecimal(4), // minHours
				new BigDecimal("15"), // maxGap
				dayArray);

		// Create Time Blocks (2 days, 2 blocks on each day, 15 minute gap between blocks, 4 hours total each.
		DateTime start = new DateTime(2010, 3, 29, 14, 0, 0, 0, zone);
		List<TimeBlock> blocks = new ArrayList<TimeBlock>();
		CalendarEntry payCalendarEntry =  HrServiceLocator.getCalendarEntryService().getCurrentCalendarDates("admin", start);
		blocks.addAll(TkTestUtils.createUniformTimeBlocks(start, 2, new BigDecimal("4"), "RGN", jobNumber, workArea));
		blocks.addAll(TkTestUtils.createUniformTimeBlocks(start.plusHours(4).plusMinutes(15), 2, new BigDecimal("2"), "RGN", jobNumber, workArea));
		blocks.addAll(TkTestUtils.createUniformTimeBlocks(new DateTime(2010, 3, 29, 12, 58, 0, 0, zone), 2, new BigDecimal(1), "RGN", jobNumber, workArea));
		TkTimeBlockAggregate aggregate = new TkTimeBlockAggregate(blocks, payCalendarEntry);

		// Verify pre-Rule Run
		TkTestUtils.verifyAggregateHourSums("admin", "Pre-Check", new HashMap<String,BigDecimal>() {{put("PRM", BigDecimal.ZERO);put("RGN", new BigDecimal(14));}},aggregate,2);

		// Run Rule
		TimesheetDocument tdoc = TkTestUtils.populateBlankTimesheetDocument(start, "admin");
		tdoc.setTimeBlocks(blocks);
		TkServiceLocator.getShiftDifferentialRuleService().processShiftDifferentialRules(tdoc, aggregate);

		// Verify post-Rule Run
		TkTestUtils.verifyAggregateHourSums("admin", "Post Rules Check", new HashMap<String,BigDecimal>() {{put("PRM", new BigDecimal(8));put("RGN", new BigDecimal(14));}},aggregate,2);
	}

	@SuppressWarnings("serial")
	@Test
	/**
	 * Runs on every day on the interval: [16:00, 24:00)
	 * Max Gap: 15 minutes
	 * Min Hours: 4
	 *
	 * @throws Exception
	 */
	public void testProcessShiftSimpleCase() throws Exception {
		// Create the Rule
		boolean[] dayArray = {true, true, true, true, true, true, true};
		// Matches HR Job ID #1 (job # 30)
		Long jobNumber = 30L;
		Long workArea = 0L;
        DateTimeZone zone = HrServiceLocator.getTimezoneService().getTargetUserTimezoneWithFallback();
		this.createShiftDifferentialRule(
				"BWS-CAL",
				"REG",
				"PRM",
				"IN", // changed from "SD1" to "IN" for changes of adding groupKeyCode to Job
				"SD1",
				"SD1",
				(new LocalTime(16, 0)), //4pm
				(new LocalTime(0, 0)),  //midnight
				new BigDecimal(4), // minHours
				new BigDecimal("15.00"), // maxGap minutes
				dayArray);

		// Create Time Blocks (2 days, 2 blocks on each day, 15 minute gap between blocks, 4 hours total each.
		DateTime start = new DateTime(2010, 3, 29, 14, 0, 0, 0, zone);
		List<TimeBlock> blocks = new ArrayList<TimeBlock>();
		CalendarEntry payCalendarEntry =  HrServiceLocator.getCalendarEntryService().getCurrentCalendarDates("admin", start);
		blocks.addAll(TkTestUtils.createUniformTimeBlocks(start, 2, new BigDecimal("4"), "REG", jobNumber, workArea));
		blocks.addAll(TkTestUtils.createUniformTimeBlocks(start.plusHours(4).plusMinutes(15), 2, new BigDecimal("2"), "REG", jobNumber, workArea));
		TkTimeBlockAggregate aggregate = new TkTimeBlockAggregate(blocks, payCalendarEntry);

		// Verify pre-Rule Run
		TkTestUtils.verifyAggregateHourSums("admin","Pre-Check", new HashMap<String,BigDecimal>() {{put("PRM", BigDecimal.ZERO);put("REG", new BigDecimal(12));}},aggregate,2);

		// Run Rule
		TimesheetDocument tdoc = TkTestUtils.populateBlankTimesheetDocument(start, "admin");
		tdoc.setTimeBlocks(blocks);
		TkServiceLocator.getShiftDifferentialRuleService().processShiftDifferentialRules(tdoc, aggregate);

		// Verify post-Rule Run
		TkTestUtils.verifyAggregateHourSums("admin","Post Rules Check", new HashMap<String,BigDecimal>() {{put("PRM", new BigDecimal(8));put("REG", new BigDecimal(12));}},aggregate,2);
	}

	/**
	 * Stores the Shift Differential Rule in the database for testing.
	 *
	 * dayBooleans[] is a 7 element array of booleans, [0, 6] is [sun, sat]
	 */
	private void createShiftDifferentialRule(String pyCalendarGroup, String fromEarnGroup, String premiumEarnCode, String location, String payGrade, String hrSalGroup, LocalTime startTime, LocalTime endTime, BigDecimal minHours, BigDecimal maxGap, boolean dayBooleans[]) {
		Assert.assertTrue("Wrong number of day booleans", dayBooleans.length == 7);

		ShiftDifferentialRuleService service = TkServiceLocator.getShiftDifferentialRuleService();
		ShiftDifferentialRule sdr = new ShiftDifferentialRule();

		sdr.setBeginTime(new Time(startTime.toDateTimeToday().getMillis()));
		sdr.setEndTime(new Time(endTime.toDateTimeToday().getMillis()));
		sdr.setMinHours(minHours);
		sdr.setMaxGap(maxGap);
		sdr.setActive(true);
		sdr.setUserPrincipalId(USER_PRINCIPAL_ID);
		sdr.setEffectiveLocalDate(JAN_AS_OF_DATE.toLocalDate());
		sdr.setLocation(location);
		sdr.setPayGrade(payGrade);
		sdr.setHrSalGroup(hrSalGroup);
		sdr.setFromEarnGroup(fromEarnGroup);
		sdr.setPyCalendarGroup(pyCalendarGroup);
		sdr.setEarnCode(premiumEarnCode);
        sdr.setRuleType("default");

		for (int i=0; i<dayBooleans.length; i++) {
			switch(i) {
			case 0:
				sdr.setSunday(dayBooleans[i]);
				break;
			case 1:
				sdr.setMonday(dayBooleans[i]);
				break;
			case 2:
				sdr.setTuesday(dayBooleans[i]);
				break;
			case 3:
				sdr.setWednesday(dayBooleans[i]);
				break;
			case 4:
				sdr.setThursday(dayBooleans[i]);
				break;
			case 5:
				sdr.setFriday(dayBooleans[i]);
				break;
			case 6:
				sdr.setSaturday(dayBooleans[i]);
				break;
			}
		}

		service.saveOrUpdate(sdr);

		ShiftDifferentialRule sdrBack = service.getShiftDifferentialRule(sdr.getTkShiftDiffRuleId());

        DateTimeZone tz = HrServiceLocator.getTimezoneService().getUserTimezoneWithFallback();
        LocalTime orig_start = new LocalTime(sdr.getBeginTime());
		LocalTime orig_end = new LocalTime(sdr.getEndTime());

		LocalTime stored_start = new LocalTime(sdrBack.getBeginTime());
		LocalTime stored_end = new LocalTime(sdrBack.getEndTime());

		Assert.assertTrue("Start times not equal.", orig_start.equals(stored_start));
		Assert.assertTrue("End times not equal.", orig_end.equals(stored_end));
	}

    @Ignore
    @Test
    /**
     * Tests WorkSchedules impact on Shift Differential Rule: Simple Case
     *
     * Create a timeblock on two days, one day has normal REG shift eligible
     * hours, one day has HOL time.
     *
     * Modified version of the simple case, SDR from 12:00 to 17:00, every day,
     * must have at least 4 hours with a maximum 15 minute gap.
     *
     */
    public void simpleCaseWithWorkSchedule() throws Exception {
		// Create the Rule
		boolean[] dayArray = {true, true, true, true, true, true, true};
		// Matches HR Job ID #1 (job # 30)
		Long jobNumber = 30L;
		Long workArea = 0L;
		this.createShiftDifferentialRule(
				"BWS-CAL",
				"REG",
				"PRM",
				"IN",  // changed from "SD1" to "IN" for changes of adding groupKeyCode to Job
				"SD1",
				"SD1",
				(new LocalTime(12, 0)),
				(new LocalTime(17, 0)),
				new BigDecimal(4), // minHours
				new BigDecimal("15.00"), // maxGap
				dayArray);

		// Create Time Blocks (2 days, 2 blocks on each day, 15 minute gap between blocks, 4 hours total each.
		DateTime start = new DateTime(2010, 3, 29, 12, 0, 0, 0, TKUtils.getSystemDateTimeZone());
        DateTime holtime = new DateTime(2010, 3, 30, 0, 0, 0, 0, TKUtils.getSystemDateTimeZone());
		List<TimeBlock> blocks = new ArrayList<TimeBlock>();
		CalendarEntry payCalendarEntry =  HrServiceLocator.getCalendarEntryService().getCurrentCalendarDates("admin", start);
		blocks.addAll(TkTestUtils.createUniformTimeBlocks(start,   1, new BigDecimal("4"), "REG", jobNumber, workArea));
        blocks.addAll(TkTestUtils.createUniformTimeBlocks(holtime, 1, new BigDecimal("4"), "HOL", jobNumber, workArea));

		TkTimeBlockAggregate aggregate = new TkTimeBlockAggregate(blocks, payCalendarEntry);

		// Verify pre-Rule Run
		TkTestUtils.verifyAggregateHourSums("admin","Pre-Check", new HashMap<String,BigDecimal>() {{put("PRM", BigDecimal.ZERO);put("REG", new BigDecimal(4));put("HOL", new BigDecimal(4));}},aggregate,2);

		// Run Rule
		TimesheetDocument tdoc = TkTestUtils.populateBlankTimesheetDocument(start, "admin");
		tdoc.setTimeBlocks(blocks);
		TkServiceLocator.getShiftDifferentialRuleService().processShiftDifferentialRules(tdoc, aggregate);

		// Verify post-Rule Run
		TkTestUtils.verifyAggregateHourSums("admin","Post Rules Check", new HashMap<String,BigDecimal>() {{put("PRM", new BigDecimal(8));put("REG", new BigDecimal(4));}},aggregate,2);

    }

    /**
     * Tests WorkSchedules impact on Shift Differential Rule: Simple Case
     *
     * Create a single 24 hour timeblock that spans two different shift, both exceeding the min hours
     */
    @Test
    public void overlapMultipleShiftsWithSameTimeBlock() {
        // Create the Rule
        boolean[] dayArray = {true, true, true, true, true, true, true};
        // Matches HR Job ID #1 (job # 30)
        Long jobNumber = 30L;
        Long workArea = 0L;
        DateTimeZone zone = HrServiceLocator.getTimezoneService().getTargetUserTimezoneWithFallback();

        //3pm to 8am, 6 hour minimum, 90 minute max gap
        this.createShiftDifferentialRule(
                "BWS-CAL",
                "REG",
                "PRM",
                "IN",
                "SD1",
                "SD1",
                (new LocalTime(15, 0)),
                (new LocalTime(8, 0)),
                new BigDecimal(6), // minHours
                new BigDecimal("90.00"), // maxGap
                dayArray);

        // Create Time Blocks (2 days, 2 blocks on each day, 15 minute gap between blocks, 4 hours total each.
        DateTime start = new DateTime(2010, 3, 29, 0, 0, 0, 0, TKUtils.getSystemDateTimeZone());
        CalendarEntry payCalendarEntry =  HrServiceLocator.getCalendarEntryService().getCurrentCalendarDates("admin", start);

        List<TimeBlock> blocks = new ArrayList<TimeBlock>();
        DateTime tbStart = new DateTime(2010, 3, 29, 0, 0, 0, 0, zone);

        //24 time block (midnight to midnight)
        blocks.addAll(TkTestUtils.createUniformTimeBlocks(tbStart, 1, new BigDecimal("24"), "REG", jobNumber, workArea));

        TkTimeBlockAggregate aggregate = new TkTimeBlockAggregate(blocks, payCalendarEntry);

        // Verify pre-Rule Run
        TkTestUtils.verifyAggregateHourSums("admin","Pre-Check", new HashMap<String,BigDecimal>() {{put("PRM", BigDecimal.ZERO);put("REG", new BigDecimal(24));}},aggregate,2);

        // Run Rule
        TimesheetDocument tdoc = TkTestUtils.populateBlankTimesheetDocument(start, "admin");
        tdoc.setTimeBlocks(blocks);
        TkServiceLocator.getShiftDifferentialRuleService().processShiftDifferentialRules(tdoc, aggregate);

        // Verify post-Rule Run
        TkTestUtils.verifyAggregateHourSums("admin","Post Rules Check", new HashMap<String,BigDecimal>() {{put("PRM", new BigDecimal(17));put("REG", new BigDecimal(24));}},aggregate,2);

    }

    /**
     * Tests WorkSchedules impact on Shift Differential Rule: Simple Case
     *
     * Create a two 24 hour timeblocks that span three different shifts, all exceeding the min hours
     */
    @Test
    public void overlapMultipleShiftsWithMultipleTimeBlocks() {
        // Create the Rule
        boolean[] dayArray = {true, true, true, true, true, true, true};
        // Matches HR Job ID #1 (job # 30)
        Long jobNumber = 30L;
        Long workArea = 0L;
        DateTimeZone zone = HrServiceLocator.getTimezoneService().getTargetUserTimezoneWithFallback();

        //3pm to 8am, 6 hour minimum, 90 minute max gap
        this.createShiftDifferentialRule(
                "BWS-CAL",
                "REG",
                "PRM",
                "IN",
                "SD1",
                "SD1",
                (new LocalTime(15, 0)),
                (new LocalTime(8, 0)),
                new BigDecimal(6), // minHours
                new BigDecimal("90.00"), // maxGap
                dayArray);

        // Create Time Blocks (2 days, 2 blocks on each day, 15 minute gap between blocks, 4 hours total each.
        DateTime start = new DateTime(2010, 3, 29, 0, 0, 0, 0, TKUtils.getSystemDateTimeZone());
        CalendarEntry payCalendarEntry =  HrServiceLocator.getCalendarEntryService().getCurrentCalendarDates("admin", start);

        List<TimeBlock> blocks = new ArrayList<TimeBlock>();
        DateTime tbStart = new DateTime(2010, 3, 29, 0, 0, 0, 0, zone);

        //24 time block (midnight to midnight)
        blocks.addAll(TkTestUtils.createUniformTimeBlocks(tbStart, 1, new BigDecimal("24"), "REG", jobNumber, workArea));

        //24 time block (midnight to midnight)
        blocks.addAll(TkTestUtils.createUniformTimeBlocks(tbStart.plusDays(1), 1, new BigDecimal("24"), "REG", jobNumber, workArea));

        TkTimeBlockAggregate aggregate = new TkTimeBlockAggregate(blocks, payCalendarEntry);

        // Verify pre-Rule Run
        TkTestUtils.verifyAggregateHourSums("admin","Pre-Check", new HashMap<String,BigDecimal>() {{put("PRM", BigDecimal.ZERO);put("REG", new BigDecimal(48));}},aggregate,2);

        // Run Rule
        TimesheetDocument tdoc = TkTestUtils.populateBlankTimesheetDocument(start, "admin");
        tdoc.setTimeBlocks(blocks);
        TkServiceLocator.getShiftDifferentialRuleService().processShiftDifferentialRules(tdoc, aggregate);

        // Verify post-Rule Run
        //overlaps from 12a-8a (8 hours), 3p-8a (17 hours), and 3p - 12a (9 hours) == 34 hours
        TkTestUtils.verifyAggregateHourSums("admin","Post Rules Check", new HashMap<String,BigDecimal>() {{put("PRM", new BigDecimal(34));put("REG", new BigDecimal(48));}},aggregate,2);

    }

    /**
     * Tests WorkSchedules impact on Shift Differential Rule: Simple Case
     *
     * Create a single 24 hour timeblock that spans two different shift, both exceeding the min hours
     */
    @Test
    public void overlapMultipleShiftsWithSameTimeBlockExceedingMinOnOneShift() {
        // Create the Rule
        boolean[] dayArray = {true, true, true, true, true, true, true};
        // Matches HR Job ID #1 (job # 30)
        Long jobNumber = 30L;
        Long workArea = 0L;
        DateTimeZone zone = HrServiceLocator.getTimezoneService().getTargetUserTimezoneWithFallback();

        //3pm to 8am, 6 hour minimum, 90 minute max gap
        this.createShiftDifferentialRule(
                "BWS-CAL",
                "REG",
                "PRM",
                "IN",
                "SD1",
                "SD1",
                (new LocalTime(15, 0)),
                (new LocalTime(8, 0)),
                new BigDecimal(6), // minHours
                new BigDecimal("90.00"), // maxGap
                dayArray);

        DateTime start = new DateTime(2010, 3, 29, 0, 0, 0, 0, TKUtils.getSystemDateTimeZone());
        List<TimeBlock> blocks = new ArrayList<TimeBlock>();
        CalendarEntry payCalendarEntry =  HrServiceLocator.getCalendarEntryService().getCurrentCalendarDates("admin", start);

        //reg timeblock 3am - midnight
        DateTime tbStart = new DateTime(2010, 3, 30, 3, 0, 0, 0, zone);
        blocks.addAll(TkTestUtils.createUniformTimeBlocks(tbStart,   1, new BigDecimal("21"), "REG", jobNumber, workArea));

        TkTimeBlockAggregate aggregate = new TkTimeBlockAggregate(blocks, payCalendarEntry);

        // Verify pre-Rule Run
        TkTestUtils.verifyAggregateHourSums("admin","Pre-Check", new ImmutableMap.Builder<String, BigDecimal>()
                .put("PRM", BigDecimal.ZERO)
                .put("REG", new BigDecimal(21)).build(), aggregate, 2);

        // Run Rule
        TimesheetDocument tdoc = TkTestUtils.populateBlankTimesheetDocument(start, "admin");
        tdoc.setTimeBlocks(blocks);
        TkServiceLocator.getShiftDifferentialRuleService().processShiftDifferentialRules(tdoc, aggregate);

        // Verify post-Rule Run
        TkTestUtils.verifyAggregateHourSums("admin","Post Rules Check", new ImmutableMap.Builder<String, BigDecimal>()
                .put("PRM", new BigDecimal(9))
                .put("REG", new BigDecimal(21)).build(),
                aggregate,
                2);

    }

    /**
     * Tests WorkSchedules impact on Shift Differential Rule: Simple Case
     *
     * Create a single 24 hour timeblock that spans two different shift, both exceeding the min hours
     */
    @Test
    public void overlapMultipleShiftsWithSameTimeBlockExceedingMinOnFirstShift() {
        // Create the Rule
        boolean[] dayArray = {true, true, true, true, true, true, true};
        // Matches HR Job ID #1 (job # 30)
        Long jobNumber = 30L;
        Long workArea = 0L;
        DateTimeZone zone = HrServiceLocator.getTimezoneService().getTargetUserTimezoneWithFallback();

        //3pm to 8am, 6 hour minimum, 90 minute max gap
        this.createShiftDifferentialRule(
                "BWS-CAL",
                "REG",
                "PRM",
                "IN",
                "SD1",
                "SD1",
                (new LocalTime(15, 0)),
                (new LocalTime(8, 0)),
                new BigDecimal(6), // minHours
                new BigDecimal("90.00"), // maxGap
                dayArray);

        DateTime start = new DateTime(2010, 3, 29, 0, 0, 0, 0, TKUtils.getSystemDateTimeZone());
        List<TimeBlock> blocks = new ArrayList<TimeBlock>();
        CalendarEntry payCalendarEntry =  HrServiceLocator.getCalendarEntryService().getCurrentCalendarDates("admin", start);

        //reg timeblock 1am - 9pm
        DateTime tbStart = new DateTime(2010, 3, 30, 1, 0, 0, 0, zone);
        blocks.addAll(TkTestUtils.createUniformTimeBlocks(tbStart,   1, new BigDecimal("19"), "REG", jobNumber, workArea));

        TkTimeBlockAggregate aggregate = new TkTimeBlockAggregate(blocks, payCalendarEntry);

        // Verify pre-Rule Run
        TkTestUtils.verifyAggregateHourSums("admin","Pre-Check", new ImmutableMap.Builder<String, BigDecimal>()
                .put("PRM", BigDecimal.ZERO)
                .put("REG", new BigDecimal(19)).build(), aggregate, 2);

        // Run Rule
        TimesheetDocument tdoc = TkTestUtils.populateBlankTimesheetDocument(start, "admin");
        tdoc.setTimeBlocks(blocks);
        TkServiceLocator.getShiftDifferentialRuleService().processShiftDifferentialRules(tdoc, aggregate);

        // Verify post-Rule Run
        TkTestUtils.verifyAggregateHourSums("admin","Post Rules Check", new ImmutableMap.Builder<String, BigDecimal>()
                        .put("PRM", new BigDecimal(7))
                        .put("REG", new BigDecimal(19)).build(),
                aggregate,
                2);

    }

    /**
     * Tests WorkSchedules impact on Shift Differential Rule: Simple Case
     *
     * Create a single 17 hour timeblock that spans two different shift, neither exceeding the min hours
     */
    @Test
    public void overlapMultipleShiftsWithSameTimeBlocNeitherExceedingMin() {
        // Create the Rule
        boolean[] dayArray = {true, true, true, true, true, true, true};
        // Matches HR Job ID #1 (job # 30)
        Long jobNumber = 30L;
        Long workArea = 0L;
        DateTimeZone zone = HrServiceLocator.getTimezoneService().getTargetUserTimezoneWithFallback();

        //3pm to 8am, 6 hour minimum, 90 minute max gap
        this.createShiftDifferentialRule(
                "BWS-CAL",
                "REG",
                "PRM",
                "IN",
                "SD1",
                "SD1",
                (new LocalTime(15, 0)),
                (new LocalTime(8, 0)),
                new BigDecimal(6), // minHours
                new BigDecimal("90.00"), // maxGap
                dayArray);

        // Create Time Blocks (2 days, 2 blocks on each day, 15 minute gap between blocks, 4 hours total each.
        DateTime start = new DateTime(2010, 3, 29, 0, 0, 0, 0, TKUtils.getSystemDateTimeZone());
        List<TimeBlock> blocks = new ArrayList<TimeBlock>();
        CalendarEntry payCalendarEntry =  HrServiceLocator.getCalendarEntryService().getCurrentCalendarDates("admin", start);

        //reg timeblock 3am - 8pm
        DateTime tbStart = new DateTime(2010, 3, 30, 3, 0, 0, 0, zone);
        blocks.addAll(TkTestUtils.createUniformTimeBlocks(tbStart,   1, new BigDecimal("17"), "REG", jobNumber, workArea));

        TkTimeBlockAggregate aggregate = new TkTimeBlockAggregate(blocks, payCalendarEntry);

        // Verify pre-Rule Run
        TkTestUtils.verifyAggregateHourSums("admin","Pre-Check", new ImmutableMap.Builder<String, BigDecimal>()
                .put("PRM", BigDecimal.ZERO)
                .put("REG", new BigDecimal(17)).build(), aggregate, 2);

        // Run Rule
        TimesheetDocument tdoc = TkTestUtils.populateBlankTimesheetDocument(start, "admin");
        tdoc.setTimeBlocks(blocks);
        TkServiceLocator.getShiftDifferentialRuleService().processShiftDifferentialRules(tdoc, aggregate);

        // Verify post-Rule Run
        TkTestUtils.verifyAggregateHourSums("admin","Post Rules Check", new ImmutableMap.Builder<String, BigDecimal>()
                        .put("PRM", BigDecimal.ZERO)
                        .put("REG", new BigDecimal(17)).build(),
                aggregate,
                2);
    }

    /**
     * Tests WorkSchedules impact on Shift Differential Rule: Simple Case
     *
     * Create a single 17 hour timeblock that spans two different shift, neither exceeding the min hours
     */
    @Test
    public void multipleTimeBlocksOvernightExceedingMin() {
        // Create the Rule
        boolean[] dayArray = {true, true, true, true, true, true, true};
        // Matches HR Job ID #1 (job # 30)
        Long jobNumber = 30L;
        Long workArea = 0L;
        DateTimeZone zone = HrServiceLocator.getTimezoneService().getTargetUserTimezoneWithFallback();

        //3pm to 8am, 6 hour minimum, 90 minute max gap
        this.createShiftDifferentialRule(
                "BWS-CAL",
                "REG",
                "PRM",
                "IN",
                "SD1",
                "SD1",
                (new LocalTime(15, 0)),
                (new LocalTime(8, 0)),
                new BigDecimal(6), // minHours
                new BigDecimal("90.00"), // maxGap
                dayArray);

        // Create Time Blocks (2 days, 2 blocks on each day, 15 minute gap between blocks, 4 hours total each.
        DateTime start = new DateTime(2010, 3, 29, 0, 0, 0, 0, TKUtils.getSystemDateTimeZone());
        List<TimeBlock> blocks = new ArrayList<TimeBlock>();
        CalendarEntry payCalendarEntry =  HrServiceLocator.getCalendarEntryService().getCurrentCalendarDates("admin", start);

        //reg timeblock 10pm - midnight
        DateTime tbStart1 = new DateTime(2010, 3, 30, 22, 0, 0, 0, zone);
        blocks.addAll(TkTestUtils.createUniformTimeBlocks(tbStart1,   1, new BigDecimal("2"), "REG", jobNumber, workArea));
        //reg timeblock midnight - 5am
        DateTime tbStart2 = new DateTime(2010, 3, 31, 0, 0, 0, 0, zone);
        blocks.addAll(TkTestUtils.createUniformTimeBlocks(tbStart2,   1, new BigDecimal("5"), "REG", jobNumber, workArea));

        TkTimeBlockAggregate aggregate = new TkTimeBlockAggregate(blocks, payCalendarEntry);

        // Verify pre-Rule Run
        TkTestUtils.verifyAggregateHourSums("admin","Pre-Check", new ImmutableMap.Builder<String, BigDecimal>()
                .put("PRM", BigDecimal.ZERO)
                .put("REG", BigDecimal.valueOf(7)).build(), aggregate, 2);

        // Run Rule
        TimesheetDocument tdoc = TkTestUtils.populateBlankTimesheetDocument(start, "admin");
        tdoc.setTimeBlocks(blocks);
        TkServiceLocator.getShiftDifferentialRuleService().processShiftDifferentialRules(tdoc, aggregate);

        // Verify post-Rule Run
        TkTestUtils.verifyAggregateHourSums("admin","Post Rules Check", new ImmutableMap.Builder<String, BigDecimal>()
                        .put("PRM", BigDecimal.valueOf(7))
                        .put("REG", BigDecimal.valueOf(7)).build(),
                aggregate,
                2);
    }

    /**
     * Tests WorkSchedules impact on Shift Differential Rule: Simple Case
     *
     * Create a single 17 hour timeblock that spans two different shift, neither exceeding the min hours
     */
    @Test
    public void multipleTimeBlocksOvernightExceedingMinWithSixtyMinuteGap() {
        // Create the Rule
        boolean[] dayArray = {true, true, true, true, true, true, true};
        // Matches HR Job ID #1 (job # 30)
        Long jobNumber = 30L;
        Long workArea = 0L;
        DateTimeZone zone = HrServiceLocator.getTimezoneService().getTargetUserTimezoneWithFallback();

        //3pm to 8am, 6 hour minimum, 90 minute max gap
        this.createShiftDifferentialRule(
                "BWS-CAL",
                "REG",
                "PRM",
                "IN",
                "SD1",
                "SD1",
                (new LocalTime(15, 0)),
                (new LocalTime(8, 0)),
                new BigDecimal(6), // minHours
                new BigDecimal("90.00"), // maxGap
                dayArray);

        // Create Time Blocks (2 days, 2 blocks on each day, 15 minute gap between blocks, 4 hours total each.
        DateTime start = new DateTime(2010, 3, 29, 0, 0, 0, 0, TKUtils.getSystemDateTimeZone());
        List<TimeBlock> blocks = new ArrayList<TimeBlock>();
        CalendarEntry payCalendarEntry =  HrServiceLocator.getCalendarEntryService().getCurrentCalendarDates("admin", start);

        //reg timeblock 10pm - midnight
        DateTime tbStart1 = new DateTime(2010, 3, 30, 22, 0, 0, 0, zone);
        blocks.addAll(TkTestUtils.createUniformTimeBlocks(tbStart1,   1, new BigDecimal("2"), "REG", jobNumber, workArea));
        //reg timeblock 1am - 5am
        DateTime tbStart2 = new DateTime(2010, 3, 31, 1, 0, 0, 0, zone);
        blocks.addAll(TkTestUtils.createUniformTimeBlocks(tbStart2,   1, new BigDecimal("4"), "REG", jobNumber, workArea));

        TkTimeBlockAggregate aggregate = new TkTimeBlockAggregate(blocks, payCalendarEntry);

        // Verify pre-Rule Run
        TkTestUtils.verifyAggregateHourSums("admin","Pre-Check", new ImmutableMap.Builder<String, BigDecimal>()
                .put("PRM", BigDecimal.ZERO)
                .put("REG", BigDecimal.valueOf(6)).build(), aggregate, 2);

        // Run Rule
        TimesheetDocument tdoc = TkTestUtils.populateBlankTimesheetDocument(start, "admin");
        tdoc.setTimeBlocks(blocks);
        TkServiceLocator.getShiftDifferentialRuleService().processShiftDifferentialRules(tdoc, aggregate);

        // Verify post-Rule Run
        TkTestUtils.verifyAggregateHourSums("admin","Post Rules Check", new ImmutableMap.Builder<String, BigDecimal>()
                        .put("PRM", BigDecimal.valueOf(6))
                        .put("REG", BigDecimal.valueOf(6)).build(),
                aggregate,
                2);
    }

    /**
     * Tests WorkSchedules impact on Shift Differential Rule: Simple Case
     *
     * Create a single 17 hour timeblock that spans two different shift, neither exceeding the min hours
     */
    @Test
    public void multipleTimeBlocksOvernightExceedingMinWithNinetyMinuteGap() {
        // Create the Rule
        boolean[] dayArray = {true, true, true, true, true, true, true};
        // Matches HR Job ID #1 (job # 30)
        Long jobNumber = 30L;
        Long workArea = 0L;
        DateTimeZone zone = HrServiceLocator.getTimezoneService().getTargetUserTimezoneWithFallback();

        //3pm to 8am, 6 hour minimum, 90 minute max gap
        this.createShiftDifferentialRule(
                "BWS-CAL",
                "REG",
                "PRM",
                "IN",
                "SD1",
                "SD1",
                (new LocalTime(15, 0)),
                (new LocalTime(8, 0)),
                new BigDecimal(6), // minHours
                new BigDecimal("90.00"), // maxGap
                dayArray);

        // Create Time Blocks (2 days, 2 blocks on each day, 15 minute gap between blocks, 4 hours total each.
        DateTime start = new DateTime(2010, 3, 29, 0, 0, 0, 0, TKUtils.getSystemDateTimeZone());
        List<TimeBlock> blocks = new ArrayList<TimeBlock>();
        CalendarEntry payCalendarEntry =  HrServiceLocator.getCalendarEntryService().getCurrentCalendarDates("admin", start);

        //reg timeblock 10pm - midnight
        DateTime tbStart1 = new DateTime(2010, 3, 30, 22, 0, 0, 0, zone);
        blocks.addAll(TkTestUtils.createUniformTimeBlocks(tbStart1,   1, new BigDecimal("2"), "REG", jobNumber, workArea));
        //reg timeblock 1:30am - 5:30pm
        DateTime tbStart2 = new DateTime(2010, 3, 31, 1, 30, 0, 0, zone);
        blocks.addAll(TkTestUtils.createUniformTimeBlocks(tbStart2,   1, new BigDecimal("4"), "REG", jobNumber, workArea));

        TkTimeBlockAggregate aggregate = new TkTimeBlockAggregate(blocks, payCalendarEntry);

        // Verify pre-Rule Run
        TkTestUtils.verifyAggregateHourSums("admin","Pre-Check", new ImmutableMap.Builder<String, BigDecimal>()
                .put("PRM", BigDecimal.ZERO)
                .put("REG", BigDecimal.valueOf(6)).build(), aggregate, 2);

        // Run Rule
        TimesheetDocument tdoc = TkTestUtils.populateBlankTimesheetDocument(start, "admin");
        tdoc.setTimeBlocks(blocks);
        TkServiceLocator.getShiftDifferentialRuleService().processShiftDifferentialRules(tdoc, aggregate);

        // Verify post-Rule Run
        TkTestUtils.verifyAggregateHourSums("admin","Post Rules Check", new ImmutableMap.Builder<String, BigDecimal>()
                        .put("PRM", BigDecimal.valueOf(6))
                        .put("REG", BigDecimal.valueOf(6)).build(),
                aggregate,
                2);
    }

    /**
     * Tests WorkSchedules impact on Shift Differential Rule: Simple Case
     *
     * Create a single 17 hour timeblock that spans two different shift, neither exceeding the min hours
     */
    @Test
    public void multipleTimeBlocksOvernightExceedingMinButExceedingGap() {
        // Create the Rule
        boolean[] dayArray = {true, true, true, true, true, true, true};
        // Matches HR Job ID #1 (job # 30)
        Long jobNumber = 30L;
        Long workArea = 0L;
        DateTimeZone zone = HrServiceLocator.getTimezoneService().getTargetUserTimezoneWithFallback();

        //3pm to 8am, 6 hour minimum, 90 minute max gap
        this.createShiftDifferentialRule(
                "BWS-CAL",
                "REG",
                "PRM",
                "IN",
                "SD1",
                "SD1",
                (new LocalTime(15, 0)),
                (new LocalTime(8, 0)),
                new BigDecimal(6), // minHours
                new BigDecimal("90.00"), // maxGap
                dayArray);

        // Create Time Blocks (2 days, 2 blocks on each day, 15 minute gap between blocks, 4 hours total each.
        DateTime start = new DateTime(2010, 3, 29, 0, 0, 0, 0, TKUtils.getSystemDateTimeZone());
        List<TimeBlock> blocks = new ArrayList<TimeBlock>();
        CalendarEntry payCalendarEntry =  HrServiceLocator.getCalendarEntryService().getCurrentCalendarDates("admin", start);

        //reg timeblock 10pm - midnight
        DateTime tbStart1 = new DateTime(2010, 3, 30, 22, 0, 0, 0, zone);
        blocks.addAll(TkTestUtils.createUniformTimeBlocks(tbStart1,   1, new BigDecimal("2"), "REG", jobNumber, workArea));
        //reg timeblock 1:36am - 5:36am
        DateTime tbStart2 = new DateTime(2010, 3, 31, 1, 36, 0, 0, zone);
        blocks.addAll(TkTestUtils.createUniformTimeBlocks(tbStart2,   1, new BigDecimal("4"), "REG", jobNumber, workArea));

        TkTimeBlockAggregate aggregate = new TkTimeBlockAggregate(blocks, payCalendarEntry);

        // Verify pre-Rule Run
        TkTestUtils.verifyAggregateHourSums("admin","Pre-Check", new ImmutableMap.Builder<String, BigDecimal>()
                .put("PRM", BigDecimal.ZERO)
                .put("REG", BigDecimal.valueOf(6)).build(), aggregate, 2);

        // Run Rule
        TimesheetDocument tdoc = TkTestUtils.populateBlankTimesheetDocument(start, "admin");
        tdoc.setTimeBlocks(blocks);
        TkServiceLocator.getShiftDifferentialRuleService().processShiftDifferentialRules(tdoc, aggregate);

        // Verify post-Rule Run
        TkTestUtils.verifyAggregateHourSums("admin","Post Rules Check", new ImmutableMap.Builder<String, BigDecimal>()
                        .put("PRM", BigDecimal.valueOf(0))
                        .put("REG", BigDecimal.valueOf(6)).build(),
                aggregate,
                2);
    }

    /**
     * Tests WorkSchedules impact on Shift Differential Rule: Simple Case
     *
     * Create a single 17 hour timeblock that spans two different shift, neither exceeding the min hours
     */
    @Test
    public void threeBlocksWithinSameShift() {
        // Create the Rule
        boolean[] dayArray = {true, true, true, true, true, true, true};
        // Matches HR Job ID #1 (job # 30)
        Long jobNumber = 30L;
        Long workArea = 0L;
        DateTimeZone zone = HrServiceLocator.getTimezoneService().getTargetUserTimezoneWithFallback();

        //3pm to 8am, 6 hour minimum, 90 minute max gap
        this.createShiftDifferentialRule(
                "BWS-CAL",
                "REG",
                "PRM",
                "IN",
                "SD1",
                "SD1",
                (new LocalTime(15, 0)),
                (new LocalTime(8, 0)),
                new BigDecimal(6), // minHours
                new BigDecimal("90.00"), // maxGap
                dayArray);

        // Create Time Blocks (2 days, 2 blocks on each day, 15 minute gap between blocks, 4 hours total each.
        DateTime start = new DateTime(2010, 3, 29, 0, 0, 0, 0, TKUtils.getSystemDateTimeZone());
        CalendarEntry payCalendarEntry =  HrServiceLocator.getCalendarEntryService().getCurrentCalendarDates("admin", start);

        List<TimeBlock> blocks = new ArrayList<TimeBlock>();

        //reg timeblock 3pm - 5pm
        DateTime tbStart1 = new DateTime(2010, 3, 30, 15, 0, 0, 0, zone);
        blocks.addAll(TkTestUtils.createUniformTimeBlocks(tbStart1,   1, new BigDecimal("2"), "REG", jobNumber, workArea));

        // 6pm - 9pm
        DateTime tbStart2 = new DateTime(2010, 3, 30, 18, 0, 0, 0, zone);
        blocks.addAll(TkTestUtils.createUniformTimeBlocks(tbStart2,   1, new BigDecimal("3"), "REG", jobNumber, workArea));

        // 10pm - 11pm
        DateTime tbStart3 = new DateTime(2010, 3, 30, 22, 0, 0, 0, zone);
        blocks.addAll(TkTestUtils.createUniformTimeBlocks(tbStart3,   1, new BigDecimal("1"), "REG", jobNumber, workArea));

        TkTimeBlockAggregate aggregate = new TkTimeBlockAggregate(blocks, payCalendarEntry);

        // Verify pre-Rule Run
        TkTestUtils.verifyAggregateHourSums("admin","Pre-Check", new ImmutableMap.Builder<String, BigDecimal>()
                .put("PRM", BigDecimal.ZERO)
                .put("REG", BigDecimal.valueOf(6)).build(), aggregate, 2);

        // Run Rule
        TimesheetDocument tdoc = TkTestUtils.populateBlankTimesheetDocument(start, "admin");
        tdoc.setTimeBlocks(blocks);
        TkServiceLocator.getShiftDifferentialRuleService().processShiftDifferentialRules(tdoc, aggregate);

        // Verify post-Rule Run
        TkTestUtils.verifyAggregateHourSums("admin","Post Rules Check", new ImmutableMap.Builder<String, BigDecimal>()
                        .put("PRM", BigDecimal.valueOf(6))
                        .put("REG", BigDecimal.valueOf(6)).build(),
                aggregate,
                2);
    }

    /**
     * Tests WorkSchedules impact on Shift Differential Rule: Simple Case
     *
     * Create a single 17 hour timeblock that spans two different shift, neither exceeding the min hours
     */
    @Test
    public void fourBlocksWithinSameShiftSpanningTwoDays() {
        // Create the Rule
        boolean[] dayArray = {true, true, true, true, true, true, true};
        // Matches HR Job ID #1 (job # 30)
        Long jobNumber = 30L;
        Long workArea = 0L;
        DateTimeZone zone = HrServiceLocator.getTimezoneService().getTargetUserTimezoneWithFallback();

        //3pm to 8am, 6 hour minimum, 90 minute max gap
        this.createShiftDifferentialRule(
                "BWS-CAL",
                "REG",
                "PRM",
                "IN",
                "SD1",
                "SD1",
                (new LocalTime(15, 0)),
                (new LocalTime(8, 0)),
                new BigDecimal(6), // minHours
                new BigDecimal("90.00"), // maxGap
                dayArray);

        // Create Time Blocks (2 days, 2 blocks on each day, 15 minute gap between blocks, 4 hours total each.
        DateTime start = new DateTime(2010, 3, 29, 0, 0, 0, 0, TKUtils.getSystemDateTimeZone());
        CalendarEntry payCalendarEntry =  HrServiceLocator.getCalendarEntryService().getCurrentCalendarDates("admin", start);

        List<TimeBlock> blocks = new ArrayList<TimeBlock>();

        //reg timeblock 5pm - 6pm
        DateTime tbStart1 = new DateTime(2010, 3, 30, 17, 0, 0, 0, zone);
        blocks.addAll(TkTestUtils.createUniformTimeBlocks(tbStart1,   1, new BigDecimal("1"), "REG", jobNumber, workArea));

        // 7:30pm - 8:30pm
        DateTime tbStart2 = new DateTime(2010, 3, 30, 19, 30, 0, 0, zone);
        blocks.addAll(TkTestUtils.createUniformTimeBlocks(tbStart2,   1, new BigDecimal("1"), "REG", jobNumber, workArea));

        // 10pm - midnight
        DateTime tbStart3 = new DateTime(2010, 3, 30, 22, 0, 0, 0, zone);
        blocks.addAll(TkTestUtils.createUniformTimeBlocks(tbStart3,   1, new BigDecimal("2"), "REG", jobNumber, workArea));

        // 1:30am - 4:30am
        DateTime tbStart4 = new DateTime(2010, 3, 31, 1, 30, 0, 0, zone);
        blocks.addAll(TkTestUtils.createUniformTimeBlocks(tbStart4,   1, new BigDecimal("3"), "REG", jobNumber, workArea));

        TkTimeBlockAggregate aggregate = new TkTimeBlockAggregate(blocks, payCalendarEntry);

        // Verify pre-Rule Run
        TkTestUtils.verifyAggregateHourSums("admin","Pre-Check", new ImmutableMap.Builder<String, BigDecimal>()
                .put("PRM", BigDecimal.ZERO)
                .put("REG", BigDecimal.valueOf(7)).build(), aggregate, 2);

        // Run Rule
        TimesheetDocument tdoc = TkTestUtils.populateBlankTimesheetDocument(start, "admin");
        tdoc.setTimeBlocks(blocks);
        TkServiceLocator.getShiftDifferentialRuleService().processShiftDifferentialRules(tdoc, aggregate);

        // Verify post-Rule Run
        TkTestUtils.verifyAggregateHourSums("admin","Post Rules Check", new ImmutableMap.Builder<String, BigDecimal>()
                        .put("PRM", BigDecimal.valueOf(7))
                        .put("REG", BigDecimal.valueOf(7)).build(),
                aggregate,
                2);
    }

    /**
     * Tests WorkSchedules impact on Shift Differential Rule: Simple Case
     *
     * Create a single 17 hour timeblock that spans two different shift, neither exceeding the min hours
     */
    @Test
    public void EarnGroupTest() {
        // Create the Rule
        // Matches HR Job ID #1 (job # 30)
        String principalId = "10112";

        Long jobNumber = 0L;
        String groupKey = "IU-IN";
        Long workArea = 1010L;
        Long task = 0L;
        DateTimeZone zone = HrServiceLocator.getTimezoneService().getTargetUserTimezoneWithFallback();

        // Create Time Blocks (2 days, 2 blocks on each day, 15 minute gap between blocks, 4 hours total each.
        DateTime start = new DateTime(2010, 3, 29, 0, 0, 0, 0, TKUtils.getSystemDateTimeZone());
        CalendarEntry payCalendarEntry =  HrServiceLocator.getCalendarEntryService().getCurrentCalendarDates("admin", start);

        TimesheetDocument td = TkTestUtils.populateBlankTimesheetDocument(start, principalId);

        List<TimeBlock> blocks = new ArrayList<TimeBlock>();

        //rgh - monday 8a-11a no-shift
        DateTime tbStart1 = new DateTime(2010, 3, 30, 8, 0, 0, 0, zone);
        blocks.addAll(TkTestUtils.createUniformTimeBlocks(tbStart1,   1, new BigDecimal("3"), "RGH", jobNumber, workArea, task, groupKey, td.getDocumentId()));

        //echr - monday 2p-5p - should have 3 hrs SHEG
        DateTime tbStart2 = new DateTime(2010, 3, 30, 14, 0, 0, 0, zone);
        blocks.addAll(TkTestUtils.createUniformTimeBlocks(tbStart2,   1, new BigDecimal("3"), "ECHR", jobNumber, workArea, task, groupKey, td.getDocumentId()));

        TkTimeBlockAggregate aggregate = new TkTimeBlockAggregate(blocks, payCalendarEntry);

        // Verify pre-Rule Run
        TkTestUtils.verifyAggregateHourSums(principalId, "Pre-Check", new ImmutableMap.Builder<String, BigDecimal>()
                .put("RGH", BigDecimal.valueOf(3))
                .put("ECHR", BigDecimal.valueOf(3)).build(), aggregate, 2);

        // Run Rule

        //td.setTimeBlocks(blocks);
        List<LeaveBlock> leaveBlocks = TimesheetUtils.getLeaveBlocksForTimesheet(td);
        List<TimeBlock> initialBlocks = TimesheetUtils.getTimesheetTimeblocksForProcessing(td, true);
        List<TimeBlock> referenceTimeBlocks = TimesheetUtils.getReferenceTimeBlocks(initialBlocks);

        //reset time block
        //List<TimeBlock> tbs = TkServiceLocator.getTimesheetService().resetTimeBlock(initialBlocks, td.getAsOfDate());
        TimesheetUtils.processTimeBlocksWithRuleChange(blocks, referenceTimeBlocks, leaveBlocks, td.getCalendarEntry(), td, HrContext.getPrincipalId());

        //refresh Timesheet
        td = TkServiceLocator.getTimesheetService().getTimesheetDocument(td.getDocumentId());
        aggregate = new TkTimeBlockAggregate(td.getTimeBlocks(), payCalendarEntry);
        // Verify post-Rule Run
        TkTestUtils.verifyAggregateHourSums(principalId, "Post Rules Check", new ImmutableMap.Builder<String, BigDecimal>()
                        .put("RGH", BigDecimal.valueOf(3))
                        .put("ECHR", BigDecimal.valueOf(3))
                        .put("SHEG", BigDecimal.valueOf(3)).build(),
                aggregate,
                2);
    }

    @Test
    public void calendarGroupTest() {
        // Create the Rule
        // Matches HR Job ID #1 (job # 30)
        String principalId = "10113";

        Long jobNumber = 0L;
        String groupKey = "IU-IN";
        Long workArea = 1010L;
        Long task = 0L;
        DateTimeZone zone = HrServiceLocator.getTimezoneService().getTargetUserTimezoneWithFallback();

        // Create Time Blocks (2 days, 2 blocks on each day, 15 minute gap between blocks, 4 hours total each.
        DateTime start = new DateTime(2010, 3, 16, 0, 0, 0, 0, TKUtils.getSystemDateTimeZone());
        CalendarEntry payCalendarEntry =  HrServiceLocator.getCalendarEntryService().getCurrentCalendarDates(principalId, start);

        TimesheetDocument td = TkTestUtils.populateBlankTimesheetDocument(start, principalId);

        List<TimeBlock> blocks = new ArrayList<TimeBlock>();

        //rgh - monday 8a-11a no-shift
        DateTime tbStart1 = new DateTime(2010, 3, 21, 8, 0, 0, 0, zone);
        blocks.addAll(TkTestUtils.createUniformTimeBlocks(tbStart1,   1, new BigDecimal("3"), "RGH", jobNumber, workArea, task, groupKey, td.getDocumentId()));

        //echr - monday 2p-5p - should have 3 hrs SHEG
        //DateTime tbStart2 = new DateTime(2010, 3, 30, 14, 0, 0, 0, zone);
        //blocks.addAll(TkTestUtils.createUniformTimeBlocks(tbStart2,   1, new BigDecimal("3"), "ECHR", jobNumber, workArea, task, groupKey, td.getDocumentId()));

        TkTimeBlockAggregate aggregate = new TkTimeBlockAggregate(blocks, payCalendarEntry);

        // Verify pre-Rule Run
        TkTestUtils.verifyAggregateHourSums(principalId, "Pre-Check", new ImmutableMap.Builder<String, BigDecimal>()
                .put("RGH", BigDecimal.valueOf(3)).build(), aggregate, 1);

        // Run Rule

        //td.setTimeBlocks(blocks);
        List<LeaveBlock> leaveBlocks = TimesheetUtils.getLeaveBlocksForTimesheet(td);
        List<TimeBlock> initialBlocks = TimesheetUtils.getTimesheetTimeblocksForProcessing(td, true);
        List<TimeBlock> referenceTimeBlocks = TimesheetUtils.getReferenceTimeBlocks(initialBlocks);

        //reset time block
        //List<TimeBlock> tbs = TkServiceLocator.getTimesheetService().resetTimeBlock(initialBlocks, td.getAsOfDate());
        TimesheetUtils.processTimeBlocksWithRuleChange(blocks, referenceTimeBlocks, leaveBlocks, td.getCalendarEntry(), td, HrContext.getPrincipalId());

        //refresh Timesheet
        td = TkServiceLocator.getTimesheetService().getTimesheetDocument(td.getDocumentId());
        aggregate = new TkTimeBlockAggregate(td.getTimeBlocks(), payCalendarEntry);
        // Verify post-Rule Run
        TkTestUtils.verifyAggregateHourSums(principalId, "Post Rules Check", new ImmutableMap.Builder<String, BigDecimal>()
                        .put("RGH", BigDecimal.valueOf(3))
                        .put("SHCG", BigDecimal.valueOf(3))
                        .put("SHDY", BigDecimal.valueOf(0)).build(),
                aggregate,
                1);
    }

    @Test
    public void daysTest() {
        // Create the Rule
        // Matches HR Job ID #1 (job # 30)
        String principalId = "10114";

        Long jobNumber = 0L;
        String groupKey = "IU-IN";
        Long workArea = 1010L;
        Long task = 0L;
        DateTimeZone zone = HrServiceLocator.getTimezoneService().getTargetUserTimezoneWithFallback();

        // Create Time Blocks (2 days, 2 blocks on each day, 15 minute gap between blocks, 4 hours total each.
        DateTime start = new DateTime(2010, 3, 21, 0, 0, 0, 0, TKUtils.getSystemDateTimeZone());
        CalendarEntry payCalendarEntry =  HrServiceLocator.getCalendarEntryService().getCurrentCalendarDates("admin", start);

        TimesheetDocument td = TkTestUtils.populateBlankTimesheetDocument(start, principalId);

        List<TimeBlock> blocks = new ArrayList<TimeBlock>();

        //rgh - sunday 3p-5p shift: 2 hr SHDY
        DateTime tbStart1 = new DateTime(2010, 3, 28, 15, 0, 0, 0, zone);
        blocks.addAll(TkTestUtils.createUniformTimeBlocks(tbStart1,   1, new BigDecimal("2"), "RGH", jobNumber, workArea, task, groupKey, td.getDocumentId()));

        //rgh - monday 3p-5p - shift: none
        DateTime tbStart2 = new DateTime(2010, 3, 29, 15, 0, 0, 0, zone);
        blocks.addAll(TkTestUtils.createUniformTimeBlocks(tbStart2,   1, new BigDecimal("2"), "RGH", jobNumber, workArea, task, groupKey, td.getDocumentId()));

        //rgh - sun 10p- mon 3a - shift: 2hr SHDY (on sunday timeblock)
        DateTime tbStart3 = new DateTime(2010, 3, 28, 22, 0, 0, 0, zone);
        blocks.addAll(TkTestUtils.createUniformTimeBlocks(tbStart3,   1, new BigDecimal("2"), "RGH", jobNumber, workArea, task, groupKey, td.getDocumentId()));
        DateTime tbStart4 = new DateTime(2010, 3, 29, 0, 0, 0, 0, zone);
        blocks.addAll(TkTestUtils.createUniformTimeBlocks(tbStart4,   1, new BigDecimal("3"), "RGH", jobNumber, workArea, task, groupKey, td.getDocumentId()));

        TkTimeBlockAggregate aggregate = new TkTimeBlockAggregate(blocks, payCalendarEntry);

        // Verify pre-Rule Run
        TkTestUtils.verifyAggregateHourSums(principalId, "Pre-Check", new ImmutableMap.Builder<String, BigDecimal>()
                .put("RGH", BigDecimal.valueOf(9)).build(), aggregate, 2);

        // Run Rule

        //td.setTimeBlocks(blocks);
        List<LeaveBlock> leaveBlocks = TimesheetUtils.getLeaveBlocksForTimesheet(td);
        List<TimeBlock> initialBlocks = TimesheetUtils.getTimesheetTimeblocksForProcessing(td, true);
        List<TimeBlock> referenceTimeBlocks = TimesheetUtils.getReferenceTimeBlocks(initialBlocks);

        //reset time block
        //List<TimeBlock> tbs = TkServiceLocator.getTimesheetService().resetTimeBlock(initialBlocks, td.getAsOfDate());
        TimesheetUtils.processTimeBlocksWithRuleChange(blocks, referenceTimeBlocks, leaveBlocks, td.getCalendarEntry(), td, HrContext.getPrincipalId());

        //refresh Timesheet
        td = TkServiceLocator.getTimesheetService().getTimesheetDocument(td.getDocumentId());
        aggregate = new TkTimeBlockAggregate(td.getTimeBlocks(), payCalendarEntry);
        // Verify post-Rule Run
        TkTestUtils.verifyAggregateHourSums(principalId, "Post Rules Check", new ImmutableMap.Builder<String, BigDecimal>()
                        .put("RGH", BigDecimal.valueOf(9))
                        .put("SHDY", BigDecimal.valueOf(4)).build(),
                aggregate,
                2);
    }

    @Test
    public void daysTestTimeZone() {
        // Create the Rule
        // Matches HR Job ID #1 (job # 30)
        String principalId = "10115";

        Long jobNumber = 0L;
        String groupKey = "IU-IN";
        Long workArea = 1010L;
        Long task = 0L;
        HrContext.setTargetPrincipalId(principalId);
        DateTimeZone zone = HrServiceLocator.getTimezoneService().getTargetUserTimezoneWithFallback();

        // Create Time Blocks (2 days, 2 blocks on each day, 15 minute gap between blocks, 4 hours total each.
        DateTime start = new DateTime(2010, 3, 21, 0, 0, 0, 0, TKUtils.getSystemDateTimeZone());
        CalendarEntry payCalendarEntry =  HrServiceLocator.getCalendarEntryService().getCurrentCalendarDates("admin", start);

        TimesheetDocument td = TkTestUtils.populateBlankTimesheetDocument(start, principalId);

        List<TimeBlock> blocks = new ArrayList<TimeBlock>();

        //rgh - sunday 3p-5p shift: 2 hr SHDY
        DateTime tbStart1 = new DateTime(2010, 3, 28, 15, 0, 0, 0, zone);
        blocks.addAll(TkTestUtils.createUniformTimeBlocks(tbStart1,   1, new BigDecimal("2"), "RGH", jobNumber, workArea, task, groupKey, td.getDocumentId()));

        //rgh - monday 3p-5p - shift: none
        DateTime tbStart2 = new DateTime(2010, 3, 29, 15, 0, 0, 0, zone);
        blocks.addAll(TkTestUtils.createUniformTimeBlocks(tbStart2,   1, new BigDecimal("2"), "RGH", jobNumber, workArea, task, groupKey, td.getDocumentId()));

        //rgh - sun 10p- mon 3a - shift: 2hr SHDY2 (on sunday timeblock)
        DateTime tbStart3 = new DateTime(2010, 3, 28, 22, 0, 0, 0, zone);
        blocks.addAll(TkTestUtils.createUniformTimeBlocks(tbStart3,   1, new BigDecimal("2"), "RGH", jobNumber, workArea, task, groupKey, td.getDocumentId()));
        DateTime tbStart4 = new DateTime(2010, 3, 29, 0, 0, 0, 0, zone);
        blocks.addAll(TkTestUtils.createUniformTimeBlocks(tbStart4,   1, new BigDecimal("3"), "RGH", jobNumber, workArea, task, groupKey, td.getDocumentId()));

        TkTimeBlockAggregate aggregate = new TkTimeBlockAggregate(blocks, payCalendarEntry);

        // Verify pre-Rule Run
        TkTestUtils.verifyAggregateHourSums(principalId, "Pre-Check", new ImmutableMap.Builder<String, BigDecimal>()
                .put("RGH", BigDecimal.valueOf(9)).build(), aggregate, 2);

        // Run Rule

        //td.setTimeBlocks(blocks);
        List<LeaveBlock> leaveBlocks = TimesheetUtils.getLeaveBlocksForTimesheet(td);
        List<TimeBlock> initialBlocks = TimesheetUtils.getTimesheetTimeblocksForProcessing(td, true);
        List<TimeBlock> referenceTimeBlocks = TimesheetUtils.getReferenceTimeBlocks(initialBlocks);

        //reset time block
        //List<TimeBlock> tbs = TkServiceLocator.getTimesheetService().resetTimeBlock(initialBlocks, td.getAsOfDate());
        TimesheetUtils.processTimeBlocksWithRuleChange(blocks, referenceTimeBlocks, leaveBlocks, td.getCalendarEntry(), td, HrContext.getPrincipalId());

        //refresh Timesheet
        td = TkServiceLocator.getTimesheetService().getTimesheetDocument(td.getDocumentId());
        aggregate = new TkTimeBlockAggregate(td.getTimeBlocks(), payCalendarEntry);
        // Verify post-Rule Run
        TkTestUtils.verifyAggregateHourSums(principalId, "Post Rules Check", new ImmutableMap.Builder<String, BigDecimal>()
                        .put("RGH", BigDecimal.valueOf(9))
                        .put("SHDY2", BigDecimal.valueOf(4)).build(),
                aggregate,
                2);
        HrContext.clearTargetUser();
    }
}


text:
<?php namespace Drivers\Database;

use Drivers\Database\MySQL\MySQL;

trait DbImplement {

	/**
	 *@var string The database type
	 *@readwrite
	 */
	protected $type;

	/**
	 *@var array Database type connection parameters
	 *@readwrite
	 */
	protected $options;

	/**
	 *This method initializes a database connection
	 *
	 *@param null
	 *@return object Instance of this database connection
	 *@throws DbException  If the database type provided is not defined for this system
	 */
	public function initialize()
	{
		//throw exception if no database type has been set
		if( ! $this->type )
		{
			//Throw exception
			throw new DbException("Invalid database type provided");

		}

		//check the type of  database provided returning instance
		//set the parameter to check in switch clause
		switch ($this->type )
		{
			case 'mysql':

				return new MySQL($this->options);

				break;

			default:

				throw new DbException("Valid database type provided");

				break;
		}

	}
}

redpajama_set_name: RedPajamaGithub


text:
#ifndef _BEAM_BP_H
#define _BEAM_BP_H

#include "sys.h"
#include "erl_vm.h"
#include "global.h"

typedef struct {
    Eterm pid;
    Sint  count;
    ErtsMonotonicTime time;
} bp_data_time_item_t;

typedef struct {
    Uint n;
    Uint used;
    bp_data_time_item_t *item;
} bp_time_hash_t;

typedef struct bp_data_time {     /* Call time */
    Uint n;
    bp_time_hash_t *hash;
    erts_refc_t refc;
} BpDataTime;

typedef struct {
    ErtsMonotonicTime time;
    ErtsCodeInfo *ci;
} process_breakpoint_time_t; /* used within psd */

typedef struct {
    erts_atomic_t acount;
    erts_refc_t refc;
} BpCount;

typedef struct {
    erts_atomic_t tracer;
    erts_refc_t refc;
} BpMetaTracer;

typedef struct generic_bp_data {
    Uint flags;
    Binary* local_ms;		/* Match spec for local call trace */
    Binary* meta_ms;		/* Match spec for meta trace */
    BpMetaTracer* meta_tracer;	/* Meta tracer */
    BpCount* count;		/* For call count */
    BpDataTime* time;		/* For time trace */
} GenericBpData;

#define ERTS_NUM_BP_IX 2

typedef struct generic_bp {
    BeamInstr orig_instr;
    GenericBpData data[ERTS_NUM_BP_IX];
} GenericBp;

#define ERTS_BP_CALL_TIME_SCHEDULE_IN      (0)
#define ERTS_BP_CALL_TIME_SCHEDULE_OUT     (1)
#define ERTS_BP_CALL_TIME_SCHEDULE_EXITING (2)

extern erts_mtx_t erts_dirty_bp_ix_mtx;

enum erts_break_op{
    ERTS_BREAK_NOP   =  0, /* Must be false */
    ERTS_BREAK_SET   = !0, /* Must be true */
    ERTS_BREAK_RESTART,
    ERTS_BREAK_PAUSE
};

typedef Uint32 ErtsBpIndex;

typedef struct {
    ErtsCodeInfo *ci;
    Module* mod;
} BpFunction;

typedef struct {
    Uint matched;		/* Number matched */
    BpFunction* matching;	/* Matching functions */
} BpFunctions;

/*
** Function interface exported from beam_bp.c
*/

void erts_bp_init(void);

void erts_prepare_bp_staging(void);
void erts_commit_staged_bp(void);

ERTS_GLB_INLINE ErtsBpIndex erts_active_bp_ix(void);
ERTS_GLB_INLINE ErtsBpIndex erts_staging_bp_ix(void);

void erts_bp_match_functions(BpFunctions* f, ErtsCodeMFA *mfa, int specified);
void erts_bp_match_export(BpFunctions* f, ErtsCodeMFA *mfa, int specified);
void erts_bp_free_matched_functions(BpFunctions* f);

void erts_install_breakpoints(BpFunctions* f);
void erts_uninstall_breakpoints(BpFunctions* f);
void erts_consolidate_bp_data(BpFunctions* f, int local);
void erts_consolidate_bif_bp_data(void);

void erts_set_trace_break(BpFunctions *f, Binary *match_spec);
void erts_clear_trace_break(BpFunctions *f);

void erts_set_call_trace_bif(ErtsCodeInfo *ci, Binary *match_spec, int local);
void erts_clear_call_trace_bif(ErtsCodeInfo *ci, int local);

void erts_set_mtrace_break(BpFunctions *f, Binary *match_spec,
			  ErtsTracer tracer);
void erts_clear_mtrace_break(BpFunctions *f);
void erts_set_mtrace_bif(ErtsCodeInfo *ci, Binary *match_spec,
			 ErtsTracer tracer);
void erts_clear_mtrace_bif(ErtsCodeInfo *ci);

void erts_set_debug_break(BpFunctions *f);
void erts_clear_debug_break(BpFunctions *f);
void erts_set_count_break(BpFunctions *f, enum erts_break_op);
void erts_clear_count_break(BpFunctions *f);

void erts_clear_all_breaks(BpFunctions* f);
int erts_clear_module_break(Module *modp);
void erts_clear_export_break(Module *modp, ErtsCodeInfo* ci);

BeamInstr erts_generic_breakpoint(Process* c_p, ErtsCodeInfo *ci, Eterm* reg);
BeamInstr erts_trace_break(Process *p, ErtsCodeInfo *ci, Eterm *args,
                           Uint32 *ret_flags, ErtsTracer *tracer);

int erts_is_trace_break(ErtsCodeInfo *ci, Binary **match_spec_ret, int local);
int erts_is_mtrace_break(ErtsCodeInfo *ci, Binary **match_spec_ret,
			 ErtsTracer *tracer_ret);
int erts_is_mtrace_bif(ErtsCodeInfo *ci, Binary **match_spec_ret,
		       ErtsTracer *tracer_ret);
int erts_is_native_break(ErtsCodeInfo *ci);
int erts_is_count_break(ErtsCodeInfo *ci, Uint *count_ret);
int erts_is_time_break(Process *p, ErtsCodeInfo *ci, Eterm *call_time);

void erts_trace_time_call(Process* c_p, ErtsCodeInfo *ci, BpDataTime* bdt);
void erts_trace_time_return(Process* c_p, ErtsCodeInfo *ci);
void erts_schedule_time_break(Process *p, Uint out);
void erts_set_time_break(BpFunctions *f, enum erts_break_op);
void erts_clear_time_break(BpFunctions *f);

int erts_is_time_trace_bif(Process *p, ErtsCodeInfo *ci, Eterm *call_time);
void erts_set_time_trace_bif(ErtsCodeInfo *ci, enum erts_break_op);
void erts_clear_time_trace_bif(ErtsCodeInfo *ci);

ErtsCodeInfo *erts_find_local_func(ErtsCodeMFA *mfa);

#if ERTS_GLB_INLINE_INCL_FUNC_DEF

extern erts_atomic32_t erts_active_bp_index;
extern erts_atomic32_t erts_staging_bp_index;

ERTS_GLB_INLINE ErtsBpIndex erts_active_bp_ix(void)
{
    return erts_atomic32_read_nob(&erts_active_bp_index);
}

ERTS_GLB_INLINE ErtsBpIndex erts_staging_bp_ix(void)
{
    return erts_atomic32_read_nob(&erts_staging_bp_index);
}
#endif

#endif /* _BEAM_BP_H */


text:
/* GRID
 *
 * starts from bottom left
 * centered at the center of objects
 *
 */

#import "KCFallScene.h"
#import "KCMenuScene.h"

int BETWEENOBSTACLES = 300;
static const uint32_t playerCategory = 0x1 << 0;
static const uint32_t otherCategory = 0x1 << 1;

@interface KCFallScene()

@property(nonatomic)SKSpriteNode *player, *popup;
@property(nonatomic)NSMutableArray *fallingObjects;
@property(nonatomic)SKLabelNode *scoreNode, *finalScoreNode, *messageNode;
@property(nonatomic)bool running;

-(void)createNode:(NSString *)node;
-(void)setPlayerPosition:(UIEvent *)event;

@end

@implementation KCFallScene{
	float lastObstacleAdditionTimeInterval,lastUpdateTimeInterval;
	int score,c;
	bool popupActionDone, notTappedYet, changing;
}

#pragma mark init

-(id)initWithSize:(CGSize)size{

	if (self = [super initWithSize:size]){

		[self setBackgroundColor:[SKColor colorWithRed:(161/255.0) green:(202/255.0) blue:(241/255.0) alpha:1.0]];
		self.physicsWorld.gravity = CGVectorMake(0.0, -2.5);
		self.physicsWorld.contactDelegate = self;
		self.fallingObjects = [NSMutableArray array];
		score = c = 0;
		notTappedYet = changing = true;
		popupActionDone = false;

		lastObstacleAdditionTimeInterval = 0.0;
		lastUpdateTimeInterval = 0.0;
		self.running = false;

		[self createNode:@"player"];
		[self createNode:@"score"];
		[self createNode:@"tapToContinue"];

	}

	return self;

}

-(void)createNode:(NSString *)node{

	if ([node isEqualToString:@"player"]){

		self.player = [[SKSpriteNode alloc]init];
		[self.player setSize:CGSizeMake(50, 25)];
		[self.player setPosition:CGPointMake(self.frame.size.width/2.0,self.frame.size.height/4.0)];
		[self.player setColor:[SKColor blackColor]];
		[self.player setPhysicsBody:[SKPhysicsBody bodyWithRectangleOfSize:self.player.size]];
		self.player.physicsBody.dynamic = false;
		[self addChild:self.player];
		self.player.physicsBody.categoryBitMask = playerCategory;
		self.player.physicsBody.collisionBitMask = otherCategory;
		self.player.physicsBody.contactTestBitMask = otherCategory;
		self.player.physicsBody.usesPreciseCollisionDetection = true;

	} else if ([node isEqualToString:@"score"]){

		score = 0;
		self.scoreNode = [SKLabelNode labelNodeWithFontNamed:@"Futura-Medium"];
		self.scoreNode.text = [NSString stringWithFormat:@"%d",score];
		self.scoreNode.fontSize = 28;
		self.scoreNode.fontColor = [SKColor whiteColor];
		self.scoreNode.position = CGPointMake(self.frame.size.width/2.0, self.frame.size.height - 60);
		[self addChild:self.scoreNode];

	} else if ([node isEqualToString:@"fallingObject"]){

        float x,y;

        SKSpriteNode *object = [SKSpriteNode spriteNodeWithImageNamed:@"circle"];
        [object setScale:0.5];

        y = self.frame.size.height + object.frame.size.height/2.0;

        if (![self.fallingObjects count]){
            x = floorf(((double)arc4random() / 0x100000000) * (self.frame.size.width - object.frame.size.width)) + object.frame.size.width/2.0;
        } else {

            float deviation = arc4random_uniform(50) + object.frame.size.width/2.0;

            if ([self.fallingObjects count]==1)
                x = [self.fallingObjects[0] position].x + (arc4random_uniform(2)==0 ? -1 : 1) * deviation;
            else {
                if ([self.fallingObjects[[self.fallingObjects count]-1] position].x < [self.fallingObjects[[self.fallingObjects count]-2] position].x)
                    x = [self.fallingObjects[[self.fallingObjects count]-1] position].x + (arc4random_uniform(7)==0 ? 1 : -1) * deviation;
                else
                    x = [self.fallingObjects[[self.fallingObjects count]-1] position].x + (arc4random_uniform(7)==0 ? -1 : 1) * deviation;
            }

            if (x - object.frame.size.width/2.0 <= 0){
                x = object.frame.size.width + [self.fallingObjects[[self.fallingObjects count]-1] position].x;
            } else if (x + object.frame.size.width/2.0 >= self.frame.size.width){
                x = [self.fallingObjects[[self.fallingObjects count]-1] position].x-object.frame.size.width;
            }

        }

        [object setPosition:CGPointMake(x, y)];
        [object setPhysicsBody:[SKPhysicsBody bodyWithCircleOfRadius:object.frame.size.width/2.0]];
        object.physicsBody.dynamic = true;
        [self addChild:object];
        [self.fallingObjects addObject:object];

	} else if ([node isEqualToString:@"fadeOut"]){

		SKSpriteNode *fadeOut = [[SKSpriteNode alloc]init];
		[fadeOut setSize:CGSizeMake(self.frame.size.width,self.frame.size.height)];
		[fadeOut setPosition:CGPointMake(self.frame.size.width/2.0,self.frame.size.height/2.0)];
		[fadeOut setColor:[SKColor blackColor]];
		[fadeOut setAlpha:0.0];
		[self addChild:fadeOut];

		[fadeOut runAction:[SKAction fadeAlphaTo:0.7 duration:0.5]];

	} else if ([node isEqualToString:@"popup"]){

		[self createNode:@"fadeOut"];
		self.running = false;

		for (SKSpriteNode *object in self.fallingObjects) [object.physicsBody setVelocity:CGVectorMake(0.0, 0.0)];
		self.physicsWorld.gravity = CGVectorMake(0.0, 0.0);

		// fade out score #
		[self.scoreNode runAction:[SKAction sequence:@[[SKAction fadeOutWithDuration:0.5],
													   [SKAction removeFromParent]]]];

        self.finalScoreNode = [SKLabelNode labelNodeWithFontNamed:@"Futura-Medium"];
		self.finalScoreNode.text = [NSString stringWithFormat:@"Score: %d",score];
		self.finalScoreNode.fontSize = 50;
		self.finalScoreNode.fontColor = [SKColor whiteColor];
		self.finalScoreNode.position = CGPointMake(self.frame.size.width/2.0, 3*self.frame.size.height/5.0);
        [self.finalScoreNode setScale:8.0];
        self.finalScoreNode.alpha = 0.0;

        [self addChild:self.messageNode];
        [self addChild:self.finalScoreNode];

        // set the action for each node
        SKAction *action = [SKAction sequence:@[[SKAction sequence:@[[SKAction waitForDuration:0.5],
                                                                     [SKAction group:@[[SKAction fadeInWithDuration:0.5],
                                                                                [SKAction scaleTo:1.0 duration:0.8]]]]],
                                                [SKAction runBlock:^(void){popupActionDone=true;}]]];

        [self.finalScoreNode runAction:action];

	} else if ([node isEqualToString:@"tapToContinue"]){

		// set properties/behaviour for 'tap to continue' before game
		self.messageNode = [SKLabelNode labelNodeWithFontNamed:@"Futura-Medium"];
		self.messageNode.text = [NSString stringWithFormat:@"Tap anywhere to start!"];
		self.messageNode.fontSize = 23;
		self.messageNode.fontColor = [SKColor whiteColor];
		self.messageNode.alpha = 0.0;
		self.messageNode.position = CGPointMake(self.frame.size.width/2.0, 3*self.frame.size.height/4.0 - self.messageNode.frame.size.height/2.0);
		[self addChild:self.messageNode];

		[self.messageNode runAction:[SKAction fadeAlphaTo:1.0 duration:0.5]];

	}

}

#pragma mark touches

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{

	if (self.running)
        [self setPlayerPosition:event];

	else if (notTappedYet) {

		self.running = true;
		notTappedYet = false;
		[self.messageNode runAction:[SKAction sequence:@[[SKAction fadeAlphaTo:0.0 duration:0.5],
														 [SKAction removeFromParent]]]];

		[self setPlayerPosition:event];

	} else if (popupActionDone)
        [self switchToMenuScene];

}

-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{

	if (self.running) [self setPlayerPosition:event];

}

-(void)setPlayerPosition:(UIEvent *)event{

	CGFloat xLocation = [[[event allTouches]anyObject] locationInView:self.view].x;
	[self.player setPosition:CGPointMake(xLocation,self.player.position.y)];

}

#pragma mark update

-(void)update:(NSTimeInterval)currentTime{

	if (self.running && [self.fallingObjects count]!=0){
		SKSpriteNode *object = self.fallingObjects[0];
		if (object.position.y + object.frame.size.height < self.player.position.y) [self createNode:@"popup"];
	}

	CFTimeInterval timeSinceLast = currentTime - lastUpdateTimeInterval;
	lastUpdateTimeInterval = currentTime;
	if (timeSinceLast > BETWEENOBSTACLES/1000.0) {
		timeSinceLast = 1.0 / 60.0;
		lastUpdateTimeInterval = currentTime;
	} [self updateWithTimeSinceLastUpdate:timeSinceLast];

}

- (void)updateWithTimeSinceLastUpdate:(CFTimeInterval)timeSinceLast {

	if (self.running){
		lastObstacleAdditionTimeInterval += timeSinceLast;
		if (lastObstacleAdditionTimeInterval > BETWEENOBSTACLES/1000.0) {
            if (changing){
                c+=1;
                // every 15 balls, decrease interval, increase gravity
                if (c%15==0){
                    BETWEENOBSTACLES -= 15;
                    [self.physicsWorld setGravity:CGVectorMake(0.0, self.physicsWorld.gravity.dy-0.5)];
                    c=0;
                }
                if (BETWEENOBSTACLES <= 100.0) changing=false;
            }

			lastObstacleAdditionTimeInterval = 0;
			[self createNode:@"fallingObject"];
		}
	}

}

#pragma mark -

- (void)didBeginContact:(SKPhysicsContact *)contact{

	SKPhysicsBody *firstBody = contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask ? contact.bodyA : contact.bodyB;
	if (firstBody.categoryBitMask != 0) {
		[self.fallingObjects[0] removeFromParent];
		[self.fallingObjects removeObject:self.fallingObjects[0]];
		self.scoreNode.text = [NSString stringWithFormat:@"%d",++score];
	}

}

// switch back to the menu
-(void)switchToMenuScene{

	SKTransition *reveal = [SKTransition fadeWithDuration:1.2];

	KCMenuScene *gameScene = [[KCMenuScene alloc]initWithSize:self.size];
	[self.scene.view presentScene:gameScene transition:reveal];

}

@end


text:
PACKAGE="$1"
if [ -z "${PACKAGE}" ]; then
  echo "ERROR: No package specified."
  exit 1
fi

LOG_DIR="/tmp/meteor-test-runner"
# CirleCI.
if [ -n "${CIRCLE_ARTIFACTS}" ]; then
  LOG_DIR="${CIRCLE_ARTIFACTS}"
fi
LOG_DIR="${LOG_DIR}/${PACKAGE}"
rm -rf ${LOG_DIR}
mkdir -p ${LOG_DIR}

SCRIPT_DIR="$(dirname "${BASH_SOURCE[0]}")"

run_meteor()
{
  # Keep a copy of Meteor output in a log file.
  ~/.meteor/meteor test-packages --once --driver-package 'test-in-console' -p 4096 ${PACKAGE} | tee ${LOG_DIR}/meteor.log
}

while true; do
  # Spawn the test process.
  echo "  > Spawning test process..."
  # Redirect standard output to file descriptor #3 so we can wait for Meteor to get ready.
  { exec 3< <(run_meteor) ; } 2>/dev/null
  # Wait until Meteor reports that it is 'listening'.
  echo "  > Waiting for Meteor to start..."
  METEOR_STARTED=0
  while read line; do
     case "$line" in
     *listening*)
        echo "  > Meteor seems ready, going to run tests in a moment."
        METEOR_STARTED=1
        sleep 5
        break
        ;;
     *)
        ;;
     esac
  done <&3

  if [ "${METEOR_STARTED}" == "1" ]; then
    break
  fi

  echo "  ? Failed to start Meteor, retrying."
  exec 3<&-
  killall node 2>/dev/null
  wait 2>/dev/null
done

# Drain file descriptor in the background. Otherwise the buffer may fill up and block I/O.
{ while read line; do true; done <&3; } &

# Run the test.
echo "  > Running the test runner..."
node ${SCRIPT_DIR}/runner.js
RESULT=$?

# Close the file descriptor.
exec 3<&-
killall node 2>/dev/null
wait 2>/dev/null
exit $RESULT


text:
package rst.pdfbox.layout.text.annotations;

import java.io.IOException;

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;

import rst.pdfbox.layout.elements.render.RenderContext;
import rst.pdfbox.layout.elements.render.RenderListener;
import rst.pdfbox.layout.text.Alignment;
import rst.pdfbox.layout.text.DrawContext;
import rst.pdfbox.layout.text.DrawListener;
import rst.pdfbox.layout.text.DrawableText;
import rst.pdfbox.layout.text.Position;

/**
 * This listener has to be passed to all
 * {@link DrawableText#drawText(org.apache.pdfbox.pdmodel.edit.PDPageContentStream, Position, Alignment, DrawListener)
 * draw()} methods, in order collect all annotation metadata. After all drawing
 * is done, you have to call {@link #finalizeAnnotations()} which creates all
 * necessary annotations and sets them to the corresponding pages. This listener
 * is used by the the rendering API, but you may also use it with the low-level
 * text API.
 */
public class AnnotationDrawListener implements DrawListener, RenderListener {

    private final DrawContext drawContext;
    private final Iterable<AnnotationProcessor> annotationProcessors;

    /**
     * Creates an AnnotationDrawListener with the given {@link DrawContext}.
     *
     * @param drawContext
     *            the context which provides the {@link PDDocument} and the
     *            {@link PDPage} currently drawn to.
     */
    public AnnotationDrawListener(final DrawContext drawContext) {
	this.drawContext = drawContext;
	annotationProcessors = AnnotationProcessorFactory
		.createAnnotationProcessors();
    }

    @Override
    public void drawn(Object drawnObject, Position upperLeft, float width,
	    float height) {
	if (!(drawnObject instanceof Annotated)) {
	    return;
	}
	for (AnnotationProcessor annotationProcessor : annotationProcessors) {
	    try {
		annotationProcessor.annotatedObjectDrawn(
			(Annotated) drawnObject, drawContext, upperLeft, width,
			height);
	    } catch (IOException e) {
		throw new RuntimeException(
			"exception on annotation processing", e);
	    }
	}
    }

    /**
     * @deprecated user {@link #afterRender()} instead.
     * @throws IOException by pdfbox.
     */
    @Deprecated
    public void finalizeAnnotations() throws IOException {
	afterRender();
    }

    @Override
    public void beforePage(RenderContext renderContext) throws IOException {
	for (AnnotationProcessor annotationProcessor : annotationProcessors) {
	    try {
		annotationProcessor.beforePage(drawContext);
	    } catch (IOException e) {
		throw new RuntimeException(
			"exception on annotation processing", e);
	    }
	}
    }

    @Override
    public void afterPage(RenderContext renderContext) throws IOException {
	for (AnnotationProcessor annotationProcessor : annotationProcessors) {
	    try {
		annotationProcessor.afterPage(drawContext);
	    } catch (IOException e) {
		throw new RuntimeException(
			"exception on annotation processing", e);
	    }
	}
    }

    public void afterRender() throws IOException {
	for (AnnotationProcessor annotationProcessor : annotationProcessors) {
	    try {
		annotationProcessor.afterRender(drawContext.getPdDocument());
	    } catch (IOException e) {
		throw new RuntimeException(
			"exception on annotation processing", e);
	    }
	}
    }

}


text:
package uk.ac.ic.wlgitbridge.data.model;

import org.jmock.Expectations;
import org.jmock.Mockery;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.mockserver.client.server.MockServerClient;
import org.mockserver.junit.MockServerRule;
import uk.ac.ic.wlgitbridge.bridge.db.DBStore;
import uk.ac.ic.wlgitbridge.bridge.repo.FSGitRepoStore;
import uk.ac.ic.wlgitbridge.bridge.repo.ProjectRepo;
import uk.ac.ic.wlgitbridge.bridge.repo.RepoStore;
import uk.ac.ic.wlgitbridge.bridge.resource.ResourceCache;
import uk.ac.ic.wlgitbridge.bridge.resource.UrlResourceCache;
import uk.ac.ic.wlgitbridge.data.filestore.RawFile;
import uk.ac.ic.wlgitbridge.git.exception.GitUserException;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

import static org.junit.Assert.assertEquals;
import static org.mockserver.model.HttpRequest.request;
import static org.mockserver.model.HttpResponse.response;

/**
 * Created by m on 20/11/15.
 */
public class ResourceFetcherTest {
    @Rule
    public MockServerRule mockServerRule = new MockServerRule(this);

    private MockServerClient mockServerClient;

    @Test
    public void fetchesFilesThatAreMissingFromUrlStoreCache() throws IOException, GitUserException {
        final String testProjectName = "123abc";
        final String testUrl = "http://localhost:" + mockServerRule.getPort() + "/123abc";
        final String oldTestPath = "testPath";
        final String newTestPath = "missingPath";

        mockServerClient.when(
            request()
            .withMethod("GET")
            .withPath("/123abc")
        )
        .respond(
            response()
            .withStatusCode(200)
            .withBody("content")
        );

        final Mockery context = new Mockery();
        final DBStore dbStore = context.mock(DBStore.class);
        context.checking(new Expectations() {{
            // It should fetch the file once it finds it is missing.
            oneOf(dbStore).getPathForURLInProject(testProjectName, testUrl);
            will(returnValue(oldTestPath));

            // It should update the URL index store once it has fetched; at present, it does not actually change the stored path.
            oneOf(dbStore).addURLIndexForProject(testProjectName, testUrl, oldTestPath);
        }});

        ResourceCache resources = new UrlResourceCache(dbStore);
        TemporaryFolder repositoryFolder = new TemporaryFolder();
        repositoryFolder.create();
        String repoStorePath = repositoryFolder.getRoot().getAbsolutePath();
        RepoStore repoStore = new FSGitRepoStore(repoStorePath, Optional.empty());
        ProjectRepo repo = repoStore.initRepo("repo");
        Map<String, RawFile> fileTable = repo.getDirectory().getFileTable();
        Map<String, byte[]> fetchedUrls = new HashMap<>();
        resources.get(
                testProjectName, testUrl, newTestPath,
                fileTable, fetchedUrls, Optional.empty());

        // We don't bother caching in this case, at present.
        assertEquals(0, fetchedUrls.size());
    }
}