CompositeDate.java :  » Testing » springunit-0.6 » org » springunit » examples » Java Open Source

Java Open Source » Testing » springunit 0.6 
springunit 0.6 » org » springunit » examples » CompositeDate.java
package org.springunit.examples;

import java.io.Serializable;

import org.apache.commons.lang.builder.CompareToBuilder;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;

/**
 * Simple domain object class to be used for demonstrating
 * Data Driven Tests.
 * CompositeDate is composed of a year, month and day of year.
 * The fact that there are many constraints on the allowed
 * combinations makes for interesting test cases.
 * Further, operations like increment and decrement on
 * each of the fields leads to many other boundary
 * conditions for which to test.
 * <br/>
 * The following are groundrules set by the class:
 * <ul>
 * <li>A year may be any positive or negative integer</li>
 * <li>A month may be any integer between 1 and 12, inclusive</li>
 * <li>A day may be any integer between 1 and 31, inclusive</li>
 * </ul>
 * <br/>
 * These being preconditions imposed on clients, the class
 * does not check, for instance,
 * for days greater than 31, or months greater than 12.
 * Of course, not all combinations of year, month and day
 * that satisfy these preconditions are valid.  These are
 * validated internally by the class.
 * 
 * @author Ted.Velkoff
 *
 */
public class CompositeDate implements Comparable<CompositeDate>, Serializable {
  
  private static final long serialVersionUID = 4537123990358625629L;
  
  /**
   * Create CompositeDate having day, month and year.<br/>
   * @Pre("1 <= day && day <= 31")
   * @Pre("1 <= month && month <= 12")
   * @throws InvalidDateException if day, month and year do
   * not specify a valid date
   */
  public CompositeDate(int year, int month, int day) throws InvalidDateException {
    assert 1 <= day && day <= 31 : "1 <= day && day <= 31";
    assert 1 <= month && month <= 12 : "1 <= month && month <= 12";
    this.day = day;
    this.month = month;
    this.year = year;
    validateDate(year, month, day);
  }
  
  /**
   * Is this less than, equal to, or greater than that?<br/>
   * @param that Object to be compared with this.
   * @return boolean
   */
  public int compareTo(CompositeDate that) {
    return new CompareToBuilder().
      append(getYear(), that.getYear()).
      append(getMonth(), that.getMonth()).
      append(getDay(), that.getDay()).
      toComparison();
  }
  
  /**
   * Decrement by one day.<br/>
   * @return true if field underflow detected, false otherwise
   * @throws DateUnderflowException if object underflow detected
   */
  public boolean decrementDay() throws DateUnderflowException {
    boolean underflow = false;
    if (this.day == 1 && (this.month == 1 || this.month == 2 || this.month == 4 || this.month == 6 || this.month == 8 || this.month == 9 || this.month == 11)) {
      underflow = decrementMonth();
      this.day = 31;
    }
    else if (this.day == 1 && (this.month == 5 || this.month == 7 || this.month == 10 || this.month == 12)) {
      underflow = decrementMonth();
      this.day = 30;
    }
    else if (this.day == 1 && this.month == 3) {
      underflow = decrementMonth();
      if (this.year % 400 == 0 || (this.year % 4 == 0 && this.year % 100 != 0)) {
        this.day = 29;
      }
      else {
        this.day = 28;
      }
    }
    else {
      this.day--;
    }
    return underflow;
  }
  
  /**
   * Decrement by one month.<br/>
   * @return true if field underflow detected, false otherwise
   * @throws DateUnderflowException if object underflow detected
   */
  public boolean decrementMonth() throws DateUnderflowException {
    boolean underflow = false;
    if (this.day > 30 && (this.month == 5 || this.month == 7 || this.month == 10 || this.month == 12)) {
      this.day = 30;
    }
    else if (this.month == 3 && (this.day > 28)) {
      this.day = 28;
    }
    if (this.month == 1) {
      underflow = decrementYear();
      this.month = 12;
    }
    else {
      this.month--;
    }
    return underflow;
  }
  
  /**
   * Decrement by one year.
   * @return true if field underflow detected, false otherwise
   * @throws DateUnderflowException if object underflow detected
   */
  public boolean decrementYear() throws DateUnderflowException {
    if (this.year == Integer.MIN_VALUE) {
      throw new DateUnderflowException("Can't decrement year past -2147483648");
    }
    if (this.month == 2 && this.day == 29) {
      this.day = 28;
    }
    this.year--;
    return false;
  }
  
  /**
   * Is this equal to obj?<br/>
   */
  public boolean equals(Object obj) {
    if (this == obj) {
      return true;
    }
    if (!(obj instanceof CompositeDate)) {
      return false;
    }
    CompositeDate other = (CompositeDate) obj;
    return new EqualsBuilder().
      append(getYear(), other.getYear()).
      append(getMonth(), other.getMonth()).
      append(getDay(), other.getDay()).
      isEquals();
  }
  
  /**
   * @return Returns the day.
   */
  public int getDay() {
    return this.day;
  }
  
  /**
   * @return Returns the month.
   */
  public int getMonth() {
    return this.month;
  }
  
  /**
   * @return Returns the year.
   */
  public int getYear() {
    return this.year;
  }
  
  /**
   * Hash code.<br/>
   */
  public int hashCode() {
    return new HashCodeBuilder(17, 37).
      append(getYear()).
      append(getMonth()).
      append(getDay()).
      toHashCode();
  }
  
  /**
   * Increment by one day.<br/>
   * @return true if field overflow detected, false otherwise
   * @throws DateOverflowException if object overflow detected
   */
  public boolean incrementDay() throws DateOverflowException {
    if (this.month == 1 || this.month == 3 || this.month == 5 || this.month == 7 || this.month == 8 || this.month == 10 || this.month == 12) {
      this.day = (this.day % 31) + 1;
    }
    else if (this.month == 4 || this.month == 6 || this.month == 9 || this.month == 11) {
      this.day = (this.day % 30) + 1;
    }
    else if (this.month == 2 && (this.year % 400 == 0 || (this.year % 4 == 0 && this.year % 100 != 0))) {
      this.day = (this.day % 29) + 1;
    }
    else {
      this.day = (this.day % 28) + 1;
    }
    boolean overflow = this.day == 1;
    if (overflow) {
      return incrementMonth();
    }
    return overflow;
  }
  
  /**
   * Increment by one month.<br/>
   * @return true if field overflow detected, false otherwise
   * @throws DateOverflowException if object overflow detected
   */
  public boolean incrementMonth() throws DateOverflowException {
    if (this.month == 1 && this.day > 28) {
      this.day = 28;
    }
    else if ((this.month == 3 || this.month == 5 || this.month == 8 || this.month == 10) && this.day > 30) {
      this.day = 30;
    }
    this.month = (this.month % 12) + 1;
    boolean overflow = this.month == 1;
    if (overflow) {
      return incrementYear();
    }
    return overflow;
  }
  
  /**
   * Increment by one year.<br/>
   * @return true if field overflow detected, false otherwise
   * @throws DateOverflowException if object overflow detected
   */
  public boolean incrementYear() throws DateOverflowException {
    if (this.year == Integer.MAX_VALUE) {
      throw new DateOverflowException("Can't increment year past 2147483647");
    }
    if (this.month == 2 && this.day == 29) {
      this.day = 28;
    }
    this.year++;
    return false;
  }
  
  /**
   * @param day The day to set.
   * @Pre("1 <= day && day <= 31")
   * @throws InvalidDateException if day, month and year do
   * not specify a valid date
   */
  public void setDay(int day) throws InvalidDateException {
    assert 1 <= day && day <= 31 : "1 <= day && day <= 31";
    validateDate(this.year, this.month, day);
    this.day = day;
  }
  
  /**
   * @param month The month to set.
   * @Pre("1 <= month && month <= 12")
   * @throws InvalidDateException if day, month and year do
   * not specify a valid date
   */
  public void setMonth(int month) throws InvalidDateException {
    assert 1 <= month && month <= 12 : "1 <= month && month <= 12";
    validateDate(this.year, month, this.day);
    this.month = month;
  }
  
  /**
   * @param year The year to set.
   * @throws InvalidDateException if day, month and year do
   * not specify a valid date
   */
  public void setYear(int year) throws InvalidDateException {
    validateDate(year, this.month, this.day);
    this.year = year;
  }
  
  /**
   * String representation.<br/>
   */
  public String toString() {
    return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE).
      append("day", getDay()).
      append("month", getMonth()).
      append("year", getYear()).
      toString();
  }
  
  /**
   * Is combination of <code>year</code>, <code>month</code>,
   * and <code>day</code> valid?<br/>
   * @Pre("1 <= month && month <= 12")
   * @Pre("1 <= day && day <= 31")
   * @return true if valid, false otherwise
   */
  public static boolean isValidDate(int year, int month, int day) {
    return isValidLeapDay(year, month, day) || isValidMonthAndDay(month, day);
  }
  
  /**
   * Is combination of <code>year</code>, <code>month</code>,
   * and <code>day</code> a valid leap day?<br/>
   * @return true if valid, false otherwise
   */
  public static boolean isValidLeapDay(int year, int month, int day) {
    return (day != 29 || month != 2) || ((year % 400 == 0) || (year % 4 == 0 && year % 100 != 0));

  }

  /**
   * Is combination of <code>month</code>
   * and <code>day</code> a valid month/day pair?<br/>
   * @Pre("1 <= month && month <= 12")
   * @Pre("1 <= day && day <= 31")
   * @return true if valid, false otherwise
   */
  public static boolean isValidMonthAndDay(int month, int day) {
    assert 1 <= month && month <= 12 : "1 <= month && month <= 12";
    assert 1 <= day && day <= 31 : "1 <= day && day <= 31";
    return !((day > 29 && month == 2) || (day > 30 && (month == 4 || month == 6 || month == 9 || month == 11)));
  }

  /**
   * Determine whether the combination of day, month and year
   * is valid and throw InvalidDateException if not.<br/>
   */
  protected static void validateDate(int year, int month, int day) throws InvalidDateException {
    validateLeapDay(year, month, day);
    validateMonthAndDay(month, day);
  }
  
  /**
   * Determine whether the combination of day, month and year
   * is a leap day and throw InvalidDateException if it is not
   * a valid leap day.<br/>
   */
  protected static void validateLeapDay(int year, int month, int day) throws InvalidDateException {
    if (!isValidLeapDay(year, month, day)) {
      throw new InvalidDateException("February 29 is not valid for the year " + year);
    }
  }

  /**
   * Determine whether the combination of day, month and year
   * is a leap day and throw InvalidDateException if it is not
   * a valid leap day.<br/>
   */
  protected static void validateMonthAndDay(int month, int day) throws InvalidDateException {
    if (!isValidMonthAndDay(month, day)) {
      throw new InvalidDateException(day + " is not valid for the month " + month);
    }
  }

  private int day;
  private int month;
  private int year;
  
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.