@Before
 public void setup() {
   promotionElement = new PromotionElement();
   promotionElement.setDiscountElements(Lists.newArrayList(firstTwo, nextOne));
   promotionElement.setMatcher(productMatcher);
   promotionElement.setTotalRequired(3);
 }
  static {
    ProductMatcher toothBrushProductMatcher = new SingleProductMatcher(toothBrush);
    DiscountElement toothBrushFirstTwo = new DiscountElement(noDiscount, 2);
    DiscountElement toothBrushFreeOne = new DiscountElement(freeDiscount, 1);

    toothBrushPromotionElement = new PromotionElement();
    toothBrushPromotionElement.setDiscountElements(
        Lists.newArrayList(toothBrushFirstTwo, toothBrushFreeOne));
    toothBrushPromotionElement.setMatcher(toothBrushProductMatcher);
    toothBrushPromotionElement.setTotalRequired(3);

    ProductMatcher chipsProductMatcher = new SingleProductMatcher(chips);
    DiscountElement chipsDiscount = new DiscountElement(fixed200Discount, 1);
    chipsPromotionElement = new PromotionElement();
    chipsPromotionElement.setDiscountElements(Lists.newArrayList(chipsDiscount));
    chipsPromotionElement.setMatcher(chipsProductMatcher);
    chipsPromotionElement.setTotalRequired(1);

    ProductMatcher salsaProductMatcher = new SingleProductMatcher(salsa);
    DiscountElement salsaDiscount = new DiscountElement(fixed299Discount, 1);
    salsaPromotionElement = new PromotionElement();
    salsaPromotionElement.setDiscountElements(Lists.newArrayList(salsaDiscount));
    salsaPromotionElement.setMatcher(salsaProductMatcher);
    salsaPromotionElement.setTotalRequired(1);
  }
  @Test
  public void testCriteriaMet_itemsInList() {
    // setup
    Transaction transaction =
        TransactionTestUtils.createTransaction(
            toothBrush, milkCarton, toothBrush, chips, toothBrush, toothBrush);
    Set<Integer> alreadyClaimedProducts = Sets.newHashSet(1, 3);

    // test
    boolean result = promotionElement.criteriaMet(transaction, alreadyClaimedProducts);

    // verify
    assertThat(result, is(false));
    assertThat(alreadyClaimedProducts, IsIterableContainingInAnyOrder.containsInAnyOrder(1, 3));
  }
  private void testCriteriaMet(
      String reason, Transaction transaction, boolean expected, Integer... ids) {
    // setup
    Set<Integer> alreadyClaimedProducts = Sets.newHashSet();

    // test
    boolean result = promotionElement.criteriaMet(transaction, alreadyClaimedProducts);

    // verify
    checkThat(reason, result, equalTo(expected));
    if (expected) {
      checkThat(
          reason, alreadyClaimedProducts, IsIterableContainingInAnyOrder.containsInAnyOrder(ids));
    } else {
      checkThat(reason, alreadyClaimedProducts, IsCollectionWithSize.hasSize(0));
    }
  }
  @Test
  public void testApplyPromotion_noDiscountsApplied() {
    // setup
    Transaction transaction =
        TransactionTestUtils.createTransaction(
            toothBrush, milkCarton, toothBrush, chips, toothBrush, toothBrush, toothBrush);

    // test
    promotionElement.applyPromotion(transaction);

    // verify
    List<TransactionItem> brushes = Lists.newArrayList(transaction.getItemMap().get(toothBrush));
    assertDiscountApplied("brush 1", brushes.get(0), true, noDiscount);
    assertDiscountApplied("brush 2", brushes.get(1), true, noDiscount);
    assertDiscountApplied("brush 3", brushes.get(2), true, freeDiscount);
    assertDiscountApplied("brush 4", brushes.get(3), false, null);
    assertDiscountApplied("brush 5", brushes.get(4), false, null);
  }