package co.smartreceipts.android.filters;
import org.json.JSONException;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import java.math.BigDecimal;
import java.sql.Date;
import java.util.ArrayList;
import java.util.TimeZone;
import co.smartreceipts.android.model.Price;
import co.smartreceipts.android.model.Trip;
import co.smartreceipts.android.model.factory.ExchangeRateBuilderFactory;
import co.smartreceipts.android.model.impl.ImmutablePriceImpl;
import co.smartreceipts.android.utils.TripUtils;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@RunWith(RobolectricTestRunner.class)
public class TripFilterTest {
// Test constants for Price checking
private static final Price PRICE_NORMAL = new ImmutablePriceImpl(new BigDecimal(100.00d), TripUtils.Constants.CURRENCY, new ExchangeRateBuilderFactory().setBaseCurrency(TripUtils.Constants.CURRENCY).build());
private static final Price PRICE_HIGH = new ImmutablePriceImpl(new BigDecimal(150.00d), TripUtils.Constants.CURRENCY, new ExchangeRateBuilderFactory().setBaseCurrency(TripUtils.Constants.CURRENCY).build());
private static final Price PRICE_LOW = new ImmutablePriceImpl(new BigDecimal(50.00d), TripUtils.Constants.CURRENCY, new ExchangeRateBuilderFactory().setBaseCurrency(TripUtils.Constants.CURRENCY).build());
// Test constants for Date checking
private static final TimeZone TZ = TimeZone.getTimeZone("America/New_York");
private static final long MILLIS = System.currentTimeMillis();
private static final Date NOW = new Date(MILLIS);
private static final Date FUTURE = new Date(MILLIS + 1000);
private static final Date PAST = new Date(MILLIS - 1000);
@Test
public void tripMinimumPriceFilterTest() throws JSONException {
final Trip tripNormal = TripUtils.newDefaultTripBuilderFactory().build();
final Trip tripHigh = TripUtils.newDefaultTripBuilderFactory().build();
final Trip tripLow = TripUtils.newDefaultTripBuilderFactory().build();
tripNormal.setPrice(PRICE_NORMAL);
tripHigh.setPrice(PRICE_HIGH);
tripLow.setPrice(PRICE_LOW);
final TripMinimumPriceFilter filter = new TripMinimumPriceFilter(PRICE_NORMAL.getPriceAsFloat(), TripUtils.Constants.CURRENCY_CODE);
assertTrue(filter.accept(tripNormal));
assertTrue(filter.accept(tripHigh));
assertFalse(filter.accept(tripLow));
assertEquals(filter, FilterFactory.getTripFilter(filter.getJsonRepresentation()));
assertEquals(filter.getNameResource(), co.smartreceipts.android.R.string.filter_name_trip_min_price);
assertEquals(filter.getType(), FilterType.Float);
}
@Test
public void tripMaximumPriceFilterTest() throws JSONException {
final Trip tripNormal = TripUtils.newDefaultTripBuilderFactory().build();
final Trip tripHigh = TripUtils.newDefaultTripBuilderFactory().build();
final Trip tripLow = TripUtils.newDefaultTripBuilderFactory().build();
tripNormal.setPrice(PRICE_NORMAL);
tripHigh.setPrice(PRICE_HIGH);
tripLow.setPrice(PRICE_LOW);
final TripMaximumPriceFilter filter = new TripMaximumPriceFilter(PRICE_NORMAL.getPriceAsFloat(), TripUtils.Constants.CURRENCY_CODE);
assertTrue(filter.accept(tripNormal));
assertFalse(filter.accept(tripHigh));
assertTrue(filter.accept(tripLow));
assertEquals(filter, FilterFactory.getTripFilter(filter.getJsonRepresentation()));
assertEquals(filter.getNameResource(), co.smartreceipts.android.R.string.filter_name_trip_max_price);
assertEquals(filter.getType(), FilterType.Float);
}
@Test
public void tripStartsOnOrAfterDayFilterTest() throws JSONException {
final Trip tripNow = TripUtils.newDefaultTripBuilderFactory().setStartDate(NOW).build();
final Trip tripFuture = TripUtils.newDefaultTripBuilderFactory().setStartDate(FUTURE).build();
final Trip tripPast = TripUtils.newDefaultTripBuilderFactory().setStartDate(PAST).build();
final TripStartsOnOrAfterDayFilter filter = new TripStartsOnOrAfterDayFilter(NOW, TZ);
assertTrue(filter.accept(tripNow));
assertTrue(filter.accept(tripFuture));
assertFalse(filter.accept(tripPast));
assertEquals(filter, FilterFactory.getTripFilter(filter.getJsonRepresentation()));
assertEquals(filter.getNameResource(), co.smartreceipts.android.R.string.filter_name_trip_starts_on_or_after);
assertEquals(filter.getType(), FilterType.Date);
}
@Test
public void tripStartsOnOrBeforeDayFilterTest() throws JSONException {
final Trip tripNow = TripUtils.newDefaultTripBuilderFactory().setStartDate(NOW).build();
final Trip tripFuture = TripUtils.newDefaultTripBuilderFactory().setStartDate(FUTURE).build();
final Trip tripPast = TripUtils.newDefaultTripBuilderFactory().setStartDate(PAST).build();
final TripStartsOnOrBeforeDayFilter filter = new TripStartsOnOrBeforeDayFilter(NOW, TZ);
assertTrue(filter.accept(tripNow));
assertFalse(filter.accept(tripFuture));
assertTrue(filter.accept(tripPast));
assertEquals(filter, FilterFactory.getTripFilter(filter.getJsonRepresentation()));
assertEquals(filter.getNameResource(), co.smartreceipts.android.R.string.filter_name_trip_starts_on_or_before);
assertEquals(filter.getType(), FilterType.Date);
}
@Test
public void tripEndsOnOrAfterDayFilterTest() throws JSONException {
final Trip tripNow = TripUtils.newDefaultTripBuilderFactory().setEndDate(NOW).build();
final Trip tripFuture = TripUtils.newDefaultTripBuilderFactory().setEndDate(FUTURE).build();
final Trip tripPast = TripUtils.newDefaultTripBuilderFactory().setEndDate(PAST).build();
final TripEndsOnOrAfterDayFilter filter = new TripEndsOnOrAfterDayFilter(NOW, TZ);
assertTrue(filter.accept(tripNow));
assertTrue(filter.accept(tripFuture));
assertFalse(filter.accept(tripPast));
assertEquals(filter, FilterFactory.getTripFilter(filter.getJsonRepresentation()));
assertEquals(filter.getNameResource(), co.smartreceipts.android.R.string.filter_name_trip_ends_on_or_after);
assertEquals(filter.getType(), FilterType.Date);
}
@Test
public void tripEndsOnOrBeforeDayFilterTest() throws JSONException {
final Trip tripNow = TripUtils.newDefaultTripBuilderFactory().setEndDate(NOW).build();
final Trip tripFuture = TripUtils.newDefaultTripBuilderFactory().setEndDate(FUTURE).build();
final Trip tripPast = TripUtils.newDefaultTripBuilderFactory().setEndDate(PAST).build();
final TripEndsOnOrBeforeDayFilter filter = new TripEndsOnOrBeforeDayFilter(NOW, TZ);
assertTrue(filter.accept(tripNow));
assertFalse(filter.accept(tripFuture));
assertTrue(filter.accept(tripPast));
assertEquals(filter, FilterFactory.getTripFilter(filter.getJsonRepresentation()));
assertEquals(filter.getNameResource(), co.smartreceipts.android.R.string.filter_name_trip_ends_on_or_before);
assertEquals(filter.getType(), FilterType.Date);
}
@Test
public void tripOrFilterTest() throws JSONException {
// in this test scenario, trip with normal price will NOT be accepted
// accept rule: price >= high OR price <= LOW
final Trip tripNormal = TripUtils.newDefaultTripBuilderFactory().build();
final Trip tripHigh = TripUtils.newDefaultTripBuilderFactory().build();
final Trip tripLow = TripUtils.newDefaultTripBuilderFactory().build();
tripNormal.setPrice(PRICE_NORMAL);
tripHigh.setPrice(PRICE_HIGH);
tripLow.setPrice(PRICE_LOW);
final TripMinimumPriceFilter minPrice = new TripMinimumPriceFilter(PRICE_HIGH.getPriceAsFloat(), TripUtils.Constants.CURRENCY_CODE);
final TripMaximumPriceFilter maxPrice = new TripMaximumPriceFilter(PRICE_LOW.getPriceAsFloat(), TripUtils.Constants.CURRENCY_CODE);
final TripOrFilter orFilter = new TripOrFilter();
orFilter.or(minPrice);
orFilter.or(maxPrice);
assertTrue(orFilter.accept(tripHigh));
assertTrue(orFilter.accept(tripLow));
assertFalse(orFilter.accept(tripNormal)); // rejected
assertEquals(orFilter, FilterFactory.getTripFilter(orFilter.getJsonRepresentation()));
assertEquals(orFilter.getNameResource(), co.smartreceipts.android.R.string.filter_name_or);
assertEquals(orFilter.getType(), FilterType.Composite);
}
@Test
public void tripAndFilterTest() throws JSONException {
// in this test scenario, we will only accept cheap trip started in the past (i.e. tripPastLow)
// accept rule: starts on or before past AND price is low
final Trip tripPastNormal = TripUtils.newDefaultTripBuilderFactory().setStartDate(PAST).build();
final Trip tripPastHigh = TripUtils.newDefaultTripBuilderFactory().setStartDate(PAST).build();
final Trip tripPastLow = TripUtils.newDefaultTripBuilderFactory().setStartDate(PAST).build();
final Trip tripFutureNormal = TripUtils.newDefaultTripBuilderFactory().setStartDate(FUTURE).build();
final Trip tripFutureHigh = TripUtils.newDefaultTripBuilderFactory().setStartDate(FUTURE).build();
final Trip tripFutureLow = TripUtils.newDefaultTripBuilderFactory().setStartDate(FUTURE).build();
tripPastHigh.setPrice(PRICE_HIGH);
tripPastNormal.setPrice(PRICE_NORMAL);
tripPastLow.setPrice(PRICE_LOW);
tripFutureHigh.setPrice(PRICE_HIGH);
tripFutureNormal.setPrice(PRICE_NORMAL);
tripFutureLow.setPrice(PRICE_LOW);
final TripStartsOnOrBeforeDayFilter dateFilter = new TripStartsOnOrBeforeDayFilter(PAST, TripUtils.Constants.START_TIMEZONE);
final TripMaximumPriceFilter priceFilter = new TripMaximumPriceFilter(PRICE_LOW.getPriceAsFloat(), TripUtils.Constants.CURRENCY_CODE);
final TripAndFilter andFilter = new TripAndFilter();
andFilter.and(dateFilter);
andFilter.and(priceFilter);
assertFalse(andFilter.accept(tripPastNormal));
assertFalse(andFilter.accept(tripPastHigh));
assertTrue(andFilter.accept(tripPastLow)); // accepted
assertFalse(andFilter.accept(tripFutureNormal));
assertFalse(andFilter.accept(tripFutureHigh));
assertFalse(andFilter.accept(tripFutureLow));
assertEquals(andFilter, FilterFactory.getTripFilter(andFilter.getJsonRepresentation()));
assertEquals(andFilter.getNameResource(), co.smartreceipts.android.R.string.filter_name_and);
assertEquals(andFilter.getType(), FilterType.Composite);
}
@Test
public void tripNotFilterTest() throws JSONException {
// in this test scenario, we will only accept tripHigh
// accept rule: NOT (price <= normal)
// equivalent to: (price > normal)
final Trip tripNormal = TripUtils.newDefaultTripBuilderFactory().build();
final Trip tripHigh = TripUtils.newDefaultTripBuilderFactory().build();
final Trip tripLow = TripUtils.newDefaultTripBuilderFactory().build();
tripNormal.setPrice(PRICE_NORMAL);
tripHigh.setPrice(PRICE_HIGH);
tripLow.setPrice(PRICE_LOW);
final TripMaximumPriceFilter priceFilter = new TripMaximumPriceFilter(PRICE_NORMAL.getPriceAsFloat(), TripUtils.Constants.CURRENCY_CODE);
final TripNotFilter notFilter = new TripNotFilter(priceFilter);
assertFalse(notFilter.accept(tripNormal));
assertTrue(notFilter.accept(tripHigh)); // accepted
assertFalse(notFilter.accept(tripLow));
assertEquals(notFilter, FilterFactory.getTripFilter(notFilter.getJsonRepresentation()));
assertEquals(notFilter.getNameResource(), co.smartreceipts.android.R.string.filter_name_not);
assertEquals(notFilter.getType(), FilterType.Composite);
}
@Test
public void tripAndFilterConstructorTest() throws JSONException {
// in this test scenario,
// filters constructed with same data but different method should be equal
final TripStartsOnOrBeforeDayFilter dateFilter = new TripStartsOnOrBeforeDayFilter(PAST, TripUtils.Constants.START_TIMEZONE);
final TripMaximumPriceFilter priceFilter = new TripMaximumPriceFilter(PRICE_LOW.getPriceAsFloat(), TripUtils.Constants.CURRENCY_CODE);
// filter 1 -- composited filters added in object instantiation (i.e. constructor)
final ArrayList<Filter<Trip>> filters = new ArrayList<>();
filters.add(dateFilter);
filters.add(priceFilter);
final TripAndFilter filter1 = new TripAndFilter(filters);
// filter 2 -- composited filters added after object instantiation
final TripAndFilter filter2 = new TripAndFilter();
filter2.and(dateFilter);
filter2.and(priceFilter);
assertEquals(filter1, filter2);
assertEquals(filter1, FilterFactory.getTripFilter(filter1.getJsonRepresentation()));
assertEquals(filter2, FilterFactory.getTripFilter(filter2.getJsonRepresentation()));
}
@Test
public void tripOrFilterConstructorTest() throws JSONException {
// in this test scenario,
// filters constructed with same data but different method should be equal
final TripStartsOnOrBeforeDayFilter dateFilter = new TripStartsOnOrBeforeDayFilter(PAST, TripUtils.Constants.START_TIMEZONE);
final TripMaximumPriceFilter priceFilter = new TripMaximumPriceFilter(PRICE_LOW.getPriceAsFloat(), TripUtils.Constants.CURRENCY_CODE);
// filter 1 -- composited filters added in object instantiation (i.e. constructor)
final ArrayList<Filter<Trip>> filters = new ArrayList<>();
filters.add(dateFilter);
filters.add(priceFilter);
final TripOrFilter filter1 = new TripOrFilter(filters);
// filter 2 -- composited filters added after object instantiation
final TripOrFilter filter2 = new TripOrFilter();
filter2.or(dateFilter);
filter2.or(priceFilter);
assertEquals(filter1, filter2);
assertEquals(filter1, FilterFactory.getTripFilter(filter1.getJsonRepresentation()));
assertEquals(filter2, FilterFactory.getTripFilter(filter2.getJsonRepresentation()));
}
}