This is code for a class that takes available ingredients and returns left over ingredients after making a dish.
- Cesars: 2 carrot 4 ice burg 1 chicken 1 beans
- Russian: 2 carrots 2 beans 2 chicken
If carrot is not there - 1 bean or 2 iceberg can replace if beans is not there - 1 iceberg can replace if chicken is not there 2 carrots or 2 beans can replace.
GitHub has the full question.
package academic.cookSalad;
public enum Dish {
CEASERS,RUSSIAN;
}
package academic.cookSalad;
public class Status {
private Ingredients leftOverIngrediants;//Ingredients passed in minus what was used. Or same what was passed in case too few ingredients
private boolean success;//false if could not make else true
public Ingredients getLeftOverIngrediants() {
return leftOverIngrediants;
}
public void setLeftOverIngrediants(Ingredients leftOverIngrediants) {
this.leftOverIngrediants = leftOverIngrediants;
}
public boolean isSuccess() {
return success;
}
public void setSuccess(boolean success) {
this.success = success;
}
}
package academic.cookSalad;
public class Ingredients implements Cloneable {
private int carrotQty;
private int iceBergLettuceQty;
private int chickenQty;
private int beansQty;
public int getCarrots() {
return carrotQty;
}
public void setCarrots(int carrotQty) {
this.carrotQty = carrotQty;
}
public int getIceBergLettuce() {
return iceBergLettuceQty;
}
public void setIceBergLettuce(int iceBergLettuceQty) {
this.iceBergLettuceQty = iceBergLettuceQty;
}
public int getChickens() {
return chickenQty;
}
public void setChickens(int chickenQty) {
this.chickenQty = chickenQty;
}
public int getBeans() {
return beansQty;
}
public void setBeans(int beansQty) {
this.beansQty = beansQty;
}
public Object clone() throws CloneNotSupportedException{
return super.clone();
}
public boolean equalValues(Ingredients other){
return this.beansQty == other.beansQty &&
this.carrotQty == other.carrotQty && this.chickenQty == other.chickenQty
&& this.iceBergLettuceQty == other.iceBergLettuceQty;
}
}
package academic.cookSalad;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Cook {
private static final Logger logger = LoggerFactory.getLogger(Cook.class);
Status cookIt(Ingredients in, Dish what) {
logger.debug("v03");
Status sta = new Status();
sta.setLeftOverIngrediants(in);
Ingredients curr = null;
try {
curr = (Ingredients) in.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
logger.error("Clone did not work do a manual copy to curr ingredients TODO");
}
Ingredients req = new Ingredients();
/*
* Cesars: Russian: 2 carrot 2 carrots 4 ice burg 2 beans 1 chicken 2
* chicken 1 beans
*/
if (what == Dish.CEASERS) {
req.setCarrots(2);
req.setIceBergLettuce(4);
req.setChickens(1);
req.setBeans(1);
} else {
req.setCarrots(2);
req.setBeans(2);
req.setChickens(2);
// req.setIceBergLettuceQty(0);//Not required
}
processCarrrots(curr, req, sta);
if (sta.isSuccess()) {
processBeans(curr, req, sta);
if (sta.isSuccess()) {
processChickens(curr, req, sta);
if (sta.isSuccess()) {
processIceburg(curr, req, sta);
if (sta.isSuccess()) {
sta.setLeftOverIngrediants(curr);
}
}
}
}
return sta;
}
private void processChickens(Ingredients curr, Ingredients req, Status sta) {
for (int i = 0; i < req.getChickens(); i++) {
processOneChicken(curr, sta);
if (!sta.isSuccess()) {
if (curr.getBeans() > 1) {
// could have put a loop if more than 2
// don't need to check for success as we checked available
// quantity already
processOneBean(curr, sta);
processOneBean(curr, sta);
} else if (curr.getCarrots() > 1) {
processOneCarrot(curr, sta);
processOneCarrot(curr, sta);
} else {
sta.setSuccess(false);
return;
}
}
}
}
private void processCarrrots(Ingredients curr, Ingredients req, Status sta) {
for (int i = 0; i < req.getCarrots(); i++) {
processOneCarrot(curr, sta);
if (!sta.isSuccess()) {
// check if failed after every ingredient. Else some other
// ingredient might
// be there and we get wrong result in some cases.
// 1 bean or 2 ice
if (curr.getBeans() > 0) {
processOneBean(curr, sta);
} else if (curr.getIceBergLettuce() > 1) {
processOneIceburg(curr, sta);
processOneIceburg(curr, sta);
}
return;
}
}
}
private void processOneCarrot(Ingredients curr, Status sta) {
sta.setSuccess(false);
if (curr.getCarrots() > 0) {
curr.setCarrots(curr.getCarrots() - 1);
sta.setSuccess(true);
} else {
sta.setSuccess(false);
}
}
private void processIceburg(Ingredients curr, Ingredients req, Status sta) {
for (int i = 0; i < req.getIceBergLettuce(); i++) {
processOneIceburg(curr, sta);
if (!sta.isSuccess()) {
return;
}
}
}
private void processOneIceburg(Ingredients curr, Status sta) {
if (curr.getIceBergLettuce() > 0) {
curr.setIceBergLettuce(curr.getIceBergLettuce() - 1);
sta.setSuccess(true);
} else {
sta.setSuccess(false);
}
}
private void processBeans(Ingredients curr, Ingredients req, Status sta) {
for (int i = 0; i < req.getBeans(); i++) {
processOneBean(curr, sta);
if (!sta.isSuccess()) {
if (curr.getIceBergLettuce() > 0) {
processOneIceburg(curr, sta);
} else {
return;
}
}
}
}
private void processOneBean(Ingredients curr, Status sta) {
if (curr.getBeans() > 0) {
curr.setBeans(curr.getBeans() - 1);
sta.setSuccess(true);
} else {
sta.setSuccess(false);
}
}
private void processOneChicken(Ingredients curr, Status sta) {
if (curr.getChickens() > 0) {
curr.setChickens(curr.getChickens() - 1);
sta.setSuccess(true);
} else {
sta.setSuccess(false);
}
}
}
Data driven test code (junit or system integration or what to call this?):
package academic.cookSalad;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.s2n.ddt.util.DdtIoUtls;
import org.s2n.ddt.util.ExcelAccess;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Can use DdtUtils excel reader (which uses POI) to read an excel and run data cases
* More pain to make but once made can add a variety of test cases
* and validations per truth table at
* Not yet complete need to check impl code and test case data for accuracy.
* TODO
* @author tushar
*
*/
public class CookDataTest {
private static final Logger logger = LoggerFactory.getLogger(CookDataTest.class);
final static String SHT_NAME = "tests";
final String TRUTH_TABLE_XLS = "./src/test/resources/TruthTableCookIt.xlsx";
@Test
public void data(){
ExcelAccess xls = initExcelData();
/*
cook = new Cook();
in = new Ingredients();
in.setBeans(100);
in.setIceBergLettuce(100);
in.setChickens(100);
in.setCarrots(100);
Status st = cook.cookIt(in, Dish.CEASERS);
assertTrue("Enough ingredients ceasrers ", st.isSuccess());
assertEquals(1, 1);
*/
Cook cook = new Cook();
Ingredients in = new Ingredients();
Dish dish = null;
int r = 11;
int c = 0;
String typ = xls.getCellValue(SHT_NAME, r, c);
int cases = 0;
int pass = 0;
while(typ != null && typ.length() > 0){
cases++;
typ = typ.toLowerCase();
if(typ.equals("ceaser")){
dish = Dish.CEASERS;
}else{
dish = Dish.RUSSIAN;
}
in.setCarrots(getInt(xls, r, 1));
in.setChickens(getInt(xls, r, 2));
in.setBeans(getInt(xls, r, 3));
in.setIceBergLettuce(getInt(xls, r, 4));
Status sta = cook.cookIt(in, dish);
Status exp = parseExpected(xls, r);
Ingredients out = exp.getLeftOverIngrediants();
if(sta.isSuccess() == exp.isSuccess()){
if(in.equalValues(out)){
pass++;
}else{
CookTest.print("Expected", exp);
CookTest.print("Actual Status okay but left over ", sta);
}
}else{
CookTest.print("Expected", exp);
CookTest.print("Actual", sta);
}
r++;
typ = xls.getCellValue(SHT_NAME, r, c);
}
System.err.println("Done " + cases + " pass " + pass);
assertEquals("Total cases vs pass ", cases, pass);
}
private Status parseExpected(ExcelAccess xls, int r) {
Status exp = new Status();
Ingredients out = new Ingredients();
out.setCarrots(getInt(xls, r, 6));
out.setChickens(getInt(xls, r, 7));
out.setBeans(getInt(xls, r, 8));
out.setIceBergLettuce(getInt(xls, r, 9));
exp.setLeftOverIngrediants(out);
String sxp = xls.getCellValue(SHT_NAME, r, 10);
boolean expb = "true".equals(sxp);
exp.setSuccess(expb);
return exp;
}
private int getInt(ExcelAccess x, int r, int c){
String d = x.getCellValue(SHT_NAME, r, c);
if(d != null && d.length() > 0){
return Integer.parseInt(d);
}
return -1;
}
private ExcelAccess initExcelData(){
DdtIoUtls.printCurrentFolderName();
ExcelAccess xlsWk = new ExcelAccess();
// /u/w/w4moh/CookSalad/src/test/resources/TruthTableCookIt.xlsx
//final String full = "/u/w/w4moh/CookSalad/src/test/resources/TruthTableCookIt.xlsx";
xlsWk.openWorkBook(new java.io.File(TRUTH_TABLE_XLS));
String ss = xlsWk.getCellValue("Sheet1", 10, 3);
logger.debug("Loaded Excel truth table ");
System.out.println("Loaded excel value at 10,3 :" + ss + ". 2 :" + xlsWk.getCellValue("Sheet1", 9, 3) + ".");
return xlsWk;
}
}
Regular junit
package academic.cookSalad;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
/**
* Unit test for cook salads.
* A more modular approach would be to make a excel reader based impl
*/
public class CookTest
{
Cook cook;
Ingredients in;
@BeforeClass
public static void once(){
System.out.println("@BeforeClass Any set up once per test class");
}
/**
* Not neccessary but a nice way to initialize before every test
* */
@Before
public void setup(){
System.out.println("setup");
cook = new Cook();
in = new Ingredients();
in.setBeans(100);
in.setIceBergLettuce(100);
in.setChickens(100);
in.setCarrots(100);
}
@Test
public void cookCeasersWithEnoughIngre() {
Status st = cook.cookIt(in, Dish.CEASERS);
assertTrue("Enough ingredients ceasrers ", st.isSuccess());
assertEquals(1, 1);
}
/*
While debugging can quickly disable other tests by commenting the annotation.
So can focus on the problematic test.
*/
@Test
public void cookCeasersLess1Chicken() {
in.setChickens(1);
Status st = cook.cookIt(in, Dish.CEASERS);
assertTrue("Enough ingredients ceasrers ", st.isSuccess());
assertEquals(1, 1);
}
@Test
public void cookRussianLess1Chicken() {
in.setChickens(1);
Status st = cook.cookIt(in, Dish.RUSSIAN);
assertTrue("1 less chicken russian, enough carrots ", st.isSuccess());
assertEquals(1, 1);
print("less 1 chicken", st);
}
public static void print(String msg, Status st) {
System.out.println(msg);
System.out.println("[Success " + st.isSuccess());
Ingredients out = st.getLeftOverIngrediants();
System.out.println(", carrots " + out.getCarrots());
System.out.println(", chicken " + out.getChickens());
System.out.println(", beans " + out.getBeans());
System.out.println(", ice burg " + out.getIceBergLettuce());
System.out.println("]");
}
}
Xls data src/test/resources/TruthTableCookIt.xlsx