Packager { public Container pack(List<BoxItem> boxes) { return pack(boxes, Long.MAX_VALUE); } Packager(List<Container> containers);  Packager(List<Container> containers, boolean rotate3D, boolean binarySearch, int checkpointsPerDeadlineCheck); Container pack(List<BoxItem> boxes); Container pack(List<BoxItem> boxes, long deadline); Container pack(List<BoxItem> boxes, BooleanSupplier interrupt); Container pack(List<BoxItem> boxes, long deadline, BooleanSupplier interrupt); Container pack(List<BoxItem> boxes, List<Container> containers, long deadline); Container pack(List<BoxItem> boxes, List<Container> containers, long deadline, BooleanSupplier interrupt); Container pack(List<BoxItem> boxes, List<Container> containers, BooleanSupplier interrupt); List<Container> packList(List<BoxItem> boxes, int limit, long deadline); List<Container> packList(List<BoxItem> boxes, int limit, long deadline, BooleanSupplier interrupt); List<Container> packList(List<BoxItem> boxes, int limit, BooleanSupplier interrupt);  }
@Test void testBinarySearchChecksBoxesBelowPositive() { long deadline = System.currentTimeMillis() + 100000; List<Container> containers = new ArrayList<>(); containers.add(new ValidatingContainer("0", 5, 5, 1, 0)); containers.add(new ValidatingContainer("1", 5, 5, 1, 0)); containers.add(new ValidatingContainer("2", 5, 5, 1, 0)); containers.add(new ValidatingContainer("3", 5, 5, 1, 0)); containers.add(new ValidatingContainer("4", 5, 5, 1, 0)); containers.add(new ValidatingContainer("5", 5, 5, 1, 0)); containers.add(new ValidatingContainer("6", 5, 5, 1, 0)); List<BoxItem> products = new ArrayList<>(); products.add(new BoxItem(new Box("1", 5, 5, 1, 0), 1)); Adapter mock = mock(Adapter.class); when(mock.attempt(eq(3))) .thenReturn(completeResult); when(mock.attempt(eq(1))) .thenReturn(incompleteResult); when(mock.attempt(eq(2))) .thenReturn(incompleteResult); when(mock.attempt(eq(0))) .thenReturn(incompleteResult); when(mock.accepted(any(PackResult.class))) .thenReturn(new ValidatingContainer("result", 5, 5, 1, 0)); when(mock.hasMore(any(PackResult.class))).thenReturn(false, true, true, true); MyPackager myPackager = new MyPackager(containers, mock); Container pack = myPackager.pack(products, deadline); assertEquals("result", pack.getName()); assertNotNull(pack); verify(mock, times(4)).attempt(any(int.class)); }
@Test void testBinarySearchChecksBoxesBelowPositiveBetterMatch() { List<Container> containers = new ArrayList<>(); containers.add(new ValidatingContainer("0", 5, 5, 1, 0)); containers.add(new ValidatingContainer("1", 5, 5, 1, 0)); containers.add(new ValidatingContainer("2", 5, 5, 1, 0)); containers.add(new ValidatingContainer("3", 5, 5, 1, 0)); containers.add(new ValidatingContainer("4", 5, 5, 1, 0)); containers.add(new ValidatingContainer("5", 5, 5, 1, 0)); containers.add(new ValidatingContainer("6", 5, 5, 1, 0)); long deadline = System.currentTimeMillis() + 100000; List<BoxItem> products = new ArrayList<>(); products.add(new BoxItem(new Box("1", 5, 5, 1, 0), 1)); Adapter mock = mock(Adapter.class); when(mock.accepted(completeResult)) .thenReturn(new ValidatingContainer("final", 5, 5, 1, 0)); when(mock.attempt(eq(3))).thenReturn(completeResult); when(mock.attempt(eq(1))).thenReturn(incompleteResult); when(mock.attempt(eq(2))).thenReturn(incompleteResult); when(mock.attempt(eq(0))).thenReturn(completeResult); when(mock.hasMore(any(PackResult.class))).thenReturn(false, true, true, false); MyPackager myPackager = new MyPackager(containers, mock); Container pack = myPackager.pack(products, deadline); assertNotNull(pack); assertEquals("final", pack.getName()); verify(mock, times(1)).attempt(eq(3)); verify(mock, times(1)).attempt(eq(2)); verify(mock, times(1)).attempt(eq(1)); verify(mock, times(1)).attempt(eq(0)); }
@Test void testBinarySearchChecksBoxesTheFirstBox() { List<Container> containers = new ArrayList<>(); containers.add(new ValidatingContainer("0", 5, 5, 1, 0)); containers.add(new ValidatingContainer("1", 5, 5, 1, 0)); containers.add(new ValidatingContainer("2", 5, 5, 1, 0)); containers.add(new ValidatingContainer("3", 5, 5, 1, 0)); containers.add(new ValidatingContainer("4", 5, 5, 1, 0)); containers.add(new ValidatingContainer("5", 5, 5, 1, 0)); containers.add(new ValidatingContainer("6", 5, 5, 1, 0)); List<BoxItem> products = new ArrayList<>(); products.add(new BoxItem(new Box("1", 5, 5, 1, 0), 1)); Adapter mock = mock(Adapter.class); when(mock.hasMore(any(PackResult.class))).thenReturn(false); long deadline = System.currentTimeMillis() + 100000; PackResult ok = mock(PackResult.class); when(mock.attempt(eq(3))).thenReturn(ok); PackResult better = mock(PackResult.class); when(mock.attempt(eq(1))).thenReturn(better); PackResult best = mock(PackResult.class); when(mock.attempt(eq(0))).thenReturn(best); when(mock.accepted(any(PackResult.class))) .thenReturn(new ValidatingContainer("final", 5, 5, 1, 0)); when(mock.hasMore(any(PackResult.class))).thenReturn(false, false, false); MyPackager myPackager = new MyPackager(containers, mock); Container pack = myPackager.pack(products, deadline); assertNotNull(pack); assertEquals("final", pack.getName()); verify(mock, times(3)).attempt(any(Integer.class)); verify(mock, times(1)).attempt(eq(3)); verify(mock, times(1)).attempt(eq(1)); verify(mock, times(1)).attempt(eq(0)); }
@Test void testBinarySearchChecksBoxesTheLastBox() { long deadline = System.currentTimeMillis() + 100000; List<Container> containers = new ArrayList<>(); containers.add(new ValidatingContainer("0", 5, 5, 1, 0)); containers.add(new ValidatingContainer("1", 5, 5, 1, 0)); containers.add(new ValidatingContainer("2", 5, 5, 1, 0)); containers.add(new ValidatingContainer("3", 5, 5, 1, 0)); containers.add(new ValidatingContainer("4", 5, 5, 1, 0)); containers.add(new ValidatingContainer("5", 5, 5, 1, 0)); containers.add(new ValidatingContainer("6", 5, 5, 1, 0)); List<BoxItem> products = new ArrayList<>(); products.add(new BoxItem(new Box("1", 5, 5, 1, 0), 1)); Adapter mock = mock(Adapter.class); when(mock.attempt(eq(3))) .thenReturn(incompleteResult).thenThrow(RuntimeException.class); when(mock.attempt(eq(5))) .thenReturn(incompleteResult).thenThrow(RuntimeException.class); when(mock.attempt(eq(6))) .thenReturn(completeResult).thenThrow(RuntimeException.class); when(mock.attempt(eq(4))) .thenReturn(incompleteResult).thenThrow(RuntimeException.class); when(mock.attempt(eq(2))) .thenReturn(incompleteResult).thenThrow(RuntimeException.class); when(mock.attempt(eq(1))) .thenReturn(incompleteResult).thenThrow(RuntimeException.class); when(mock.attempt(eq(0))) .thenReturn(incompleteResult).thenThrow(RuntimeException.class); when(mock.accepted(any(PackResult.class))) .thenReturn(new ValidatingContainer("result", 5, 5, 1, 0)); when(mock.hasMore(any(PackResult.class))).thenReturn(true, true, false, true, true, true, true); MyPackager myPackager = new MyPackager(containers, mock); Container pack = myPackager.pack(products, deadline); assertNotNull(pack); assertEquals("result", pack.getName()); for (int i = 0; i < containers.size(); i++) { verify(mock, times(1)).attempt(eq(i)); } }
@Test void packagerCanBeInterrupted() throws InterruptedException { final Container container = new ValidatingContainer("", 1000, 1500, 3200, 0); final List<Container> singleContainer = Collections.singletonList(container); final BruteForcePackager bruteForcePackager = new BruteForcePackager(singleContainer); final LargestAreaFitFirstPackager largestAreaFitFirstPackager = new LargestAreaFitFirstPackager(container.rotations()); final AtomicBoolean laffFinished = new AtomicBoolean(false); final AtomicBoolean bruteForceFinished = new AtomicBoolean(false); new Thread(() -> { final Container pack = bruteForcePackager.pack(listOf28Products(), System.currentTimeMillis() + 1000, () -> laffFinished.get()); bruteForceFinished.set(pack != null); }).start(); new Thread(() -> { final Container pack = largestAreaFitFirstPackager.pack(listOf28Products(), System.currentTimeMillis() + 1000, () -> bruteForceFinished.get()); laffFinished.set(pack != null); }).start(); Thread.sleep(100); assertTrue(laffFinished.get()); assertFalse(bruteForceFinished.get()); }
@Test void packagerCanBeInterruptedWithAFunction() throws InterruptedException { final Container container = new ValidatingContainer("", 1000, 1500, 3200, 0); final List<Container> singleContainer = Collections.singletonList(container); final BruteForcePackager bruteForcePackager = new BruteForcePackager(singleContainer); final LargestAreaFitFirstPackager largestAreaFitFirstPackager = new LargestAreaFitFirstPackager(container.rotations()); final AtomicBoolean laffFinishedBool = new AtomicBoolean(false); final AtomicBoolean bruteForceFinishedBool = new AtomicBoolean(false); final long start = System.currentTimeMillis(); BooleanSupplier deadlineReached = () -> System.currentTimeMillis() > start + 1000; BooleanSupplier interruptLaff = () -> deadlineReached.getAsBoolean() || bruteForceFinishedBool.get(); BooleanSupplier interruptBruteForce = () -> deadlineReached.getAsBoolean() || laffFinishedBool.get(); new Thread(() -> { final Container pack = bruteForcePackager.pack(listOf28Products(), interruptBruteForce); bruteForceFinishedBool.set(pack != null); }).start(); new Thread(() -> { final Container pack = largestAreaFitFirstPackager.pack(listOf28Products(), interruptLaff); laffFinishedBool.set(pack != null); }).start(); Thread.sleep(100); assertTrue(laffFinishedBool.get()); assertFalse(bruteForceFinishedBool.get()); }