Tina Comston
Comp-111 Lab 3
Franklin University
Lab 3
Lab 3
  • Instructions - posted on Piazza
  • Data Files - Posted on Piazza
  • Readme.txt
  • WebCat
***Do not modify the driver class.  This is simply there to provide you with some output - it is not part of the lab.  If webcat identifies any problems with the driver program - just ignore them.  I will adjust your score accordingly.  You can also opt to remove the driver class and not submit it to webcat.

***Do not modify the declaration - public - statement of any method.  These methods have been defined to webcat.  If you change the name or add/remove an explicit parameter, or modify the return type, webcat will reject your lab  entirely as it will not recognize the method.  This will result in a 0 score by webcat.  

This lab builds upon Lab 1 & 2. The Location class is no longer visible, but it's still there and you can still create a Location object and call it's associated methods.  It is included as an executable and is fully functional, it's just not visible.  You can, however refer back to Lab 2 and the documentation provided for Lab 2 if need be.

For this lab you are going to continue to work on the Station class.  Additional enhancements are being made to this class on the price per gallon calculation and also some tracking elements.

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.

Here are some key points that I pulled out of the documentation:

  • New calculation for the price per gallon
    • Different fuel types will be provided and the price per gallon varies based upon the fuel types
      • propane 
        • fuel type will equal "PROPANE"
        • BTUs per gallon = 83500, to be contains in final constant variable with name of PROPANE_BTPG
        • conversion factor = GASOLINE_BTPG / PROPANE_BTPG
      • biodiesel
        • fuel type will equal "BIODIESEL"
        • BTUs per gallon = 127250, to be contains in final constant variable with name of BIODIESEL_BTPG
        • conversion factor = GASOLINE_BTPG / BIODIESEL_BTPG
      • ethanol
        • fuel type will start with "E" with remaining portion being percentage, for example E80 would be 80% or .80
        • BTUs per gallon = 75670, to be contains in final constant variable with name of ETHANOL_BTPG
        • conversion factor = percentage * ETHANOL_BTPG + (1-percentage)*GASOLINE_BTPG
      • biobutanol
        • fuel type will start with "B" with remaining portion being percentage, for example B20 would be 20% or .20
        • BTUs per gallon = 104800, to be contains in final constant variable with name of BIOBUTANOL_BTPG
        • conversion factor = percentage * BIOBUTANOL_BTPG + (1-percentage)*GASOLINE_BTPG
    • The conversion factors above are then multiplied against the price per gallon to calculate the price.
  • Rating of the Stations
    • Each station can receive ratings ranging from 1 through 5. These are to be accumulated and then averaged.
    • Will need to make sure a rating has been received before an average can be calculated or a divide by 0 error will be generated.
  • Categories
    • Stations are categorized by fuel type and by rating.l
  • Output - a to string method is written to generate a string containing information on the station.

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 3
While it is tempting to work on this entire lab all at once, I would like to recommend that you break it into pieces.

First - work on the constructors and the set/get methods.  These are actually very similar to what you've done in Lab 2, so this should be very straight forward.  It is also good to point out that if the constructors and set/get methods are not working, the rest of the methods will not work.  So, get your foundation working first and then more on to the rest of the class.

Step 4a - develop the test cases for the constructors and set methods. 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 distanceInMiles() Method
  • This method is the same as what you had in Lab 2. The test cases have been provided for you.

Step 5a - 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.  In Lab 2 there were 4 instance variables, description, pricePerGallon, fuelType, and a Location object.  Notice that in Lab 3 there are 6.  Two new instance variables have been added - ratingsTotal and ratingsCount.  These will also need to be initialized in your constructors.
Constant Variables
  • The constants for the fuel type have been coded for you.  These are used in determining the type of fuel.  The constant for the gasoline BTPG has been coded for you.  You will need to code the constants for the BTPG of the other fuel types.  Refer to the Word document instructions for these values.  Note that there are some additional constants that contain the category types for the stations.
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
    • both the ratings total and the ratings count will 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;
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);
Step 6a - Complile both your Station and StationTest classes.  When they compile cleanly - no syntax errors, run your tests.  Do all of your test cases pass for the constructors and set methods?  If so you are ready to proceed on to the next portion of the code.  If not - then go back and review your logic and make corrections.  Do not proceed until these are working correctly as the remainder of your code cannot function without these being correct!

Step 4b - develop the test cases for the calcPricePerGGE method.

testCalcPricePerGGE()
  • The conversion factor will vary based upon the fuel type, so the first thing to do is to figure out what fuel type you currently have.  If you refer back to the Word document you will find that the fuel type instance variable will contain either:
    • PROPANE
    • BIODIESEL
    • E followed by a percentage for ETHANOL
    • B  followed by a percentage for BIOBUTANOL
  • You will need to develop test cases for each of the fuel types.
  • I created an excel spreadsheet, plugged in the BTPGs for each fuel type, created the formula based upon the Word document instructions, and computed the price per GGE.  
  • I made sure to include each fuel type and for the ethanol and biobutanol I include several different percentages, one that was 100, one that was 0 and several inbetween.
  • I entered these values for my test cases.
Step 5b - code the pricePerGGE method.

calcPricePerGGE()
  • The conversion factor will vary based upon the fuel type, so the first thing to do is to figure out what fuel type you currently have.  If you refer back to the Word document you will find that the fuel type instance variable will contain either:
    • PROPANE
    • BIODIESEL
    • E followed by a percentage for ETHANOL
    • B  followed by a percentage for BIOBUTANOL
  • The fuel type instance variable is data type string which means you cannot use the == operator for comparison, you must use the .equals() method.
  • One other thing to note - you're going to have to be careful when checking for your fuel type.  BIOBUTANOL will start with a B followed by a percentage, but BIODIESEL will also start with a B.  You need to make sure you are differentiating between these two fuel types.
  • The best way to is have an If/else if construct
    • create a local variable to hold your computed conversion factor
    • check first for propane
      • if it is, then move the propane BTPG value to the conversion factor
    • if it's not propane then check if it's biodiesel
      • if it is, then move the biodiesel BTPG value to the conversion factor
    • if it's not biodiesel, then check if it's ethanol
      • if it is - then you can to calculate the ethanol conversion factor
        • 1st - parse out the percentage.  You'll need to use the .substring() method to retrieve everything after the E.  Keep in mind that you can't assume there will be just 2 digits after the E, there could be 3 if it's 100% ethanol, so you cannot hardcode in an ending value.  Another thing to consider is that the value you end up with will be a string.  You can't multiply a string against a number.  You're going to have to convert your string value to a number value.
        • After you've obtained the percentage and it has been converted from a string to a number, you can then plug in your values to the formula in the Word document and determine the conversion factor.
    • if it's not ethanol, then check if it's biobutanol
      • Follow the same steps outlined for ethanol above
  • Now that you've figured out the conversion factor you're ready to determine the price per GGE.  It would be computed as:
    • price per gallon * (gasoline BTPG / convFactor)
    • Hmmm - what if your conversion factor is equal to 0 - that will end up with a divide by 0 error.  So, you first need to check your conversion factor.  If it is equal to 0, then return 0, otherwise calculate the price per GGE and return the value.
    • Hmmm again - make sure that you do not get caught by integer division!  Make sure that you conversion factor is a double value or that you case the result as double or you will lose your precision.
Step 6b - Complile both your Station and StationTest classes.  When they compile cleanly - no syntax errors, run your tests.  Is the test case for your price per GGE calculation passing along with all of the constructors and set methods?  If so you are ready to proceed on to the next portion of the code.  If not - then go back and review your logic and make corrections.  Do not proceed until these are working correctly!

Step 4c - develop the test cases for the rateStation and calcAvgRating methods.

testRateStation()
  • The purpose of this method is to record a rating for a station.  It will increment the number of ratings that have been received by 1 and add the rating to the rating total instance variable.
  • The test cases for this method have already been written for you.  Please take a moment to review.
testCalcRatingsAvg()
  • The purpose of this method is to compute the average rating for a station.  This is done by dividing the total ratings by the number of ratings received.
  • Several test cases are needed.
  • The test case that is provided is to test if there are no ratings.  This should return a -1.0.
  • Add a rating - then test to make sure the average returned is what you expect.
  • Add a second rating - test again.
  • Add 2 or 3 more and test again.
Step 5c - code the rateStation and calcRatingsAvg methods.

rateStation()
  • The purpose of this method is to record a rating for a station.  It will increment the number of ratings that have been received by 1 and add the rating to the rating total instance variable.
  • First check to make sure the rating is valid, valid ratings are 1 through 5 inclusive.  If a rating is invalid, do not do anything.
  • For valid ratings, add the rating to the ratingsTotal instance variable and increment the ratingsCount instance variable.
calcRatingsAvg()
  • The purpose of this method is to compute the average rating for a station.  This is done by dividing the total ratings by the number of ratings received.
  • First check to make sure the ratingsCount is > 0, if it is not return -1.0.  No ratings have been received.
  • If the count is greater than 0 then divide the ratingsTotal by the ratingsCount - but.....  both of these are integer values.  Integer division will result in the loss of the decimal places and as a result loss of precision.  One or the other must be converted to a double value or the result must be cast as double.
Step 6c - Complile both your Station and StationTest classes.  When they compile cleanly - no syntax errors, run your tests.  Is the test case for your rate station and calculate ratings average passing along with all of the previous test cases?  If so you are ready to proceed on to the next portion of the code.  If not - then go back and review your logic and make corrections.  Do not proceed until these are working correctly!
Step 4d - develop the test cases for the inCategory method.

testIsInCategory()
  • The purpose of this method is to determine if a fuel type is within a specific category.  There are 6 potential categories.
    • ANY - true should be returned regardless of the fuel type
    • ETH_REGULAR - true should be returned if the fuel type is ethanol and the percentage is 
    • ETH_LOW- true should be returned if the fuel type is ethanol and the percentage is 
    • ETH_HIGH - true should be returned if the fuel type is ethanol and the percentage is 
    • ETH_FLEX_FUEL - true should be returned if the fuel type is ethanol and the percentage is
    • HIGH_RATED - true should be return if the rating average for a station is 4 or greater 
  • Some of the test cases have been developed for you.  You must add additional test cases to test all of the categories.
Step 5d - code the rateStation and calcRatingsAvg methods.

isInCategory()
  • The purpose of this method is to determine if a fuel type is within a specific category.  There are 6 potential categories.
    • ANY - true should be returned regardless of the fuel type
    • ETH_REGULAR - true should be returned if the fuel type is ethanol and the percentage is 
    • ETH_LOW- true should be returned if the fuel type is ethanol and the percentage is 
    • ETH_HIGH - true should be returned if the fuel type is ethanol and the percentage is 
    • ETH_FLEX_FUEL - true should be returned if the fuel type is ethanol and the percentage is
    • HIGH_RATED - true should be return if the rating average for a station is 4 or greater 
  • This method will contain a bunch of IF statements.
  • First - check for the ANY category.  It doesn't matter the fuel type for this category so if it is the ANY category - return true.
  • Next work your way through the ethanol categories
    • The process for each of these is the same.
    • Is the category an ethanol category?
      • Is the fuel type ethanol?
        • Is the percentage within the range for the category?
          • return true
  • Last check for the rating
    • If the category is the high rated category, then call the method to calculate the rating and check to see if the value returned is > 4, if it is return true
  • last return false - if you made it this far, then none of your above conditions were met and false should be returned.
Step 6d - Complile both your Station and StationTest classes.  When they compile cleanly - no syntax errors, run your tests.  Is the test case for your is in category passing along with all of the previous test cases?  If so you are ready to proceed on to the next portion of the code.  If not - then go back and review your logic and make corrections.  Do not proceed until these are working correctly!


Step 4e - develop the test cases for the toString method.

testToString()
  • The purpose of this method is to provide an output string in a specified format.
  • The test cases have been developed for you.  Please review to ensure you understand the testing that is taking place.



First to write - the test case.  Looking at the javadocs, we can see that this method returns a value of type String and accepts no explicit parameters.  The format of the first line is to be:
description [latitude, longitude] price: $price
This is the same format we've had all along.  Refer back to your code from Lab 2 to see what you did and duplicate this here in both the test case and the method.  

The format of the second line is to be:  
Selling fuelType fuel
Where fuelType is to be replaced by the contained in the instance field.  This is a new line for this method.

The format of the third line is to be:
Rated avg (out of 4) based on count customer ratings
Where avg is to be replaced by the value returned from the calcRatingsAvg() method and count is taken from the ratingsCount instance variable.

An example of what this might look like altogether is provided in the javadocs.  In addition, there is a note at the end that says if there are no customer ratings (ratingsCount = 0), then the third line should read:
No customer ratings
That's a red flag for testing.  That means there are 2 situations for which you need to test.  The situation is when the ratingsCount is greater than 0 and the second is when the ratingsCount is equal to 0.

If you take a look at the toString test case, you'll see that the case when the ratingsCount is equal to 0 has already been coded for you.  What remains is for you to test when the ratingsCount is greater than 0.  The situation has already been set.  If you view the code directly following the assertEquals statements you'll see:
        station1.rateStation(1);
        station1.rateStation(4);
        station1.rateStation(2);
              
        result = station1.toString();
Three ratings have already been added to the object station1 for you and the toString() method has been called with the result put into the String variable result.  All that remains is for you to test the result variable to make sure it contains what you are expecting.  The first 2 lines should contain the same value as above - right?  The longitude, latitude, description, price, fuel type didn't change.  So you really don't need to retest those lines.  What did change was the rating, so you really only need to test the third line.
  • What are you expecting the count to be after these 4 lines execute?
  • What average are you expecting to be returned?  (1 + 4 + 2) / total count
Write a test statement that looks for the correct count and average, properly formatted as you are expecting line 3 to be.  (Don't forget to check for all spaces, etc.)

Compile. Correct syntax errors.

Step 5e - code the toString method

toString() Ok - test case is written, now to the actual method itself.  Remember, we've already done quite a bit of the legwork while writing our test cases.  We've read through the javadocs, we've determined what the output should look like.  We've also discovered a special case, that we need to display one thing if the ratingsCount is equal to 0 and something else if it is not.  Go ahead and write your code.  Don't forget the spaces between words and your variables.  Use an IF statement to check the ratingsCount, adding the appropriate statement if the count is equal to 0 or if not.

Step 6e - Complile both your Station and StationTest classes.  When they compile cleanly - no syntax errors, run your tests.  Is the test case for your to string passing along with all of the previous test cases?  If so you are ready to proceed on to the next portion of the code.  If not - then go back and review your logic and make corrections.  Do not proceed until these are working correctly!


Really - I cannot stress this enough.  Do not try to code the entire class/test cases at one time.  Please follow my guidance and break this down into components.  When you work on the entire thing at one time and you encounter an error - you will have no idea where this error is located.  Is it in the original constructor?  Is it in the set or get?  You'll have to review all of your code.  If, however, you've been working in pieces and testing each piece after it's completion, you'll know that when you encounter an error it must be associated with the code that you just wrote.  You've narrowed down the scope which makes debugging much easier.

Step 7 - 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 8 - 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 9 - 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.