Initial commit

This commit is contained in:
2021-01-07 17:30:11 +01:00
commit 664f034751
29 changed files with 1229 additions and 0 deletions

6
.gitignore vendored Normal file
View File

@@ -0,0 +1,6 @@
.gradle
.idea
build
gradle
gradlew
gradlew.bat

72
README.md Normal file
View File

@@ -0,0 +1,72 @@
<h1>ConsoleTwitter</h1>
Implementation of a console-based social networking application (similar to Twitter) satisfying the scenarios below.
<h2>Scenarios</h2>
Posting: Alice can publish messages to a personal timeline
```
> Alice -> I love the weather today
> Bob -> Damn! We lost!
> Bob -> Good game though.
```
Reading: Bob can view Alices timeline
```
> Alice
I love the weather today (5 minutes ago)
> Bob
Good game though. (1 minute ago)
Damn! We lost! (2 minutes ago)
```
Following: Charlie can subscribe to Alices and Bobs timelines, and view an aggregated list of all subscriptions
```
> Charlie -> I'm in New York today! Anyone want to have a coffee?
> Charlie follows Alice
> Charlie wall
Charlie - I'm in New York today! Anyone want to have a coffee? (2 seconds ago)
Alice - I love the weather today (5 minutes ago)
> Charlie follows Bob
> Charlie wall
Charlie - I'm in New York today! Anyone wants to have a coffee? (15 seconds ago)
Bob - Good game though. (1 minute ago)
Bob - Damn! We lost! (2 minutes ago)
Alice - I love the weather today (5 minutes ago)
```
<h2>Details</h2>
* The application uses the console for input and output.
* Users submit commands to the application.
* There are four commands. “posting”, “reading”, etc. are not part of the commands.
* Commands always start with the users name.
* posting: user name -> message
* reading: user name
* following: user name follows another user
* wall: user name wall
<h2>How to run the application</h2>
* Clone the repository.
* Enter repository folder.
* Run the app with:
`.\gradlew run -q --console=plain` in Windows or
`./gradlew run -q --console=plain` in Linux.
* Alternatively you can also run from within the IDE:
Load the class `com.lookiero.ConsoleTwitter` and run the `main()` function.
* To stop the app, `press Ctrl + C`
<h2>Tests</h2>
A series of tests have been added with the following coverage:
![](src/main/resources/coverage.png)
To run the tests, execute `.\gradlew test` (`./gradlew test` in Linux)
Report is generated in `.\consoletwitter\build\reports\tests\test\index.html`

21
build.gradle Normal file
View File

@@ -0,0 +1,21 @@
plugins {
id 'java'
id "application"
}
group = 'com.droideparanoico'
version = '0.0.1-SNAPSHOT'
mainClassName = 'com.droideparanoico.consoletwitter.ConsoleTwitter'
run{
standardInput = System.in
}
repositories {
mavenCentral()
}
dependencies {
testImplementation 'junit:junit:4.13.1'
testImplementation 'org.mockito:mockito-core:3.6.28'
}

View File

@@ -0,0 +1,33 @@
package com.droideparanoico.consoletwitter;
import java.util.Scanner;
import com.droideparanoico.consoletwitter.command.CommandInterpreter;
import com.droideparanoico.consoletwitter.repository.Repository;
import com.droideparanoico.consoletwitter.ui.ConsoleTwitterPrinter;
import com.droideparanoico.consoletwitter.ui.Printer;
import com.droideparanoico.consoletwitter.repository.UserRepository;
/**
* ConsoleTwitter - Main class.
*/
public class ConsoleTwitter {
private static final String WELCOME = "Welcome to Console Twitter. Please, enter a command:\n";
private static final String PROMPT = "> ";
private static final Scanner scanner = new Scanner(System.in);
@SuppressWarnings("InfiniteLoopStatement")
public static void main(String[] args) {
Repository userRepository = new UserRepository();
Printer printer = new ConsoleTwitterPrinter(System.out);
CommandInterpreter commandInterpreter = new CommandInterpreter(userRepository, printer);
System.out.print(WELCOME);
// Infinite loop to accept and display commands
while (true) {
System.out.print(PROMPT);
String input = scanner.nextLine();
commandInterpreter.executeCommand(input);
}
}
}

View File

@@ -0,0 +1,20 @@
package com.droideparanoico.consoletwitter.command;
public interface Command {
/**
* Executes the input command string
*
* @param commandLine
* Command string to execute
*/
void execute(String commandLine);
/**
* Checks if the given command is able to execute the given string
*
* @param input
* command string which is able to be executed with this command
* @return boolean
*/
boolean matches(String input);
}

View File

@@ -0,0 +1,35 @@
package com.droideparanoico.consoletwitter.command;
import java.util.ArrayList;
import java.util.List;
import com.droideparanoico.consoletwitter.repository.Repository;
import com.droideparanoico.consoletwitter.ui.Printer;
public class CommandInterpreter {
private final List<Command> commands = new ArrayList<>();
private final Command invalidCommand;
public CommandInterpreter(Repository userRepository, Printer printer) {
commands.add(new PostCommand(userRepository));
commands.add(new ReadCommand(userRepository, printer));
commands.add(new FollowCommand(userRepository));
commands.add(new WallCommand(userRepository, printer));
invalidCommand = new InvalidCommand(printer);
}
public void executeCommand(String commandLine) {
Command command = getCommand(commandLine);
command.execute(commandLine);
}
public Command getCommand(String commandLine) {
for (Command command : commands) {
if (command.matches(commandLine))
return command;
}
return invalidCommand;
}
}

View File

@@ -0,0 +1,36 @@
package com.droideparanoico.consoletwitter.command;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.droideparanoico.consoletwitter.domain.User;
import com.droideparanoico.consoletwitter.repository.Repository;
public class FollowCommand implements Command {
private static final Pattern REGEX = Pattern.compile("^(\\S+) follows (\\S+)$");
private final Repository repository;
public FollowCommand(Repository userRepository) {
this.repository = userRepository;
}
public void execute(String commandLine) {
Matcher matcher = REGEX.matcher(commandLine);
matcher.find();
String userName = matcher.group(1);
String userNameToFollow = matcher.group(2);
User currentUser = repository.getOrCreateUser(userName);
User userToFollow = repository.getOrCreateUser(userNameToFollow);
currentUser.addFollowing(userToFollow);
}
public boolean matches(String input) {
if (input != null && !input.isEmpty()) {
Matcher matcher = REGEX.matcher(input);
return matcher.find();
}
return false;
}
}

View File

@@ -0,0 +1,23 @@
package com.droideparanoico.consoletwitter.command;
import com.droideparanoico.consoletwitter.ui.Printer;
public class InvalidCommand implements Command {
private final Printer postDisplayer;
public InvalidCommand(Printer postDisplayer) {
this.postDisplayer = postDisplayer;
}
@Override
public void execute(String commandLine) {
postDisplayer.printMessage(String.format("Command: %s is invalid!", commandLine));
}
@Override
public boolean matches(String input) {
return false;
}
}

View File

@@ -0,0 +1,37 @@
package com.droideparanoico.consoletwitter.command;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.droideparanoico.consoletwitter.domain.User;
import com.droideparanoico.consoletwitter.repository.Repository;
public class PostCommand implements Command {
private static final Pattern REGEX = Pattern.compile("^(\\S+) -> (.+)$");
private final Repository userRepository;
public PostCommand(Repository userRepository) {
this.userRepository = userRepository;
}
public void execute(String commandLine) {
Matcher matcher = REGEX.matcher(commandLine);
matcher.find();
String userName = matcher.group(1);
String message = matcher.group(2);
User user = userRepository.getOrCreateUser(userName);
user.addPost(message);
}
public boolean matches(String input) {
if (input != null && !input.isEmpty()) {
Matcher matcher = REGEX.matcher(input);
return matcher.find();
}
return false;
}
}

View File

@@ -0,0 +1,43 @@
package com.droideparanoico.consoletwitter.command;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.droideparanoico.consoletwitter.domain.Message;
import com.droideparanoico.consoletwitter.domain.User;
import com.droideparanoico.consoletwitter.repository.Repository;
import com.droideparanoico.consoletwitter.ui.Printer;
public class ReadCommand implements Command {
private static final Pattern REGEX = Pattern.compile("^\\S+$");
private final Repository userRepository;
private final Printer postDisplayer;
public ReadCommand(Repository userRepository, Printer postDisplayer) {
this.userRepository = userRepository;
this.postDisplayer = postDisplayer;
}
@Override
public void execute(String commandLine) {
User user = userRepository.getOrCreateUser(commandLine.trim());
List<Message> messages = user.getPosts();
// Sort messages.
messages.sort((p1, p2) -> p2.getPublishDate().compareTo(p1.getPublishDate()));
for (Message message : messages) {
postDisplayer.printPostForUser(message);
}
}
@Override
public boolean matches(String input) {
if (input != null && !input.isEmpty()) {
Matcher matcher = REGEX.matcher(input);
return matcher.find();
}
return false;
}
}

View File

@@ -0,0 +1,53 @@
package com.droideparanoico.consoletwitter.command;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.droideparanoico.consoletwitter.domain.Message;
import com.droideparanoico.consoletwitter.domain.User;
import com.droideparanoico.consoletwitter.repository.Repository;
import com.droideparanoico.consoletwitter.ui.Printer;
public class WallCommand implements Command {
private static final Pattern REGEX = Pattern.compile("^(\\S+) wall$");
private final Repository userRepository;
private final Printer postDisplayer;
public WallCommand(Repository userRepository, Printer postDisplayer) {
this.userRepository = userRepository;
this.postDisplayer = postDisplayer;
}
@Override
public void execute(String commandLine) {
Matcher matcher = REGEX.matcher(commandLine);
matcher.find();
String userName = matcher.group(1);
User user = userRepository.getOrCreateUser(userName);
// Get user's messages.
List<Message> messages = new ArrayList<>(user.getPosts());
// Add following users post.
for (User following : user.getFollowingUsers()) {
messages.addAll(following.getPosts());
}
// Sort messages.
messages.sort((p1, p2) -> p2.getPublishDate().compareTo(p1.getPublishDate()));
for (Message message : messages) {
postDisplayer.printPostForWall(message);
}
}
@Override
public boolean matches(String input) {
if (input != null && !input.isEmpty()) {
Matcher matcher = REGEX.matcher(input);
return matcher.find();
}
return false;
}
}

View File

@@ -0,0 +1,46 @@
package com.droideparanoico.consoletwitter.domain;
import java.util.Date;
public class Message {
private String userName;
private String message;
private Date publishDate;
public Message(String userName, String message) {
this.userName = userName;
this.message = message;
this.publishDate = new Date();
}
public Message(String userName, String message, Date publishDate) {
this.userName = userName;
this.message = message;
this.publishDate = publishDate;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public Date getPublishDate() {
return publishDate;
}
public void setPublishDate(Date publishDate) {
this.publishDate = publishDate;
}
}

View File

@@ -0,0 +1,68 @@
package com.droideparanoico.consoletwitter.domain;
import java.util.ArrayList;
import java.util.List;
public class User {
private String name;
private List<Message> messages = new ArrayList<>();
private List<User> followingUsers = new ArrayList<>();
public User(String userName) {
this.name = userName;
}
public void addPost(String message) {
messages.add(new Message(name, message));
}
public void addFollowing(User user) {
if (!followingUsers.contains(user)) {
followingUsers.add(user);
}
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Message> getPosts() {
return messages;
}
public void setPosts(List<Message> messages) {
this.messages = messages;
}
public List<User> getFollowingUsers() {
return followingUsers;
}
public void setFollowingUsers(List<User> followingUsers) {
this.followingUsers = followingUsers;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
User other = (User) obj;
return name.equals(other.name);
}
}

View File

@@ -0,0 +1,16 @@
package com.droideparanoico.consoletwitter.repository;
import com.droideparanoico.consoletwitter.domain.User;
public interface Repository {
/**
* Recovers the user from the repository, if the user does not exist, the method creates it.
*
* @param userName
* The username.
* @return The requested user.
*
*/
User getOrCreateUser(String userName);
}

View File

@@ -0,0 +1,20 @@
package com.droideparanoico.consoletwitter.repository;
import java.util.HashMap;
import java.util.Map;
import com.droideparanoico.consoletwitter.domain.User;
public class UserRepository implements Repository {
private final Map<String, User> userMap = new HashMap<>();
public User getOrCreateUser(String userName) {
User user = userMap.get(userName);
if (user == null) {
user = new User(userName);
userMap.put(userName, user);
}
return user;
}
}

View File

@@ -0,0 +1,59 @@
package com.droideparanoico.consoletwitter.ui;
import java.io.PrintStream;
import java.util.concurrent.TimeUnit;
import com.droideparanoico.consoletwitter.domain.Message;
public class ConsoleTwitterPrinter implements Printer {
private static final String MESSAGE_FORMAT_FOR_WALL = "%s - %s %s";
private static final String MESSAGE_FORMAT_FOR_USER = "%s %s";
private final PrintStream printStream;
public ConsoleTwitterPrinter(PrintStream printStream) {
this.printStream = printStream;
}
@Override
public void printPostForWall(Message message) {
printStream.printf((MESSAGE_FORMAT_FOR_WALL) + "%n", message.getUserName(), message.getMessage(),
getTimeAgo(message.getPublishDate().getTime()));
}
@Override
public void printPostForUser(Message message) {
printStream.printf((MESSAGE_FORMAT_FOR_USER) + "%n", message.getMessage(),
getTimeAgo(message.getPublishDate().getTime()));
}
@Override
public void printMessage(String message) {
printStream.println(message);
}
private static String getTimeAgo(long publishDate) {
long now = System.currentTimeMillis();
long diff = now - publishDate;
long timeUnitDiff;
String timeUnit;
if (diff < TimeUnit.MINUTES.toMillis(1)) {
timeUnitDiff = TimeUnit.MILLISECONDS.toSeconds(diff);
timeUnit = "second";
} else if (diff < TimeUnit.HOURS.toMillis(1)) {
timeUnitDiff = TimeUnit.MILLISECONDS.toMinutes(diff);
timeUnit = "minute";
} else if (diff < TimeUnit.DAYS.toMillis(1)) {
timeUnitDiff = TimeUnit.MILLISECONDS.toHours(diff);
timeUnit = "hour";
} else {
timeUnitDiff = TimeUnit.MILLISECONDS.toDays(diff);
timeUnit = "day";
}
if (timeUnitDiff > 1) {
timeUnit = timeUnit + "s";
}
return String.format("(%d %s ago)", timeUnitDiff, timeUnit);
}
}

View File

@@ -0,0 +1,31 @@
package com.droideparanoico.consoletwitter.ui;
import com.droideparanoico.consoletwitter.domain.Message;
public interface Printer {
/**
* Print the message as it will display on the wall.
*
* @param message
* The message to be printed.
*/
void printPostForWall(Message message);
/**
* print the message as it will display on the user timeline.
*
* @param message
* The message to be printed.
*/
void printPostForUser(Message message);
/**
* Print the message.
*
* @param message
* The message to be printed.
*/
void printMessage(String message);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

View File

@@ -0,0 +1,22 @@
package com.droideparanoico.consoletwitter;
import com.droideparanoico.consoletwitter.command.*;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
import com.droideparanoico.consoletwitter.domain.MessageTest;
import com.droideparanoico.consoletwitter.domain.UserTest;
import com.droideparanoico.consoletwitter.repository.UserRepositoryTest;
import com.droideparanoico.consoletwitter.ui.ConsoleTwitterPrinterTest;
/**
* Unit tests for Console Twitter.
*/
@RunWith(Suite.class)
@SuiteClasses({ CommandInterpreterTest.class, FollowCommandTest.class, MessageCommandTest.class, ReadCommandTest.class,
WallCommandTest.class, MessageTest.class, UserTest.class, ConsoleTwitterPrinterTest.class,
UserRepositoryTest.class, InvalidCommandTest.class })
public class ConsoleTwitterTest {
}

View File

@@ -0,0 +1,74 @@
package com.droideparanoico.consoletwitter.command;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.io.PrintStream;
import com.droideparanoico.consoletwitter.repository.Repository;
import com.droideparanoico.consoletwitter.ui.ConsoleTwitterPrinter;
import com.droideparanoico.consoletwitter.ui.Printer;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import com.droideparanoico.consoletwitter.domain.User;
@RunWith(MockitoJUnitRunner.class)
public class CommandInterpreterTest {
private static final String USER = "David";
private static final String USER_2 = "Julia";
private static final String MESSAGE = "Happy new year!";
private static final String POST_COMMAND = USER + " -> " + MESSAGE;
private static final String FOLLOW_COMMAND = USER + " follows " + USER_2;
private static final String WALL_COMMAND = USER + " wall";
private CommandInterpreter commandInterpreter;
@Mock
private Repository userRepository;
private PrintStream printStream;
@Before
public void setUp() {
Printer printer = new ConsoleTwitterPrinter(printStream);
commandInterpreter = spy(new CommandInterpreter(userRepository, printer));
}
@Test
public void executePostCommandTest() {
User user = mock(User.class);
when(userRepository.getOrCreateUser(USER)).thenReturn(user);
commandInterpreter.executeCommand(POST_COMMAND);
verify(commandInterpreter).getCommand(POST_COMMAND);
}
@Test
public void getPostCommandTest() {
Command returnedCommand = commandInterpreter.getCommand(POST_COMMAND);
Assert.assertTrue(returnedCommand instanceof PostCommand);
}
@Test
public void getFollowCommandTest() {
Command returnedCommand = commandInterpreter.getCommand(FOLLOW_COMMAND);
Assert.assertTrue(returnedCommand instanceof FollowCommand);
}
@Test
public void getReadCommandTest() {
Command returnedCommand = commandInterpreter.getCommand(USER);
Assert.assertTrue(returnedCommand instanceof ReadCommand);
}
@Test
public void getWallCommandTest() {
Command returnedCommand = commandInterpreter.getCommand(WALL_COMMAND);
Assert.assertTrue(returnedCommand instanceof WallCommand);
}
}

View File

@@ -0,0 +1,65 @@
package com.droideparanoico.consoletwitter.command;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import com.droideparanoico.consoletwitter.repository.Repository;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import com.droideparanoico.consoletwitter.domain.User;
@RunWith(MockitoJUnitRunner.class)
public class FollowCommandTest {
private static final String USER_1 = "David";
private static final String USER_2 = "Julia";
private static final String COMMAND = USER_1 + " follows " + USER_2;
private FollowCommand command;
@Mock
private Repository userRepository;
@Before
public void setUp() {
command = new FollowCommand(userRepository);
}
@Test
public void testMatch() {
Assert.assertTrue(command.matches(COMMAND));
}
@Test
public void testMatchNull() {
Assert.assertFalse(command.matches(null));
}
@Test
public void testMatchEmptyl() {
Assert.assertFalse(command.matches(""));
}
@Test
public void testFollow() {
User user1 = spy(new User(USER_1));
User user2 = mock(User.class);
when(userRepository.getOrCreateUser(USER_1)).thenReturn(user1);
when(userRepository.getOrCreateUser(USER_2)).thenReturn(user2);
command.execute(COMMAND);
verify(userRepository).getOrCreateUser(USER_1);
verify(userRepository).getOrCreateUser(USER_2);
verify(user1).addFollowing(user2);
Assert.assertTrue(user1.getFollowingUsers().contains(user2));
}
}

View File

@@ -0,0 +1,53 @@
package com.droideparanoico.consoletwitter.command;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.nio.charset.StandardCharsets;
import com.droideparanoico.consoletwitter.ui.ConsoleTwitterPrinter;
import com.droideparanoico.consoletwitter.ui.Printer;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class InvalidCommandTest {
private static final String USER = "David cucu";
private InvalidCommand command;
private ByteArrayOutputStream baos;
@Before
public void setUp() {
baos = new ByteArrayOutputStream();
PrintStream printStream = new PrintStream(baos);
Printer printer = new ConsoleTwitterPrinter(printStream);
command = new InvalidCommand(printer);
}
@Test
public void testMatch() {
Assert.assertFalse(command.matches(USER));
}
@Test
public void testMatchNull() {
Assert.assertFalse(command.matches(null));
}
@Test
public void testMatchEmptyl() {
Assert.assertFalse(command.matches(""));
}
@Test
public void testRead() {
command.execute(USER);
String result = baos.toString(StandardCharsets.UTF_8);
String expectedResult = String.format("Command: %s is invalid!\r\n", USER);
Assert.assertEquals(expectedResult, result);
}
}

View File

@@ -0,0 +1,61 @@
package com.droideparanoico.consoletwitter.command;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import com.droideparanoico.consoletwitter.repository.Repository;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import com.droideparanoico.consoletwitter.domain.User;
@RunWith(MockitoJUnitRunner.class)
public class MessageCommandTest {
private static final String USER = "David";
private static final String MESSAGE = "Happy new year!";
private static final String COMMAND = USER + " -> " + MESSAGE;
private PostCommand command;
@Mock
private Repository userRepository;
@Before
public void setUp() {
command = new PostCommand(userRepository);
}
@Test
public void testMatch() {
Assert.assertTrue(command.matches(COMMAND));
}
@Test
public void testMatchNull() {
Assert.assertFalse(command.matches(null));
}
@Test
public void testMatchEmptyl() {
Assert.assertFalse(command.matches(""));
}
@Test
public void testPost() {
User user = mock(User.class);
when(userRepository.getOrCreateUser(USER)).thenReturn(user);
command.execute(COMMAND);
verify(userRepository).getOrCreateUser(USER);
verify(user).addPost(MESSAGE);
}
}

View File

@@ -0,0 +1,76 @@
package com.droideparanoico.consoletwitter.command;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Date;
import com.droideparanoico.consoletwitter.domain.Message;
import com.droideparanoico.consoletwitter.repository.Repository;
import com.droideparanoico.consoletwitter.ui.ConsoleTwitterPrinter;
import com.droideparanoico.consoletwitter.ui.Printer;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import com.droideparanoico.consoletwitter.domain.User;
@RunWith(MockitoJUnitRunner.class)
public class ReadCommandTest {
private static final String USER = "David";
private ReadCommand command;
@Mock
private Repository userRepository;
private ByteArrayOutputStream baos;
@Before
public void setUp() {
baos = new ByteArrayOutputStream();
PrintStream printStream = new PrintStream(baos);
Printer printer = new ConsoleTwitterPrinter(printStream);
command = new ReadCommand(userRepository, printer);
}
@Test
public void testMatch() {
Assert.assertTrue(command.matches(USER));
}
@Test
public void testMatchNull() {
Assert.assertFalse(command.matches(null));
}
@Test
public void testMatchEmptyl() {
Assert.assertFalse(command.matches(""));
}
@Test
public void testRead() {
User user = spy(new User(USER));
user.setPosts(Arrays.asList(new Message(USER, "Happy new year!", new Date(
System.currentTimeMillis() - 5 * 1000L)),
new Message(USER, "Best wishes to everyone", new Date(System.currentTimeMillis() - 10 * 1000L))));
when(userRepository.getOrCreateUser(USER)).thenReturn(user);
command.execute(USER);
verify(userRepository).getOrCreateUser(USER);
String result = baos.toString(StandardCharsets.UTF_8);
String expectedResult = "Happy new year! (5 seconds ago)\r\nBest wishes to everyone (10 seconds ago)\r\n";
Assert.assertEquals(expectedResult, result);
}
}

View File

@@ -0,0 +1,87 @@
package com.droideparanoico.consoletwitter.command;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import com.droideparanoico.consoletwitter.domain.Message;
import com.droideparanoico.consoletwitter.repository.Repository;
import com.droideparanoico.consoletwitter.ui.ConsoleTwitterPrinter;
import com.droideparanoico.consoletwitter.ui.Printer;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import com.droideparanoico.consoletwitter.domain.User;
@RunWith(MockitoJUnitRunner.class)
public class WallCommandTest {
private static final String USER = "David";
private static final String USER_2 = "Julia";
private static final String COMMAND = USER + " wall";
private WallCommand command;
@Mock
private Repository userRepository;
private ByteArrayOutputStream baos;
@Before
public void setUp() {
baos = new ByteArrayOutputStream();
PrintStream printStream = new PrintStream(baos);
Printer printer = new ConsoleTwitterPrinter(printStream);
command = new WallCommand(userRepository, printer);
}
@Test
public void testMatch() {
Assert.assertTrue(command.matches(COMMAND));
}
@Test
public void testMatchNull() {
Assert.assertFalse(command.matches(null));
}
@Test
public void testMatchEmpty() {
Assert.assertFalse(command.matches(""));
}
@Test
public void testRead() {
User user = spy(new User(USER));
user.setPosts(Arrays.asList(new Message(USER, "Happy new year!", new Date(
System.currentTimeMillis() - 5 * 1000L)),
new Message(USER, "Best wishes to everyone", new Date(System.currentTimeMillis() - 20 * 1000L))));
User user2 = spy(new User(USER_2));
user2.setPosts(Collections.singletonList(new Message(USER_2, "Time to get cozy", new Date(System.currentTimeMillis() - 10 * 1000L))));
user.addFollowing(user2);
when(userRepository.getOrCreateUser(USER)).thenReturn(user);
command.execute(COMMAND);
verify(userRepository).getOrCreateUser(USER);
verify(user).getPosts();
verify(user).getFollowingUsers();
verify(user2).getPosts();
String result = baos.toString(StandardCharsets.UTF_8);
String expectedResult = "David - Happy new year! (5 seconds ago)\r\nJulia - Time to get cozy (10 seconds ago)\r\nDavid - Best wishes to everyone (20 seconds ago)\r\n";
Assert.assertEquals(expectedResult, result);
}
}

View File

@@ -0,0 +1,19 @@
package com.droideparanoico.consoletwitter.domain;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class MessageTest {
@Test
public void testPost() {
Message message = new Message("David", "Happy new year!");
Assert.assertEquals("Happy new year!", message.getMessage());
Assert.assertEquals("David", message.getUserName());
Assert.assertNotNull(message.getPublishDate());
}
}

View File

@@ -0,0 +1,48 @@
package com.droideparanoico.consoletwitter.domain;
import java.util.Collections;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class UserTest {
private User user;
@Before
public void setup() {
user = new User("David");
}
@Test
public void testPost() {
user.addPost("Happy new year!");
Assert.assertEquals(1, user.getPosts().size());
Assert.assertEquals("Happy new year!", user.getPosts().get(0).getMessage());
Assert.assertEquals("David", user.getPosts().get(0).getUserName());
}
@Test
public void testFollowing() {
user.addFollowing(new User("Julia"));
Assert.assertEquals(1, user.getFollowingUsers().size());
Assert.assertEquals("Julia", user.getFollowingUsers().get(0).getName());
}
@Test
public void testUniqueFollowing() {
user.addFollowing(new User("Julia"));
user.addFollowing(new User("Julia"));
Assert.assertEquals(1, user.getFollowingUsers().size());
}
@Test
public void testSetFollowing() {
user.setFollowingUsers(Collections.singletonList(new User("Julia")));
Assert.assertEquals(1, user.getFollowingUsers().size());
}
}

View File

@@ -0,0 +1,32 @@
package com.droideparanoico.consoletwitter.repository;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import com.droideparanoico.consoletwitter.domain.User;
public class UserRepositoryTest {
private static final String USER = "David";
private UserRepository userRepository;
@Before
public void setUp() {
userRepository = new UserRepository();
}
@Test
public void testGetOrCreateUser() {
User user = userRepository.getOrCreateUser(USER);
Assert.assertNotNull(user);
Assert.assertEquals(USER, user.getName());
}
@Test
public void testGetExistingUser() {
User user = userRepository.getOrCreateUser(USER);
User existingUser = userRepository.getOrCreateUser(USER);
Assert.assertEquals(user, existingUser);
}
}

View File

@@ -0,0 +1,73 @@
package com.droideparanoico.consoletwitter.ui;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import com.droideparanoico.consoletwitter.domain.Message;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class ConsoleTwitterPrinterTest {
private ConsoleTwitterPrinter printer;
private ByteArrayOutputStream baos;
@Before
public void setUp() {
baos = new ByteArrayOutputStream();
PrintStream printStream = new PrintStream(baos);
printer = new ConsoleTwitterPrinter(printStream);
}
@Test
public void testDisplayPostForUserWithSeconds() {
Message message = new Message("David", "Happy new year!", new Date(System.currentTimeMillis() - 10 * 1000L));
printer.printPostForUser(message);
String expectedResult = "Happy new year! (10 seconds ago)\r\n";
Assert.assertEquals(expectedResult, baos.toString(StandardCharsets.UTF_8));
}
@Test
public void testDisplayPostForUserWithMinutes() {
Message message = new Message("David", "Happy new year!", new Date(System.currentTimeMillis() - 10 * 60 * 1000L));
printer.printPostForUser(message);
String expectedResult = "Happy new year! (10 minutes ago)\r\n";
Assert.assertEquals(expectedResult, baos.toString(StandardCharsets.UTF_8));
}
@Test
public void testDisplayPostForUserWithHours() {
Message message = new Message("David", "Happy new year!", new Date(System.currentTimeMillis() - 2 * 60 * 60 * 1000L));
printer.printPostForUser(message);
String expectedResult = "Happy new year! (2 hours ago)\r\n";
Assert.assertEquals(expectedResult, baos.toString(StandardCharsets.UTF_8));
}
@Test
public void testDisplayPostForUserWithDays() {
Message message = new Message("David", "Happy new year!", new Date(System.currentTimeMillis() - 24 * 60 * 60 * 1000L));
printer.printPostForUser(message);
String expectedResult = "Happy new year! (1 day ago)\r\n";
Assert.assertEquals(expectedResult, baos.toString(StandardCharsets.UTF_8));
}
@Test
public void testDisplayPostForWall() {
Message message = new Message("David", "Happy new year!", new Date(System.currentTimeMillis() - 10 * 1000L));
printer.printPostForWall(message);
String expectedResult = "David - Happy new year! (10 seconds ago)\r\n";
Assert.assertEquals(expectedResult, baos.toString(StandardCharsets.UTF_8));
}
@Test
public void testDisplayMessage() {
String message = "Hello!";
printer.printMessage(message);
Assert.assertEquals(message + "\r\n", baos.toString(StandardCharsets.UTF_8));
}
}