ある期間が他の期間と被ってるかを検査する

仕様

  • ある期間が他の期間と被ってるかを検査する。
  • 検査する期間は閉じているか、下に開いているか、上に開いているかのどれか。
  • 上下ともに開いている期間は扱わない。
    • とりあえず面倒なので。

本体

public class Util {
    public static <T extends Comparable<? super T>> Period<T> period(T lowerBound, T upperBound) {
        return new Period<T>(lowerBound, upperBound);
    }
    
    public static class Period<T extends Comparable<? super T>> {
        public final T lowerBound;
        public final T upperBound;
        public Period(T lowerBound, T upperBound) {
            if (lowerBound==null && upperBound==null)
                throw new IllegalArgumentException(
                    "either lowerBound or upperBound should be not null.");
            if (lowerBound!=null && upperBound!=null &&
                    lowerBound.compareTo(upperBound)>0)
                throw new IllegalArgumentException(
                    "lowerBound should be less equal than upperBound.");
            this.lowerBound = lowerBound;
            this.upperBound = upperBound;
        }
        
        public boolean laps(T lowerBound, T upperBound) {
            return this.laps(new Period<T>(lowerBound, upperBound));
        }
        
        public boolean laps(Period<T> that) {
            if (this.isLowerUnbounded()) {
                if (that.isLowerUnbounded()) return true;
                if (this.upperBound.compareTo(that.lowerBound)>=0) return true;
            } else if (this.isUpperUnbounded()) {
                if (that.isUpperUnbounded()) return true;
                if (this.lowerBound.compareTo(that.upperBound)<=0) return true;
            } else {
                if (that.isLowerUnbounded()) {
                    if (this.lowerBound.compareTo(that.upperBound)<=0) return true;
                } else if (that.isUpperUnbounded()) {
                    if (this.upperBound.compareTo(that.lowerBound)>=0) return true;
                } else {
                    if (this.lowerBound.compareTo(that.upperBound)<=0 && 
                            this.upperBound.compareTo(that.lowerBound)>=0) return true;
                }
            }
            return false;
        }
        
        private boolean isLowerUnbounded(){return lowerBound == null;}
        private boolean isUpperUnbounded(){return upperBound == null;}
    }
}

テストケース

import org.junit.Test;
import static org.junit.Assert.*;

public class UtilTest {
    @Test
    public void testPriod() {
        {
            assertFalse(Util.period(0, 10).laps(-10, -1));
            assertTrue(Util.period(0, 10).laps(-1, 0));
            assertTrue(Util.period(0, 10).laps(0, 5));
            assertTrue(Util.period(0, 10).laps(5, 10));
            assertTrue(Util.period(0, 10).laps(10, 15));
            assertFalse(Util.period(0, 10).laps(15, 25));
            
            assertTrue(Util.period(0, 10).laps(0, 10));
            assertTrue(Util.period(0, 10).laps(-10, 15));
            
            assertFalse(Util.period(0, 10).laps(null, -1));
            assertTrue(Util.period(0, 10).laps(null, 0));
            assertTrue(Util.period(0, 10).laps(null, 10));
            assertTrue(Util.period(0, 10).laps(null, 20));
            
            assertTrue(Util.period(0, 10).laps(-10, null));
            assertTrue(Util.period(0, 10).laps(0, null));
            assertTrue(Util.period(0, 10).laps(10, null));
            assertFalse(Util.period(0, 10).laps(20, null));
        }
        
        {
            assertFalse(Util.period(0, 0).laps(-10, -1));
            assertTrue(Util.period(0, 0).laps(-10, 0));
            assertTrue(Util.period(0, 0).laps(0, 10));
            assertFalse(Util.period(0, 0).laps(10, 20));
            
            assertTrue(Util.period(0, 0).laps(-10, null));
            assertTrue(Util.period(0, 0).laps(0, null));
            assertFalse(Util.period(0, 0).laps(10, null));
            assertFalse(Util.period(0, 0).laps(null, -10));
            assertTrue(Util.period(0, 0).laps(null, 0));
            assertTrue(Util.period(0, 0).laps(null, 10));
        }
        
        {
            assertFalse(Util.period(0, null).laps(-10, -1));
            assertTrue(Util.period(0, null).laps(-10, 0));
            assertTrue(Util.period(0, null).laps(0, 5));
            assertTrue(Util.period(0, null).laps(5, 10));
            
            assertFalse(Util.period(0, null).laps(null, -1));
            assertTrue(Util.period(0, null).laps(null, 0));
            assertTrue(Util.period(0, null).laps(null, 5));
            
            assertTrue(Util.period(0, null).laps(-10, null));
            assertTrue(Util.period(0, null).laps(0, null));
            assertTrue(Util.period(0, null).laps(5, null));
        }
        
        {
            assertTrue(Util.period(null, 10).laps(-10, 5));
            assertTrue(Util.period(null, 10).laps(5, 10));
            assertTrue(Util.period(null, 10).laps(10, 15));
            assertFalse(Util.period(null, 10).laps(15, 20));
            
            assertTrue(Util.period(null, 10).laps(null, 5));
            assertTrue(Util.period(null, 10).laps(null, 10));
            assertTrue(Util.period(null, 10).laps(null, 20));
            
            assertTrue(Util.period(null, 10).laps(5, null));
            assertTrue(Util.period(null, 10).laps(10, null));
            assertFalse(Util.period(null, 10).laps(15, null));
        }
    }
    
    @Test(expected=IllegalArgumentException.class)
    public void testPriodWithNullNullParameter() {
        Util.period(null, null);
    }
    
    @Test(expected=IllegalArgumentException.class)
    public void testPriodWithIllegalParameter() {
        Util.period(10, 2);
    }
}

蛇足

案外ややこしい。
適当に条件をいじってたら緑になったので、取り合えず良しとするw
内部クラスを使う理由は全くないです。