ResourceAggregator { public List<? extends Resource> deduct( List<? extends Resource> sourceResources, List<? extends Resource> resourcesToDeduct) throws NoEnoughResourcesException { checkSupporting(sourceResources); checkSupporting(resourcesToDeduct); final Map<String, Resource> result = sourceResources.stream().collect(Collectors.toMap(Resource::getType, Function.identity())); final List<Resource> missingResources = new ArrayList<>(); for (Resource toDeduct : resourcesToDeduct) { final Resource sourceResource = result.get(toDeduct.getType()); if (sourceResource != null) { try { result.put(toDeduct.getType(), deduct(sourceResource, toDeduct)); } catch (NoEnoughResourcesException e) { result.remove(toDeduct.getType()); missingResources.addAll(e.getMissingResources()); } } else { missingResources.add(toDeduct); } } if (!missingResources.isEmpty()) { throw new NoEnoughResourcesException(sourceResources, resourcesToDeduct, missingResources); } return new ArrayList<>(result.values()); } @Inject  ResourceAggregator(Set<ResourceType> resourcesTypes); Map<String, Resource> aggregateByType(List<? extends Resource> resources); List<? extends Resource> deduct(
      List<? extends Resource> sourceResources, List<? extends Resource> resourcesToDeduct); List<? extends Resource> excess(
      List<? extends Resource> sourceResources, List<? extends Resource> resourcesToCompare); Resource aggregate(Resource resourceA, Resource resourceB); Resource deduct(Resource totalResource, Resource deduction); List<? extends Resource> intersection(
      List<? extends Resource> resourcesA, List<? extends Resource> resourcesB); List<? extends Resource> min(Collection<? extends Resource> resources);  }
@Test public void shouldTestResourcesDeduction() throws Exception { final ResourceImpl aResource = new ResourceImpl(A_RESOURCE_TYPE, 123, "unit"); final ResourceImpl bResource = new ResourceImpl(B_RESOURCE_TYPE, 123, "unit"); final ResourceImpl anotherBResource = new ResourceImpl(B_RESOURCE_TYPE, 321, "unit"); final ResourceImpl aggregatedBResources = new ResourceImpl(A_RESOURCE_TYPE, 444, "unit"); when(bResourceType.deduct(any(), any())).thenReturn(aggregatedBResources); final List<? extends Resource> deductedResources = resourceAggregator.deduct(asList(aResource, bResource), singletonList(anotherBResource)); verify(bResourceType).deduct(eq(bResource), eq(anotherBResource)); verify(aResourceType, never()).deduct(any(), any()); assertEquals(deductedResources.size(), 2); assertTrue(deductedResources.contains(aResource)); assertTrue(deductedResources.contains(aggregatedBResources)); }
@Test(expectedExceptions = NoEnoughResourcesException.class) public void shouldThrowConflictExceptionWhenTotalResourcesDoNotHaveEnoughAmountToDeduct() throws Exception { final ResourceImpl aResource = new ResourceImpl(A_RESOURCE_TYPE, 111, "unit"); final ResourceImpl anotherAResource = new ResourceImpl(A_RESOURCE_TYPE, 333, "unit"); when(aResourceType.deduct(any(), any())) .thenThrow( new NoEnoughResourcesException( singletonList(aResource), singletonList(anotherAResource), singletonList(new ResourceImpl(A_RESOURCE_TYPE, 222, "unit")))); resourceAggregator.deduct(singletonList(aResource), singletonList(anotherAResource)); }
@Test(expectedExceptions = NoEnoughResourcesException.class) public void shouldThrowConflictExceptionWhenTotalResourcesDoNotContainsRequiredResourcesAtAll() throws Exception { final ResourceImpl aResource = new ResourceImpl(A_RESOURCE_TYPE, 123, "unit"); final ResourceImpl bResource = new ResourceImpl(B_RESOURCE_TYPE, 321, "unit"); resourceAggregator.deduct(singletonList(aResource), singletonList(bResource)); }
@Test(expectedExceptions = IllegalArgumentException.class) public void shouldThrowIllegalArgumentExceptionWhenTotalResourcesListContainsNotSupportedResourceOnResourcesDeduction() throws Exception { final ResourceImpl dResource = mock(ResourceImpl.class); when(dResource.getType()).thenReturn("resourceD"); resourceAggregator.deduct(emptyList(), singletonList(dResource)); }
@Test(expectedExceptions = IllegalArgumentException.class) public void shouldThrowIllegalArgumentExceptionWhenResourcesToDeductListContainsNotSupportedResourceOnResourcesDeduction() throws Exception { final ResourceImpl dResource = mock(ResourceImpl.class); when(dResource.getType()).thenReturn("resourceD"); resourceAggregator.deduct(singletonList(dResource), emptyList()); }