Tina Comston
Comp-111 Lab 2
Franklin University
Lab 2
Lab 2
This lab builds upon Lab 1.  It continues to have a Station class, but there have been some changes made to it.  Eventually there will be a Customer class - not just yet, but there will be eventually.  The customer will have a location that is represented by latitude and longitude.  The Station class in Lab 1 also had a location represented by latitude and longitude.  There really isn't a difference in the location, both have a latitude and longitude.  The distance is calculated in the same manner.  The only difference is that one is the location for a service station and one is a location for a customer.

So, since the instance fields are the same, the calculations are the same, the decision is made to pull out the location and make it a class all by itself.  That way, both the Station and Customer classes can take advantage of it.  If the location were to be left in both classes, then there would need to be get/set methods in both classes, the instance fields in both classes, and any other methods in both classes. In other words, duplication of effort. By pulling it out and making it its own class, all of these items need to be written just once.  Much more efficient!

Step 1 - read through the lab instructions in the Word document.  While the scenario presented is for fun, there is some key information that should be gleaned from the instructions.
  • Creating a separate Location class:
    • 2 instance fields
      • latitude
      • longitude
    • improved calculation for distance between 2 locations - Great Circle Distance Formula
      • previous calculation was in degrees, this will be in radians, so first have to convert the latitude and longitude (in degrees) to radians
        • Math.toRadians()
      • Great Circle Distance Formula is calculated as:
        • 3959.0 * arccos [ sin(lat1) * sin(lat2) + cos(lat1) * cos(lat2) * cos(lon2 - lon1)]
          • use Math.acos(), Math.cos(), Math.sin()
          • 3959.0 is the approximate radius of the earth in miles
  • Changes to the Station class:
    • instance variables:
      • remove the instance variables latitude and longitude and replace them with a Location object instance - default values of 0.0
      • fuel type - default value of 0
      • description - default value of "NO DESCRIPTION PROVIDED"
      • price per gallon - default value of 0
    • calcDistance will call the calcDistance method in the Location class
    • pricePerGallon method will have a new calculation
      • the conversion factor is no longer 1.41, but is instead:
        • factor / (coeff1 * t + coeff2 * (100 - t))
        • factor = 115400
        • coeff1 = 756.7
        • coeff2 = 1154
        • t = type of fuel
      • This conversion factor is multiplied by the price per gallon
Step 2 - now let's take a look at the program documentation.  The javadocs have already been created for you in this project.  Javadocs provide a description of each method including the purpose, what will be returned, if anything, and what explicit parameters are to be provided, if any.  This is really helpful information that you will definitely want to check out before you begin working on your test cases - which is what you should do BEFORE you begin working on the program itself.

To generate the documentation in BlueJ, select TOOLS, PROJECT DOCUMENTATION.  When you view the documentation, you will see a listing for both of the constructors and all of the methods.  If you click on a constructor or method name you will be taken to that particular constructor or method where you will be able to see a description of the method.  You will also be shown what will be returned, if anything, and what explicit parameters are expected if any.  A description of each is provided.  This is really useful information and can guide you as you develop your test cases and eventually start working on coding the object itself.

Step 3a   

Location Class
  • Start with the Location and testLocation classes.  The Location class does not have any dependencies.  What this means is that the Location class does not rely upon any other classes in order to be able to work.  The Station class, on the other hand, does.  Because of the modifications that have been made, the Station class now depends upon the Location class in order to be able to work.  Remember - longitude and latitude were replaced with a Location object.  As a result, the Station class cannot be successfully written and tested until the Location class is complete.  In object-oriented lingo this is a dependency.  The Station class depends upon the Location class.
Step 4a - develop the test cases for the Location class. Open up the javadocs for the Location class and open up the LocationTest class.  If you have a wide screen monitor, put the javadocs on one side and the LocationTest class code on the other so that they are side by side and you can see both at the same time.

Test the constructor
  • Viewing the javadocs tells you that there is one Location constructor.  This constructor is an explicit constructor.  It is expecting the latitude and longitude to be passed to the constructor as explicit parameters.
  • How should the constructor be tested?  
    • 1st - create a Location object and make sure that it actually exists.  This is done by making sure the newly created object is not equal to null.
    • 2nd - using the Location object you just created,  call the get methods for both the longitude and latitude and make sure that the value that is returned is what you are expecting.
      • These will be set equal to whatever values you pass in, so that is what should be returned.
  • If this method (it does not, but if it did) have a default constructor, this is how it would be tested:
    /**
     * Test object creation with default constructor.
     */
    public void testDefaultConstructor()
    {
        // create new instance & check that an object reference was returned
        Location location1 = new Location();
        assertNotNull(location1);
           
        // test for default values using accessors
        assertEquals(0.0, location1.getLatitude(), 0.01); 
        assertEquals(0.0, location1.getLongitude(), 0.01); 
    }
    • The 1st step from above is shown in green.  A new Location object is created using the default constructor (notice the empty parenthesis).  Then the assertNotNull method is called which will return true is the newly created Location object is not null, meaning it has been created and will return false if it is meaning that the object wasn't created and so has failed the test.
    • The 2nd step from above is shown in blue.  Because this is the default constructor, the expectation is that both the longitude and latitude have been set to a value of 0.0.  So, the assertEquals() method is called with the first value saying what is expected, 0.0, and the second value being what is actually there.  The second value is provided by calling the get method for each.  
      • But what is the 0.01?  That is the delta value.  Java takes double numbers out to insanely long decimal places.  In order for the numbers to match you would have to match all of the decimals places exactly.  That is extremely tedious testing.  So instead you can provide a delta value.  What is says is that as along as the number are within .01 of each other - it's good enough - let's consider them equal.
        • for example, let's says that you are expecting a value of 7.653, but when Java computed the value it came up with 7.6534683190555432.  If you were just to compare these two numbers Java would fail the test - not equal - because of all those decimal places.  If, however, you provided a delta value of .001, Java will only compare out to the 3rd decimal place and as long as those are equal - then the test passes, good enough.
  • To test the explicit constructor you will follow the same format as above:
    • Create the object, calling the explicit constructor (passing in values for latitude and longitude)
    • Assert that the object is not null (if it is null then the object creation was unsuccessful)
    • Check each of the instance variables to make sure they contain the expected value.
      • For this second constructor, two explicit parameters are passed as part of the object creation.  You'll want to make sure that the instance fields contain their values after the constructor creates the object:
        • verify that the latitude is equal to the value you provided 
        • verify that the longitude is equal to the value you provided 
        • These values can be anything.  You could provide 21.7 for the latitude and 45.6 for the longitude.  These might be a location in the middle of the ocean - but that's OK.  You are aren't checking for a land location, just that whatever values you pass in as explicit parameters are being stored in the instance variables.
Test the set methods
  • Testing the setLatitude() and setLongitude() methods will be pretty much the same as for the constructors above.  
    • Create a Location object.
    • Set the latitude/longitude to a new value.
    • Use the assertEquals to compare the value returned from the get method to what you are expecting.
Testing the calcDistance() method
  • The purpose of this method is to determine the distance in miles between two locations.  Remember a location contains both a latitude and a longitude.
  • Again, when testing this method the steps to take are the same as those for the test cases above.
    • Create a location object to be your initial location.
    • Create a second location object to be the new location.
    • Call the method.
    • Check the result to make sure it is equal to what you expect.
  • Several test situations have been provided for you.  You are to write one more test case.  To do so you must first determine the latitude and longitude for a central Ohio location.
    • I wanted to use the latitude/longitude for Plain City, Ohio, home of the Der Dutchman.  I googled latitude and longitude of Plain City Ohio and the following link came up:
      • http://www.travelmath.com/
      • On this site in the trip calculator you can set the GET for latitude/longitude.
      •  You can then type in the name of a town.  I typed in Plain City Ohio.
      • The latitude/longitude of Plain City Ohio was then displayed.
      • It was given as 40 degrees, 6' 27" N/83 degrees 16' 3" W
      • Since I'm really only interested in the degrees, I went with 40 for the latitude and -83 for the longitude.
      • So - I would create a new location object, perhaps with a name of plainCity and explicit parameters of 40.0 for the latitude and -83.0 for the longitude.
      • Next, I need to manually calculate the distance from location 1 - which has a latitude of 39.95 and a longitude of -82.1 to my new location of latitude 40.0 and longitude -83.0.
      • The formula for doing so was given in the word document instructions.  You can do this manually using a calculator, using excel, or any other tool you might prefer.  When you can calculated the value you can then complete the assertEquals() statement, following the format for the test cases already in place for this method.  **Remember, when doing your calculation, don't round.  The computer won't be rounding and if you round you'll find that your result does not match the result of the computer.
      • *****An excel spreadsheet has been provided for you to assist in developing your test cases for this method.  All you need to do is plug in the latitudes and longitudes and it will calculate the distance for you.
Testing the toString()
  • This code has been provided for you, but it's a good idea to review the code to ensure you understand how it is testing the method.
  • A toString() method will be added to the Location class to provide both the longitude and latitude in a particular format.  Viewing the documentation for the Location class tells us that the format is:
     Format of the string should be
           [latitude, longitude]
     Example: [39.9571, 82.81] 
  • So, the test case should make sure that value returned is indeed in this format, with a starting [, then the latitude, then a comma, then a space, then the longitude, and finally a closing ].
  • How can this be tested?
  • Follow the same format as above:
    • Create a Location object using the first explicit constructor (providing values for both the longitude and latitude)
    • Use the assertEquals to compare the output from the toString() method to what you are expecting.
    • For example:
      • If you creating your location object using the values of 14.25 for the latitude and 67.2 for the longitude then you would expect the output from the toString() method to be "[14.25, 67.2]".
Step 5a - code the Location class
  • Now that the test cases have been written, writing the Location class itself becomes much easier.  You are already familiar with the methods because you have reviewed the documentation and have written tests for them.
Instance Variables
  • These have already been coded for you.  There are 2 instance variables, latitude and longitude.  Both are of type double.
Constant Variables
  • One constant has been coded for you.  This contains the number 3959 which is the radius of the earth.  This constant will be used in the Great Circle Distance Calculation.
Constructor
  • The purpose of a constructor is to create the object by initializing the values of the instance variables.
  • You are to complete the code for the explicit constructor.  For this constructor explicit parameters have been passed which contain the values the latitude and longitude are to be set equal to.
get Methods
  • A get method is an accessor method.  It accesses the values of the instance variables and returns their value.
  • The code for the getLatitude() method is provided for you.  Use this as a guide for writing the code for the getLongitude() method.
calcDistance() Method
  • This method will calculate the distance, in miles, between 2 specified locations.  This is NOT the same as what you coded in Lab 1.  This has a new calculation.  The calculation is provided for you in the Word document as:

1.  First convert latitude and longitude (in degrees) to latitude and longitude in radians
NOTE: use the Math.toRadians method

2.  Use the formula
3959.0 * arccos[  sin(lat1) *  sin(lat2) + cos(lat1) * cos(lat2) * cos(lon2 - lon1) ]

Use Math.acos, Math.cos, Math.sin
3959.0 is the approximate radius of the earth in miles

  • The references to latitude 1 and longitude 1 above, refer to the instance fields latitude and longitude.  The references to latitude and longitude 2 above, refer to the Location that is passed in to the method.  (You will need to use the getLatitude() and getLongitude() methods to retrieve these values)
    • The first step to take - before you can even begin with the calculation, is to retrieve the latitude and longitude from the location that is passed in as an explicit parameter.  I would recommend putting these into variables named lat2 and lon2 just so you can keep them straight.  Here's how this might look for the latitude.
      • double lat2 = inLocation.getLatitude();
    • You're still not ready for the calculation - next you need to convert your latitudes and longitudes from degrees to radians.  This is done with the Math.toRadians() method.  Here's how this might look for the latitude 1.
      • double lat1 = Math.toRadians(this.latitude);
    • Now you're ready to write the formula above.
toString() Method
  • Produce a string value in the format that is specified in the method documentation.  This code has been written for you - but it's a good idea to review it to see how it is done.
After you get a clean compile, run your test cases against the code.  If a test case fails, take a look at both the test case and the class code.  Fix the problem.  Continue with this process until everything compiles cleanly and all test cases run successfully.

Step 3b   
Station Class
  • Now that the Location class is written and tested, you are ready to start working on the Station class.
Step 4b - develop the test cases for the Station class. Open up the javadocs for the Station class and open up the StationTest class.  If you have a wide screen monitor, put the javadocs on one side and the StationTest class code on the other so that they are side by side and you can see both at the same time.

Test the constructors
  • The process for testing a constructor is the same, regardless of whether it is an empty/default constructor or an explicit constructor.
  • Call the constructor you are testing to create the object.
  • Assert that the object is not null
  • Check each of the instance variables to make sure they are equal to what you are expecting.
  • The empty/default constructor test case has been written for you.
    • Take a moment to review how this is done.
  • You will be writing the test case for the explicit constructor.  The process is the same as above:
    • Call the explicit constructor, passing in values for latitude, longitude, description, price, and fuel type.  Check the javadocs for the order of the parameters and the data types that are expected.
    • Asset not null to make sure the object has been created successfully.
    • Call the get methods for each instance variable, making sure the value returned is what you specified in the constructor.
Test the set Methods
  • The format for testing a set method is:
    • Use a constructor, default or explicit, to create the object.
    • Call the set method to set the instance variable to a new value.
    • Call the get method to retrieve the value of the instance variable.
    • Compare what is returned from the get method against what you used when setting the value to make sure they match.
  • The code for testing the description and fuel type is provided for you.  Use these as a model when writing the test case for the setPricePerGallon().
Test the calcPricePerGGE() Method
  • The format for testing - really no matter what you are testing is:
    • Use a constructor, default or explicit, to create the object.
    • Call a set method if needed.
    • Call the method you are testing.
    • Call the get method if needed.
    • Compare what is returned against what you are expecting.
  • For this method, the price per gallon and fuel type values factor into the calculation of price per GGE.
  • One test case has been provided with a price per gallon of 2.13 and fuel type of 85.
  • Call the set methods to set a different price per gallon and fuel type.
  • Manually calculate what the price per GGE should be using paper/pencil, calculator, excel or any other tool you might prefer.
  • Compare what you expect against what is returned using an assert statement.
Test the distanceInMiles() Method
  • This is really tested in the same way as the location method done above.  The test cases for this method are provided for you.
Test the toString() Method
  • The test cases for this method are provided for you.  Please take a moment to review so that you understand how it is tested.
Step 5b - code the Station class
  • Now that the test cases have been written, writing the Station class itself becomes much easier.  You are already familiar with the methods because you have reviewed the documentation and have written tests for them.
  • Documentation - Take a moment, before you begin, to review the javadoc documentation for this class.  It can be viewed from BlueJ by,  Tools, Project Documentation.
    • This will show you the constructors and all of the methods.  From this documentation you will be able to determine if anything is returned and what explicit parameters are expected.
  • Coding - Look for the comments lines inserted within the methods that tell you that code should be inserted.  This is where you will be writing code.  If you see a method that does not have any comments saying you should code, then please do not modify the method.  It is correct as it is.
Instance Variables
  • These have already been coded for you.  There are 4 instance variables, description, pricePerGallon, fuelType, and a Location object.
Constant Variables
  • Three constants have been coded for you.  These are used in the calculation of the price per GGE.
Constructors
  • You will be writing the code for the default/empty constructor.  Remember the purpose of a constructor is to set the instance variables equal to default values.
    • the description should be set equal to "NO DESCRIPTION PROVIDED"
    • the price per gallon should be set equal to 0.0
    • the fuel type should be set equal to 0
    • location - this one is a bit different.  You're not going to set it equal to value, but rather create a location object passing in the default values.
      • If you take a look at the instance variable you'll see:
        • private Location stationLocation;
          • notice there's no equal sign.  What this means is that the object variable has been defined as holding data type Location - but that it hasn't yet been initialized.  It doesn't contain anything.  If you were to try and access the contents of this variable you would get an error.
          • In the constructor you need to complete the right hand side of the equals sign.  You need to initialize your object variable by calling the Location constructor.
          • = new Location(0.0, 0.0);
          • Now DO NOT do the following:
            • Location stationLocation = new Location(0.0, 0.0);
              • See the data type Location?  As soon as you put this in front of a variable you end up with a local variable that exists only within the method.
          • Instead do:
            • this.stationLocation = new Location(0.0, 0.0);
            • This says to take the existing object variable and just assign it to a new Location object.
    • Explicit Constructor - This has been coded for you.  Take a moment to see how this was done. 
get Methods()
  • The purpose of a get method is to return the value of an instance variable.
    • For the description, price per gallon, and fuel type it's very straight forward.
    • For the latitude and longitude - there's a slight twist.  You can't just return the latitude and longitude because they don't exist within the station class itself.  Instead you have to call the getLatitude and getLongitude methods from the Location class.  See the getLatitude() method for an example of how this is done.
set Methods()
  • The purpose of a set method is to change the value of an instance variable.  An explicit parameter is passed to the method containing the value that the instance variable should be set to.
    • The format will be:
      • this.instanceVariableName = passedInParameterName;
calcPricePerGGE() Method
  • Use the formula provided in the word document to complete this method.  Return the calculated value.
calcDistance() Method
  • The formula for calculating the distance between 2 locations was written in the Location class.  What you have to do here is call that method.  But.... the method is the location class is expecting a Location object to be passed to it as an explicit parameter.  If you take a look at the explicit parameters passed to this method, however, you have a latitude and longitude, not a Location class.  So, the first thing you need to do is create a temporary location object using the passed in latitude and longitude.
  • Then call the Location object method using your Location instance variable as the calling object and passing in your temporary location object as the explicit parameter.  Something like:
    • return stationLocation.calcDistance(tmpLocation);
toString Method
      • The code for this method has been completed for you.  Please take a moment to review.
      After you get a clean compile, run your test cases against the code.  If a test case fails, take a look at both the test case and the class code.  Fix the problem.  Continue with this process until everything compiles cleanly and all test cases run successfully.

      Step 6 - update the Readme.txt file.  Specific information is required to be entered into this file.  Make sure you view the instructions for this file so that you do not lose points for an incorrect format.

      Step 7 - use the check style feature in BlueJ.  This can be found under Tools, Checkstyle.  This tool will evaluate your program for style.  Each of the classes will be listed.  Clicking on a class name will reveal any style problems that have been found.  These would include such things as lines that are too long, incorrect indentation, missing periods, etc.  Correct all of these identified problems.  Recompile, retest.  ****It is really important that you do this.  For each check style error found, webcat will deduct 1 pt.  These can really add up and you don't want to lose points for things that can easily be corrected.

      Step 8 - submit to WebCat.  This is not a one time submission.  Webcat is a tool that can be used to ensure you receive the maximum number of points possible.  Submit, review the output.  Make corrections and submit again.  Continue this process until you have perfected your lab.