Description:
Bob is a lackadaisical teenager. In conversation, his responses are very limited.
Bob answers 'Sure.' if you ask him a question.
He answers 'Whoa, chill out!' if you yell at him.
He says 'Fine. Be that way!' if you address him without actually saying anything.
He answers 'Whatever.' to anything else.
Code:
import java.util.Optional;
enum SentenceType {
Question, Yell, Silence, Misc
}
public class Bob {
public String hey(String sentence) {
String trimmedSentence = Optional.ofNullable(sentence).orElse("").trim();
SentenceType classifiedSentence = classify(trimmedSentence);
if (classifiedSentence == SentenceType.Silence) {
return "Fine. Be that way!";
} else if (classifiedSentence == SentenceType.Question) {
return "Sure.";
} else if (classifiedSentence == SentenceType.Yell) {
return "Whoa, chill out!";
}
return "Whatever.";
}
private SentenceType classify(String sentence) {
if (sentence.isEmpty()) {
return SentenceType.Silence;
} else if (isAllLettersUpperCase(sentence)) {
return SentenceType.Yell;
} else if (isQuestion(sentence)) {
return SentenceType.Question;
}
return SentenceType.Misc;
}
private boolean isAllLettersUpperCase(String sentence) {
char[] charArray = sentence.toCharArray();
boolean hasLetters = false;
for (char ch : charArray) {
if (Character.isLetter(ch)) {
hasLetters = true;
if (Character.isLowerCase(ch)) {
return false;
}
}
}
return hasLetters && true;
}
private boolean isQuestion(String sentence) {
return (sentence.charAt(sentence.length() - 1) == '?') ? true : false;
}
}
Test Suite:
import org.junit.Test;
import static org.junit.Assert.*;
public class BobTest {
private final Bob bob = new Bob();
@Test
public void saySomething() {
assertEquals(
"Whatever.",
bob.hey("Tom-ay-to, tom-aaaah-to.")
);
}
@Test
public void shouting() {
assertEquals(
"Whoa, chill out!",
bob.hey("WATCH OUT!")
);
}
@Test
public void askingAQuestion() {
assertEquals(
"Sure.",
bob.hey("Does this cryogenic chamber make me look fat?")
);
}
@Test
public void askingANumericQuestion() {
assertEquals(
"Sure.",
bob.hey("You are, what, like 15?")
);
}
@Test
public void talkingForcefully() {
assertEquals(
"Whatever.",
bob.hey("Let's go make out behind the gym!")
);
}
@Test
public void usingAcronymsInRegularSpeech() {
assertEquals(
"Whatever.", bob.hey("It's OK if you don't want to go to the DMV.")
);
}
@Test
public void forcefulQuestions() {
assertEquals(
"Whoa, chill out!", bob.hey("WHAT THE HELL WERE YOU THINKING?")
);
}
@Test
public void shoutingNumbers() {
assertEquals(
"Whoa, chill out!", bob.hey("1, 2, 3 GO!")
);
}
@Test
public void onlyNumbers() {
assertEquals(
"Whatever.", bob.hey("1, 2, 3")
);
}
@Test
public void questionWithOnlyNumbers() {
assertEquals(
"Sure.", bob.hey("4?")
);
}
@Test
public void shoutingWithSpecialCharacters() {
assertEquals(
"Whoa, chill out!", bob.hey("ZOMG THE %^*@#$(*^ ZOMBIES ARE COMING!!11!!1!")
);
}
@Test
public void shoutingWithUmlauts() {
assertEquals(
"Whoa, chill out!", bob.hey("\u00dcML\u00c4\u00dcTS!")
);
}
@Test
public void calmlySpeakingWithUmlauts() {
assertEquals(
"Whatever.", bob.hey("\u00dcML\u00e4\u00dcTS!")
);
}
@Test
public void shoutingWithNoExclamationMark() {
assertEquals(
"Whoa, chill out!", bob.hey("I HATE YOU")
);
}
@Test
public void statementContainingQuestionMark() {
assertEquals(
"Whatever.", bob.hey("Ending with ? means a question.")
);
}
@Test
public void prattlingOn() {
assertEquals(
"Sure.", bob.hey("Wait! Hang on. Are you going to be OK?")
);
}
@Test
public void silence() {
assertEquals(
"Fine. Be that way!", bob.hey("")
);
}
@Test
public void prolongedSilence() {
assertEquals(
"Fine. Be that way!", bob.hey(" ")
);
}
}
Question
- At first I was skeptical about the unicode issue but I think library handles the uppercase and lowercase unicode well.
- It took me much time to write so simple looking
isAllLettersUpperCase
I am still doubtful that I have written it well and it handles all corner cases, how to write such method with more confidence? - There is code smell in the order of method called i.e. between
isAllLettersUpperCase
andisQuestion
by changing the order I would break tests. Hopefully there is a scope of handling this better. - The overall idea was to reduce coupling as much as possible, hopefully I handled it fine to some extent by using enums.
PS: For more details refer here.
Character.isUpperCase()
takes a single character. \$\endgroup\$String.toUpperCase()
would work for his isAllLetterUpperCase() method. Or would it return different results than the current method? \$\endgroup\$