Exercises in this lecture   Go to the notes, in which this exercise belongs -- Keyboard shortcut: 'u'   Alphabetic index   Course home   

Exercise solution:
Unit test of struct Interval


There is an error in the OverlapWith method of struct Interval. The two cases other inside this and this inside other (see the trailing comment lines) have been switched.

The following version of Interval-test.cs reveals the error:

using System;
using NUnit.Framework;

[TestFixture]  
public class IntervalTestExtra{

  Interval iv_1, iv_2, iv_3, iv_4;

  [SetUp]   
  public void Init(){
     iv_1 = new Interval(3,8);
     iv_2 = new Interval(8,3);
     iv_3 = new Interval(3,3);
     iv_4 = Interval.MakeEmptyInterval(); 
  }

  // All tests proposed initially should be here.

  [Test]  
  public void IndexerTest1(){
    Assert.AreEqual(iv_1[0], 3, "Indexer of iv_1 - at index 0");
  }

  [Test]  
  public void IndexerTest2(){
    Assert.AreEqual(iv_1[iv_1.Length-1], 8, "Indexer of iv_1 - at index Length-1");
  }

  [Test]  
  public void IndexerTest3(){
    Assert.AreEqual(iv_2[0], 8, "Indexer of iv_2 - at index 0");
  }

  [Test]  
  public void IndexerTest4(){
    Assert.AreEqual(iv_2[iv_2.Length-1], 3, "Indexer of iv_2 - at index Length-1");
  }

  [Test]  
  public void IndexerTest5(){
    Assert.AreEqual(iv_3[0], 3, "Indexer of iv_3 - at index 0");
  }

  [Test]  
  public void IndexerTest6(){
    Assert.AreEqual(iv_3[iv_3.Length-1], 3, "Indexer of iv_3 - at index Length-1");
  }

  [Test, ExpectedException("System.IndexOutOfRangeException")]  
  public void IndexerTestEmpty(){
    int res = iv_4[0];
  }

  [Test, ExpectedException("System.IndexOutOfRangeException")]  
  public void IndexerRangeProblem_1(){
    int res = iv_1[6];
  }

  [Test, ExpectedException("System.IndexOutOfRangeException")]  
  public void IndexerRangeProblem_2(){
    int res = iv_1[-1];
  }

  // I have NOT included tests of <<, >>, *, -, !, and the conversion to an array.
  // Do it yourself!

  [Test]  
  public void OverlapTest1(){
    Interval iv_1 = new Interval(3,8),
             iv_2 = new Interval(3,8);

    Assert.AreEqual(iv_1.OverlapWith(iv_2).From, 3, "part 1", "Overlap: Indentical");
    Assert.AreEqual(iv_1.OverlapWith(iv_2).To, 8, "part 2", "Overlap: Indentical");
  }

  [Test]  
  public void OverlapTestIdentical(){
    Interval iv_1 = Interval.MakeEmptyInterval(), 
             iv_2 = Interval.MakeEmptyInterval();

    Assert.IsTrue(iv_1.OverlapWith(iv_2).Empty);
  }

  [Test]  
  public void OverlapTest_Empty_NonEmpty(){
    Interval iv_1 = Interval.MakeEmptyInterval(), 
             iv_2 = new Interval(3,8);

    Assert.IsTrue(iv_1.OverlapWith(iv_2).Empty);
  }

  [Test]  
  public void OverlapTest_NonEmpty_Empty(){
    Interval iv_1 = new Interval(3,8),
             iv_2 = Interval.MakeEmptyInterval();

    Assert.IsTrue(iv_1.OverlapWith(iv_2).Empty);
  }


  [Test]  
  public void OverlapTest_Disjoint_Left(){
    Interval iv_1 = new Interval(3,8),
             iv_2 = new Interval(9,13);

    Assert.IsTrue(iv_1.OverlapWith(iv_2).Empty);
  }

  [Test]  
  public void OverlapTest_Disjoint_Right(){
    Interval iv_1 = new Interval(3,8),
             iv_2 = new Interval(-3,0);

    Assert.IsTrue(iv_1.OverlapWith(iv_2).Empty);
  }

  [Test]  
  public void OverlapTest_Other_ContainedIn_This(){
    Interval iv_1 = new Interval(3,8),
             iv_2 = new Interval(4,7);

    Assert.AreEqual(iv_1.OverlapWith(iv_2).From, 4, "To");
    Assert.AreEqual(iv_1.OverlapWith(iv_2).To, 7, "From" );
  }

  [Test]  
  public void OverlapTest_This_ContainedIn_Other(){
    Interval iv_1 = new Interval(4,7),
             iv_2 = new Interval(3,8);

    Assert.AreEqual(iv_1.OverlapWith(iv_2).From, 4, "To");
    Assert.AreEqual(iv_1.OverlapWith(iv_2).To, 7, "From");
  }

  [Test]  
  public void OverlapTest_OverlapsAtLeft(){
    Interval iv_1 = new Interval(4,7),
             iv_2 = new Interval(2,5);

    Assert.AreEqual(iv_1.OverlapWith(iv_2).From, 4);
    Assert.AreEqual(iv_1.OverlapWith(iv_2).To, 5);
  }

  [Test]  
  public void OverlapTest_OverlapsAtRight(){
    Interval iv_1 = new Interval(4,7),
             iv_2 = new Interval(6,10);

    Assert.AreEqual(iv_1.OverlapWith(iv_2).From, 6);
    Assert.AreEqual(iv_1.OverlapWith(iv_2).To, 7);
  }

}

In the systematic tests shown above the test methods OverlapTest_This_ContainedIn_Other and OverlapTest_Other_ContainedIn_This both fail.

The above version of Interval-test.cs also shows the test of the indexer.

Here is the correct version of the method OverlapWith:

public Interval OverlapWith (Interval other){
    // Positively oriented intervals:
    Interval thisPI = (this.Orientation < 0) ? !this : this,
             otherPI = (other.Orientation < 0) ? !other : other,
             res;

    if (thisPI.Empty || otherPI.Empty)                                  // both empty
         res = MakeEmptyInterval();
    else if (thisPI.From > otherPI.To || thisPI.To < otherPI.From)      // disjoint
         res = MakeEmptyInterval();
    else if (thisPI.From < otherPI.From && otherPI.To < thisPI.To)      // other inside this
         res = otherPI;
    else if (otherPI.From <= thisPI.From && thisPI.To <= otherPI.To)    // this inside other
         res = thisPI;
    else if (thisPI.From <= otherPI.From && otherPI.From <= thisPI.To)  // this overlaps left border of other
         res = new Interval(otherPI.From, thisPI.To);
    else if (otherPI.From <= thisPI.From && thisPI.From <= otherPI.To)  // other overlaps left border of this
         res = new Interval(thisPI.From, otherPI.To);
    else throw new Exception("Should not happen");

    return (this.Orientation < 0) ? !res : res;
  }

With this version of OverlapWith all test are executed successfully.