text:
<file_sep><?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<parent>
		<groupId>io.github.klsmith</groupId>
		<artifactId>todo</artifactId>
		<version>${revision}</version>
	</parent>

	<artifactId>todo-cli</artifactId>
	<packaging>jar</packaging>

	<build>
		<pluginManagement>
			<plugins>
				<!--This plugin's configuration is used to store Eclipse m2e settings
					only. It has no influence on the Maven build itself. -->
				<plugin>
					<groupId>org.eclipse.m2e</groupId>
					<artifactId>lifecycle-mapping</artifactId>
					<version>${lifecycle.mapping.version}</version>
					<configuration>
						<lifecycleMappingMetadata>
							<pluginExecutions>
								<pluginExecution>
									<pluginExecutionFilter>
										<groupId> org.codehaus.mojo</groupId>
										<artifactId> flatten-maven-plugin</artifactId>
										<versionRange>${flatten.version}</versionRange>
										<goals>
											<goal>flatten</goal>
										</goals>
									</pluginExecutionFilter>
									<action>
										<ignore></ignore>
									</action>
								</pluginExecution>
							</pluginExecutions>
						</lifecycleMappingMetadata>
					</configuration>
				</plugin>
			</plugins>
		</pluginManagement>

		<plugins>
			<plugin>
				<artifactId>maven-assembly-plugin</artifactId>
				<executions>
					<execution>
						<phase>package</phase>
						<goals>
							<goal>single</goal>
						</goals>
					</execution>
				</executions>
				<configuration>
					<finalName>todo-cli</finalName>
					<appendAssemblyId>false</appendAssemblyId>
					<archive>
						<manifest>
							<mainClass>io.github.klsmith.todo.cli.CommandLineApp</mainClass>
						</manifest>
					</archive>
					<descriptorRefs>
						<descriptorRef>jar-with-dependencies</descriptorRef>
					</descriptorRefs>
				</configuration>
			</plugin>
		</plugins>
	</build>

	<dependencies>
		<!-- Module Dependencies -->
		<dependency>
			<groupId>io.github.klsmith</groupId>
			<artifactId>todo-core</artifactId>
			<version>${project.version}</version>
		</dependency>

		<!-- Core Dependencies -->
		<dependency>
			<groupId>com.google.code.gson</groupId>
			<artifactId>gson</artifactId>
		</dependency>
	</dependencies>

</project>
<file_sep>package io.github.klsmith.util;

public final class StringUtil {

    private static final String REGEX_SPLIT_ON_SPACE_WITH_QUOTE_ESCAPES = "\"?( |$)(?=(([^\"]*\"){2})*[^\"]*$)\"?";

    private StringUtil() {}

    public static String[] splitOnSpaceWithQuoteEscapes(String string) {
        // if first token has quotes, remove the first one
        // this is a workaround for a quirk in the regex
        return string.replaceAll("^\"", "").split(REGEX_SPLIT_ON_SPACE_WITH_QUOTE_ESCAPES);
    }

}
<file_sep>package io.github.klsmith.todo.core.urgency;

import java.time.LocalDateTime;
import java.util.Objects;
import java.util.Optional;

public class Urgency implements Comparable<Urgency> {

	private final UrgencyLevel level;
	private final LocalDateTime dateTime;

	/**
	 * Only for use by subclasses and {@link UrgencyFactory}.
	 */
	protected Urgency(UrgencyLevel level, LocalDateTime date) {
		this.level = level;
		this.dateTime = date;
		validate();
	}

	private void validate() {
		if (null == level) {
			throw new InvalidUrgencyException("Cannot have a null urgency level.");
		}
		if (UrgencyLevel.DATE == level && null == dateTime) {
			throw new InvalidUrgencyException("Cannot have null dateTime on DATE level urgency.");
		}
		if ((UrgencyLevel.ASAP == level || UrgencyLevel.WHENEVER == level)
				&& null != dateTime) {
			throw new InvalidUrgencyException(
					String.format("Cannot have a dateTime on non-DATE level urgency %s.", level));
		}
	}

	public Optional<LocalDateTime> getDate() {
		return Optional.ofNullable(dateTime);
	}

	public UrgencyLevel getLevel() {
		return level;
	}

	@Override
	public int hashCode() {
		return Objects.hash(level, dateTime);
	}

	@Override
	public boolean equals(Object obj) {
		if (obj instanceof Urgency) {
			final Urgency other = (Urgency) obj;
			return level == other.level
					&& Objects.equals(dateTime, other.dateTime);
		}
		return false;
	}

	@Override
	public int compareTo(Urgency other) {
		if (UrgencyLevel.DATE == level &&
				UrgencyLevel.DATE == other.level) {
			return dateTime.compareTo(other.dateTime);
		}
		return level.compareTo(other.level);
	}

	@Override
	public String toString() {
		return String.format("Urgency(%s, %s)", level, dateTime);
	}

	public String getDisplayString() {
		if (UrgencyLevel.DATE == level) {
			return dateTime.toString();
		}
		return level.toString();
	}

}
<file_sep>#!/usr/bin/env bash
./todo-cli/install
./todo-web/install<file_sep>package io.github.klsmith.todo.core.urgency;

public enum UrgencyLevel {

    // order matters for sorting
    ASAP, DATE, WHENEVER;

}
<file_sep>package io.github.klsmith.todo.core.urgency;

public class InvalidUrgencyException extends RuntimeException {

    public InvalidUrgencyException(String message) {
        super(message);
    }

}
<file_sep>package io.github.klsmith.todo.cli;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.lang.reflect.Type;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;

import io.github.klsmith.todo.core.task.Task;
import io.github.klsmith.todo.core.task.TaskRepository;

public class WebServiceTaskRepository implements TaskRepository {

	private static final int TIMEOUT = 15 * 1000; // 15 seconds
//    private static final String BASE_URI = "http://localhost:4564/api/";

	private final Gson gson;
	private final String baseApiUri;

	public WebServiceTaskRepository(String baseApiUri) {
		gson = new GsonBuilder().setPrettyPrinting().create();
		this.baseApiUri = baseApiUri;
	}

	@Override
	public void add(Task task) {
		try {
			final URL url = new URL(baseApiUri + "task");
			final HttpURLConnection connection = (HttpURLConnection) url.openConnection();
			connection.setRequestMethod("POST");
			connection.setRequestProperty("Content-Type", "application/json");
			final String json = gson.toJson(task);
			connection.setDoOutput(true);
			try (final OutputStream out = connection.getOutputStream()) {
				out.write(json.getBytes(StandardCharsets.UTF_8));
			}
			connection.setReadTimeout(TIMEOUT);
			connection.connect();
			final int code = connection.getResponseCode();
			if (200 != code) {
				throw new RuntimeException(String.valueOf(code) + ": " + connection.getResponseMessage());
			}
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}

	@Override
	public List<Task> getAll() {
		final List<Task> results = new ArrayList<>();
		try {
			final URL url = new URL(baseApiUri + "task");
			final HttpURLConnection connection = (HttpURLConnection) url.openConnection();
			connection.setRequestMethod("GET");
			connection.setRequestProperty("Content-Type", "application/json");
			connection.setReadTimeout(TIMEOUT);
			connection.connect();
			final int code = connection.getResponseCode();
			if (200 != code) {
				throw new RuntimeException(String.valueOf(code) + ": " + connection.getResponseMessage());
			}
			final StringBuilder jsonBuilder = new StringBuilder();
			try (BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
				String line = reader.readLine();
				while (null != line) {
					jsonBuilder.append(line).append("\n");
					line = reader.readLine();
				}
			}
			final String json = jsonBuilder.toString();
			final Type listType = new TypeToken<ArrayList<Task>>() {
			}.getType();
			try {
				final List<Task> parsedTasks = gson.fromJson(json.toString(), listType);
				results.addAll(parsedTasks);
			} catch (RuntimeException e) {
				throw new RuntimeException("Could not parse \"" + json + "\".", e);
			}
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
		return results;
	}

	@Override
	public void remove(Task task) {
		throw new UnsupportedOperationException("Whoops");
	}

	@Override
	public Task removeByListNumber(int listNumber) {
		Task deletedTask = null;
		try {
			final URL url = new URL(baseApiUri + "task/" + listNumber);
			final HttpURLConnection connection = (HttpURLConnection) url.openConnection();
			connection.setRequestMethod("DELETE");
			connection.setRequestProperty("Content-Type", "application/json");
			connection.setReadTimeout(TIMEOUT);
			connection.connect();
			final int code = connection.getResponseCode();
			if (200 != code) {
				throw new RuntimeException(String.valueOf(code) + ": " + connection.getResponseMessage());
			}
			final StringBuilder jsonBuilder = new StringBuilder();
			try (BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
				String line = reader.readLine();
				while (null != line) {
					jsonBuilder.append(line).append("\n");
					line = reader.readLine();
				}
			}
			final String json = jsonBuilder.toString();
			try {
				deletedTask = gson.fromJson(json.toString(), Task.class);
			} catch (RuntimeException e) {
				throw new RuntimeException("Could not parse \"" + json + "\".", e);
			}
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
		return deletedTask;
	}

	@Override
	public Task completeByListNumber(int listNumber) {
		Task completedTask = null;
		try {
			final URL url = new URL(baseApiUri + "task/" + listNumber + "/complete");
			final HttpURLConnection connection = (HttpURLConnection) url.openConnection();
			connection.setRequestMethod("POST");
			connection.setRequestProperty("Content-Type", "application/json");
			connection.setReadTimeout(TIMEOUT);
			connection.connect();
			final int code = connection.getResponseCode();
			if (200 != code) {
				throw new RuntimeException(String.valueOf(code) + ": " + connection.getResponseMessage());
			}
			final StringBuilder jsonBuilder = new StringBuilder();
			try (BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
				String line = reader.readLine();
				while (null != line) {
					jsonBuilder.append(line).append("\n");
					line = reader.readLine();
				}
			}
			final String json = jsonBuilder.toString();
			try {
				completedTask = gson.fromJson(json.toString(), Task.class);
			} catch (RuntimeException e) {
				throw new RuntimeException("Could not parse \"" + json + "\".", e);
			}
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
		return completedTask;
	}

}
<file_sep>package io.github.klsmith.todo.cli;

import java.util.Arrays;
import java.util.List;

public enum CommandType {

    ADD, LIST(""), REMOVE("rm"), COMPLETE, UNKNOWN;

    private final List<String> aliasList;

    private CommandType(String... aliasArray) {
        aliasList = Arrays.asList(aliasArray);
    }

    public static CommandType fromArgs(String... args) {
        final String commandString = args.length > 0 ? args[0] : "";
        if (null != commandString) {
            for (CommandType command : values()) {
                if (command.isCommandAlias(commandString)) {
                    return command;
                }
            }
        }
        return UNKNOWN;
    }

    public boolean isCommandAlias(String string) {
        if (this == UNKNOWN) {
            return false;
        }
        return name().equalsIgnoreCase(string)
                || aliasList.contains(string);
    }

}
<file_sep>#!/usr/bin/env bash
mvn -U clean package && (rm "${TODO_HOME}/todo-web.jar"; cp "todo-web/target/todo-web.jar" $TODO_HOME/)<file_sep>package io.github.klsmith.todo.core.task;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.junit.jupiter.api.Test;

class InMemoryTaskRepositoryTest implements TaskRepositoryTest {

    @Override
    public TaskRepository getTaskRepositoryImplementation() {
        return new InMemoryTaskRepository();
    }

    @Test
    void testTaskRepositoryStartsEmpty() {
        final InMemoryTaskRepository repo = new InMemoryTaskRepository();
        assertTrue(repo.getAll().isEmpty());
    }

    @Test
    void testCanBeInitialized() {
        final List<Task> initialList = Arrays.asList(
                TaskRepositoryTest.TASK_1,
                TaskRepositoryTest.TASK_2);
        final InMemoryTaskRepository repo = new InMemoryTaskRepository(initialList);
        assertEquals(initialList, repo.getAll());
    }

    @Test
    void testIntializationIsCopy() {
        final List<Task> initialList = new ArrayList<>();
        initialList.add(TaskRepositoryTest.TASK_1);
        initialList.add(TaskRepositoryTest.TASK_2);
        final InMemoryTaskRepository repo = new InMemoryTaskRepository(initialList);
        initialList.add(TaskRepositoryTest.TASK_3);
        assertNotEquals(initialList, repo.getAll());
    }

}
<file_sep>package io.github.klsmith.todo.core.task;

import java.util.ArrayList;
import java.util.List;

public class InMemoryTaskRepository implements TaskRepository {

    private final List<Task> list;

    public InMemoryTaskRepository() {
        list = new ArrayList<>();
    }

    public InMemoryTaskRepository(List<Task> existingData) {
        this();
        list.addAll(existingData);
    }

    @Override
    public void add(Task task) {
        list.add(task);
    }

    @Override
    public List<Task> getAll() {
        return new ArrayList<>(list);
    }

    @Override
    public void remove(Task task) {
        list.remove(task);
    }

    @Override
    public Task removeByListNumber(int listNumber) {
        final List<Task> list = getAll();
        final Task task = list.get(listNumber - 1);
        list.remove(task);
        return task;
    }

    @Override
    public Task completeByListNumber(int listNumber) {
        final List<Task> list = getAll();
        final Task task = list.get(listNumber - 1);
        final Task completedTask = new Task(
                task.getText(),
                true,
                task.getImportance(),
                task.getUrgency());
        list.set(listNumber - 1, completedTask);
        return completedTask;
    }

}
<file_sep>package io.github.klsmith.todo.cli;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import io.github.klsmith.todo.core.task.Task;
import io.github.klsmith.todo.core.task.TaskRepository;

public class Command {

	private final CommandType type;
	private final String[] tokens;

	public Command(String... args) {
		final CommandType temp = CommandType.fromArgs(args);
		if (CommandType.UNKNOWN == temp) {
			type = CommandType.ADD;
			tokens = args;
		} else if (args.length > 0) {
			type = temp;
			tokens = Arrays.copyOfRange(args, 1, args.length);
		} else {
			type = temp;
			tokens = new String[] {};
		}
	}

	public CommandType getType() {
		return type;
	}

	public Status execute() {
		final Status status;
		switch (type) {
		case ADD:
			status = add();
			break;
		case LIST:
			status = list();
			break;
		case REMOVE:
			status = remove();
			break;
		case COMPLETE:
			status = complete();
			break;
		default:
			status = badCommand();
			break;
		}
		return status;
	}

	private TaskRepository getRepository() {
		final CliConfig config = CliConfig.load();
		return new WebServiceTaskRepository(config.getBaseApiUri());
	}

	private Status add() {
		final TaskParser parser = new TaskParser();
		final Task task = parser.parse(tokens);
		getRepository().add(task);
		System.out.printf("Task Added: %s%n", task.getDisplayString());
		return Status.OK;
	}

	private Status list() {
		final List<Task> results = getRepository().getAll();
		Collections.sort(results);
		for (int i = 0; i < results.size(); i++) {
			final Task task = results.get(i);
			System.out.printf("%d. %s%n", i + 1, task.getDisplayString());
		}
		if (results.isEmpty()) {
			System.out.println("Your todo list is empty!");
		}
		return Status.OK;
	}

	private Status remove() {
		final int listNumber = Integer.parseInt(tokens[0]);
		final Task removedTask = getRepository().removeByListNumber(listNumber);
		System.out.printf("Task Removed: %s%n", removedTask.getDisplayString());
		return Status.OK;
	}

	private Status complete() {
		final int listNumber = Integer.parseInt(tokens[0]);
		final Task completedTask = getRepository().completeByListNumber(listNumber);
		System.out.printf("Task Completed: %s%n", completedTask.getDisplayString());
		return Status.OK;
	}

	private Status badCommand() {
		System.out.printf("Command \"%s\" not recognized.%n", tokens[0]);
		return Status.BAD_COMMAND;
	}

}
<file_sep>package io.github.klsmith.todo.cli;

public enum Status {

    OK, UNKNOWN_ERROR, BAD_COMMAND;

    public int code() {
        return ordinal();
    }

}
<file_sep>package io.github.klsmith.todo.core.task;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import org.junit.jupiter.api.Test;

import io.github.klsmith.todo.core.importance.Importance;
import io.github.klsmith.todo.core.urgency.Urgency;
import io.github.klsmith.todo.core.urgency.UrgencyFactory;

class TaskTest {

    private static final LocalDateTime TEST_DATE = LocalDateTime.of(2019, 9, 6, 10, 30);

    @Test
    void testConstructTask() {
        final String text = "TEST TEXT";
        final boolean complete = true;
        final Importance importance = Importance.NEED;
        final Urgency urgency = UrgencyFactory.asap();
        final Task task = new Task(text, complete, importance, urgency);
        assertEquals(text, task.getText());
        assertEquals(complete, task.isComplete());
        assertEquals(importance, task.getImportance());
        assertEquals(urgency, task.getUrgency());
    }

    @Test
    void testIdentityEquality() {
        final String text = "TEST TEXT";
        final boolean complete = true;
        final Importance importance = Importance.NEED;
        final Urgency urgency = UrgencyFactory.asap();
        final Task task = new Task(text, complete, importance, urgency);
        assertTrue(task.equals(task), "Identity equality failure.");
        assertEquals(0, task.compareTo(task), "Identity compareTo failure.");
    }

    @Test
    void testSimpleEquality() {
        final String text = "TEST TEXT";
        final boolean complete = true;
        final Importance importance = Importance.NEED;
        final Urgency urgency = UrgencyFactory.asap();
        final Task taskA = new Task(text, complete, importance, urgency);
        final Task taskB = new Task(text, complete, importance, urgency);
        assertEquals(taskA, taskB);
        assertEquals(taskB, taskA);
        assertEquals(taskA.hashCode(), taskB.hashCode());
        assertEquals(0, taskA.compareTo(taskB));
        assertEquals(0, taskB.compareTo(taskA));
    }

    @Test
    void testSimpleInequality() {
        final String text = "TEST TEXT";
        final boolean complete = true;
        final Importance importance = Importance.NEED;
        final Urgency urgency = UrgencyFactory.asap();
        final Task taskA = new Task(text.toUpperCase(), complete, importance, urgency);
        final Task taskB = new Task(text.toLowerCase(), complete, importance, urgency);
        assertNotEquals(taskA, taskB);
        assertNotEquals(taskB, taskA);
        assertNotEquals(taskA.hashCode(), taskB.hashCode());
        assertNotEquals(0, taskA.compareTo(taskB));
        assertNotEquals(0, taskB.compareTo(taskA));
    }

    @Test
    void testSortTask() {
        final List<Task> expected = Arrays.asList(
                newTestTask(Importance.NEED, UrgencyFactory.asap()),
                newTestTask(Importance.NEED, UrgencyFactory.fromDate(TEST_DATE)),
                newTestTask(Importance.NEED, UrgencyFactory.fromDate(TEST_DATE.plusDays(1))),
                newTestTask(Importance.NEED, UrgencyFactory.whenever()),
                newTestTask(Importance.NEED, UrgencyFactory.whenever()),
                newTestTask(Importance.WANT, UrgencyFactory.asap()),
                newTestTask(Importance.WANT, UrgencyFactory.asap()),
                newTestTask(Importance.WANT, UrgencyFactory.fromDate(TEST_DATE)),
                newTestTask(Importance.WANT, UrgencyFactory.fromDate(TEST_DATE.plusDays(1))),
                newTestTask(Importance.WANT, UrgencyFactory.whenever()),
                newTestTask(Importance.NONE, UrgencyFactory.asap()),
                newTestTask(Importance.NONE, UrgencyFactory.fromDate(TEST_DATE)),
                newTestTask(Importance.NONE, UrgencyFactory.fromDate(TEST_DATE)),
                newTestTask(Importance.NONE, UrgencyFactory.fromDate(TEST_DATE.plusDays(1))),
                newTestTask(Importance.NONE, UrgencyFactory.whenever()));
        final List<Task> actual = new ArrayList<>(expected);
        Collections.reverse(actual);
        Collections.sort(actual);
        assertEquals(expected, actual);
    }

    private static Task newTestTask(Importance importance, Urgency urgency) {
        return new Task("TEST TEXT", false, importance, urgency);
    }

}
<file_sep>#!/usr/bin/env bash
mvn -U clean package && (rm "${TODO_HOME}/todo-cli.jar"; cp "todo-cli/target/todo-cli.jar" $TODO_HOME/)
<file_sep>package io.github.klsmith.todo.core.task;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import org.junit.jupiter.api.Test;

import io.github.klsmith.todo.core.importance.Importance;
import io.github.klsmith.todo.core.urgency.UrgencyFactory;

public interface TaskRepositoryTest {

    static final Task TASK_1 = new Task("TASK 1", false, Importance.NEED, UrgencyFactory.asap());
    static final Task TASK_2 = new Task("TASK 2", false, Importance.WANT, UrgencyFactory.whenever());
    static final Task TASK_3 = new Task("TASK 3", false, Importance.NONE, UrgencyFactory.whenever());

    TaskRepository getTaskRepositoryImplementation();

    @Test
    default void testResultListDoesNotMutateRepository() {
        final TaskRepository repo = getTaskRepositoryImplementation();
        final List<Task> firstList = repo.getAll();
        firstList.add(TASK_1);
        final List<Task> secondList = repo.getAll();
        assertNotEquals(firstList, secondList);
    }

    @Test
    default void testSimpleAdd() {
        final TaskRepository repo = getTaskRepositoryImplementation();
        repo.add(TASK_1);
        repo.add(TASK_2);
        final List<Task> expected = Arrays.asList(TASK_1, TASK_2);
        final List<Task> actual = repo.getAll();
        assertEquals(expected, actual);
    }

    @Test
    default void testSortingResultListDoesNotThrowException() {
        final TaskRepository repo = getTaskRepositoryImplementation();
        repo.add(TASK_1);
        repo.add(TASK_2);
        final List<Task> result = repo.getAll();
        Collections.sort(result);
        // verify exception is not thrown
    }

}

languages:
Java
Shell
Maven POM

repo_language: Java

repo_name: klsmith/todo