diff --git a/pom.xml b/pom.xml index 48a52b74..644a5637 100644 --- a/pom.xml +++ b/pom.xml @@ -140,7 +140,7 @@ - fi.helsinki.cs.tmc.cli.command.core.CommandAnnotationProcessor + fi.helsinki.cs.tmc.cli.core.CommandAnnotationProcessor true diff --git a/src/main/java/fi/helsinki/cs/tmc/cli/Application.java b/src/main/java/fi/helsinki/cs/tmc/cli/Application.java index 3093a098..6a49309e 100644 --- a/src/main/java/fi/helsinki/cs/tmc/cli/Application.java +++ b/src/main/java/fi/helsinki/cs/tmc/cli/Application.java @@ -1,13 +1,15 @@ package fi.helsinki.cs.tmc.cli; -import fi.helsinki.cs.tmc.cli.command.core.AbstractCommand; -import fi.helsinki.cs.tmc.cli.command.core.CommandFactory; +import fi.helsinki.cs.tmc.cli.core.AbstractCommand; +import fi.helsinki.cs.tmc.cli.core.CliContext; +import fi.helsinki.cs.tmc.cli.core.CommandFactory; import fi.helsinki.cs.tmc.cli.io.Color; +import fi.helsinki.cs.tmc.cli.io.ColorUtil; import fi.helsinki.cs.tmc.cli.io.EnvironmentUtil; import fi.helsinki.cs.tmc.cli.io.HelpGenerator; import fi.helsinki.cs.tmc.cli.io.Io; import fi.helsinki.cs.tmc.cli.io.ShutdownHandler; -import fi.helsinki.cs.tmc.cli.updater.TmcCliUpdater; +import fi.helsinki.cs.tmc.cli.updater.AutoUpdater; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.GnuParser; @@ -58,13 +60,13 @@ public Application(CliContext context) { } private boolean runCommand(String name, String[] args) { - AbstractCommand command = CommandFactory.createCommand(this.context, name); + AbstractCommand command = CommandFactory.createCommand(name); if (command == null) { io.println("Command " + name + " doesn't exist."); return false; } - command.execute(args, io); + command.execute(context, args); return true; } @@ -169,7 +171,7 @@ private boolean versionCheck() { public boolean runAutoUpdate() { Map properties = context.getProperties(); Date now = new Date(); - TmcCliUpdater update = TmcCliUpdater.createUpdater(io, + AutoUpdater update = AutoUpdater.createUpdater(io, EnvironmentUtil.getVersion(), EnvironmentUtil.isWindows()); boolean updated = update.run(); @@ -181,16 +183,16 @@ public boolean runAutoUpdate() { } //TODO rename this as getColorProperty and move it somewhere else - public Color.AnsiColor getColor(String propertyName) { + public Color getColor(String propertyName) { String propertyValue = context.getProperties().get(propertyName); - Color.AnsiColor color = Color.getColor(propertyValue); + Color color = ColorUtil.getColor(propertyValue); if (color == null) { switch (propertyName) { - case "progressbar-left": return Color.AnsiColor.ANSI_CYAN; - case "progressbar-right": return Color.AnsiColor.ANSI_CYAN; - case "testresults-left": return Color.AnsiColor.ANSI_GREEN; - case "testresults-right": return Color.AnsiColor.ANSI_RED; - default: return Color.AnsiColor.ANSI_NONE; + case "progressbar-left": return Color.CYAN; + case "progressbar-right": return Color.CYAN; + case "testresults-left": return Color.GREEN; + case "testresults-right": return Color.RED; + default: return Color.NONE; } } return color; diff --git a/src/main/java/fi/helsinki/cs/tmc/cli/backend/Account.java b/src/main/java/fi/helsinki/cs/tmc/cli/backend/Account.java new file mode 100644 index 00000000..b1810166 --- /dev/null +++ b/src/main/java/fi/helsinki/cs/tmc/cli/backend/Account.java @@ -0,0 +1,52 @@ +package fi.helsinki.cs.tmc.cli.backend; + +/** + * This object stores all login info. + */ +public class Account { + + static Account NULL_ACCOUNT = new Account(null, null, null); + + private String serverAddress; + private String username; + private String password; + + // for gson + public Account() { } + + public Account(String serverAddress, String username, String password) { + this.serverAddress = serverAddress; + this.username = username; + this.password = password; + } + + public String getServerAddress() { + return serverAddress; + } + + public String getPassword() { + return password; + } + + public String getUsername() { + return username; + } + + private static boolean stringEquals(String str1, String str2) { + return (str1 == null ? str2 == null : str1.equals(str2)); + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (!(obj instanceof Account)) { + return false; + } + Account another = (Account) obj; + return stringEquals(this.serverAddress, another.serverAddress) + && stringEquals(this.username, another.username) + && stringEquals(this.password, another.password); + } +} diff --git a/src/main/java/fi/helsinki/cs/tmc/cli/backend/AccountList.java b/src/main/java/fi/helsinki/cs/tmc/cli/backend/AccountList.java new file mode 100644 index 00000000..13a5ffd9 --- /dev/null +++ b/src/main/java/fi/helsinki/cs/tmc/cli/backend/AccountList.java @@ -0,0 +1,86 @@ +package fi.helsinki.cs.tmc.cli.backend; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +/** + * This is a class for storing all different accounts as a single array. + */ +public class AccountList implements Iterable { + + private List accountArray; + + public AccountList() { + this.accountArray = new ArrayList<>(); + } + + //TODO This should not be used + public Account getAccount() { + if (this.accountArray.size() > 0) { + // Get last used account by default + return this.accountArray.get(0); + } + return null; + } + + public Account getAccount(String username, String server) { + if (username == null || server == null) { + return getAccount(); + } + for (Account account : this.accountArray) { + if (account.getUsername().equals(username) + && account.getServerAddress().equals(server)) { + // Move account to index 0 so we can always use the last used account by default + this.accountArray.remove(account); + this.accountArray.add(0, account); + return account; + } + } + return null; + } + + public void addAccount(Account newSettings) { + for (Account account : this.accountArray) { + if (account.getUsername().equals(newSettings.getUsername()) + && account.getServerAddress().equals(newSettings.getServerAddress())) { + // Replace old account if username and server match + this.accountArray.remove(account); + break; + } + } + this.accountArray.add(0, newSettings); + } + + public void deleteAccount(String username, String server) { + Account remove = null; + for (Account account : this.accountArray) { + if (account.getUsername().equals(username) + && account.getServerAddress().equals(server)) { + remove = account; + break; + } + } + if (remove != null) { + this.accountArray.remove(remove); + } + } + + public void deleteAllAccounts() { + this.accountArray = new ArrayList<>(); + } + + public int getAccountCount() { + return this.accountArray.size(); + } + + public List getAccountList() { + return Collections.unmodifiableList(this.accountArray); + } + + @Override + public Iterator iterator() { + return getAccountList().iterator(); + } +} diff --git a/src/main/java/fi/helsinki/cs/tmc/cli/tmcstuff/CourseInfo.java b/src/main/java/fi/helsinki/cs/tmc/cli/backend/CourseInfo.java similarity index 90% rename from src/main/java/fi/helsinki/cs/tmc/cli/tmcstuff/CourseInfo.java rename to src/main/java/fi/helsinki/cs/tmc/cli/backend/CourseInfo.java index db74f38c..413470c8 100644 --- a/src/main/java/fi/helsinki/cs/tmc/cli/tmcstuff/CourseInfo.java +++ b/src/main/java/fi/helsinki/cs/tmc/cli/backend/CourseInfo.java @@ -1,6 +1,5 @@ -package fi.helsinki.cs.tmc.cli.tmcstuff; +package fi.helsinki.cs.tmc.cli.backend; -import fi.helsinki.cs.tmc.core.configuration.TmcSettings; import fi.helsinki.cs.tmc.core.domain.Course; import fi.helsinki.cs.tmc.core.domain.Exercise; @@ -19,12 +18,12 @@ public class CourseInfo { private List localCompletedExercises; private HashMap properties; - public CourseInfo(TmcSettings settings, Course course) { - this.username = settings.getUsername(); - this.serverAddress = settings.getServerAddress(); + public CourseInfo(Account account, Course course) { + this.username = account.getUsername(); + this.serverAddress = account.getServerAddress(); this.course = course; this.properties = new HashMap<>(); - this.localCompletedExercises = new ArrayList(); + this.localCompletedExercises = new ArrayList<>(); } public String getUsername() { @@ -47,7 +46,7 @@ public List getLocalCompletedExercises() { // Check for null pointer in case of old .tmc.json files // Remove this when we are sure nobody's using 0.5.1 anymore if (this.localCompletedExercises == null) { - this.localCompletedExercises = new ArrayList(); + this.localCompletedExercises = new ArrayList<>(); } return this.localCompletedExercises; } @@ -78,6 +77,7 @@ public List getExerciseNames() { return names; } + //TODO This is exactly same method as TmcUtil.findExercise(course, name) public Exercise getExercise(String name) { for (Exercise exercise : this.course.getExercises()) { if (exercise.getName().equals(name)) { diff --git a/src/main/java/fi/helsinki/cs/tmc/cli/tmcstuff/CourseInfoIo.java b/src/main/java/fi/helsinki/cs/tmc/cli/backend/CourseInfoIo.java similarity index 78% rename from src/main/java/fi/helsinki/cs/tmc/cli/tmcstuff/CourseInfoIo.java rename to src/main/java/fi/helsinki/cs/tmc/cli/backend/CourseInfoIo.java index 933ade75..cf3f2289 100644 --- a/src/main/java/fi/helsinki/cs/tmc/cli/tmcstuff/CourseInfoIo.java +++ b/src/main/java/fi/helsinki/cs/tmc/cli/backend/CourseInfoIo.java @@ -1,4 +1,6 @@ -package fi.helsinki.cs.tmc.cli.tmcstuff; +package fi.helsinki.cs.tmc.cli.backend; + +import fi.helsinki.cs.tmc.core.domain.Course; import com.google.gson.Gson; import org.slf4j.Logger; @@ -50,4 +52,14 @@ public static CourseInfo load(Path courseInfoFile) { } return gson.fromJson(reader, CourseInfo.class); } + + public static void createNewCourse(Course course, Account account, Path parentDir) { + Path configFile = parentDir + .resolve(course.getName()) + .resolve(CourseInfoIo.COURSE_CONFIG); + + CourseInfo info = new CourseInfo(account, course); + info.setExercises(course.getExercises()); + CourseInfoIo.save(info, configFile); + } } diff --git a/src/main/java/fi/helsinki/cs/tmc/cli/tmcstuff/Settings.java b/src/main/java/fi/helsinki/cs/tmc/cli/backend/Settings.java similarity index 56% rename from src/main/java/fi/helsinki/cs/tmc/cli/tmcstuff/Settings.java rename to src/main/java/fi/helsinki/cs/tmc/cli/backend/Settings.java index 3ca4f004..281e8996 100644 --- a/src/main/java/fi/helsinki/cs/tmc/cli/tmcstuff/Settings.java +++ b/src/main/java/fi/helsinki/cs/tmc/cli/backend/Settings.java @@ -1,6 +1,8 @@ -package fi.helsinki.cs.tmc.cli.tmcstuff; +package fi.helsinki.cs.tmc.cli.backend; import fi.helsinki.cs.tmc.cli.io.EnvironmentUtil; +import fi.helsinki.cs.tmc.cli.io.WorkDir; + import fi.helsinki.cs.tmc.core.configuration.TmcSettings; import fi.helsinki.cs.tmc.core.domain.Course; @@ -12,72 +14,57 @@ public class Settings implements TmcSettings { - private String serverAddress; - private String username; - private String password; + private WorkDir workDir; + private Account account; - private transient WorkDir workDir; + public Settings() { + this.account = Account.NULL_ACCOUNT; + } public Settings(String serverAddress, String username, String password) { - this.serverAddress = serverAddress; - this.username = username; - this.password = password; - } - - public Settings() { + this.account = new Account(serverAddress, username, password); } /** * This method is used for changing the main settings object. - * @param settings settings object where from the new values are copied + * @param account account that has the login info */ - public void set(Settings settings) { - this.serverAddress = settings.serverAddress; - this.username = settings.username; - this.password = settings.password; - } - - public void setWorkDir(WorkDir workDir) { - this.workDir = workDir; + public void setAccount(Account account) { + if (account == null) { + /* NULL_ACCOUNT is used so that the NullPointerException + * is not thrown in the getters. + */ + account = Account.NULL_ACCOUNT; + } + this.account = account; } - public static boolean stringEquals(String str1, String str2) { - return (str1 == null ? str2 == null : str1.equals(str2)); + public Account getAccount() { + return account; } - @Override - public boolean equals(Object obj) { - if (obj == null) { - return false; - } - if (!(obj instanceof Settings)) { - return false; - } - Settings another = (Settings)obj; - return stringEquals(this.serverAddress, another.serverAddress) - && stringEquals(this.username, another.username) - && stringEquals(this.password, another.password); + public void setWorkDir(WorkDir workDir) { + this.workDir = workDir; } @Override public String getServerAddress() { - return serverAddress; + return account.getServerAddress(); } @Override public String getPassword() { - return password; + return account.getPassword(); } @Override public String getUsername() { - return username; + return account.getUsername(); } @Override public boolean userDataExists() { - return this.username != null && this.password != null - && !this.username.isEmpty() && !this.password.isEmpty(); + return getUsername() != null && getPassword() != null; } @Override @@ -105,7 +92,7 @@ public String getFormattedUserData() { if (!userDataExists()) { return ""; } - return this.username + ":" + this.password; + return getUsername() + ":" + this.getPassword(); } @Override @@ -125,7 +112,7 @@ public SystemDefaultRoutePlanner proxy() { @Override public Path getConfigRoot() { - return SettingsIo.getDefaultConfigRoot(); + return SettingsIo.getConfigDirectory(); } @Override diff --git a/src/main/java/fi/helsinki/cs/tmc/cli/tmcstuff/SettingsIo.java b/src/main/java/fi/helsinki/cs/tmc/cli/backend/SettingsIo.java similarity index 69% rename from src/main/java/fi/helsinki/cs/tmc/cli/tmcstuff/SettingsIo.java rename to src/main/java/fi/helsinki/cs/tmc/cli/backend/SettingsIo.java index 983d9e32..08d73555 100644 --- a/src/main/java/fi/helsinki/cs/tmc/cli/tmcstuff/SettingsIo.java +++ b/src/main/java/fi/helsinki/cs/tmc/cli/backend/SettingsIo.java @@ -1,9 +1,8 @@ -package fi.helsinki.cs.tmc.cli.tmcstuff; +package fi.helsinki.cs.tmc.cli.backend; import fi.helsinki.cs.tmc.cli.io.EnvironmentUtil; import com.google.gson.Gson; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -14,7 +13,6 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.HashMap; -import java.util.List; /** * Reads and writes to config files on the system. @@ -22,11 +20,11 @@ public class SettingsIo { private static final Logger logger = LoggerFactory.getLogger(SettingsIo.class); - + // CONFIG_DIR is the sub-directory located within the system specific // configuration folder, ex. /home/user/.config/CONFIG_DIR/ public static final String CONFIG_DIR = "tmc-cli"; - + // ACCOUNTS_CONFIG is the _global_ configuration file containing all // user login information including usernames, passwords (in plain text) // and servers. Is located under CONFIG_DIR @@ -37,11 +35,66 @@ public class SettingsIo { // was last updated. Is located under CONFIG_DIR public static final String PROPERTIES_CONFIG = "properties.json"; + public static AccountList loadAccountList() { + return loadAccountList(getConfigDirectory()); + } + + public static AccountList loadAccountList(Path configRoot) { + Path file = getAccountsFile(configRoot); + if (!Files.exists(file)) { + return new AccountList(); + } + return getHolderFromJson(file); + } + + public static boolean saveAccountList(AccountList list) { + return saveAccountList(list, getConfigDirectory()); + } + + public static boolean saveAccountList(AccountList list, Path configRoot) { + Path file = getAccountsFile(configRoot); + return saveHolderToJson(list, file); + } + + public static boolean delete() { + Path file = getAccountsFile(getConfigDirectory()); + try { + Files.deleteIfExists(file); + } catch (IOException e) { + logger.error("Could not delete config file in " + file.toString(), e); + return false; + } + return true; + } + + public static HashMap loadProperties() { + return loadPropertiesFrom(getConfigDirectory()); + } + + public static HashMap loadPropertiesFrom(Path path) { + Path file = getPropertiesFile(path); + HashMap properties = getPropertiesFromJson(file); + if (properties != null) { + return properties; + } else { + return new HashMap<>(); + } + } + + public static boolean saveProperties(HashMap properties) { + return savePropertiesTo(properties, getConfigDirectory()); + } + + public static boolean savePropertiesTo(HashMap properties, Path path) { + Path file = getPropertiesFile(path); + return savePropertiesToJson(properties, file); + } + /** * Get the correct directory in which our config files go - * ie. /home/user/.config/tmc-cli/ + * ie /home/user/.config/tmc-cli/. */ - public static Path getDefaultConfigRoot() { + protected static Path getConfigDirectory() { Path configPath; if (EnvironmentUtil.isWindows()) { String appdata = System.getenv("APPDATA"); @@ -64,6 +117,7 @@ public static Path getDefaultConfigRoot() { return configPath.resolve(CONFIG_DIR); } + //TODO handle exceptions private static Path getAccountsFile(Path configRoot) { Path file = configRoot.resolve(ACCOUNTS_CONFIG); if (!Files.exists(configRoot)) { @@ -77,6 +131,7 @@ private static Path getAccountsFile(Path configRoot) { return file; } + //TODO handle exceptions private static Path getPropertiesFile(Path configRoot) { Path file = configRoot.resolve(PROPERTIES_CONFIG); if (!Files.exists(configRoot)) { @@ -90,56 +145,7 @@ private static Path getPropertiesFile(Path configRoot) { return file; } - public static Boolean save(Settings settings) { - return saveTo(settings, getDefaultConfigRoot()); - } - - public static Boolean saveTo(Settings settings, Path configRoot) { - Path file = getAccountsFile(configRoot); - SettingsHolder holder; - if (!Files.exists(file)) { - holder = new SettingsHolder(); - } else { - holder = getHolderFromJson(file); - } - holder.addSettings(settings); - return saveHolderToJson(holder, file); - } - - public static Settings load(String username, String server) { - return loadFrom(username, server, getDefaultConfigRoot()); - } - - public static Settings load() { - // Calling the method without parametres returns the last used settings - return load(null, null); - } - - public static Settings loadFrom(Path configRoot) { - return loadFrom(null, null, configRoot); - } - - public static Settings loadFrom(String username, String server, Path configRoot) { - Path file = getAccountsFile(configRoot); - if (!Files.exists(file)) { - return null; - } - SettingsHolder holder = getHolderFromJson(file); - Settings ret = holder.getSettings(username, server); - saveHolderToJson(holder, file); - return ret; - } - - public static List getSettingsList() { - Path file = getAccountsFile(getDefaultConfigRoot()); - if (!Files.exists(file)) { - return null; - } - SettingsHolder holder = getHolderFromJson(file); - return holder.getSettingsList(); - } - - private static SettingsHolder getHolderFromJson(Path file) { + private static AccountList getHolderFromJson(Path file) { Gson gson = new Gson(); Reader reader; try { @@ -148,16 +154,16 @@ private static SettingsHolder getHolderFromJson(Path file) { logger.error("Accounts file located, but failed to read from it", e); return null; } - return gson.fromJson(reader, SettingsHolder.class); + return gson.fromJson(reader, AccountList.class); } - private static Boolean saveHolderToJson(SettingsHolder holder, Path file) { + private static boolean saveHolderToJson(AccountList holder, Path file) { Gson gson = new Gson(); byte[] json = gson.toJson(holder).getBytes(); try { Files.write(file, json); } catch (IOException e) { - logger.error("Could not write settings to accounts file", e); + logger.error("Could not write account to accounts file", e); return false; } return true; @@ -177,7 +183,7 @@ private static HashMap getPropertiesFromJson(Path file) { return map; } - private static Boolean savePropertiesToJson(HashMap properties, Path file) { + private static boolean savePropertiesToJson(HashMap properties, Path file) { Gson gson = new Gson(); byte[] json = gson.toJson(properties).getBytes(); try { @@ -188,38 +194,4 @@ private static Boolean savePropertiesToJson(HashMap properties, } return true; } - - public static Boolean delete() { - Path file = getAccountsFile(getDefaultConfigRoot()); - try { - Files.deleteIfExists(file); - } catch (IOException e) { - logger.error("Could not delete config file in " + file.toString(), e); - return false; - } - return true; - } - - public static HashMap loadProperties() { - return loadPropertiesFrom(getDefaultConfigRoot()); - } - - public static HashMap loadPropertiesFrom(Path path) { - Path file = getPropertiesFile(path); - HashMap properties = getPropertiesFromJson(file); - if (properties != null) { - return properties; - } else { - return new HashMap<>(); - } - } - - public static Boolean saveProperties(HashMap properties) { - return savePropertiesTo(properties, getDefaultConfigRoot()); - } - - public static Boolean savePropertiesTo(HashMap properties, Path path) { - Path file = getPropertiesFile(path); - return savePropertiesToJson(properties, file); - } } diff --git a/src/main/java/fi/helsinki/cs/tmc/cli/tmcstuff/TmcUtil.java b/src/main/java/fi/helsinki/cs/tmc/cli/backend/TmcUtil.java similarity index 85% rename from src/main/java/fi/helsinki/cs/tmc/cli/tmcstuff/TmcUtil.java rename to src/main/java/fi/helsinki/cs/tmc/cli/backend/TmcUtil.java index 37f50b2b..474a8f15 100644 --- a/src/main/java/fi/helsinki/cs/tmc/cli/tmcstuff/TmcUtil.java +++ b/src/main/java/fi/helsinki/cs/tmc/cli/backend/TmcUtil.java @@ -1,7 +1,8 @@ -package fi.helsinki.cs.tmc.cli.tmcstuff; +package fi.helsinki.cs.tmc.cli.backend; -import fi.helsinki.cs.tmc.cli.CliContext; +import fi.helsinki.cs.tmc.cli.core.CliContext; import fi.helsinki.cs.tmc.cli.io.Io; + import fi.helsinki.cs.tmc.core.TmcCore; import fi.helsinki.cs.tmc.core.commands.GetUpdatableExercises.UpdateResult; import fi.helsinki.cs.tmc.core.domain.Course; @@ -17,6 +18,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.net.InetAddress; +import java.net.UnknownHostException; import java.net.URI; import java.util.ArrayList; import java.util.List; @@ -26,9 +29,31 @@ public class TmcUtil { private static final Logger logger = LoggerFactory.getLogger(TmcUtil.class); - public static boolean tryToLogin(CliContext ctx, Settings settings) { + /** + * Check if we have internet connection. + * This is done with making dns lookup + * for the www.mooc.fi domain. This isn't + * 100% exact way to check internet access, + * but it's good enough. + * TODO the method could be changed into requireConnection(), + * which also would print error message. + * + * @param ctx context object + * @return true if we have internet access. + */ + public static boolean hasConnection(CliContext ctx) { + try { + InetAddress.getByName("www.mooc.fi"); + } catch (Exception e) { + TmcUtil.logger.warn("No internet", e.getCause()); + return false; + } + return true; + } + + public static boolean tryToLogin(CliContext ctx, Account account) { TmcCore core = ctx.getTmcCore(); - ctx.useSettings(settings); + ctx.useAccount(account); Callable> callable = core.listCourses(ProgressObserver.NULL_OBSERVER); //TODO restore the settings object @@ -80,6 +105,7 @@ public static Course findCourse(CliContext ctx, String name) { return null; } + //TODO This is exactly same method as CourseInfo.getExercise(course, name) public static Exercise findExercise(Course course, String name) { List exercises; exercises = course.getExercises(); @@ -206,6 +232,11 @@ protected static void handleTmcExceptions(CliContext ctx, Exception exception) { ctx.getApp().runAutoUpdate(); return; } + if (cause != null && cause.getCause() instanceof UnknownHostException) { + logger.error("No internet connection"); + io.println("You have no internet connection."); + return; + } logger.error("Command failed in tmc-core", exception); io.println("Command failed in tmc-core, check tmc-cli.log file for more info"); } diff --git a/src/main/java/fi/helsinki/cs/tmc/cli/command/DocumentCommand.java b/src/main/java/fi/helsinki/cs/tmc/cli/command/DocumentCommand.java index e80edea5..6adaa93e 100644 --- a/src/main/java/fi/helsinki/cs/tmc/cli/command/DocumentCommand.java +++ b/src/main/java/fi/helsinki/cs/tmc/cli/command/DocumentCommand.java @@ -1,8 +1,10 @@ package fi.helsinki.cs.tmc.cli.command; -import fi.helsinki.cs.tmc.cli.command.core.AbstractCommand; -import fi.helsinki.cs.tmc.cli.command.core.Command; +import fi.helsinki.cs.tmc.cli.core.AbstractCommand; +import fi.helsinki.cs.tmc.cli.core.CliContext; +import fi.helsinki.cs.tmc.cli.core.Command; import fi.helsinki.cs.tmc.cli.io.Color; +import fi.helsinki.cs.tmc.cli.io.ColorUtil; import fi.helsinki.cs.tmc.cli.io.EnvironmentUtil; import fi.helsinki.cs.tmc.cli.io.Io; @@ -78,8 +80,8 @@ public void getOptions(Options options) { } @Override - public void run(CommandLine args, Io io) { - this.io = io; + public void run(CliContext context, CommandLine args) { + this.io = context.getIo(); this.width = EnvironmentUtil.getTerminalWidth(); this.height = 30; this.cursorX = 0; @@ -139,7 +141,7 @@ public void run(CommandLine args, Io io) { setCursor(0, 0); io.print("\u001B[0J"); - blitter(Color.colorString("Original dev team", Color.AnsiColor.ANSI_BLUE), + blitter(ColorUtil.colorString("Original dev team", Color.BLUE), Math.max(centerX - 10, 0), centerY - 2); blitter("Johannes L. (jclc)", centerX, centerY++); centerY++; @@ -156,7 +158,7 @@ public void run(CommandLine args, Io io) { io.print("\u001B[0J"); centerY = height / 2 - 3; - blitter(Color.colorString("Special thanks for", Color.AnsiColor.ANSI_CYAN), + blitter(ColorUtil.colorString("Special thanks for", Color.CYAN), Math.max(centerX - 10, 0), centerY - 2); blitter("Jarmo Isotalo (Jamo)", centerX, centerY++); centerY++; diff --git a/src/main/java/fi/helsinki/cs/tmc/cli/command/DownloadExercisesCommand.java b/src/main/java/fi/helsinki/cs/tmc/cli/command/DownloadExercisesCommand.java index 804a988d..353c064b 100644 --- a/src/main/java/fi/helsinki/cs/tmc/cli/command/DownloadExercisesCommand.java +++ b/src/main/java/fi/helsinki/cs/tmc/cli/command/DownloadExercisesCommand.java @@ -1,29 +1,25 @@ package fi.helsinki.cs.tmc.cli.command; -import fi.helsinki.cs.tmc.cli.CliContext; -import fi.helsinki.cs.tmc.cli.command.core.AbstractCommand; -import fi.helsinki.cs.tmc.cli.command.core.Command; +import fi.helsinki.cs.tmc.cli.backend.CourseInfoIo; +import fi.helsinki.cs.tmc.cli.backend.TmcUtil; +import fi.helsinki.cs.tmc.cli.core.AbstractCommand; +import fi.helsinki.cs.tmc.cli.core.CliContext; +import fi.helsinki.cs.tmc.cli.core.Command; +import fi.helsinki.cs.tmc.cli.io.CliProgressObserver; import fi.helsinki.cs.tmc.cli.io.Color; +import fi.helsinki.cs.tmc.cli.io.ColorUtil; import fi.helsinki.cs.tmc.cli.io.Io; -import fi.helsinki.cs.tmc.cli.io.TmcCliProgressObserver; -import fi.helsinki.cs.tmc.cli.tmcstuff.CourseInfo; -import fi.helsinki.cs.tmc.cli.tmcstuff.CourseInfoIo; -import fi.helsinki.cs.tmc.cli.tmcstuff.Settings; -import fi.helsinki.cs.tmc.cli.tmcstuff.SettingsIo; -import fi.helsinki.cs.tmc.cli.tmcstuff.TmcUtil; -import fi.helsinki.cs.tmc.cli.tmcstuff.WorkDir; +import fi.helsinki.cs.tmc.cli.io.WorkDir; +import fi.helsinki.cs.tmc.cli.shared.CourseFinder; + import fi.helsinki.cs.tmc.core.domain.Course; import fi.helsinki.cs.tmc.core.domain.Exercise; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.Options; -import java.nio.file.Path; import java.util.ArrayList; -import java.util.LinkedHashMap; import java.util.List; -import java.util.Map; -import java.util.Map.Entry; @Command(name = "download", desc = "Download exercises for a specific course") public class DownloadExercisesCommand extends AbstractCommand { @@ -41,7 +37,10 @@ public void getOptions(Options options) { } @Override - public void run(CommandLine args, Io io) { + public void run(CliContext context, CommandLine args) { + Io io = context.getIo(); + ctx = context; + String[] stringArgs = args.getArgs(); if (stringArgs.length == 0 || stringArgs.length > 1) { io.println("You must give a course name as an argument."); @@ -49,7 +48,7 @@ public void run(CommandLine args, Io io) { return; } - ctx = getContext(); + ctx = context; showAll = args.hasOption("a"); if (!ctx.loadBackend()) { @@ -63,18 +62,20 @@ public void run(CommandLine args, Io io) { } String courseName = stringArgs[0]; - Course course = findCourse(courseName); - if (course == null) { + CourseFinder finder = new CourseFinder(ctx); + if (!finder.search(courseName)) { return; } + Course course = finder.getCourse(); List filtered = getFilteredExercises(course); // todo: If -c switch, use core.downloadCompletedExercises() to download user's old // submissions. Not yet implemented in tmc-core. - Color.AnsiColor color1 = ctx.getApp().getColor("progressbar-left"); - Color.AnsiColor color2 = ctx.getApp().getColor("progressbar-right"); - TmcCliProgressObserver progobs = new TmcCliProgressObserver(io, color1, color2); + Color color1 = ctx.getApp().getColor("progressbar-left"); + Color color2 = ctx.getApp().getColor("progressbar-right"); + CliProgressObserver progobs = new CliProgressObserver(io, color1, color2); + ctx.useAccount(finder.getAccount()); List exercises = TmcUtil.downloadExercises(ctx, filtered, progobs); if (exercises == null) { io.println("Failed to download exercises"); @@ -82,50 +83,9 @@ public void run(CommandLine args, Io io) { } printStatistics(course, filtered.size(), exercises.size()); - createNewCourse(course); - } - - // TODO This method could be moved somewhere else. - private Course findCourse(String courseName) { - Io io = ctx.getIo(); - List accountsList = SettingsIo.getSettingsList(); - // LinkedHashMap is used here to preserve ordering. - Map matches = new LinkedHashMap<>(); - - for (Settings settings : accountsList) { - ctx.useSettings(settings); - Course course = TmcUtil.findCourse(ctx, courseName); - if (course != null) { - matches.put(settings, course); - } - } - - if (matches.size() == 1) { - Entry firstEntry = matches.entrySet().iterator().next(); - ctx.useSettings(firstEntry.getKey()); - return firstEntry.getValue(); - } else if (matches.isEmpty()) { - io.println("Course doesn't exist."); - return null; - } - - io.println("There is " + matches.size() - + " courses with same name at different servers."); - - for (Entry entrySet : matches.entrySet()) { - Settings settings = entrySet.getKey(); - Course course = entrySet.getValue(); - - if (io.readConfirmation("Download course from " - + settings.getServerAddress() + " with '" - + settings.getUsername() + "' account", false)) { - ctx.useSettings(settings); - return course; - } - } - io.println("The previous course was last that matched."); - return null; + CourseInfoIo.createNewCourse(course, finder.getAccount(), + workDir.getWorkingDirectory()); } private List getFilteredExercises(Course course) { @@ -159,8 +119,8 @@ private void printStatistics(Course course, int requestCount, int downloadCount) if (failedCount > 0) { io.println(" of which " + (requestCount - failedCount) + " exercises were succesfully downloaded"); - io.println(Color.colorString(" and of which " + failedCount + " failed.", - Color.AnsiColor.ANSI_RED)); + io.println(ColorUtil.colorString(" and of which " + failedCount + " failed.", + Color.RED)); //TODO we could print the names of the not downloaded exercises here } else { io.println(" of which " @@ -171,15 +131,4 @@ private void printStatistics(Course course, int requestCount, int downloadCount) } } } - - private void createNewCourse(Course course) { - WorkDir workDir = ctx.getWorkDir(); - Path configFile = workDir.getWorkingDirectory() - .resolve(course.getName()) - .resolve(CourseInfoIo.COURSE_CONFIG); - - CourseInfo info = ctx.createCourseInfo(course); - info.setExercises(course.getExercises()); - CourseInfoIo.save(info, configFile); - } } diff --git a/src/main/java/fi/helsinki/cs/tmc/cli/command/HelpCommand.java b/src/main/java/fi/helsinki/cs/tmc/cli/command/HelpCommand.java index 429c7e60..bb3ed760 100644 --- a/src/main/java/fi/helsinki/cs/tmc/cli/command/HelpCommand.java +++ b/src/main/java/fi/helsinki/cs/tmc/cli/command/HelpCommand.java @@ -1,9 +1,10 @@ package fi.helsinki.cs.tmc.cli.command; import fi.helsinki.cs.tmc.cli.Application; -import fi.helsinki.cs.tmc.cli.command.core.AbstractCommand; -import fi.helsinki.cs.tmc.cli.command.core.Command; -import fi.helsinki.cs.tmc.cli.command.core.CommandFactory; +import fi.helsinki.cs.tmc.cli.core.AbstractCommand; +import fi.helsinki.cs.tmc.cli.core.CliContext; +import fi.helsinki.cs.tmc.cli.core.Command; +import fi.helsinki.cs.tmc.cli.core.CommandFactory; import fi.helsinki.cs.tmc.cli.io.Io; import org.apache.commons.cli.CommandLine; @@ -24,9 +25,9 @@ public void getOptions(Options options) { } @Override - public void run(CommandLine args, Io io) { - Application app = getContext().getApp(); - this.io = io; + public void run(CliContext context, CommandLine args) { + Application app = context.getApp(); + this.io = context.getIo(); StringBuilder sb = new StringBuilder(); sb.append("TMC commands:\n"); diff --git a/src/main/java/fi/helsinki/cs/tmc/cli/command/CourseInfoCommand.java b/src/main/java/fi/helsinki/cs/tmc/cli/command/InfoCommand.java similarity index 51% rename from src/main/java/fi/helsinki/cs/tmc/cli/command/CourseInfoCommand.java rename to src/main/java/fi/helsinki/cs/tmc/cli/command/InfoCommand.java index 53ebe9a0..a2616cdb 100644 --- a/src/main/java/fi/helsinki/cs/tmc/cli/command/CourseInfoCommand.java +++ b/src/main/java/fi/helsinki/cs/tmc/cli/command/InfoCommand.java @@ -1,18 +1,14 @@ package fi.helsinki.cs.tmc.cli.command; -import static fi.helsinki.cs.tmc.cli.io.Color.AnsiColor.ANSI_BLUE; -import static fi.helsinki.cs.tmc.cli.io.Color.AnsiColor.ANSI_GREEN; -import static fi.helsinki.cs.tmc.cli.io.Color.AnsiColor.ANSI_PURPLE; -import static fi.helsinki.cs.tmc.cli.io.Color.AnsiColor.ANSI_RED; - -import fi.helsinki.cs.tmc.cli.CliContext; -import fi.helsinki.cs.tmc.cli.command.core.AbstractCommand; -import fi.helsinki.cs.tmc.cli.command.core.Command; +import fi.helsinki.cs.tmc.cli.backend.CourseInfo; +import fi.helsinki.cs.tmc.cli.core.AbstractCommand; +import fi.helsinki.cs.tmc.cli.core.CliContext; +import fi.helsinki.cs.tmc.cli.core.Command; import fi.helsinki.cs.tmc.cli.io.Color; +import fi.helsinki.cs.tmc.cli.io.ColorUtil; import fi.helsinki.cs.tmc.cli.io.Io; -import fi.helsinki.cs.tmc.cli.tmcstuff.CourseInfo; -import fi.helsinki.cs.tmc.cli.tmcstuff.TmcUtil; -import fi.helsinki.cs.tmc.cli.tmcstuff.WorkDir; +import fi.helsinki.cs.tmc.cli.io.WorkDir; +import fi.helsinki.cs.tmc.cli.shared.CourseFinder; import fi.helsinki.cs.tmc.core.domain.Course; import fi.helsinki.cs.tmc.core.domain.Exercise; @@ -24,15 +20,17 @@ import java.util.List; @Command(name = "info", desc = "Show info about the current directory") -public class CourseInfoCommand extends AbstractCommand { +public class InfoCommand extends AbstractCommand { - private Course course; - private Exercise exercise; private CourseInfo info; private WorkDir workDir; private Io io; private CliContext ctx; + private boolean useWorkingDirectory; + private boolean fetchFromInternet; + private boolean showAll; + @Override public void getOptions(Options options) { options.addOption("a", "all", false, "Show all information for a specific course"); @@ -40,109 +38,124 @@ public void getOptions(Options options) { } @Override - public void run(CommandLine args, Io io) { - this.io = io; - this.ctx = getContext(); - workDir = ctx.getWorkDir(); + public void run(CliContext context, CommandLine args) { + this.ctx = context; + this.workDir = ctx.getWorkDir(); + this.io = ctx.getIo(); - boolean fetchFromInternet = args.hasOption("i"); + String[] stringArgs = args.getArgs(); + useWorkingDirectory = (stringArgs.length == 0); + fetchFromInternet = args.hasOption("i"); + showAll = args.hasOption("a"); if (!ctx.loadBackendWithoutLogin()) { return; } - if (!fetchFromInternet) { - printLocalCourseOrExercise(args); - return; - } - - String[] stringArgs = args.getArgs(); - if (stringArgs.length == 0) { - io.println("You must give a course as an argument."); - return; + if (fetchFromInternet) { + if (useWorkingDirectory) { + io.println("You must give a course as an argument."); + return; + } + String courseName = stringArgs[0]; + printInfoFromInternet(courseName); + } else { + printLocalInfo(args.getArgs()); } + } + private void printInfoFromInternet(String courseName) { if (!ctx.hasLogin()) { io.println("Loading a course from a server requires login."); return; } - course = TmcUtil.findCourse(ctx, stringArgs[0]); - if (course == null) { - io.println("The course " + stringArgs[0] + " doesn't exist on the server."); - return; + CourseFinder finder = ctx.createCourseFinder(); + + if (finder.search(courseName)) { + printCourse(finder.getCourse()); } - printCourse(args.hasOption("a")); } - private void printLocalCourseOrExercise(CommandLine args) { + private void printLocalInfo(String[] stringArgs) { info = ctx.getCourseInfo(); - if (info != null) { - course = info.getCourse(); - printCourseOrExercise(args); - } else { - this.io.println("You have to be in a course directory" + if (info == null) { + io.println("You have to be in a course directory" + " or use the -i option with the course name " + "to get the information from the server."); - } - } - - private void printCourseOrExercise(CommandLine args) { - String[] stringArgs = args.getArgs(); - workDir.getExerciseNames(false, false, false); - - // if in exercise directory and no parameters given, print info for that exercise. - if (workDir.getExerciseNames(false, false, false).size() == 1 && stringArgs.length == 0) { - String currentExercise = workDir.getExerciseNames(false, false, false).get(0); - exercise = info.getExercise(currentExercise); - printOneExercise(args.hasOption("a")); return; } - if (stringArgs.length != 0) { - printCourseOrExerciseFromParameters(args); - return; + if (useWorkingDirectory) { + // if in exercise directory, print info for that exercise. + String exerciseName = getCurrentExercise(workDir); + if (exerciseName == null) { + printCourse(info.getCourse()); + } else { + printExercise(info.getExercise(exerciseName)); + } + } else { + if (stringArgs.length != 1) { + io.println("You can only give one path for this command."); + return; + } + String path = stringArgs[0]; + printInfoFromParameters(path); } - printCourse(args.hasOption("a")); } - private void printCourseOrExerciseFromParameters(CommandLine args) { - String[] stringArgs = args.getArgs(); - // if parameter is given, check if it is an exercise - // or a course. If neither, print an error message. - if (info.getExercise(stringArgs[0]) != null) { - exercise = info.getExercise(stringArgs[0]); - printOneExercise(args.hasOption("a")); + private void printInfoFromParameters(String pathName) { + // Check if path pointed to exercise directory + Exercise exercise = info.getExercise(pathName); + if (exercise != null) { + printExercise(exercise); return; - } - course = info.getCourse(); - if (course != null && course.getName().equals(stringArgs[0])) { - printCourse(args.hasOption("a")); + + // Check if path pointed to course directory + Course course = info.getCourse(); + if (course != null) { + printCourse(course); } else { - this.io.println("Wrong course directory." - + " Navigate to the correct course directory or" - + " use the -i option with the course name" - + " to get the information from the server."); + io.println("Not a course directory. "); + io.println("Use the -i option to get course from " + + "server."); } } - private void printCourse(boolean showAll) { - printCourseShort(); + private void printCourse(Course course) { + printCourseShort(course); if (showAll) { - printCourseDetails(); + printCourseDetails(course); + } + printExerciseList(course); + } + + private void printExerciseList(Course course) { + List exercises = course.getExercises(); + if (exercises == null || exercises.isEmpty()) { + io.println("Exercises: -"); + return; + } + + io.println("Exercises: "); + for (Exercise exercise : exercises) { + if (showAll) { + printExerciseFull(exercise); + } else { + io.println(" " + exercise.getName()); + } } - printExercises(showAll); } - - private void printCourseShort() { + + private void printCourseShort(Course course) { io.println("Course name: " + course.getName()); io.println("Number of available exercises: " + course.getExercises().size()); - io.println("Number of completed exercises: " + completedExercises()); + io.println("Number of completed exercises: " + getCompletedExerciseCount(course)); io.println("Number of locked exercises: " + course.getUnlockables().size()); } - - private void printCourseDetails() { + + private void printCourseDetails(Course course) { io.println("Unlockables:" + course.getUnlockables().toString()); io.println("Course id: " + course.getId()); io.println("Details URL: " + course.getDetailsUrl()); @@ -152,58 +165,33 @@ private void printCourseDetails() { io.println("CometUrl: " + course.getCometUrl()); } - private void printOneExercise(boolean showAll) { + private void printExercise(Exercise exercise) { if (showAll) { - printExercise(exercise); + printExerciseFull(exercise); } else { - printExerciseShort(); + printExerciseShort(exercise); } } - private void printExerciseShort() { + private void printExerciseShort(Exercise exercise) { io.println("Exercise: " + exercise.getName()); - io.println("Deadline: " + getDeadline(exercise)); + io.println("Deadline: " + exercise.getDeadlineDate()); if (exercise.hasDeadlinePassed() && !exercise.isCompleted()) { - io.println(Color.colorString("deadline passed", ANSI_PURPLE)); + io.println(ColorUtil.colorString("deadline passed", Color.PURPLE)); } else { if (!exercise.isCompleted() && exercise.isAttempted()) { - io.println(Color.colorString("attempted", ANSI_BLUE)); + io.println(ColorUtil.colorString("attempted", Color.BLUE)); } else { - io.println(formatString("completed", exercise.isCompleted())); + printFlag("completed", exercise.isCompleted()); } if (exercise.requiresReview()) { - io.println(formatString("reviewed", exercise.isReviewed())); + printFlag("reviewed", exercise.isReviewed()); } } } - private String formatString(String string, boolean color) { - if (color) { - return Color.colorString(string, ANSI_GREEN); - } else { - return Color.colorString("not " + string, ANSI_RED); - } - } - - private void printExercises(boolean showAll) { - List exercises = course.getExercises(); - if (exercises == null || exercises.isEmpty()) { - io.println("Exercises: -"); - return; - } - - io.println("Exercises: "); - for (Exercise exercise : exercises) { - if (showAll) { - printExercise(exercise); - } else { - io.println(" " + exercise.getName()); - } - } - } - - private int completedExercises() { + private int getCompletedExerciseCount(Course course) { int completed = 0; for (Exercise exercise : course.getExercises()) { if (exercise.isCompleted()) { @@ -212,14 +200,32 @@ private int completedExercises() { } return completed; } - - private void printExercise(Exercise exercise) { + + private String getCurrentExercise(WorkDir workDir) { + List exercises = workDir.getExerciseNames(false, false, false); + if (exercises.size() == 1) { + return exercises.get(0); + } + return null; + } + + private void printFlag(String string, boolean setting) { + Color color; + if (setting) { + color = Color.GREEN; + } else { + color = Color.RED; + string = "not " + string; + } + io.println(ColorUtil.colorString(string, color)); + } + + private void printExerciseFull(Exercise exercise) { io.println(" Exercise name: " + exercise.getName()); io.println(" Exercise id: " + exercise.getId()); io.println(" Is locked: " + exercise.isLocked()); io.println(" Deadline description: " + exercise.getDeadlineDescription()); - io.println(" Deadline: " + exercise.getDeadline()); - io.println(" Deadline date: " + exercise.getDeadlineDate()); + io.println(" Deadline: " + exercise.getDeadlineDate()); io.println(" Deadline passed: " + exercise.hasDeadlinePassed()); io.println(" Is returnable: " + exercise.isReturnable()); io.println(" Review required: " + exercise.requiresReview()); @@ -239,13 +245,4 @@ private void printExercise(Exercise exercise) { io.println(" Checksum: " + exercise.getChecksum()); io.println(""); } - - private String getDeadline(Exercise exercise) { - String deadline = exercise.getDeadline(); - if (deadline == null) { - return "not available"; - } - deadline = deadline.substring(0, 19); - return deadline.replace("T", " at "); - } } diff --git a/src/main/java/fi/helsinki/cs/tmc/cli/command/ListCoursesCommand.java b/src/main/java/fi/helsinki/cs/tmc/cli/command/ListCoursesCommand.java index dd3cf4b3..51285b3d 100644 --- a/src/main/java/fi/helsinki/cs/tmc/cli/command/ListCoursesCommand.java +++ b/src/main/java/fi/helsinki/cs/tmc/cli/command/ListCoursesCommand.java @@ -1,13 +1,15 @@ package fi.helsinki.cs.tmc.cli.command; -import fi.helsinki.cs.tmc.cli.CliContext; -import fi.helsinki.cs.tmc.cli.command.core.AbstractCommand; -import fi.helsinki.cs.tmc.cli.command.core.Command; +import fi.helsinki.cs.tmc.cli.backend.Account; +import fi.helsinki.cs.tmc.cli.backend.AccountList; +import fi.helsinki.cs.tmc.cli.backend.SettingsIo; +import fi.helsinki.cs.tmc.cli.backend.TmcUtil; +import fi.helsinki.cs.tmc.cli.core.AbstractCommand; +import fi.helsinki.cs.tmc.cli.core.CliContext; +import fi.helsinki.cs.tmc.cli.core.Command; import fi.helsinki.cs.tmc.cli.io.Color; +import fi.helsinki.cs.tmc.cli.io.ColorUtil; import fi.helsinki.cs.tmc.cli.io.Io; -import fi.helsinki.cs.tmc.cli.tmcstuff.Settings; -import fi.helsinki.cs.tmc.cli.tmcstuff.SettingsIo; -import fi.helsinki.cs.tmc.cli.tmcstuff.TmcUtil; import fi.helsinki.cs.tmc.core.domain.Course; @@ -30,33 +32,44 @@ public void getOptions(Options options) { } @Override - public void run(CommandLine args, Io io) { - this.ctx = getContext(); + public void run(CliContext context, CommandLine args) { + this.ctx = context; this.io = ctx.getIo(); - if (! getContext().loadBackend()) { + if (! ctx.loadBackendWithoutLogin()) { return; } - List accountsList = SettingsIo.getSettingsList(); + if (!TmcUtil.hasConnection(ctx)) { + io.println("You don't have internet connection currently."); + io.println("Check the tmc-cli logs to get exact problem."); + return; + } + + AccountList accountsList = SettingsIo.loadAccountList(); boolean isFirst = true; - for (Settings settings : accountsList) { + if (accountsList.getAccountCount() == 0) { + io.println("You haven't logged in on any tmc server."); + return; + } + + for (Account settings : accountsList) { if (!isFirst) { io.println(""); } - if (accountsList.size() > 1) { - io.println(Color.colorString("Server " + settings.getServerAddress(), - Color.AnsiColor.ANSI_YELLOW)); + if (accountsList.getAccountCount() > 1) { + io.println(ColorUtil.colorString("Server " + settings.getServerAddress(), + Color.YELLOW)); } printCourseList(settings); isFirst = false; } } - private void printCourseList(Settings settings) { - ctx.useSettings(settings); - List courses = TmcUtil.listCourses(getContext()); + private void printCourseList(Account account) { + ctx.useAccount(account); + List courses = TmcUtil.listCourses(ctx); if (courses.isEmpty()) { io.println("No courses found from the server."); return; diff --git a/src/main/java/fi/helsinki/cs/tmc/cli/command/ListExercisesCommand.java b/src/main/java/fi/helsinki/cs/tmc/cli/command/ListExercisesCommand.java index a01558ff..31816ca9 100755 --- a/src/main/java/fi/helsinki/cs/tmc/cli/command/ListExercisesCommand.java +++ b/src/main/java/fi/helsinki/cs/tmc/cli/command/ListExercisesCommand.java @@ -1,16 +1,16 @@ package fi.helsinki.cs.tmc.cli.command; -import fi.helsinki.cs.tmc.cli.CliContext; -import fi.helsinki.cs.tmc.cli.command.core.AbstractCommand; -import fi.helsinki.cs.tmc.cli.command.core.Command; +import fi.helsinki.cs.tmc.cli.backend.CourseInfo; +import fi.helsinki.cs.tmc.cli.backend.TmcUtil; +import fi.helsinki.cs.tmc.cli.core.AbstractCommand; +import fi.helsinki.cs.tmc.cli.core.CliContext; +import fi.helsinki.cs.tmc.cli.core.Command; import fi.helsinki.cs.tmc.cli.io.Color; +import fi.helsinki.cs.tmc.cli.io.ColorUtil; import fi.helsinki.cs.tmc.cli.io.EnvironmentUtil; import fi.helsinki.cs.tmc.cli.io.ExternalsUtil; import fi.helsinki.cs.tmc.cli.io.Io; -import fi.helsinki.cs.tmc.cli.tmcstuff.CourseInfo; -import fi.helsinki.cs.tmc.cli.tmcstuff.CourseInfoIo; -import fi.helsinki.cs.tmc.cli.tmcstuff.TmcUtil; -import fi.helsinki.cs.tmc.cli.tmcstuff.WorkDir; +import fi.helsinki.cs.tmc.cli.io.WorkDir; import fi.helsinki.cs.tmc.core.domain.Course; import fi.helsinki.cs.tmc.core.domain.Exercise; @@ -33,9 +33,9 @@ public void getOptions(Options options) { } @Override - public void run(CommandLine args, Io io) { - this.ctx = getContext(); - this.io = io; + public void run(CliContext context, CommandLine args) { + this.ctx = context; + this.io = ctx.getIo(); String courseName = getCourseName(args); if (courseName == null) { @@ -156,16 +156,16 @@ private String getExerciseStatus(Exercise exercise) { String status; if (exercise.isCompleted()) { if (exercise.requiresReview() && !exercise.isReviewed()) { - status = Color.colorString(" Requires review: ", Color.AnsiColor.ANSI_YELLOW); + status = ColorUtil.colorString(" Requires review: ", Color.YELLOW); } else { - status = Color.colorString(" Completed: ", Color.AnsiColor.ANSI_GREEN); + status = ColorUtil.colorString(" Completed: ", Color.GREEN); } } else if (exercise.hasDeadlinePassed()) { - status = Color.colorString(" Deadline passed: ", Color.AnsiColor.ANSI_PURPLE); + status = ColorUtil.colorString(" Deadline passed: ", Color.PURPLE); } else if (exercise.isAttempted()) { - status = Color.colorString(" Attempted: ", Color.AnsiColor.ANSI_BLUE); + status = ColorUtil.colorString(" Attempted: ", Color.BLUE); } else { - status = Color.colorString(" Not completed: ", Color.AnsiColor.ANSI_RED); + status = ColorUtil.colorString(" Not completed: ", Color.RED); } status += exercise.getName() + "\n"; diff --git a/src/main/java/fi/helsinki/cs/tmc/cli/command/LoginCommand.java b/src/main/java/fi/helsinki/cs/tmc/cli/command/LoginCommand.java index 15286f23..4747fba4 100644 --- a/src/main/java/fi/helsinki/cs/tmc/cli/command/LoginCommand.java +++ b/src/main/java/fi/helsinki/cs/tmc/cli/command/LoginCommand.java @@ -1,13 +1,14 @@ package fi.helsinki.cs.tmc.cli.command; -import fi.helsinki.cs.tmc.cli.CliContext; -import fi.helsinki.cs.tmc.cli.command.core.AbstractCommand; -import fi.helsinki.cs.tmc.cli.command.core.Command; +import fi.helsinki.cs.tmc.cli.backend.Account; +import fi.helsinki.cs.tmc.cli.backend.AccountList; +import fi.helsinki.cs.tmc.cli.backend.CourseInfo; +import fi.helsinki.cs.tmc.cli.backend.SettingsIo; +import fi.helsinki.cs.tmc.cli.backend.TmcUtil; +import fi.helsinki.cs.tmc.cli.core.AbstractCommand; +import fi.helsinki.cs.tmc.cli.core.CliContext; +import fi.helsinki.cs.tmc.cli.core.Command; import fi.helsinki.cs.tmc.cli.io.Io; -import fi.helsinki.cs.tmc.cli.tmcstuff.CourseInfo; -import fi.helsinki.cs.tmc.cli.tmcstuff.Settings; -import fi.helsinki.cs.tmc.cli.tmcstuff.SettingsIo; -import fi.helsinki.cs.tmc.cli.tmcstuff.TmcUtil; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.Options; @@ -30,14 +31,20 @@ public void getOptions(Options options) { } @Override - public void run(CommandLine args, Io io) { - this.ctx = getContext(); - this.io = io; + public void run(CliContext context, CommandLine args) { + this.ctx = context; + this.io = ctx.getIo(); if (!ctx.loadBackendWithoutLogin()) { return; } + if (!TmcUtil.hasConnection(ctx)) { + io.println("You don't have internet connection currently."); + io.println("Check the tmc-cli logs to get exact problem."); + return; + } + CourseInfo info = ctx.getCourseInfo(); if (info != null) { serverAddress = info.getServerAddress(); @@ -48,12 +55,14 @@ public void run(CommandLine args, Io io) { username = getLoginInfo(args, username, "u", "username: "); password = getLoginInfo(args, null, "p", "password: "); - //TODO don't create new settings object. - Settings settings = new Settings(serverAddress, username, password); - if (!TmcUtil.tryToLogin(ctx, settings)) { + Account account = new Account(serverAddress, username, password); + if (!TmcUtil.tryToLogin(ctx, account)) { return; } - if (!SettingsIo.save(settings)) { + + AccountList list = SettingsIo.loadAccountList(); + list.addAccount(account); + if (!SettingsIo.saveAccountList(list)) { io.println("Failed to write the accounts file."); return; } @@ -64,12 +73,17 @@ public void run(CommandLine args, Io io) { private String getLoginInfo(CommandLine line, String oldValue, String option, String prompt) { String value = oldValue; + boolean isPassword = option.equals("p"); if (line.hasOption(option)) { value = line.getOptionValue(option); } - if (value == null && option.equals("p")) { + if (value != null && !isPassword) { + io.println(prompt + value); + } + + if (value == null && isPassword) { value = io.readPassword(prompt); } else if (value == null) { value = io.readLine(prompt); diff --git a/src/main/java/fi/helsinki/cs/tmc/cli/command/LogoutCommand.java b/src/main/java/fi/helsinki/cs/tmc/cli/command/LogoutCommand.java index 09ee7908..45495e02 100644 --- a/src/main/java/fi/helsinki/cs/tmc/cli/command/LogoutCommand.java +++ b/src/main/java/fi/helsinki/cs/tmc/cli/command/LogoutCommand.java @@ -1,9 +1,9 @@ package fi.helsinki.cs.tmc.cli.command; -import fi.helsinki.cs.tmc.cli.command.core.AbstractCommand; -import fi.helsinki.cs.tmc.cli.command.core.Command; -import fi.helsinki.cs.tmc.cli.io.Io; -import fi.helsinki.cs.tmc.cli.tmcstuff.SettingsIo; +import fi.helsinki.cs.tmc.cli.backend.SettingsIo; +import fi.helsinki.cs.tmc.cli.core.AbstractCommand; +import fi.helsinki.cs.tmc.cli.core.CliContext; +import fi.helsinki.cs.tmc.cli.core.Command; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.Options; @@ -16,8 +16,8 @@ public void getOptions(Options options) { } @Override - public void run(CommandLine args, Io io) { + public void run(CliContext context, CommandLine args) { SettingsIo.delete(); - io.println("Logged out."); + context.getIo().println("Logged out."); } } diff --git a/src/main/java/fi/helsinki/cs/tmc/cli/command/PasteCommand.java b/src/main/java/fi/helsinki/cs/tmc/cli/command/PasteCommand.java index b31279aa..798a70d4 100644 --- a/src/main/java/fi/helsinki/cs/tmc/cli/command/PasteCommand.java +++ b/src/main/java/fi/helsinki/cs/tmc/cli/command/PasteCommand.java @@ -1,13 +1,14 @@ package fi.helsinki.cs.tmc.cli.command; -import fi.helsinki.cs.tmc.cli.CliContext; -import fi.helsinki.cs.tmc.cli.command.core.AbstractCommand; -import fi.helsinki.cs.tmc.cli.command.core.Command; +import fi.helsinki.cs.tmc.cli.backend.CourseInfo; +import fi.helsinki.cs.tmc.cli.backend.TmcUtil; +import fi.helsinki.cs.tmc.cli.core.AbstractCommand; +import fi.helsinki.cs.tmc.cli.core.CliContext; +import fi.helsinki.cs.tmc.cli.core.Command; import fi.helsinki.cs.tmc.cli.io.ExternalsUtil; import fi.helsinki.cs.tmc.cli.io.Io; -import fi.helsinki.cs.tmc.cli.tmcstuff.CourseInfo; -import fi.helsinki.cs.tmc.cli.tmcstuff.TmcUtil; -import fi.helsinki.cs.tmc.cli.tmcstuff.WorkDir; +import fi.helsinki.cs.tmc.cli.io.WorkDir; + import fi.helsinki.cs.tmc.core.domain.Exercise; import org.apache.commons.cli.CommandLine; @@ -33,9 +34,9 @@ public void getOptions(Options options) { } @Override - public void run(CommandLine args, Io io) { - this.io = io; - CliContext ctx = getContext(); + public void run(CliContext context, CommandLine args) { + CliContext ctx = context; + this.io = ctx.getIo(); if (!ctx.loadBackend()) { return; } diff --git a/src/main/java/fi/helsinki/cs/tmc/cli/command/PropertiesCommand.java b/src/main/java/fi/helsinki/cs/tmc/cli/command/PropertiesCommand.java index d777300a..47848416 100644 --- a/src/main/java/fi/helsinki/cs/tmc/cli/command/PropertiesCommand.java +++ b/src/main/java/fi/helsinki/cs/tmc/cli/command/PropertiesCommand.java @@ -1,8 +1,8 @@ package fi.helsinki.cs.tmc.cli.command; -import fi.helsinki.cs.tmc.cli.CliContext; -import fi.helsinki.cs.tmc.cli.command.core.AbstractCommand; -import fi.helsinki.cs.tmc.cli.command.core.Command; +import fi.helsinki.cs.tmc.cli.core.AbstractCommand; +import fi.helsinki.cs.tmc.cli.core.CliContext; +import fi.helsinki.cs.tmc.cli.core.Command; import fi.helsinki.cs.tmc.cli.io.Io; import org.apache.commons.cli.CommandLine; @@ -27,10 +27,11 @@ public void getOptions(Options options) { } @Override - public void run(CommandLine args, Io io) { - this.io = io; - CliContext ctx = getContext(); - Boolean unset = args.hasOption("u"); + public void run(CliContext context, CommandLine args) { + CliContext ctx = context; + this.io = ctx.getIo(); + + boolean unset = args.hasOption("u"); String[] arguments = args.getArgs(); HashMap props = ctx.getProperties(); if (arguments.length == 0) { diff --git a/src/main/java/fi/helsinki/cs/tmc/cli/command/RunTestsCommand.java b/src/main/java/fi/helsinki/cs/tmc/cli/command/RunTestsCommand.java index b3946809..56504800 100644 --- a/src/main/java/fi/helsinki/cs/tmc/cli/command/RunTestsCommand.java +++ b/src/main/java/fi/helsinki/cs/tmc/cli/command/RunTestsCommand.java @@ -1,15 +1,16 @@ package fi.helsinki.cs.tmc.cli.command; -import fi.helsinki.cs.tmc.cli.CliContext; -import fi.helsinki.cs.tmc.cli.command.core.AbstractCommand; -import fi.helsinki.cs.tmc.cli.command.core.Command; +import fi.helsinki.cs.tmc.cli.backend.CourseInfo; +import fi.helsinki.cs.tmc.cli.backend.CourseInfoIo; +import fi.helsinki.cs.tmc.cli.backend.TmcUtil; +import fi.helsinki.cs.tmc.cli.core.AbstractCommand; +import fi.helsinki.cs.tmc.cli.core.CliContext; +import fi.helsinki.cs.tmc.cli.core.Command; import fi.helsinki.cs.tmc.cli.io.Color; +import fi.helsinki.cs.tmc.cli.io.ColorUtil; import fi.helsinki.cs.tmc.cli.io.Io; -import fi.helsinki.cs.tmc.cli.io.ResultPrinter; -import fi.helsinki.cs.tmc.cli.tmcstuff.CourseInfo; -import fi.helsinki.cs.tmc.cli.tmcstuff.CourseInfoIo; -import fi.helsinki.cs.tmc.cli.tmcstuff.TmcUtil; -import fi.helsinki.cs.tmc.cli.tmcstuff.WorkDir; +import fi.helsinki.cs.tmc.cli.io.WorkDir; +import fi.helsinki.cs.tmc.cli.shared.ResultPrinter; import fi.helsinki.cs.tmc.core.domain.Exercise; import fi.helsinki.cs.tmc.langs.abstraction.ValidationResult; @@ -39,13 +40,15 @@ public void getOptions(Options options) { } @Override - public void run(CommandLine args, Io io) { + public void run(CliContext context, CommandLine args) { + CliContext ctx = context; + Io io = ctx.getIo(); + String[] exercisesFromArgs = parseArgs(args); if (exercisesFromArgs == null) { return; } - CliContext ctx = getContext(); if (!ctx.loadBackendWithoutLogin()) { return; } @@ -66,15 +69,15 @@ public void run(CommandLine args, Io io) { CourseInfo info = ctx.getCourseInfo(); - Color.AnsiColor passedColor = ctx.getApp().getColor("testresults-left"); - Color.AnsiColor failedColor = ctx.getApp().getColor("testresults-right"); + Color passedColor = ctx.getApp().getColor("testresults-left"); + Color failedColor = ctx.getApp().getColor("testresults-right"); ResultPrinter resultPrinter = new ResultPrinter(io, showDetails, showPassed, passedColor, failedColor); boolean isOnlyExercise = (exerciseNames.size() == 1); for (String name : exerciseNames) { - io.println(Color.colorString("Testing: " + name, Color.AnsiColor.ANSI_YELLOW)); + io.println(ColorUtil.colorString("Testing: " + name, Color.YELLOW)); Exercise exercise = info.getExercise(name); RunResult runResult = TmcUtil.runLocalTests(ctx, exercise); diff --git a/src/main/java/fi/helsinki/cs/tmc/cli/command/ShellHelperCommand.java b/src/main/java/fi/helsinki/cs/tmc/cli/command/ShellHelperCommand.java index fcef29e3..72ba39cd 100644 --- a/src/main/java/fi/helsinki/cs/tmc/cli/command/ShellHelperCommand.java +++ b/src/main/java/fi/helsinki/cs/tmc/cli/command/ShellHelperCommand.java @@ -1,8 +1,9 @@ package fi.helsinki.cs.tmc.cli.command; -import fi.helsinki.cs.tmc.cli.command.core.AbstractCommand; -import fi.helsinki.cs.tmc.cli.command.core.Command; -import fi.helsinki.cs.tmc.cli.command.core.CommandFactory; +import fi.helsinki.cs.tmc.cli.core.AbstractCommand; +import fi.helsinki.cs.tmc.cli.core.CliContext; +import fi.helsinki.cs.tmc.cli.core.Command; +import fi.helsinki.cs.tmc.cli.core.CommandFactory; import fi.helsinki.cs.tmc.cli.io.Io; import org.apache.commons.cli.CommandLine; @@ -18,7 +19,9 @@ public void getOptions(Options options) { } @Override - public void run(CommandLine args, Io io) { + public void run(CliContext context, CommandLine args) { + Io io = context.getIo(); + if (args.hasOption("c")) { for (Class commandClass : CommandFactory.getCommands()) { Command command = CommandFactory.getCommand(commandClass); diff --git a/src/main/java/fi/helsinki/cs/tmc/cli/command/SubmitCommand.java b/src/main/java/fi/helsinki/cs/tmc/cli/command/SubmitCommand.java index 276918e9..dd378c78 100644 --- a/src/main/java/fi/helsinki/cs/tmc/cli/command/SubmitCommand.java +++ b/src/main/java/fi/helsinki/cs/tmc/cli/command/SubmitCommand.java @@ -1,17 +1,19 @@ package fi.helsinki.cs.tmc.cli.command; -import fi.helsinki.cs.tmc.cli.CliContext; -import fi.helsinki.cs.tmc.cli.command.core.AbstractCommand; -import fi.helsinki.cs.tmc.cli.command.core.Command; +import fi.helsinki.cs.tmc.cli.backend.CourseInfo; +import fi.helsinki.cs.tmc.cli.backend.CourseInfoIo; +import fi.helsinki.cs.tmc.cli.backend.TmcUtil; +import fi.helsinki.cs.tmc.cli.core.AbstractCommand; +import fi.helsinki.cs.tmc.cli.core.CliContext; +import fi.helsinki.cs.tmc.cli.core.Command; import fi.helsinki.cs.tmc.cli.io.Color; +import fi.helsinki.cs.tmc.cli.io.ColorUtil; import fi.helsinki.cs.tmc.cli.io.Io; -import fi.helsinki.cs.tmc.cli.io.ResultPrinter; -import fi.helsinki.cs.tmc.cli.tmcstuff.CourseInfo; -import fi.helsinki.cs.tmc.cli.tmcstuff.CourseInfoIo; -import fi.helsinki.cs.tmc.cli.tmcstuff.ExerciseUpdater; -import fi.helsinki.cs.tmc.cli.tmcstuff.FeedbackHandler; -import fi.helsinki.cs.tmc.cli.tmcstuff.TmcUtil; -import fi.helsinki.cs.tmc.cli.tmcstuff.WorkDir; +import fi.helsinki.cs.tmc.cli.io.WorkDir; +import fi.helsinki.cs.tmc.cli.shared.ExerciseUpdater; +import fi.helsinki.cs.tmc.cli.shared.FeedbackHandler; +import fi.helsinki.cs.tmc.cli.shared.ResultPrinter; + import fi.helsinki.cs.tmc.core.domain.Course; import fi.helsinki.cs.tmc.core.domain.Exercise; import fi.helsinki.cs.tmc.core.domain.submission.FeedbackQuestion; @@ -46,9 +48,9 @@ public void getOptions(Options options) { } @Override - public void run(CommandLine args, Io io) { - this.ctx = getContext(); - this.io = io; + public void run(CliContext context, CommandLine args) { + this.ctx = context; + this.io = ctx.getIo(); String[] exercisesFromArgs = parseArgs(args); if (exercisesFromArgs == null) { @@ -90,8 +92,8 @@ public void run(CommandLine args, Io io) { return; } - Color.AnsiColor color1 = ctx.getApp().getColor("testresults-left"); - Color.AnsiColor color2 = ctx.getApp().getColor("testresults-right"); + Color color1 = ctx.getApp().getColor("testresults-left"); + Color color2 = ctx.getApp().getColor("testresults-right"); ResultPrinter resultPrinter = new ResultPrinter(io, this.showDetails, this.showAll, color1, color2); @@ -103,8 +105,8 @@ public void run(CommandLine args, Io io) { List feedbackUris = new ArrayList<>(); for (Exercise exercise : submitExercises) { - io.println(Color.colorString("Submitting: " + exercise.getName(), - Color.AnsiColor.ANSI_YELLOW)); + io.println(ColorUtil.colorString("Submitting: " + exercise.getName(), + Color.YELLOW)); SubmissionResult result = TmcUtil.submitExercise(ctx, exercise); if (result == null) { io.println("Submission failed."); @@ -201,7 +203,7 @@ private void checkForExerciseUpdates(Course course) { msg += "Use 'tmc update' to download " + (total > 1 ? "them." : "it."); io.println(""); - io.println(Color.colorString(msg, Color.AnsiColor.ANSI_YELLOW)); + io.println(ColorUtil.colorString(msg, Color.YELLOW)); } private String[] parseArgs(CommandLine args) { diff --git a/src/main/java/fi/helsinki/cs/tmc/cli/command/UpdateCommand.java b/src/main/java/fi/helsinki/cs/tmc/cli/command/UpdateCommand.java index e1862b89..ae38c594 100644 --- a/src/main/java/fi/helsinki/cs/tmc/cli/command/UpdateCommand.java +++ b/src/main/java/fi/helsinki/cs/tmc/cli/command/UpdateCommand.java @@ -1,16 +1,15 @@ package fi.helsinki.cs.tmc.cli.command; -import fi.helsinki.cs.tmc.cli.CliContext; -import fi.helsinki.cs.tmc.cli.command.core.AbstractCommand; -import fi.helsinki.cs.tmc.cli.command.core.Command; +import fi.helsinki.cs.tmc.cli.backend.CourseInfo; +import fi.helsinki.cs.tmc.cli.core.AbstractCommand; +import fi.helsinki.cs.tmc.cli.core.CliContext; +import fi.helsinki.cs.tmc.cli.core.Command; +import fi.helsinki.cs.tmc.cli.io.CliProgressObserver; import fi.helsinki.cs.tmc.cli.io.Color; import fi.helsinki.cs.tmc.cli.io.Io; -import fi.helsinki.cs.tmc.cli.io.TmcCliProgressObserver; -import fi.helsinki.cs.tmc.cli.tmcstuff.CourseInfo; -import fi.helsinki.cs.tmc.cli.tmcstuff.CourseInfoIo; -import fi.helsinki.cs.tmc.cli.tmcstuff.ExerciseUpdater; -import fi.helsinki.cs.tmc.cli.tmcstuff.WorkDir; -import fi.helsinki.cs.tmc.core.TmcCore; +import fi.helsinki.cs.tmc.cli.io.WorkDir; +import fi.helsinki.cs.tmc.cli.shared.ExerciseUpdater; + import fi.helsinki.cs.tmc.core.domain.Exercise; import org.apache.commons.cli.CommandLine; @@ -31,9 +30,9 @@ public void getOptions(Options options) { } @Override - public void run(CommandLine args, Io io) { - this.ctx = getContext(); - this.io = io; + public void run(CliContext context, CommandLine args) { + this.ctx = context; + this.io = ctx.getIo(); String[] stringArgs = args.getArgs(); //TODO: Do this in all commands @@ -68,10 +67,10 @@ private void updateExercises(CourseInfo info, Path configFile) { printExercises(exerciseUpdater.getUpdatedExercises(), "Modified exercises:"); io.println(""); - Color.AnsiColor color1 = getContext().getApp().getColor("progressbar-left"); - Color.AnsiColor color2 = getContext().getApp().getColor("progressbar-right"); + Color color1 = ctx.getApp().getColor("progressbar-left"); + Color color2 = ctx.getApp().getColor("progressbar-right"); List downloaded = exerciseUpdater.downloadUpdates( - new TmcCliProgressObserver(io, color1, color2)); + new CliProgressObserver(io, color1, color2)); if (downloaded.isEmpty()) { io.println("Failed to download exercises"); return; diff --git a/src/main/java/fi/helsinki/cs/tmc/cli/command/core/AbstractCommand.java b/src/main/java/fi/helsinki/cs/tmc/cli/core/AbstractCommand.java similarity index 76% rename from src/main/java/fi/helsinki/cs/tmc/cli/command/core/AbstractCommand.java rename to src/main/java/fi/helsinki/cs/tmc/cli/core/AbstractCommand.java index 810025ef..ab66ff3f 100644 --- a/src/main/java/fi/helsinki/cs/tmc/cli/command/core/AbstractCommand.java +++ b/src/main/java/fi/helsinki/cs/tmc/cli/core/AbstractCommand.java @@ -1,7 +1,5 @@ -package fi.helsinki.cs.tmc.cli.command.core; +package fi.helsinki.cs.tmc.cli.core; -import fi.helsinki.cs.tmc.cli.CliContext; -import fi.helsinki.cs.tmc.cli.command.LoginCommand; import fi.helsinki.cs.tmc.cli.io.HelpGenerator; import fi.helsinki.cs.tmc.cli.io.Io; @@ -14,17 +12,7 @@ import org.slf4j.LoggerFactory; public abstract class AbstractCommand { - private static final Logger logger = LoggerFactory.getLogger(LoginCommand.class); - - private CliContext context; - - protected void setContext(CliContext context) { - this.context = context; - } - - protected CliContext getContext() { - return this.context; - } + private static final Logger logger = LoggerFactory.getLogger(AbstractCommand.class); /** * Override this method if you want longer description for the command than @@ -53,18 +41,18 @@ private Options getOptions() { * TODO io param isn't needed anymore!!!! * * @param args Command line arguments for this command. - * @param io The terminal IO object + * @param ctx The context object. */ - public abstract void run(CommandLine args, Io io); + public abstract void run(CliContext ctx, CommandLine args); - public void execute(String[] stringArgs, Io io) { - CommandLine args = parseArgs(stringArgs); + public void execute(CliContext context, String[] stringArgs) { + CommandLine args = parseArgs(context, stringArgs); if (args != null) { - run(args, io); + run(context, args); } } - public CommandLine parseArgs(String[] stringArgs) { + public CommandLine parseArgs(CliContext context, String[] stringArgs) { GnuParser parser = new GnuParser(); CommandLine args; Options options = getOptions(); diff --git a/src/main/java/fi/helsinki/cs/tmc/cli/CliContext.java b/src/main/java/fi/helsinki/cs/tmc/cli/core/CliContext.java similarity index 80% rename from src/main/java/fi/helsinki/cs/tmc/cli/CliContext.java rename to src/main/java/fi/helsinki/cs/tmc/cli/core/CliContext.java index 4cda3ba0..8b64c690 100644 --- a/src/main/java/fi/helsinki/cs/tmc/cli/CliContext.java +++ b/src/main/java/fi/helsinki/cs/tmc/cli/core/CliContext.java @@ -1,14 +1,18 @@ -package fi.helsinki.cs.tmc.cli; - +package fi.helsinki.cs.tmc.cli.core; + +import fi.helsinki.cs.tmc.cli.Application; +import fi.helsinki.cs.tmc.cli.backend.Account; +import fi.helsinki.cs.tmc.cli.backend.AccountList; +import fi.helsinki.cs.tmc.cli.backend.CourseInfo; +import fi.helsinki.cs.tmc.cli.backend.CourseInfoIo; +import fi.helsinki.cs.tmc.cli.backend.Settings; +import fi.helsinki.cs.tmc.cli.backend.SettingsIo; import fi.helsinki.cs.tmc.cli.io.Io; import fi.helsinki.cs.tmc.cli.io.TerminalIo; -import fi.helsinki.cs.tmc.cli.tmcstuff.CourseInfo; -import fi.helsinki.cs.tmc.cli.tmcstuff.CourseInfoIo; -import fi.helsinki.cs.tmc.cli.tmcstuff.Settings; -import fi.helsinki.cs.tmc.cli.tmcstuff.SettingsIo; -import fi.helsinki.cs.tmc.cli.tmcstuff.WorkDir; +import fi.helsinki.cs.tmc.cli.io.WorkDir; +import fi.helsinki.cs.tmc.cli.shared.CourseFinder; + import fi.helsinki.cs.tmc.core.TmcCore; -import fi.helsinki.cs.tmc.core.domain.Course; import fi.helsinki.cs.tmc.langs.util.TaskExecutor; import fi.helsinki.cs.tmc.langs.util.TaskExecutorImpl; @@ -42,14 +46,11 @@ public CliContext(Io io, TmcCore core, WorkDir workDir) { if (!inTest) { io = new TerminalIo(System.in); } - // This is only used when we want to mock the tmc core. - if (core != null) { - this.settings = new Settings(); - } this.io = io; this.workDir = workDir; this.properties = SettingsIo.loadProperties(); + this.settings = new Settings(); this.tmcCore = core; this.hasLogin = (core != null); this.courseInfo = null; @@ -105,15 +106,14 @@ public WorkDir getWorkDir() { } /** - * Create local course info file after download. + * Create new instance of course finder. + * This is used so that it's easy to mock out the course finder. * - * @param course local copy of course object - * @return cached course data object + * @return new instance of CourseFinder */ - public CourseInfo createCourseInfo(Course course) { - return new CourseInfo(settings, course); + public CourseFinder createCourseFinder() { + return new CourseFinder(this); } - /** * Get map of the properties. * @@ -213,49 +213,41 @@ public boolean loadBackendWithoutLogin() { /** * Copy login info from different settings object and them. - * TODO: separate settings object and login info. - * @param settings login info + * @param account login info */ - public void useSettings(Settings settings) { - if (this.tmcCore == null) { - createTmcCore(settings); - } - this.settings.set(settings); + public void useAccount(Account account) { + this.settings.setAccount(account); } - private void createTmcCore(Settings settings) { + private void createTmcCore(Account account) { TaskExecutor tmcLangs; tmcLangs = new TaskExecutorImpl(); - this.settings = settings; + this.settings.setAccount(account); this.tmcCore = new TmcCore(settings, tmcLangs); settings.setWorkDir(workDir); } private boolean createTmcCore() { - Settings cachedSettings = null; + Account cachedAccount = null; + AccountList list = SettingsIo.loadAccountList(); if (workDir.getConfigFile() != null) { // If we're in a course directory, we load settings matching the course // Otherwise we just load the last used settings courseInfo = getCourseInfo(); if (courseInfo != null) { - cachedSettings = SettingsIo.load(courseInfo.getUsername(), + cachedAccount = list.getAccount(courseInfo.getUsername(), courseInfo.getServerAddress()); } } else { // Bug: if we are not inside course directory // then we may not correctly guess the correct settings. - cachedSettings = SettingsIo.load(); - } - - hasLogin = true; - if (cachedSettings == null) { - hasLogin = false; - cachedSettings = new Settings(); + cachedAccount = list.getAccount(); } - createTmcCore(cachedSettings); + hasLogin = (cachedAccount != null); + createTmcCore(cachedAccount); return true; } } diff --git a/src/main/java/fi/helsinki/cs/tmc/cli/command/core/Command.java b/src/main/java/fi/helsinki/cs/tmc/cli/core/Command.java similarity index 89% rename from src/main/java/fi/helsinki/cs/tmc/cli/command/core/Command.java rename to src/main/java/fi/helsinki/cs/tmc/cli/core/Command.java index 192a085f..38401e75 100644 --- a/src/main/java/fi/helsinki/cs/tmc/cli/command/core/Command.java +++ b/src/main/java/fi/helsinki/cs/tmc/cli/core/Command.java @@ -1,4 +1,4 @@ -package fi.helsinki.cs.tmc.cli.command.core; +package fi.helsinki.cs.tmc.cli.core; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; diff --git a/src/main/java/fi/helsinki/cs/tmc/cli/command/core/CommandAnnotationProcessor.java b/src/main/java/fi/helsinki/cs/tmc/cli/core/CommandAnnotationProcessor.java similarity index 89% rename from src/main/java/fi/helsinki/cs/tmc/cli/command/core/CommandAnnotationProcessor.java rename to src/main/java/fi/helsinki/cs/tmc/cli/core/CommandAnnotationProcessor.java index 2dd69df7..0817c8f3 100644 --- a/src/main/java/fi/helsinki/cs/tmc/cli/command/core/CommandAnnotationProcessor.java +++ b/src/main/java/fi/helsinki/cs/tmc/cli/core/CommandAnnotationProcessor.java @@ -1,4 +1,4 @@ -package fi.helsinki.cs.tmc.cli.command.core; +package fi.helsinki.cs.tmc.cli.core; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -12,8 +12,6 @@ import java.util.Set; import javax.annotation.processing.AbstractProcessor; -import javax.annotation.processing.Messager; -import javax.annotation.processing.ProcessingEnvironment; import javax.annotation.processing.RoundEnvironment; import javax.annotation.processing.SupportedAnnotationTypes; import javax.annotation.processing.SupportedSourceVersion; @@ -21,16 +19,15 @@ import javax.lang.model.element.Element; import javax.lang.model.element.ElementKind; import javax.lang.model.element.TypeElement; -import javax.tools.Diagnostic; import javax.tools.JavaFileObject; @SupportedSourceVersion(SourceVersion.RELEASE_6) -@SupportedAnnotationTypes({"fi.helsinki.cs.tmc.cli.command.Command", "java.lang.Override"}) +@SupportedAnnotationTypes({"fi.helsinki.cs.tmc.cli.core.Command"}) public class CommandAnnotationProcessor extends AbstractProcessor { private static final Logger logger = LoggerFactory.getLogger(CommandAnnotationProcessor.class); private static final String CLASS_NAME = "CommandList"; - private static final String PACKAGE_NAME = "fi.helsinki.cs.tmc.cli.command.core"; + private static final String PACKAGE_NAME = "fi.helsinki.cs.tmc.cli.core"; private static final String TAB = " "; private void generateSourceFile(Map map) throws IOException { @@ -77,8 +74,8 @@ public boolean process(Set annotations, RoundEnvironment return false; } Command command = elem.getAnnotation(Command.class); - logger.info("element with annotation: " + elem.toString()); - logger.info("element name with annotation: " + elem.getClass().getCanonicalName()); + logger.info("Element with annotation: " + elem.toString()); + logger.info("Element name with annotation: " + elem.getClass().getCanonicalName()); TypeElement classElement = (TypeElement) elem; map.put(command.name(), processingEnv.getElementUtils() diff --git a/src/main/java/fi/helsinki/cs/tmc/cli/command/core/CommandFactory.java b/src/main/java/fi/helsinki/cs/tmc/cli/core/CommandFactory.java similarity index 91% rename from src/main/java/fi/helsinki/cs/tmc/cli/command/core/CommandFactory.java rename to src/main/java/fi/helsinki/cs/tmc/cli/core/CommandFactory.java index bbaa5710..90e71f3c 100644 --- a/src/main/java/fi/helsinki/cs/tmc/cli/command/core/CommandFactory.java +++ b/src/main/java/fi/helsinki/cs/tmc/cli/core/CommandFactory.java @@ -1,6 +1,4 @@ -package fi.helsinki.cs.tmc.cli.command.core; - -import fi.helsinki.cs.tmc.cli.CliContext; +package fi.helsinki.cs.tmc.cli.core; import org.slf4j.LoggerFactory; @@ -12,7 +10,6 @@ /** * Class used for creating new instances of commands. - * TODO make this class completely static. */ public class CommandFactory { @@ -25,7 +22,7 @@ public class CommandFactory { * class. */ try { - Class.forName("fi.helsinki.cs.tmc.cli.command.core.CommandList"); + Class.forName("fi.helsinki.cs.tmc.cli.core.CommandList"); } catch (ClassNotFoundException ex) { System.out.println("Fail " + ex); } @@ -68,14 +65,13 @@ public static void addCommand(Class commandClass) { * @param name Name of the command * @return A new command instance */ - public static AbstractCommand createCommand(CliContext context, String name) { + public static AbstractCommand createCommand(String name) { Class commandClass = CommandFactory.commands.get(name); if (commandClass == null) { return null; } try { AbstractCommand command = (AbstractCommand)commandClass.newInstance(); - command.setContext(context); return command; } catch (InstantiationException | IllegalAccessException ex) { throw new RuntimeException("getCommand failed", ex); diff --git a/src/main/java/fi/helsinki/cs/tmc/cli/io/TmcCliProgressObserver.java b/src/main/java/fi/helsinki/cs/tmc/cli/io/CliProgressObserver.java similarity index 83% rename from src/main/java/fi/helsinki/cs/tmc/cli/io/TmcCliProgressObserver.java rename to src/main/java/fi/helsinki/cs/tmc/cli/io/CliProgressObserver.java index 1cbbbf75..befaa7d9 100644 --- a/src/main/java/fi/helsinki/cs/tmc/cli/io/TmcCliProgressObserver.java +++ b/src/main/java/fi/helsinki/cs/tmc/cli/io/CliProgressObserver.java @@ -2,7 +2,7 @@ import fi.helsinki.cs.tmc.core.domain.ProgressObserver; -public class TmcCliProgressObserver extends ProgressObserver { +public class CliProgressObserver extends ProgressObserver { protected static final char PIPCHAR = 'â–ˆ'; protected static final char EMPTYCHAR = 'â–‘'; protected static final char BARLEFT = '['; @@ -11,20 +11,20 @@ public class TmcCliProgressObserver extends ProgressObserver { protected Io io; private int pips; protected int maxline; - private Color.AnsiColor color1; - private Color.AnsiColor color2; + private Color color1; + private Color color2; protected String lastMessage; protected Boolean hasProgressBar; - public TmcCliProgressObserver() { + public CliProgressObserver() { this(new TerminalIo(System.in)); } - public TmcCliProgressObserver(Io io) { - this(io, Color.AnsiColor.ANSI_CYAN, Color.AnsiColor.ANSI_CYAN); + public CliProgressObserver(Io io) { + this(io, Color.CYAN, Color.CYAN); } - public TmcCliProgressObserver(Io io, Color.AnsiColor color1, Color.AnsiColor color2) { + public CliProgressObserver(Io io, Color color1, Color color2) { this.hasProgressBar = false; this.io = io; this.maxline = EnvironmentUtil.getTerminalWidth(); @@ -97,7 +97,7 @@ protected void flush(int length) { } public static String progressBar(double progress, int length, - Color.AnsiColor color1, Color.AnsiColor color2) { + Color color1, Color color2) { return progressBar(progress, length, color1, color2, BARLEFT, BARRIGHT, PIPCHAR, EMPTYCHAR); } @@ -105,8 +105,8 @@ public static String progressBar(double progress, int length, public static String progressBar( double progress, int length, - Color.AnsiColor color1, - Color.AnsiColor color2, + Color color1, + Color color2, char barLeft, char barRight, char donePip, @@ -122,8 +122,8 @@ public static String progressBar( } return percentage(progress) + barLeft - + Color.colorString(sbLeft.toString(), color1) - + Color.colorString(sbRight.toString(), color2) + + ColorUtil.colorString(sbLeft.toString(), color1) + + ColorUtil.colorString(sbRight.toString(), color2) + barRight; } @@ -141,8 +141,8 @@ protected static String percentage(double progress) { } public static String getPassedTestsBar(int passed, int total, - Color.AnsiColor color1, Color.AnsiColor color2) { - return TmcCliProgressObserver.progressBar( + Color color1, Color color2) { + return CliProgressObserver.progressBar( (double) passed / total, EnvironmentUtil.getTerminalWidth(), color1, color2, diff --git a/src/main/java/fi/helsinki/cs/tmc/cli/io/Color.java b/src/main/java/fi/helsinki/cs/tmc/cli/io/Color.java index 9492feb6..0099969d 100644 --- a/src/main/java/fi/helsinki/cs/tmc/cli/io/Color.java +++ b/src/main/java/fi/helsinki/cs/tmc/cli/io/Color.java @@ -1,53 +1,25 @@ package fi.helsinki.cs.tmc.cli.io; -public class Color { +public enum Color { + NONE(""), + RESET("\u001B[0m"), + BLACK("\u001B[30m"), + RED("\u001B[31m"), + GREEN("\u001B[32m"), + YELLOW("\u001B[33m"), + BLUE("\u001B[34m"), + PURPLE("\u001B[35m"), + CYAN("\u001B[36m"), + WHITE("\u001B[37m"); - public enum AnsiColor { - ANSI_NONE(""), - ANSI_RESET("\u001B[0m"), - ANSI_BLACK("\u001B[30m"), - ANSI_RED("\u001B[31m"), - ANSI_GREEN("\u001B[32m"), - ANSI_YELLOW("\u001B[33m"), - ANSI_BLUE("\u001B[34m"), - ANSI_PURPLE("\u001B[35m"), - ANSI_CYAN("\u001B[36m"), - ANSI_WHITE("\u001B[37m"); + private final String escCode; - private String escCode; - - AnsiColor(String color) { - this.escCode = color; - } - - public String toString() { - return this.escCode; - } - } - - public static String colorString(String string, AnsiColor color) { - if (!EnvironmentUtil.isWindows() && color != AnsiColor.ANSI_NONE) { - return color + string + AnsiColor.ANSI_RESET; - } else { - return string; - } + Color(String escCode) { + this.escCode = escCode; } - public static AnsiColor getColor(String color) { - if (color == null) { - return null; - } - switch (color) { - case "black": return AnsiColor.ANSI_BLACK; - case "red": return AnsiColor.ANSI_RED; - case "green": return AnsiColor.ANSI_GREEN; - case "yellow": return AnsiColor.ANSI_YELLOW; - case "blue": return AnsiColor.ANSI_BLUE; - case "purple": return AnsiColor.ANSI_PURPLE; - case "cyan": return AnsiColor.ANSI_CYAN; - case "white": return AnsiColor.ANSI_WHITE; - case "none": return AnsiColor.ANSI_NONE; - default: return null; - } + @Override + public String toString() { + return this.escCode; } } diff --git a/src/main/java/fi/helsinki/cs/tmc/cli/io/ColorUtil.java b/src/main/java/fi/helsinki/cs/tmc/cli/io/ColorUtil.java new file mode 100644 index 00000000..4b4d433c --- /dev/null +++ b/src/main/java/fi/helsinki/cs/tmc/cli/io/ColorUtil.java @@ -0,0 +1,24 @@ +package fi.helsinki.cs.tmc.cli.io; + +public class ColorUtil { + + public static String colorString(String string, Color color) { + if (!EnvironmentUtil.isWindows() && color != Color.NONE) { + return color + string + Color.RESET; + } else { + return string; + } + } + + public static Color getColor(String name) { + try { + Color color = Color.valueOf(name.toUpperCase()); + if (color == Color.NONE || color == Color.RESET) { + color = null; + } + return color; + } catch (IllegalArgumentException | NullPointerException e) { + return null; + } + } +} diff --git a/src/main/java/fi/helsinki/cs/tmc/cli/io/ShutdownHandler.java b/src/main/java/fi/helsinki/cs/tmc/cli/io/ShutdownHandler.java index 1912c870..8e6dc5f9 100644 --- a/src/main/java/fi/helsinki/cs/tmc/cli/io/ShutdownHandler.java +++ b/src/main/java/fi/helsinki/cs/tmc/cli/io/ShutdownHandler.java @@ -15,7 +15,7 @@ public ShutdownHandler(Io io) { public void run() { // Reset terminal color back to default in case we exit in the middle of // colored printing. Otherwise user is left with a colored terminal. - io.println(Color.AnsiColor.ANSI_RESET.toString()); + io.println(Color.RESET.toString()); } public void enable() { diff --git a/src/main/java/fi/helsinki/cs/tmc/cli/tmcstuff/WorkDir.java b/src/main/java/fi/helsinki/cs/tmc/cli/io/WorkDir.java similarity index 98% rename from src/main/java/fi/helsinki/cs/tmc/cli/tmcstuff/WorkDir.java rename to src/main/java/fi/helsinki/cs/tmc/cli/io/WorkDir.java index 71ab2c97..398ef04b 100644 --- a/src/main/java/fi/helsinki/cs/tmc/cli/tmcstuff/WorkDir.java +++ b/src/main/java/fi/helsinki/cs/tmc/cli/io/WorkDir.java @@ -1,5 +1,7 @@ -package fi.helsinki.cs.tmc.cli.tmcstuff; +package fi.helsinki.cs.tmc.cli.io; +import fi.helsinki.cs.tmc.cli.backend.CourseInfo; +import fi.helsinki.cs.tmc.cli.backend.CourseInfoIo; import fi.helsinki.cs.tmc.core.domain.Exercise; import java.io.File; @@ -9,7 +11,6 @@ import java.util.ArrayList; import java.util.List; -//TODO should this be in io package? public class WorkDir { // Course root directory. null if n/a. diff --git a/src/main/java/fi/helsinki/cs/tmc/cli/shared/CourseFinder.java b/src/main/java/fi/helsinki/cs/tmc/cli/shared/CourseFinder.java new file mode 100644 index 00000000..85debd65 --- /dev/null +++ b/src/main/java/fi/helsinki/cs/tmc/cli/shared/CourseFinder.java @@ -0,0 +1,107 @@ +package fi.helsinki.cs.tmc.cli.shared; + +import fi.helsinki.cs.tmc.cli.backend.Account; +import fi.helsinki.cs.tmc.cli.backend.AccountList; +import fi.helsinki.cs.tmc.cli.backend.SettingsIo; +import fi.helsinki.cs.tmc.cli.backend.TmcUtil; +import fi.helsinki.cs.tmc.cli.core.CliContext; +import fi.helsinki.cs.tmc.cli.io.Io; + +import fi.helsinki.cs.tmc.core.domain.Course; + +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * This class is used for searching courses from tmc servers. + * TODO move some of the test from DownloadExercisesCommand to CourseFinder + */ +public class CourseFinder { + + private final CliContext ctx; + private Course course; + private Account account; + + public CourseFinder(CliContext ctx) { + this.ctx = ctx; + } + + public Course getCourse() { + verifySearchIsCalled(); + return course; + } + + public Account getAccount() { + verifySearchIsCalled(); + return account; + } + + public boolean search(String courseName) { + Io io = ctx.getIo(); + + AccountList accountsList = SettingsIo.loadAccountList(); + // LinkedHashMap is used here to preserve ordering. + Map matches = new LinkedHashMap<>(); + + if (accountsList.getAccountCount() == 0) { + io.println("You haven't logged in on any tmc server."); + return false; + } + + for (Account settings : accountsList) { + ctx.useAccount(settings); + Course found = TmcUtil.findCourse(ctx, courseName); + if (found != null) { + matches.put(settings, found); + } + } + + if (matches.isEmpty()) { + //TODO we could search here for similar courses. + io.println("Course doesn't exist."); + return false; + } else if (matches.size() == 1) { + return handleSingleMatchingCourses(matches); + } else { + return handleMultipleMatchingCourses(matches); + } + } + + private boolean handleSingleMatchingCourses(Map matches) { + Map.Entry firstEntry; + firstEntry = matches.entrySet().iterator().next(); + + this.account = firstEntry.getKey(); + this.course = firstEntry.getValue(); + return true; + } + + private boolean handleMultipleMatchingCourses(Map matches) { + Io io = ctx.getIo(); + io.println("There is " + matches.size() + + " courses with same name at different servers."); + + for (Map.Entry entrySet : matches.entrySet()) { + Account entryAccount = entrySet.getKey(); + Course entryCourse = entrySet.getValue(); + + if (io.readConfirmation("Download course from " + + entryAccount.getServerAddress() + " with '" + + entryAccount.getUsername() + "' account", false)) { + this.account = entryAccount; + this.course = entryCourse; + return true; + } + } + + io.println("The previous course was last that matched."); + return false; + } + + private void verifySearchIsCalled() { + if (course != null) { + return; + } + throw new RuntimeException("You must search before using getters"); + } +} diff --git a/src/main/java/fi/helsinki/cs/tmc/cli/tmcstuff/ExerciseUpdater.java b/src/main/java/fi/helsinki/cs/tmc/cli/shared/ExerciseUpdater.java similarity index 89% rename from src/main/java/fi/helsinki/cs/tmc/cli/tmcstuff/ExerciseUpdater.java rename to src/main/java/fi/helsinki/cs/tmc/cli/shared/ExerciseUpdater.java index eefefea8..3e47c29a 100644 --- a/src/main/java/fi/helsinki/cs/tmc/cli/tmcstuff/ExerciseUpdater.java +++ b/src/main/java/fi/helsinki/cs/tmc/cli/shared/ExerciseUpdater.java @@ -1,7 +1,11 @@ -package fi.helsinki.cs.tmc.cli.tmcstuff; +package fi.helsinki.cs.tmc.cli.shared; + +import fi.helsinki.cs.tmc.cli.backend.CourseInfo; +import fi.helsinki.cs.tmc.cli.backend.CourseInfoIo; +import fi.helsinki.cs.tmc.cli.backend.TmcUtil; +import fi.helsinki.cs.tmc.cli.core.CliContext; +import fi.helsinki.cs.tmc.cli.io.CliProgressObserver; -import fi.helsinki.cs.tmc.cli.CliContext; -import fi.helsinki.cs.tmc.cli.io.TmcCliProgressObserver; import fi.helsinki.cs.tmc.core.commands.GetUpdatableExercises.UpdateResult; import fi.helsinki.cs.tmc.core.domain.Course; import fi.helsinki.cs.tmc.core.domain.Exercise; @@ -80,7 +84,7 @@ public boolean updatesAvailable() { return newExercisesAvailable() || updatedExercisesAvailable(); } - public List downloadUpdates(TmcCliProgressObserver progobs) { + public List downloadUpdates(CliProgressObserver progobs) { List newAndUpdated = getNewAndUpdatedExercises(); for (Iterator iterator = newAndUpdated.iterator(); iterator.hasNext();) { Exercise next = iterator.next(); diff --git a/src/main/java/fi/helsinki/cs/tmc/cli/tmcstuff/FeedbackHandler.java b/src/main/java/fi/helsinki/cs/tmc/cli/shared/FeedbackHandler.java similarity index 95% rename from src/main/java/fi/helsinki/cs/tmc/cli/tmcstuff/FeedbackHandler.java rename to src/main/java/fi/helsinki/cs/tmc/cli/shared/FeedbackHandler.java index ec92ea5d..c730b9fe 100644 --- a/src/main/java/fi/helsinki/cs/tmc/cli/tmcstuff/FeedbackHandler.java +++ b/src/main/java/fi/helsinki/cs/tmc/cli/shared/FeedbackHandler.java @@ -1,8 +1,10 @@ -package fi.helsinki.cs.tmc.cli.tmcstuff; +package fi.helsinki.cs.tmc.cli.shared; -import fi.helsinki.cs.tmc.cli.CliContext; +import fi.helsinki.cs.tmc.cli.backend.TmcUtil; +import fi.helsinki.cs.tmc.cli.core.CliContext; import fi.helsinki.cs.tmc.cli.io.ExternalsUtil; import fi.helsinki.cs.tmc.cli.io.Io; + import fi.helsinki.cs.tmc.core.domain.submission.FeedbackAnswer; import fi.helsinki.cs.tmc.core.domain.submission.FeedbackQuestion; diff --git a/src/main/java/fi/helsinki/cs/tmc/cli/io/ResultPrinter.java b/src/main/java/fi/helsinki/cs/tmc/cli/shared/ResultPrinter.java similarity index 90% rename from src/main/java/fi/helsinki/cs/tmc/cli/io/ResultPrinter.java rename to src/main/java/fi/helsinki/cs/tmc/cli/shared/ResultPrinter.java index e733bf4f..92392351 100644 --- a/src/main/java/fi/helsinki/cs/tmc/cli/io/ResultPrinter.java +++ b/src/main/java/fi/helsinki/cs/tmc/cli/shared/ResultPrinter.java @@ -1,4 +1,9 @@ -package fi.helsinki.cs.tmc.cli.io; +package fi.helsinki.cs.tmc.cli.shared; + +import fi.helsinki.cs.tmc.cli.io.CliProgressObserver; +import fi.helsinki.cs.tmc.cli.io.Color; +import fi.helsinki.cs.tmc.cli.io.ColorUtil; +import fi.helsinki.cs.tmc.cli.io.Io; import fi.helsinki.cs.tmc.core.domain.submission.SubmissionResult; import fi.helsinki.cs.tmc.langs.abstraction.Strategy; @@ -16,14 +21,14 @@ public class ResultPrinter { private static final String COMPILE_ERROR_MESSAGE - = Color.colorString("Failed to compile project", Color.AnsiColor.ANSI_PURPLE); + = ColorUtil.colorString("Failed to compile project", Color.PURPLE); private static final String FAIL_MESSAGE = "Failed: "; private static final String PASS_MESSAGE = "Passed: "; private static final String PADDING = createPaddingString(PASS_MESSAGE.length()); private final Io io; - private final Color.AnsiColor passedColor; - private final Color.AnsiColor failedColor; + private final Color passedColor; + private final Color failedColor; private boolean showDetails; private boolean showPassed; @@ -31,7 +36,7 @@ public class ResultPrinter { private int passedExercises; public ResultPrinter(Io io, boolean showDetails, boolean showPassed, - Color.AnsiColor passedColor, Color.AnsiColor failedColor) { + Color passedColor, Color failedColor) { this.io = io; this.passedColor = passedColor; this.failedColor = failedColor; @@ -117,7 +122,7 @@ public boolean printLocalTestResult(RunResult runResult, ValidationResult valRes } if (runResult.status == RunResult.Status.PASSED && validationsPassed) { - io.print(Color.colorString("All tests passed!", Color.AnsiColor.ANSI_GREEN)); + io.print(ColorUtil.colorString("All tests passed!", Color.GREEN)); io.println(" Submit to server with 'tmc submit'"); passedExercises++; return true; @@ -160,7 +165,7 @@ private void printResultBar(int passed, int total) { return; } io.println( - TmcCliProgressObserver.getPassedTestsBar(passed, total, passedColor, failedColor) + CliProgressObserver.getPassedTestsBar(passed, total, passedColor, failedColor) ); } @@ -174,7 +179,7 @@ private boolean validationsPassed(ValidationResult result) { private void printValidationErrors(ValidationResult result) { Map> errors = result.getValidationErrors(); - io.println(Color.colorString("Validation error:", failedColor)); + io.println(ColorUtil.colorString("Validation error:", failedColor)); for (Map.Entry> entry : errors.entrySet()) { io.println("File: " + entry.getKey()); @@ -199,7 +204,7 @@ private void printTestCases(List testResults) { } private void printFailedTest(TestResult testResult) { - io.print(Color.colorString(FAIL_MESSAGE, failedColor)); + io.print(ColorUtil.colorString(FAIL_MESSAGE, failedColor)); io.println(testResult.getName()); io.println(PADDING + testResult.getMessage()); @@ -221,7 +226,7 @@ private void printFailedTest(TestResult testResult) { } private void printPassedTest(TestResult testResult) { - io.print(Color.colorString(PASS_MESSAGE, passedColor)); + io.print(ColorUtil.colorString(PASS_MESSAGE, passedColor)); io.println(testResult.getName()); } @@ -235,7 +240,7 @@ private void printPassedSubmissionResult(SubmissionResult submResult, boolean pr printResultBar(passedTests, totalTests); } - io.println(Color.colorString("All tests passed on server!", passedColor)); + io.println(ColorUtil.colorString("All tests passed on server!", passedColor)); passedExercises++; if (!submResult.getPoints().isEmpty()) { @@ -253,7 +258,7 @@ private void printFailedSubmissionResult(SubmissionResult submResult, boolean pr String valgrind = submResult.getValgrind(); if (valgrind != null && !valgrind.isEmpty()) { - io.println(Color.colorString("Valgrind error:", failedColor)); + io.println(ColorUtil.colorString("Valgrind error:", failedColor)); io.println(valgrind); totalTests++; } diff --git a/src/main/java/fi/helsinki/cs/tmc/cli/tmcstuff/SettingsHolder.java b/src/main/java/fi/helsinki/cs/tmc/cli/tmcstuff/SettingsHolder.java deleted file mode 100644 index aace9f3d..00000000 --- a/src/main/java/fi/helsinki/cs/tmc/cli/tmcstuff/SettingsHolder.java +++ /dev/null @@ -1,78 +0,0 @@ -package fi.helsinki.cs.tmc.cli.tmcstuff; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -/** - * This is a class for storing all different login settings as a single array. - */ -public class SettingsHolder { - private ArrayList settingsArray; - - public SettingsHolder() { - this.settingsArray = new ArrayList<>(); - } - - public Settings getSettings() { - if (this.settingsArray.size() > 0) { - // Get last used settings by default - return this.settingsArray.get(0); - } - return null; - } - - public Settings getSettings(String username, String server) { - if (username == null || server == null) { - return getSettings(); - } - for (Settings settings : this.settingsArray) { - if (settings.getUsername().equals(username) - && settings.getServerAddress().equals(server)) { - // Move settings to index 0 so we can always use the last used settings by default - this.settingsArray.remove(settings); - this.settingsArray.add(0, settings); - return settings; - } - } - return null; - } - - public void addSettings(Settings newSettings) { - for (Settings settings : this.settingsArray) { - if (settings.getUsername().equals(newSettings.getUsername()) - && settings.getServerAddress().equals(newSettings.getServerAddress())) { - // Replace old settings if username and server match - this.settingsArray.remove(settings); - break; - } - } - this.settingsArray.add(0, newSettings); - } - - public void deleteSettings(String username, String server) { - Settings remove = null; - for (Settings settings : this.settingsArray) { - if (settings.getUsername().equals(username) - && settings.getServerAddress().equals(server)) { - remove = settings; - break; - } - } - if (remove != null) { - this.settingsArray.remove(remove); - } - } - - public void deleteAllSettings() { - this.settingsArray = new ArrayList(); - } - - public int settingsCount() { - return this.settingsArray.size(); - } - - public List getSettingsList() { - return Collections.unmodifiableList(this.settingsArray); - } -} diff --git a/src/main/java/fi/helsinki/cs/tmc/cli/updater/TmcCliUpdater.java b/src/main/java/fi/helsinki/cs/tmc/cli/updater/AutoUpdater.java similarity index 94% rename from src/main/java/fi/helsinki/cs/tmc/cli/updater/TmcCliUpdater.java rename to src/main/java/fi/helsinki/cs/tmc/cli/updater/AutoUpdater.java index 23c45217..b3358c22 100644 --- a/src/main/java/fi/helsinki/cs/tmc/cli/updater/TmcCliUpdater.java +++ b/src/main/java/fi/helsinki/cs/tmc/cli/updater/AutoUpdater.java @@ -20,7 +20,7 @@ import java.net.URL; import java.net.URLConnection; -public class TmcCliUpdater { +public class AutoUpdater { /** * URL to a JSON that contains information about the latest tmc-cli release. @@ -29,20 +29,20 @@ public class TmcCliUpdater { = "https://api.github.com/repos/tmc-cli/tmc-cli/releases/latest"; private static final Logger logger - = LoggerFactory.getLogger(TmcCliUpdater.class); + = LoggerFactory.getLogger(AutoUpdater.class); private final Io io; private final boolean isWindows; private final String currentVersion; - public TmcCliUpdater(Io io, String currentVersion, boolean isWindows) { + public AutoUpdater(Io io, String currentVersion, boolean isWindows) { this.io = io; this.currentVersion = currentVersion; this.isWindows = isWindows; } - public static TmcCliUpdater createUpdater(Io io, String currentVersion, boolean isWindows) { - return new TmcCliUpdater(io, currentVersion, isWindows); + public static AutoUpdater createUpdater(Io io, String currentVersion, boolean isWindows) { + return new AutoUpdater(io, currentVersion, isWindows); } /** @@ -229,7 +229,7 @@ private JsonObject toJsonObject(String jsonString) { private static String getJarLocation() { try { - return new File(TmcCliUpdater.class.getProtectionDomain() + return new File(AutoUpdater.class.getProtectionDomain() .getCodeSource().getLocation().toURI()).getParent() + File.separator; } catch (Exception ex) { diff --git a/src/test/java/fi/helsinki/cs/tmc/cli/ApplicationTest.java b/src/test/java/fi/helsinki/cs/tmc/cli/ApplicationTest.java index 2b436979..9e0f6234 100644 --- a/src/test/java/fi/helsinki/cs/tmc/cli/ApplicationTest.java +++ b/src/test/java/fi/helsinki/cs/tmc/cli/ApplicationTest.java @@ -1,6 +1,5 @@ package fi.helsinki.cs.tmc.cli; -import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyString; import static org.mockito.Mockito.doReturn; @@ -12,9 +11,10 @@ import static org.powermock.api.mockito.PowerMockito.mockStatic; import static org.powermock.api.mockito.PowerMockito.verifyStatic; +import fi.helsinki.cs.tmc.cli.core.CliContext; import fi.helsinki.cs.tmc.cli.io.Io; import fi.helsinki.cs.tmc.cli.io.TestIo; -import fi.helsinki.cs.tmc.cli.updater.TmcCliUpdater; +import fi.helsinki.cs.tmc.cli.updater.AutoUpdater; import org.junit.Before; import org.junit.Test; @@ -25,7 +25,7 @@ import java.util.HashMap; @RunWith(PowerMockRunner.class) -@PrepareForTest(TmcCliUpdater.class) +@PrepareForTest(AutoUpdater.class) public class ApplicationTest { private Application app; @@ -35,14 +35,14 @@ public class ApplicationTest { public void setUp() { io = new TestIo(); app = new Application(new CliContext(io)); - mockStatic(TmcCliUpdater.class); + mockStatic(AutoUpdater.class); } @Test public void versionWorksWithRightParameter() { String[] args = {"-v", "foo"}; app.run(args); - assertTrue(io.out().contains("TMC-CLI version")); + io.assertContains("TMC-CLI version"); io.assertNotContains("Command foo doesn't exist."); } @@ -78,8 +78,8 @@ public void runCommandWorksWithWrongParameter() { @Test public void runAutoUpdate() { String[] args = {"help"}; - TmcCliUpdater mockUpdater = mock(TmcCliUpdater.class); - when(TmcCliUpdater.createUpdater(any(Io.class), anyString(), any(Boolean.class))) + AutoUpdater mockUpdater = mock(AutoUpdater.class); + when(AutoUpdater.createUpdater(any(Io.class), anyString(), any(Boolean.class))) .thenReturn(mockUpdater); when(mockUpdater.run()).thenReturn(true); @@ -90,7 +90,7 @@ public void runAutoUpdate() { app.run(args); verifyStatic(times(1)); - TmcCliUpdater.createUpdater(any(Io.class), anyString(), any(Boolean.class)); + AutoUpdater.createUpdater(any(Io.class), anyString(), any(Boolean.class)); } @Test diff --git a/src/test/java/fi/helsinki/cs/tmc/cli/backend/AccountListTest.java b/src/test/java/fi/helsinki/cs/tmc/cli/backend/AccountListTest.java new file mode 100644 index 00000000..e1a9d681 --- /dev/null +++ b/src/test/java/fi/helsinki/cs/tmc/cli/backend/AccountListTest.java @@ -0,0 +1,104 @@ +package fi.helsinki.cs.tmc.cli.backend; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertSame; + +import org.junit.Before; +import org.junit.Test; + +import java.util.Iterator; + +public class AccountListTest { + + private AccountList list; + private Account account; + + @Before + public void setUp() { + list = new AccountList(); + account = new Account("testserver", "testuser", "testpassword"); + } + + @Test + public void newHolderIsEmpty() { + assertEquals(0, list.getAccountCount()); + } + + @Test + public void addingAccountIncreasesHolderCount() { + list.addAccount(new Account("eee", "aaa", "ooo")); + assertEquals(1, list.getAccountCount()); + } + + @Test + public void loadingFromHolderWorks() { + list.addAccount(account); + Account loaded = list.getAccount(); + assertSame(account, loaded); + } + + @Test + public void addingMoreThanOneSettingWorks() { + list.addAccount(account); + list.addAccount(new Account("1", "2", "e")); + list.addAccount(new Account(":", "-", "D")); + assertEquals(3, list.getAccountCount()); + } + + @Test + public void loadingLatestAccountWorks() { + list.addAccount(new Account(":", "-", "D")); + list.addAccount(new Account("1", "2", "e")); + list.addAccount(account); + Account latest = list.getAccount(); + assertSame(account, latest); + } + + @Test + public void gettingAccountByNameAndServerWorks() { + Account wanted = new Account("1", "2", "e"); + list.addAccount(new Account(":", "-", "D")); + list.addAccount(wanted); + list.addAccount(new Account("344", "wc", "fffssshhhh aaahhh")); + Account get = list.getAccount("2", "1"); + assertSame(wanted, get); + } + + @Test + public void gettingLatestAccountSetsItToTheTop() { + Account wanted = new Account("1", "2", "e"); + list.addAccount(wanted); + list.addAccount(new Account(":", "-", "D")); + list.getAccount("2", "1"); + Account get = list.getAccount(); + assertSame(wanted, get); + } + + @Test + public void iterateOverZeroAccounts() { + Iterator iterator = list.iterator(); + assertEquals(false, iterator.hasNext()); + } + + @Test + public void iterateOverOneAccount() { + list.addAccount(account); + Iterator iterator = list.iterator(); + assertEquals(true, iterator.hasNext()); + assertEquals(account, iterator.next()); + assertEquals(false, iterator.hasNext()); + } + + @Test + public void iterateOverTwoAccounts() { + Account account2 = new Account("1", "2", "e"); + list.addAccount(account); + list.addAccount(account2); + Iterator iterator = list.iterator(); + assertEquals(true, iterator.hasNext()); + assertEquals(account2, iterator.next()); + assertEquals(true, iterator.hasNext()); + assertEquals(account, iterator.next()); + assertEquals(false, iterator.hasNext()); + } +} diff --git a/src/test/java/fi/helsinki/cs/tmc/cli/backend/AccountTest.java b/src/test/java/fi/helsinki/cs/tmc/cli/backend/AccountTest.java new file mode 100644 index 00000000..e7161f13 --- /dev/null +++ b/src/test/java/fi/helsinki/cs/tmc/cli/backend/AccountTest.java @@ -0,0 +1,35 @@ +package fi.helsinki.cs.tmc.cli.backend; + +import static org.junit.Assert.assertEquals; + +import org.junit.Before; +import org.junit.Test; + +public class AccountTest { + + private Account account; + + @Before + public void setUp() { + account = new Account("testserver", "testuser", "testpassword"); + } + + @Test + public void equalsWorksWithSameValues() { + Account compared = new Account("testserver", "testuser", "testpassword"); + assertEquals(true, account.equals(compared)); + } + + @Test + public void equalsWorksWithNull() { + Account compared = new Account(null, "testuser", "testpassword"); + assertEquals(false, account.equals(compared)); + } + + @Test + public void equalsWorksWithRandomValue() { + Account compared = new Account("xyz", "testuser", "testpassword"); + assertEquals(false, account.equals(compared)); + } + +} \ No newline at end of file diff --git a/src/test/java/fi/helsinki/cs/tmc/cli/tmcstuff/CourseInfoIoTest.java b/src/test/java/fi/helsinki/cs/tmc/cli/backend/CourseInfoIoTest.java similarity index 82% rename from src/test/java/fi/helsinki/cs/tmc/cli/tmcstuff/CourseInfoIoTest.java rename to src/test/java/fi/helsinki/cs/tmc/cli/backend/CourseInfoIoTest.java index 13862b48..966352c1 100644 --- a/src/test/java/fi/helsinki/cs/tmc/cli/tmcstuff/CourseInfoIoTest.java +++ b/src/test/java/fi/helsinki/cs/tmc/cli/backend/CourseInfoIoTest.java @@ -1,4 +1,4 @@ -package fi.helsinki.cs.tmc.cli.tmcstuff; +package fi.helsinki.cs.tmc.cli.backend; import fi.helsinki.cs.tmc.core.domain.Course; @@ -14,7 +14,6 @@ public class CourseInfoIoTest { - private Settings settings; private CourseInfo course; private Path courseFile; private String tempDir; @@ -25,12 +24,7 @@ public void setup() { this.courseFile = Paths.get(tempDir) .resolve("test-course") .resolve(CourseInfoIo.COURSE_CONFIG); - this.settings = new Settings(); - this.course = new CourseInfo(this.settings, new Course("test-course")); - try { - FileUtils.deleteDirectory(Paths.get(tempDir) - .resolve("test-course").toFile()); - } catch (Exception e) { } + this.course = new CourseInfo(new Account(), new Course("test-course")); } @After diff --git a/src/test/java/fi/helsinki/cs/tmc/cli/tmcstuff/CourseInfoTest.java b/src/test/java/fi/helsinki/cs/tmc/cli/backend/CourseInfoTest.java similarity index 96% rename from src/test/java/fi/helsinki/cs/tmc/cli/tmcstuff/CourseInfoTest.java rename to src/test/java/fi/helsinki/cs/tmc/cli/backend/CourseInfoTest.java index 962f9bf3..fcc7f2e7 100644 --- a/src/test/java/fi/helsinki/cs/tmc/cli/tmcstuff/CourseInfoTest.java +++ b/src/test/java/fi/helsinki/cs/tmc/cli/backend/CourseInfoTest.java @@ -1,4 +1,4 @@ -package fi.helsinki.cs.tmc.cli.tmcstuff; +package fi.helsinki.cs.tmc.cli.backend; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -19,7 +19,7 @@ public class CourseInfoTest { @Before public void setUp() { - courseInfo = new CourseInfo(new Settings(), new Course("test-course")); + courseInfo = new CourseInfo(new Account(), new Course("test-course")); } @Test diff --git a/src/test/java/fi/helsinki/cs/tmc/cli/backend/SettingsIoTest.java b/src/test/java/fi/helsinki/cs/tmc/cli/backend/SettingsIoTest.java new file mode 100644 index 00000000..0a7eda4d --- /dev/null +++ b/src/test/java/fi/helsinki/cs/tmc/cli/backend/SettingsIoTest.java @@ -0,0 +1,117 @@ +package fi.helsinki.cs.tmc.cli.backend; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import org.apache.commons.io.FileUtils; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.HashMap; + +public class SettingsIoTest { + + private AccountList accountList; + private Account account; + private Path tempDir; + + @Before + public void setUp() { + tempDir = Paths.get(System.getProperty("java.io.tmpdir")).resolve(SettingsIo.CONFIG_DIR); + account = new Account("testserver", "testuser", "testpassword"); + accountList = new AccountList(); + try { + FileUtils.deleteDirectory(tempDir.toFile()); + } catch (Exception e) { } + } + + @After + public void cleanUp() { + try { + FileUtils.deleteDirectory(tempDir.toFile()); + } catch (Exception e) { } + } + + @Test + public void correctConfigPath() { + Path path = SettingsIo.getConfigDirectory(); + String fs = System.getProperty("file.separator"); + assertTrue(path.toString().contains(SettingsIo.CONFIG_DIR)); + assertTrue(path.toString().contains(fs)); + assertTrue(!path.toString().contains(fs + fs)); + assertTrue(path.toString().contains(System.getProperty("user.home"))); + } + + @Test + public void saveZeroAccountsToFile() { + boolean success = SettingsIo.saveAccountList(accountList, tempDir); + assertTrue(success); + Path path = tempDir + .resolve(SettingsIo.ACCOUNTS_CONFIG); + assertTrue(Files.exists(path)); + } + + @Test + public void saveOneAccountToFile() { + accountList.addAccount(account); + boolean success = SettingsIo.saveAccountList(accountList, tempDir); + assertTrue(success); + Path path = tempDir + .resolve(SettingsIo.ACCOUNTS_CONFIG); + assertTrue(Files.exists(path)); + } + + @Test + public void saveAndLoadZeroAccountsFromFile() { + boolean success = SettingsIo.saveAccountList(accountList, tempDir); + AccountList loadedList = SettingsIo.loadAccountList(tempDir); + assertNotNull(loadedList); + assertEquals(0, loadedList.getAccountCount()); + } + + @Test + public void saveAndLoadOneAccountFromFile() { + accountList.addAccount(account); + boolean success = SettingsIo.saveAccountList(accountList, tempDir); + AccountList loadedList = SettingsIo.loadAccountList(tempDir); + assertNotNull(loadedList); + assertEquals(1, loadedList.getAccountCount()); + Account loadedAccount = loadedList.iterator().next(); + assertEquals(account.getUsername(), loadedAccount.getUsername()); + assertEquals(account.getPassword(), loadedAccount.getPassword()); + assertEquals(account.getServerAddress(), loadedAccount.getServerAddress()); + } + + @Test + public void loadingWhenNoFilePresentReturnsNull() { + Path path = tempDir.getParent(); + AccountList loadedList = SettingsIo.loadAccountList(path); + assertNotNull(loadedList); + assertEquals(0, loadedList.getAccountCount()); + } + + @Test + public void savingPropertiesWorks() { + HashMap props = new HashMap<>(); + props.put("lastupdated", "1970-01-01"); + props.put("nextupdate", "2038-01-20"); + SettingsIo.savePropertiesTo(props, tempDir); + assertTrue("Properties file exists", + Files.exists(tempDir.resolve(SettingsIo.PROPERTIES_CONFIG))); + } + + @Test + public void loadingPropertiesWorks() { + HashMap props = new HashMap<>(); + props.put("lastupdated", "1970-01-01"); + props.put("nextupdate", "2038-01-20"); + SettingsIo.savePropertiesTo(props, tempDir); + HashMap loadedProps = SettingsIo.loadPropertiesFrom(tempDir); + assertEquals(props, loadedProps); + } +} diff --git a/src/test/java/fi/helsinki/cs/tmc/cli/tmcstuff/SettingsTest.java b/src/test/java/fi/helsinki/cs/tmc/cli/backend/SettingsTest.java similarity index 66% rename from src/test/java/fi/helsinki/cs/tmc/cli/tmcstuff/SettingsTest.java rename to src/test/java/fi/helsinki/cs/tmc/cli/backend/SettingsTest.java index e58a6555..2a8bbafb 100644 --- a/src/test/java/fi/helsinki/cs/tmc/cli/tmcstuff/SettingsTest.java +++ b/src/test/java/fi/helsinki/cs/tmc/cli/backend/SettingsTest.java @@ -1,6 +1,7 @@ -package fi.helsinki.cs.tmc.cli.tmcstuff; +package fi.helsinki.cs.tmc.cli.backend; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import fi.helsinki.cs.tmc.cli.io.EnvironmentUtil; @@ -27,21 +28,10 @@ public void constructorInitializesFields() { } @Test - public void equalsWorksWithSameValues() { - Settings compared = new Settings("testserver", "testuser", "testpassword"); - assertEquals(true, settings.equals(compared)); - } - - @Test - public void equalsWorksWithNull() { - Settings compared = new Settings(null, "testuser", "testpassword"); - assertEquals(false, settings.equals(compared)); - } - - @Test - public void equalsWorksWithRandomValue() { - Settings compared = new Settings("xyz", "testuser", "testpassword"); - assertEquals(false, settings.equals(compared)); + public void setAndGetAccount() { + Account account = new Account(); + settings.setAccount(account); + assertEquals(account, settings.getAccount()); } @Test @@ -59,6 +49,12 @@ public void correctClientName() { assertEquals("tmc_cli", settings.clientName()); } + @Test + public void userDataDoesntExistsIfUsernameAndPasswordAtStart() { + settings = new Settings(); + assertFalse(settings.userDataExists()); + } + @Test public void userDataExistsIfUsernameAndPasswordAreSet() { assertTrue(settings.userDataExists()); @@ -66,10 +62,8 @@ public void userDataExistsIfUsernameAndPasswordAreSet() { @Test public void userDataDoesNotExistIfUsernameIsNotSet() { - settings = new Settings("testserver", null, "testpassword"); - assertTrue(!settings.userDataExists()); - - settings = new Settings("testserver", "", "testpassword"); + Account account = new Account("testserver", null, "testpassword"); + settings.setAccount(account); assertTrue(!settings.userDataExists()); } @@ -80,16 +74,15 @@ public void formattedUserDataIsCorrectIfSet() { @Test public void formattedUserDataIsCorrectIfNotSet() { - settings = new Settings("testserver", null, "testpassword"); + Account account = new Account("testserver", null, "testpassword"); + settings.setAccount(account); assertEquals("", settings.getFormattedUserData()); } @Test public void userDataDoesNotExistIfPasswordIsNotSet() { - settings = new Settings("testserver", "testuser", null); - assertTrue(!settings.userDataExists()); - - settings = new Settings("testserver", "testuser", ""); + Account account = new Account("testserver", "testuser", null); + settings.setAccount(account); assertTrue(!settings.userDataExists()); } diff --git a/src/test/java/fi/helsinki/cs/tmc/cli/tmcstuff/TmcUtilTest.java b/src/test/java/fi/helsinki/cs/tmc/cli/backend/TmcUtilTest.java similarity index 90% rename from src/test/java/fi/helsinki/cs/tmc/cli/tmcstuff/TmcUtilTest.java rename to src/test/java/fi/helsinki/cs/tmc/cli/backend/TmcUtilTest.java index cec53986..43201513 100644 --- a/src/test/java/fi/helsinki/cs/tmc/cli/tmcstuff/TmcUtilTest.java +++ b/src/test/java/fi/helsinki/cs/tmc/cli/backend/TmcUtilTest.java @@ -1,4 +1,4 @@ -package fi.helsinki.cs.tmc.cli.tmcstuff; +package fi.helsinki.cs.tmc.cli.backend; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -6,16 +6,19 @@ import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyListOf; +import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static org.powermock.api.mockito.PowerMockito.mockStatic; import fi.helsinki.cs.tmc.cli.Application; -import fi.helsinki.cs.tmc.cli.CliContext; +import fi.helsinki.cs.tmc.cli.core.CliContext; +import fi.helsinki.cs.tmc.cli.io.CliProgressObserver; import fi.helsinki.cs.tmc.cli.io.TestIo; -import fi.helsinki.cs.tmc.cli.io.TmcCliProgressObserver; + import fi.helsinki.cs.tmc.core.TmcCore; import fi.helsinki.cs.tmc.core.commands.GetUpdatableExercises.UpdateResult; import fi.helsinki.cs.tmc.core.domain.Course; @@ -38,6 +41,8 @@ import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; +import java.net.InetAddress; +import java.net.UnknownHostException; import java.net.URI; import java.net.URISyntaxException; import java.nio.file.Path; @@ -46,7 +51,7 @@ import java.util.concurrent.Callable; @RunWith(PowerMockRunner.class) -@PrepareForTest(RunResult.class) +@PrepareForTest({RunResult.class, InetAddress.class, TmcUtil.class}) public class TmcUtilTest { static Path workDir; @@ -105,16 +110,31 @@ public List call() throws Exception { }; } + @Test + public void hasInternetConnection() throws UnknownHostException { + mockStatic(InetAddress.class); + when(InetAddress.getByName(anyString())).thenReturn(null); + assertTrue(TmcUtil.hasConnection(ctx)); + } + + @Test + public void hasNoInternetConnection() throws UnknownHostException { + mockStatic(InetAddress.class); + when(InetAddress.getByName(anyString())).thenThrow( + new UnknownHostException()); + assertFalse(TmcUtil.hasConnection(ctx)); + } + @Test public void failToLogin() throws URISyntaxException { when(mockCore.listCourses(any(ProgressObserver.class))) .thenReturn(createThrowingCallbackOfList(Course.class, "failed")); - Settings settings = new Settings(); - assertFalse(TmcUtil.tryToLogin(ctx, settings)); + Account account = new Account(); + assertFalse(TmcUtil.tryToLogin(ctx, account)); } @Test - public void tryToLoginCatchesObsoleteClientException() { + public void loginCatchesObsoleteClientException() { Callable> callable = new Callable>() { @Override public List call() throws Exception { @@ -128,13 +148,13 @@ public List call() throws Exception { when(app.runAutoUpdate()).thenReturn(true); when(mockCore.listCourses(any(ProgressObserver.class))) .thenReturn(callable); - TmcUtil.tryToLogin(ctx, new Settings()); + TmcUtil.tryToLogin(ctx, new Account()); io.assertContains("Your tmc-cli is outdated"); verify(app, times(1)).runAutoUpdate(); } @Test - public void tryToLoginCatchesFailedHttpResponseException() { + public void loginCatchesFailedHttpResponseException() { Callable> callable = new Callable>() { @Override public List call() throws Exception { @@ -145,7 +165,7 @@ public List call() throws Exception { when(mockCore.listCourses(any(ProgressObserver.class))) .thenReturn(callable); - TmcUtil.tryToLogin(ctx, new Settings()); + TmcUtil.tryToLogin(ctx, new Account()); io.assertContains("Incorrect username or password"); } @@ -209,7 +229,7 @@ public void downloadSomeExercises() { .thenReturn(createReturningCallback(expectedResult)); List result = TmcUtil.downloadExercises(ctx, expectedResult, - new TmcCliProgressObserver(io)); + new CliProgressObserver(io)); assertEquals(expectedResult, result); } @@ -222,7 +242,7 @@ public void failToDownloadCourses() throws Exception { eq(exercises))).thenReturn(callable); assertNull(TmcUtil.downloadExercises(ctx, exercises, - new TmcCliProgressObserver(io))); + new CliProgressObserver(io))); } @Test diff --git a/src/test/java/fi/helsinki/cs/tmc/cli/command/DocumentCommandTest.java b/src/test/java/fi/helsinki/cs/tmc/cli/command/DocumentCommandTest.java index 9087ea29..d403b0e9 100644 --- a/src/test/java/fi/helsinki/cs/tmc/cli/command/DocumentCommandTest.java +++ b/src/test/java/fi/helsinki/cs/tmc/cli/command/DocumentCommandTest.java @@ -4,7 +4,7 @@ import static org.powermock.api.mockito.PowerMockito.mockStatic; import fi.helsinki.cs.tmc.cli.Application; -import fi.helsinki.cs.tmc.cli.CliContext; +import fi.helsinki.cs.tmc.cli.core.CliContext; import fi.helsinki.cs.tmc.cli.io.EnvironmentUtil; import fi.helsinki.cs.tmc.cli.io.TestIo; diff --git a/src/test/java/fi/helsinki/cs/tmc/cli/command/DownloadExercisesCommandTest.java b/src/test/java/fi/helsinki/cs/tmc/cli/command/DownloadExercisesCommandTest.java index ed0bfeb7..5387a3f2 100644 --- a/src/test/java/fi/helsinki/cs/tmc/cli/command/DownloadExercisesCommandTest.java +++ b/src/test/java/fi/helsinki/cs/tmc/cli/command/DownloadExercisesCommandTest.java @@ -13,12 +13,14 @@ import static org.powermock.api.mockito.PowerMockito.verifyStatic; import fi.helsinki.cs.tmc.cli.Application; -import fi.helsinki.cs.tmc.cli.CliContext; +import fi.helsinki.cs.tmc.cli.backend.Account; +import fi.helsinki.cs.tmc.cli.backend.AccountList; +import fi.helsinki.cs.tmc.cli.backend.Settings; +import fi.helsinki.cs.tmc.cli.backend.SettingsIo; +import fi.helsinki.cs.tmc.cli.backend.TmcUtil; +import fi.helsinki.cs.tmc.cli.core.CliContext; import fi.helsinki.cs.tmc.cli.io.TestIo; -import fi.helsinki.cs.tmc.cli.tmcstuff.Settings; -import fi.helsinki.cs.tmc.cli.tmcstuff.SettingsIo; -import fi.helsinki.cs.tmc.cli.tmcstuff.TmcUtil; -import fi.helsinki.cs.tmc.cli.tmcstuff.WorkDir; +import fi.helsinki.cs.tmc.cli.io.WorkDir; import fi.helsinki.cs.tmc.core.TmcCore; import fi.helsinki.cs.tmc.core.domain.Course; import fi.helsinki.cs.tmc.core.domain.Exercise; @@ -63,11 +65,14 @@ public void setUp() { mockCore = mock(TmcCore.class); ctx = new CliContext(io, mockCore, workDir); app = new Application(ctx); - Settings settings = new Settings("http://test.test", "", ""); + Account account = new Account("server", "user", "password"); + ctx.useAccount(account); + AccountList accountList = new AccountList(); + accountList.addAccount(account); mockStatic(TmcUtil.class); mockStatic(SettingsIo.class); - when(SettingsIo.getSettingsList()).thenReturn(Arrays.asList(settings)); + when(SettingsIo.loadAccountList()).thenReturn(accountList); } @After @@ -113,9 +118,6 @@ public void worksRightIfCourseIsFound() throws IOException { when(TmcUtil.downloadExercises(eq(ctx), anyListOf(Exercise.class), any(ProgressObserver.class))).thenReturn(exercises); - Settings settings = new Settings("server", "user", "password"); - ctx.useSettings(settings); - String[] args = {"download", "course1"}; app.run(args); @@ -132,6 +134,7 @@ public void filtersCompletedExercisesByDefault() throws ParseException { notCompleted.setCompleted(false); completed1.setCompleted(true); completed2.setCompleted(true); + workDir.setWorkdir(tempDir); List filteredExercises = Arrays.asList(notCompleted); @@ -142,10 +145,6 @@ public void filtersCompletedExercisesByDefault() throws ParseException { when(TmcUtil.downloadExercises(eq(ctx), anyListOf(Exercise.class), any(ProgressObserver.class))).thenReturn(filteredExercises); - Settings settings = new Settings("server", "user", "password"); - workDir.setWorkdir(tempDir); - ctx.useSettings(settings); - String[] args = {"download", "course1"}; app.run(args); @@ -161,6 +160,7 @@ public void getsAllExercisesWithAllSwitch() throws ParseException { notCompleted.setCompleted(false); completed1.setCompleted(true); completed2.setCompleted(true); + workDir.setWorkdir(tempDir); List exercises = Arrays.asList(completed1, notCompleted, completed2); @@ -171,10 +171,6 @@ public void getsAllExercisesWithAllSwitch() throws ParseException { when(TmcUtil.downloadExercises(eq(ctx), anyListOf(Exercise.class), any(ProgressObserver.class))).thenReturn(exercises); - Settings settings = new Settings("server", "user", "password"); - workDir.setWorkdir(tempDir); - ctx.useSettings(settings); - String[] args = {"download", "-a", "course1"}; app.run(args); @@ -191,15 +187,12 @@ public void failsToLoadExercises() throws ParseException { List downloaded = Arrays.asList(exercise1, exercise3); Course course = new Course("course1"); course.setExercises(exercises); + workDir.setWorkdir(tempDir); when(TmcUtil.findCourse(eq(ctx), eq("course1"))).thenReturn(course); when(TmcUtil.downloadExercises(eq(ctx), anyListOf(Exercise.class), any(ProgressObserver.class))).thenReturn(downloaded); - Settings settings = new Settings("server", "user", "password"); - workDir.setWorkdir(tempDir); - ctx.useSettings(settings); - String[] args = {"download", "course1"}; app.run(args); @@ -210,13 +203,15 @@ public void failsToLoadExercises() throws ParseException { @Test public void findFromMultipleServer() { - Settings settings1 = new Settings("http://test.test", "", ""); - Settings settings2 = new Settings("http://hello.test", "", ""); + Account account1 = new Account("http://test.test", "", ""); + Account account2 = new Account("http://hello.test", "", ""); + AccountList accountList = new AccountList(); + accountList.addAccount(account1); + accountList.addAccount(account2); when(TmcUtil.findCourse(eq(ctx), eq("course1"))).thenReturn(new Course("course1")) .thenReturn(new Course("course2")); - when(SettingsIo.getSettingsList()).thenReturn( - Arrays.asList(settings1, settings2)); + when(SettingsIo.loadAccountList()).thenReturn(accountList); String[] args = {"download", "course2"}; app.run(args); @@ -224,13 +219,15 @@ public void findFromMultipleServer() { @Test public void findFromMultipleServerWithSameNameWithoutTakingAny() { - Settings settings1 = new Settings("http://test.test", "abc", ""); - Settings settings2 = new Settings("http://hello.test", "def", ""); + Account account1 = new Account("http://test.test", "abc", ""); + Account account2 = new Account("http://hello.test", "def", ""); + AccountList accountList = new AccountList(); + accountList.addAccount(account1); + accountList.addAccount(account2); when(TmcUtil.findCourse(eq(ctx), eq("course1"))).thenReturn(new Course("course1")) .thenReturn(new Course("course1")); - when(SettingsIo.getSettingsList()).thenReturn( - Arrays.asList(settings1, settings2)); + when(SettingsIo.loadAccountList()).thenReturn(accountList); List exercises = Arrays.asList(); when(TmcUtil.downloadExercises(eq(ctx), anyListOf(Exercise.class), @@ -249,13 +246,15 @@ public void findFromMultipleServerWithSameNameWithoutTakingAny() { @Test public void findFromMultipleServerWithSameNameWithTakingFirst() { - Settings settings1 = new Settings("http://test.test", "abc", ""); - Settings settings2 = new Settings("http://hello.test", "def", ""); + Account account1 = new Account("http://test.test", "abc", ""); + Account account2 = new Account("http://hello.test", "def", ""); + AccountList accountList = new AccountList(); + accountList.addAccount(account2); + accountList.addAccount(account1); when(TmcUtil.findCourse(eq(ctx), eq("course1"))).thenReturn(new Course("course1")) .thenReturn(new Course("course1")); - when(SettingsIo.getSettingsList()).thenReturn( - Arrays.asList(settings1, settings2)); + when(SettingsIo.loadAccountList()).thenReturn(accountList); String[] args = {"download", "course1"}; io.addConfirmationPrompt(true); @@ -270,6 +269,6 @@ public void findFromMultipleServerWithSameNameWithTakingFirst() { any(ProgressObserver.class)); Settings usedSettings = Whitebox.getInternalState(ctxCaptor.getValue(), "settings"); - assertEquals(settings1, usedSettings); + assertEquals(account1, usedSettings.getAccount()); } } diff --git a/src/test/java/fi/helsinki/cs/tmc/cli/command/HelpCommandTest.java b/src/test/java/fi/helsinki/cs/tmc/cli/command/HelpCommandTest.java index eda83fea..dc4aed2e 100644 --- a/src/test/java/fi/helsinki/cs/tmc/cli/command/HelpCommandTest.java +++ b/src/test/java/fi/helsinki/cs/tmc/cli/command/HelpCommandTest.java @@ -3,7 +3,7 @@ import static org.mockito.Mockito.mock; import fi.helsinki.cs.tmc.cli.Application; -import fi.helsinki.cs.tmc.cli.CliContext; +import fi.helsinki.cs.tmc.cli.core.CliContext; import fi.helsinki.cs.tmc.cli.io.TestIo; import fi.helsinki.cs.tmc.core.TmcCore; diff --git a/src/test/java/fi/helsinki/cs/tmc/cli/command/CourseInfoCommandTest.java b/src/test/java/fi/helsinki/cs/tmc/cli/command/InfoCommandTest.java similarity index 67% rename from src/test/java/fi/helsinki/cs/tmc/cli/command/CourseInfoCommandTest.java rename to src/test/java/fi/helsinki/cs/tmc/cli/command/InfoCommandTest.java index bdb3c68c..07dc59d8 100644 --- a/src/test/java/fi/helsinki/cs/tmc/cli/command/CourseInfoCommandTest.java +++ b/src/test/java/fi/helsinki/cs/tmc/cli/command/InfoCommandTest.java @@ -9,10 +9,13 @@ import static org.powermock.api.mockito.PowerMockito.mockStatic; import fi.helsinki.cs.tmc.cli.Application; -import fi.helsinki.cs.tmc.cli.CliContext; +import fi.helsinki.cs.tmc.cli.backend.Account; +import fi.helsinki.cs.tmc.cli.backend.TmcUtil; +import fi.helsinki.cs.tmc.cli.core.CliContext; import fi.helsinki.cs.tmc.cli.io.TestIo; -import fi.helsinki.cs.tmc.cli.tmcstuff.TmcUtil; -import fi.helsinki.cs.tmc.cli.tmcstuff.WorkDir; +import fi.helsinki.cs.tmc.cli.io.WorkDir; +import fi.helsinki.cs.tmc.cli.shared.CourseFinder; + import fi.helsinki.cs.tmc.core.TmcCore; import fi.helsinki.cs.tmc.core.domain.Course; import fi.helsinki.cs.tmc.core.domain.Exercise; @@ -31,7 +34,7 @@ @RunWith(PowerMockRunner.class) @PrepareForTest(TmcUtil.class) -public class CourseInfoCommandTest { +public class InfoCommandTest { private static final String COURSE_NAME = "2016-aalto-c"; private static final String EXERCISE1_NAME = "Module_1-02_intro"; @@ -98,17 +101,28 @@ public void showErrorMessageIfNoCourseGivenWithIOption() { io.assertContains("You must give a course"); } + //TODO we should test this in CourseFinder not here. @Test - public void showMessageIfCourseDoesNotExistOnTheServer() { - when(TmcUtil.findCourse(eq(ctx), eq("foo"))).thenReturn(null); + public void dontShowCourseInfoIfTheCourseDoesntExist() { + ctx = spy(ctx); + app = new Application(ctx); + CourseFinder mockCourseFinder = mock(CourseFinder.class); + doReturn(mockCourseFinder).when(ctx).createCourseFinder(); + when(mockCourseFinder.search(eq("foo"))).thenReturn(false); String[] args = {"info", "foo", "-i"}; app.run(args); - io.assertContains("course foo doesn't exist"); + io.assertNotContains("Course name:"); } @Test - public void printCourseWithOptionI() { - when(TmcUtil.findCourse(eq(ctx), eq("test-course123"))).thenReturn(course); + public void printCourseWithInternet() { + ctx = spy(ctx); + app = new Application(ctx); + CourseFinder mockCourseFinder = mock(CourseFinder.class); + doReturn(mockCourseFinder).when(ctx).createCourseFinder(); + when(mockCourseFinder.search(eq("test-course123"))).thenReturn(true); + when(mockCourseFinder.getCourse()).thenReturn(course); + when(mockCourseFinder.getAccount()).thenReturn(new Account()); String[] args = {"info", "test-course123", "-i"}; app.run(args); @@ -117,8 +131,14 @@ public void printCourseWithOptionI() { } @Test - public void printCourseWithOptionsIAndA() { - when(TmcUtil.findCourse(eq(ctx), eq("test-course123"))).thenReturn(course); + public void printAllCourseExercisesWithInternet() { + ctx = spy(ctx); + app = new Application(ctx); + CourseFinder mockCourseFinder = mock(CourseFinder.class); + doReturn(mockCourseFinder).when(ctx).createCourseFinder(); + when(mockCourseFinder.search(eq("test-course123"))).thenReturn(true); + when(mockCourseFinder.getCourse()).thenReturn(course); + when(mockCourseFinder.getAccount()).thenReturn(new Account()); String[] args = {"info", "test-course123", "-a", "-i"}; app.run(args); @@ -127,8 +147,15 @@ public void printCourseWithOptionsIAndA() { @Test public void printCourseWithNoExercisesFromTheServer() { + ctx = spy(ctx); + app = new Application(ctx); + CourseFinder mockCourseFinder = mock(CourseFinder.class); + doReturn(mockCourseFinder).when(ctx).createCourseFinder(); + when(mockCourseFinder.search(eq("test-course123"))).thenReturn(true); + when(mockCourseFinder.getCourse()).thenReturn(course); + when(mockCourseFinder.getAccount()).thenReturn(new Account()); + course.setExercises(new ArrayList()); - when(TmcUtil.findCourse(eq(ctx), eq("test-course123"))).thenReturn(course); String[] args = {"info", "test-course123", "-i"}; app.run(args); @@ -172,8 +199,14 @@ public void printErrorMessageIfNotInCourseDirectoryAndCourseDoesntExist() { public void printGivenCourseFromTheServerIfInCourseDirectoryAndGivenCourseName() { workDir.setWorkdir(pathToDummyCourse); + ctx = spy(ctx); + app = new Application(ctx); + CourseFinder mockCourseFinder = mock(CourseFinder.class); + doReturn(mockCourseFinder).when(ctx).createCourseFinder(); + when(mockCourseFinder.search(eq("test-course123"))).thenReturn(true); + when(mockCourseFinder.getCourse()).thenReturn(course); + when(mockCourseFinder.getAccount()).thenReturn(new Account()); course.setExercises(new ArrayList()); - when(TmcUtil.findCourse(eq(ctx), eq("test-course123"))).thenReturn(course); String[] args = {"info", "test-course123", "-i"}; app.run(args); @@ -184,11 +217,15 @@ public void printGivenCourseFromTheServerIfInCourseDirectoryAndGivenCourseName() public void printsErrorIfInCourseDirectoryAndGivenCourseNameThatDoesntExistOnTheServer() { workDir.setWorkdir(pathToDummyCourse); - when(TmcUtil.findCourse(eq(ctx), eq("test-course123"))).thenReturn(course); + ctx = spy(ctx); + app = new Application(ctx); + CourseFinder mockCourseFinder = mock(CourseFinder.class); + doReturn(mockCourseFinder).when(ctx).createCourseFinder(); + when(mockCourseFinder.search(eq("test-course123"))).thenReturn(false); String[] args = {"info", "notacourse", "-i"}; app.run(args); - io.assertContains("doesn't exist on the server."); + io.assertNotContains("Course name:"); } @Test diff --git a/src/test/java/fi/helsinki/cs/tmc/cli/command/ListCoursesCommandTest.java b/src/test/java/fi/helsinki/cs/tmc/cli/command/ListCoursesCommandTest.java index 536e8be1..bc0f7de9 100644 --- a/src/test/java/fi/helsinki/cs/tmc/cli/command/ListCoursesCommandTest.java +++ b/src/test/java/fi/helsinki/cs/tmc/cli/command/ListCoursesCommandTest.java @@ -8,11 +8,13 @@ import static org.powermock.api.mockito.PowerMockito.mockStatic; import fi.helsinki.cs.tmc.cli.Application; -import fi.helsinki.cs.tmc.cli.CliContext; +import fi.helsinki.cs.tmc.cli.backend.Account; +import fi.helsinki.cs.tmc.cli.backend.AccountList; +import fi.helsinki.cs.tmc.cli.backend.SettingsIo; +import fi.helsinki.cs.tmc.cli.backend.TmcUtil; +import fi.helsinki.cs.tmc.cli.core.CliContext; import fi.helsinki.cs.tmc.cli.io.TestIo; -import fi.helsinki.cs.tmc.cli.tmcstuff.Settings; -import fi.helsinki.cs.tmc.cli.tmcstuff.SettingsIo; -import fi.helsinki.cs.tmc.cli.tmcstuff.TmcUtil; + import fi.helsinki.cs.tmc.core.TmcCore; import fi.helsinki.cs.tmc.core.domain.Course; @@ -40,24 +42,36 @@ public void setUp() { mockCore = mock(TmcCore.class); ctx = new CliContext(io, mockCore); app = new Application(ctx); - Settings settings = new Settings("http://test.test", "", ""); + Account account = new Account("http://test.test", "", ""); + AccountList accountList = new AccountList(); + accountList.addAccount(account); mockStatic(TmcUtil.class); mockStatic(SettingsIo.class); - when(SettingsIo.getSettingsList()).thenReturn(Arrays.asList(settings)); + when(TmcUtil.hasConnection(eq(ctx))).thenReturn(true); + when(SettingsIo.loadAccountList()).thenReturn(accountList); } @Test public void failIfBackendFails() { - CliContext ctx = spy(new CliContext(io, mockCore)); + ctx = spy(ctx); app = new Application(ctx); - doReturn(false).when(ctx).loadBackend(); + doReturn(false).when(ctx).loadBackendWithoutLogin(); String[] args = {"courses", "foo"}; app.run(args); io.assertNotContains("Course doesn't exist"); } + @Test + public void failIfThereIsNoConnection() { + when(TmcUtil.hasConnection(eq(ctx))).thenReturn(false); + + String[] args = {"courses"}; + app.run(args); + io.assertContains("don't have internet connection"); + } + @Test public void listCoursesWorksWithNoCourses() { List list = Arrays.asList(); @@ -80,10 +94,13 @@ public void listCoursesWorksWithCourses() { @Test public void listCoursesWorksWithTwoServers() { - Settings settings1 = new Settings("http://test.test", "", ""); - Settings settings2 = new Settings("http://hello.test", "", ""); - when(SettingsIo.getSettingsList()).thenReturn( - Arrays.asList(settings1, settings2)); + Account account1 = new Account("http://test.test", "", ""); + Account account2 = new Account("http://hello.test", "", ""); + + AccountList accountList = new AccountList(); + accountList.addAccount(account1); + accountList.addAccount(account2); + when(SettingsIo.loadAccountList()).thenReturn(accountList); List list1 = Arrays.asList(new Course("course1")); List list2 = Arrays.asList(new Course("course2")); diff --git a/src/test/java/fi/helsinki/cs/tmc/cli/command/ListExercisesCommandTest.java b/src/test/java/fi/helsinki/cs/tmc/cli/command/ListExercisesCommandTest.java index fcad2e7d..0083387b 100644 --- a/src/test/java/fi/helsinki/cs/tmc/cli/command/ListExercisesCommandTest.java +++ b/src/test/java/fi/helsinki/cs/tmc/cli/command/ListExercisesCommandTest.java @@ -9,10 +9,11 @@ import static org.powermock.api.mockito.PowerMockito.mockStatic; import fi.helsinki.cs.tmc.cli.Application; -import fi.helsinki.cs.tmc.cli.CliContext; +import fi.helsinki.cs.tmc.cli.backend.TmcUtil; +import fi.helsinki.cs.tmc.cli.core.CliContext; import fi.helsinki.cs.tmc.cli.io.TestIo; -import fi.helsinki.cs.tmc.cli.tmcstuff.TmcUtil; -import fi.helsinki.cs.tmc.cli.tmcstuff.WorkDir; +import fi.helsinki.cs.tmc.cli.io.WorkDir; + import fi.helsinki.cs.tmc.core.TmcCore; import fi.helsinki.cs.tmc.core.domain.Course; import fi.helsinki.cs.tmc.core.domain.Exercise; diff --git a/src/test/java/fi/helsinki/cs/tmc/cli/command/LoginCommandTest.java b/src/test/java/fi/helsinki/cs/tmc/cli/command/LoginCommandTest.java index be92896c..b2d9ddf6 100644 --- a/src/test/java/fi/helsinki/cs/tmc/cli/command/LoginCommandTest.java +++ b/src/test/java/fi/helsinki/cs/tmc/cli/command/LoginCommandTest.java @@ -9,19 +9,19 @@ import static org.powermock.api.mockito.PowerMockito.verifyStatic; import fi.helsinki.cs.tmc.cli.Application; -import fi.helsinki.cs.tmc.cli.CliContext; +import fi.helsinki.cs.tmc.cli.backend.Account; +import fi.helsinki.cs.tmc.cli.backend.AccountList; +import fi.helsinki.cs.tmc.cli.backend.CourseInfo; +import fi.helsinki.cs.tmc.cli.backend.SettingsIo; +import fi.helsinki.cs.tmc.cli.backend.TmcUtil; +import fi.helsinki.cs.tmc.cli.core.CliContext; import fi.helsinki.cs.tmc.cli.io.TestIo; -import fi.helsinki.cs.tmc.cli.tmcstuff.CourseInfo; -import fi.helsinki.cs.tmc.cli.tmcstuff.Settings; -import fi.helsinki.cs.tmc.cli.tmcstuff.SettingsIo; -import fi.helsinki.cs.tmc.cli.tmcstuff.TmcUtil; + import fi.helsinki.cs.tmc.core.TmcCore; -import fi.helsinki.cs.tmc.core.configuration.TmcSettings; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; - import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; @@ -48,7 +48,9 @@ public void setUp() { mockStatic(TmcUtil.class); mockStatic(SettingsIo.class); - when(SettingsIo.save(any(Settings.class))).thenReturn(true); + when(TmcUtil.hasConnection(eq(ctx))).thenReturn(true); + when(SettingsIo.loadAccountList()).thenReturn(new AccountList()); + when(SettingsIo.saveAccountList(any(AccountList.class))).thenReturn(true); } @Test @@ -61,10 +63,19 @@ public void failIfBackendFails() { io.assertNotContains("Login successful"); } + @Test + public void failIfThereIsNoConnection() { + when(TmcUtil.hasConnection(eq(ctx))).thenReturn(false); + + String[] args = {"login"}; + app.run(args); + io.assertContains("don't have internet connection"); + } + @Test public void logsInWithCorrectServerUserAndPassword() { - when(TmcUtil.tryToLogin(eq(ctx), any(Settings.class))).thenReturn(true); - when(SettingsIo.save(any(Settings.class))).thenReturn(true); + when(TmcUtil.tryToLogin(eq(ctx), any(Account.class))).thenReturn(true); + when(SettingsIo.saveAccountList(any(AccountList.class))).thenReturn(true); String[] args = {"login", "-s", SERVER, "-u", USERNAME, "-p", PASSWORD}; app.run(args); io.assertContains("Login successful."); @@ -72,8 +83,8 @@ public void logsInWithCorrectServerUserAndPassword() { @Test public void userGetsErrorMessageIfLoginFails() { - when(TmcUtil.tryToLogin(eq(ctx), any(Settings.class))).thenReturn(true); - when(SettingsIo.save(any(Settings.class))).thenReturn(false); + when(TmcUtil.tryToLogin(eq(ctx), any(Account.class))).thenReturn(true); + when(SettingsIo.saveAccountList(any(AccountList.class))).thenReturn(false); String[] args = {"login", "-s", SERVER, "-u", USERNAME, "-p", "WrongPassword"}; app.run(args); io.assertContains("Failed to write the accounts file."); @@ -81,7 +92,8 @@ public void userGetsErrorMessageIfLoginFails() { @Test public void loginAsksUsernameFromUserIfNotGiven() { - when(TmcUtil.tryToLogin(eq(ctx), any(Settings.class))).thenReturn(true); + when(SettingsIo.loadAccountList()).thenReturn(new AccountList()); + when(SettingsIo.saveAccountList(any(AccountList.class))).thenReturn(true); String[] args = {"login", "-s", SERVER, "-p", PASSWORD}; io.addLinePrompt(USERNAME); app.run(args); @@ -90,7 +102,7 @@ public void loginAsksUsernameFromUserIfNotGiven() { @Test public void loginAsksPasswordFromUserIfNotGiven() { - when(TmcUtil.tryToLogin(eq(ctx), any(Settings.class))).thenReturn(true); + when(TmcUtil.tryToLogin(eq(ctx), any(Account.class))).thenReturn(true); String[] args = {"login", "-s", SERVER, "-u", USERNAME}; io.addPasswordPrompt(PASSWORD); app.run(args); @@ -99,7 +111,7 @@ public void loginAsksPasswordFromUserIfNotGiven() { @Test public void loginAsksServerFromUserIfNotGiven() { - when(TmcUtil.tryToLogin(eq(ctx), any(Settings.class))).thenReturn(true); + when(TmcUtil.tryToLogin(eq(ctx), any(Account.class))).thenReturn(true); String[] args = {"login", "-p", PASSWORD, "-u", USERNAME}; io.addLinePrompt(SERVER); app.run(args); @@ -108,9 +120,9 @@ public void loginAsksServerFromUserIfNotGiven() { @Test public void serverAndNotAskedAfterLogout() { - TmcSettings settings = new Settings(SERVER, "username", "pass"); - CourseInfo info = new CourseInfo(settings, null); - when(TmcUtil.tryToLogin(eq(ctx), any(Settings.class))).thenReturn(true); + Account account = new Account(SERVER, "username", "pass"); + CourseInfo info = new CourseInfo(account, null); + when(TmcUtil.tryToLogin(eq(ctx), any(Account.class))).thenReturn(true); when(ctx.getCourseInfo()).thenReturn(info); String[] args = {"login"}; io.addPasswordPrompt(PASSWORD); @@ -120,16 +132,16 @@ public void serverAndNotAskedAfterLogout() { @Test public void courseInfoValuesOverridedByOptions() { - Settings settings = new Settings(SERVER, "username", "pass"); - CourseInfo info = new CourseInfo(settings, null); - when(TmcUtil.tryToLogin(eq(ctx), any(Settings.class))).thenReturn(true); + Account account = new Account(SERVER, "username", "pass"); + CourseInfo info = new CourseInfo(account, null); + when(TmcUtil.tryToLogin(eq(ctx), any(Account.class))).thenReturn(true); when(ctx.getCourseInfo()).thenReturn(info); String[] args = {"login", "-p", PASSWORD, "-u", USERNAME}; app.run(args); io.assertAllPromptsUsed(); - Settings expectedSettings = new Settings(SERVER, USERNAME, PASSWORD); + Account expectedAccount = new Account(SERVER, USERNAME, PASSWORD); verifyStatic(); - TmcUtil.tryToLogin(eq(ctx), eq(expectedSettings)); + TmcUtil.tryToLogin(eq(ctx), eq(expectedAccount)); } } diff --git a/src/test/java/fi/helsinki/cs/tmc/cli/command/LogoutCommandTest.java b/src/test/java/fi/helsinki/cs/tmc/cli/command/LogoutCommandTest.java index 417d88df..564c66ad 100644 --- a/src/test/java/fi/helsinki/cs/tmc/cli/command/LogoutCommandTest.java +++ b/src/test/java/fi/helsinki/cs/tmc/cli/command/LogoutCommandTest.java @@ -5,9 +5,9 @@ import static org.powermock.api.mockito.PowerMockito.verifyStatic; import fi.helsinki.cs.tmc.cli.Application; -import fi.helsinki.cs.tmc.cli.CliContext; +import fi.helsinki.cs.tmc.cli.backend.SettingsIo; +import fi.helsinki.cs.tmc.cli.core.CliContext; import fi.helsinki.cs.tmc.cli.io.TestIo; -import fi.helsinki.cs.tmc.cli.tmcstuff.SettingsIo; import org.junit.Before; import org.junit.Test; diff --git a/src/test/java/fi/helsinki/cs/tmc/cli/command/PasteCommandTest.java b/src/test/java/fi/helsinki/cs/tmc/cli/command/PasteCommandTest.java index c5f7652e..819175a9 100644 --- a/src/test/java/fi/helsinki/cs/tmc/cli/command/PasteCommandTest.java +++ b/src/test/java/fi/helsinki/cs/tmc/cli/command/PasteCommandTest.java @@ -14,13 +14,14 @@ import static org.powermock.api.mockito.PowerMockito.verifyStatic; import fi.helsinki.cs.tmc.cli.Application; -import fi.helsinki.cs.tmc.cli.CliContext; +import fi.helsinki.cs.tmc.cli.backend.CourseInfo; +import fi.helsinki.cs.tmc.cli.backend.CourseInfoIo; +import fi.helsinki.cs.tmc.cli.backend.TmcUtil; +import fi.helsinki.cs.tmc.cli.core.CliContext; import fi.helsinki.cs.tmc.cli.io.ExternalsUtil; import fi.helsinki.cs.tmc.cli.io.TestIo; -import fi.helsinki.cs.tmc.cli.tmcstuff.CourseInfo; -import fi.helsinki.cs.tmc.cli.tmcstuff.CourseInfoIo; -import fi.helsinki.cs.tmc.cli.tmcstuff.TmcUtil; -import fi.helsinki.cs.tmc.cli.tmcstuff.WorkDir; +import fi.helsinki.cs.tmc.cli.io.WorkDir; + import fi.helsinki.cs.tmc.core.TmcCore; import fi.helsinki.cs.tmc.core.domain.Exercise; diff --git a/src/test/java/fi/helsinki/cs/tmc/cli/command/PropertiesCommandTest.java b/src/test/java/fi/helsinki/cs/tmc/cli/command/PropertiesCommandTest.java index 54f7fc8f..58d8ad14 100644 --- a/src/test/java/fi/helsinki/cs/tmc/cli/command/PropertiesCommandTest.java +++ b/src/test/java/fi/helsinki/cs/tmc/cli/command/PropertiesCommandTest.java @@ -5,7 +5,7 @@ import static org.mockito.Mockito.when; import fi.helsinki.cs.tmc.cli.Application; -import fi.helsinki.cs.tmc.cli.CliContext; +import fi.helsinki.cs.tmc.cli.core.CliContext; import fi.helsinki.cs.tmc.cli.io.TestIo; import org.junit.Before; diff --git a/src/test/java/fi/helsinki/cs/tmc/cli/command/RunTestsCommandTest.java b/src/test/java/fi/helsinki/cs/tmc/cli/command/RunTestsCommandTest.java index 4f6b473f..4277fedd 100644 --- a/src/test/java/fi/helsinki/cs/tmc/cli/command/RunTestsCommandTest.java +++ b/src/test/java/fi/helsinki/cs/tmc/cli/command/RunTestsCommandTest.java @@ -10,10 +10,10 @@ import static org.powermock.api.mockito.PowerMockito.mockStatic; import fi.helsinki.cs.tmc.cli.Application; -import fi.helsinki.cs.tmc.cli.CliContext; +import fi.helsinki.cs.tmc.cli.backend.TmcUtil; +import fi.helsinki.cs.tmc.cli.core.CliContext; import fi.helsinki.cs.tmc.cli.io.TestIo; -import fi.helsinki.cs.tmc.cli.tmcstuff.TmcUtil; -import fi.helsinki.cs.tmc.cli.tmcstuff.WorkDir; +import fi.helsinki.cs.tmc.cli.io.WorkDir; import fi.helsinki.cs.tmc.core.TmcCore; import fi.helsinki.cs.tmc.core.domain.Exercise; diff --git a/src/test/java/fi/helsinki/cs/tmc/cli/command/ShellHelperCommandTest.java b/src/test/java/fi/helsinki/cs/tmc/cli/command/ShellHelperCommandTest.java index ed5eddb6..6133a548 100644 --- a/src/test/java/fi/helsinki/cs/tmc/cli/command/ShellHelperCommandTest.java +++ b/src/test/java/fi/helsinki/cs/tmc/cli/command/ShellHelperCommandTest.java @@ -1,7 +1,7 @@ package fi.helsinki.cs.tmc.cli.command; import fi.helsinki.cs.tmc.cli.Application; -import fi.helsinki.cs.tmc.cli.CliContext; +import fi.helsinki.cs.tmc.cli.core.CliContext; import fi.helsinki.cs.tmc.cli.io.TestIo; import org.junit.Before; diff --git a/src/test/java/fi/helsinki/cs/tmc/cli/command/SubmitCommandTest.java b/src/test/java/fi/helsinki/cs/tmc/cli/command/SubmitCommandTest.java index bea1fd5e..877cee2f 100644 --- a/src/test/java/fi/helsinki/cs/tmc/cli/command/SubmitCommandTest.java +++ b/src/test/java/fi/helsinki/cs/tmc/cli/command/SubmitCommandTest.java @@ -10,12 +10,12 @@ import static org.powermock.api.mockito.PowerMockito.verifyStatic; import fi.helsinki.cs.tmc.cli.Application; -import fi.helsinki.cs.tmc.cli.CliContext; +import fi.helsinki.cs.tmc.cli.backend.CourseInfo; +import fi.helsinki.cs.tmc.cli.backend.CourseInfoIo; +import fi.helsinki.cs.tmc.cli.backend.TmcUtil; +import fi.helsinki.cs.tmc.cli.core.CliContext; import fi.helsinki.cs.tmc.cli.io.TestIo; -import fi.helsinki.cs.tmc.cli.tmcstuff.CourseInfo; -import fi.helsinki.cs.tmc.cli.tmcstuff.CourseInfoIo; -import fi.helsinki.cs.tmc.cli.tmcstuff.TmcUtil; -import fi.helsinki.cs.tmc.cli.tmcstuff.WorkDir; +import fi.helsinki.cs.tmc.cli.io.WorkDir; import fi.helsinki.cs.tmc.core.TmcCore; import fi.helsinki.cs.tmc.core.commands.GetUpdatableExercises.UpdateResult; diff --git a/src/test/java/fi/helsinki/cs/tmc/cli/command/UpdateCommandTest.java b/src/test/java/fi/helsinki/cs/tmc/cli/command/UpdateCommandTest.java index 6b9ba04a..942e688f 100644 --- a/src/test/java/fi/helsinki/cs/tmc/cli/command/UpdateCommandTest.java +++ b/src/test/java/fi/helsinki/cs/tmc/cli/command/UpdateCommandTest.java @@ -9,12 +9,13 @@ import static org.mockito.Mockito.when; import fi.helsinki.cs.tmc.cli.Application; -import fi.helsinki.cs.tmc.cli.CliContext; +import fi.helsinki.cs.tmc.cli.backend.CourseInfo; +import fi.helsinki.cs.tmc.cli.core.CliContext; +import fi.helsinki.cs.tmc.cli.io.CliProgressObserver; import fi.helsinki.cs.tmc.cli.io.TestIo; -import fi.helsinki.cs.tmc.cli.io.TmcCliProgressObserver; -import fi.helsinki.cs.tmc.cli.tmcstuff.CourseInfo; -import fi.helsinki.cs.tmc.cli.tmcstuff.ExerciseUpdater; -import fi.helsinki.cs.tmc.cli.tmcstuff.WorkDir; +import fi.helsinki.cs.tmc.cli.io.WorkDir; +import fi.helsinki.cs.tmc.cli.shared.ExerciseUpdater; + import fi.helsinki.cs.tmc.core.TmcCore; import fi.helsinki.cs.tmc.core.domain.Exercise; @@ -132,7 +133,7 @@ public void updatesNewAndChangedExercises() { List newAndChanged = new ArrayList<>(); newAndChanged.addAll(newExercises); newAndChanged.addAll(changedExercises); - when(exerciseUpdater.downloadUpdates(any(TmcCliProgressObserver.class))) + when(exerciseUpdater.downloadUpdates(any(CliProgressObserver.class))) .thenReturn(newAndChanged); when(exerciseUpdater.updateCourseJson(any(CourseInfo.class), any(Path.class))) .thenReturn(true); diff --git a/src/test/java/fi/helsinki/cs/tmc/cli/command/core/AbstractCommandTest.java b/src/test/java/fi/helsinki/cs/tmc/cli/core/AbstractCommandTest.java similarity index 73% rename from src/test/java/fi/helsinki/cs/tmc/cli/command/core/AbstractCommandTest.java rename to src/test/java/fi/helsinki/cs/tmc/cli/core/AbstractCommandTest.java index 9135c03e..e23a45bd 100644 --- a/src/test/java/fi/helsinki/cs/tmc/cli/command/core/AbstractCommandTest.java +++ b/src/test/java/fi/helsinki/cs/tmc/cli/core/AbstractCommandTest.java @@ -1,6 +1,5 @@ -package fi.helsinki.cs.tmc.cli.command.core; +package fi.helsinki.cs.tmc.cli.core; -import fi.helsinki.cs.tmc.cli.CliContext; import fi.helsinki.cs.tmc.cli.io.Io; import fi.helsinki.cs.tmc.cli.io.TestIo; @@ -10,6 +9,7 @@ import org.junit.Test; public class AbstractCommandTest { + AbstractCommand emptyCommand; CliContext ctx; TestIo io; @@ -18,14 +18,14 @@ public class AbstractCommandTest { private class EmptyCommand extends AbstractCommand { @Override - public void run(CommandLine args, Io io) { + public void run(CliContext context, CommandLine args) { } @Override public void getOptions(Options options) { } } - + public AbstractCommandTest() { emptyCommand = new EmptyCommand(); io = new TestIo(); @@ -35,24 +35,21 @@ public AbstractCommandTest() { @Test public void helpMessagePrints() { String[] args = {"-h"}; - emptyCommand.setContext(ctx); - emptyCommand.execute(args, io); + emptyCommand.execute(ctx, args); io.assertContains("tmc empty"); } @Test public void emptyCommandHasHelpOption() { String[] args = {"-h"}; - emptyCommand.setContext(ctx); - emptyCommand.execute(args, io); + emptyCommand.execute(ctx, args); io.assertContains("--help"); } @Test public void failWhenInvalidOption() { String[] args = {"-a34t3"}; - emptyCommand.setContext(ctx); - emptyCommand.execute(args, io); + emptyCommand.execute(ctx, args); io.assertContains("Invalid command"); } } \ No newline at end of file diff --git a/src/test/java/fi/helsinki/cs/tmc/cli/CliContextTest.java b/src/test/java/fi/helsinki/cs/tmc/cli/core/CliContextTest.java similarity index 71% rename from src/test/java/fi/helsinki/cs/tmc/cli/CliContextTest.java rename to src/test/java/fi/helsinki/cs/tmc/cli/core/CliContextTest.java index 10f7b5dc..acab6b2b 100644 --- a/src/test/java/fi/helsinki/cs/tmc/cli/CliContextTest.java +++ b/src/test/java/fi/helsinki/cs/tmc/cli/core/CliContextTest.java @@ -1,28 +1,31 @@ -package fi.helsinki.cs.tmc.cli; +package fi.helsinki.cs.tmc.cli.core; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import static org.powermock.api.mockito.PowerMockito.mockStatic; +import fi.helsinki.cs.tmc.cli.Application; +import fi.helsinki.cs.tmc.cli.backend.Account; +import fi.helsinki.cs.tmc.cli.backend.AccountList; +import fi.helsinki.cs.tmc.cli.backend.CourseInfo; +import fi.helsinki.cs.tmc.cli.backend.CourseInfoIo; +import fi.helsinki.cs.tmc.cli.backend.Settings; +import fi.helsinki.cs.tmc.cli.backend.SettingsIo; import fi.helsinki.cs.tmc.cli.io.TerminalIo; import fi.helsinki.cs.tmc.cli.io.TestIo; -import fi.helsinki.cs.tmc.cli.tmcstuff.CourseInfo; -import fi.helsinki.cs.tmc.cli.tmcstuff.CourseInfoIo; -import fi.helsinki.cs.tmc.cli.tmcstuff.Settings; -import fi.helsinki.cs.tmc.cli.tmcstuff.SettingsIo; -import fi.helsinki.cs.tmc.cli.tmcstuff.WorkDir; +import fi.helsinki.cs.tmc.cli.io.WorkDir; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; +import org.powermock.reflect.Whitebox; import java.nio.file.Path; @@ -31,10 +34,15 @@ public class CliContextTest { private TestIo io; + private AccountList list; @Before public void setUp() { io = new TestIo(); + list = new AccountList(); + + mockStatic(SettingsIo.class); + when(SettingsIo.loadAccountList()).thenReturn(list); } @Test @@ -57,6 +65,26 @@ public void setAppAndGetIt() { assertEquals(app, ctx.getApp()); } + @Test + public void useDifferentAccount() { + mockStatic(CourseInfoIo.class); + + WorkDir workDir = mock(WorkDir.class); + Path path = mock(Path.class); + Account newAccount = new Account(); + + when(CourseInfoIo.load(eq(path))).thenReturn(mock(CourseInfo.class)); + when(workDir.getConfigFile()).thenReturn(path); + CliContext ctx = new CliContext(io, null, workDir); + + ctx.loadBackend(); + ctx.useAccount(newAccount); + + //TODO replace the Whitebox usage somehow + Settings usedSettings = Whitebox.getInternalState(ctx, "settings"); + assertEquals(newAccount, usedSettings.getAccount()); + } + @Test(expected = RuntimeException.class) public void getAppWithoutSettingIt() { CliContext ctx = new CliContext(io); @@ -101,14 +129,13 @@ public void getCourseInfoWhenItDoesntExist() { @Test public void backendInitWithInternet() { mockStatic(CourseInfoIo.class); - mockStatic(SettingsIo.class); CourseInfo info = mock(CourseInfo.class); WorkDir workDir = mock(WorkDir.class); Path path = mock(Path.class); + list.addAccount(new Account()); when(CourseInfoIo.load(eq(path))).thenReturn(info); - when(SettingsIo.load(anyString(), anyString())).thenReturn(new Settings()); when(workDir.getConfigFile()).thenReturn(path); CliContext ctx = new CliContext(io, null, workDir); @@ -116,10 +143,27 @@ public void backendInitWithInternet() { assertEquals(true, ctx.hasLogin()); } + @Test + public void failBackendInitWithCourseButWithoutInternet() { + mockStatic(CourseInfoIo.class); + + WorkDir workDir = mock(WorkDir.class); + Path path = mock(Path.class); + CourseInfo info = mock(CourseInfo.class); + + when(info.getUsername()).thenReturn("user"); + when(CourseInfoIo.load(eq(path))).thenReturn(info); + when(workDir.getConfigFile()).thenReturn(path); + CliContext ctx = new CliContext(io, null, workDir); + + assertFalse(ctx.loadBackend()); + assertEquals(false, ctx.hasLogin()); + io.assertContains("You are not logged in as user. Log in using: tmc login"); + } + @Test public void failBackendInitWithInternetButWithoutCourse() { mockStatic(CourseInfoIo.class); - mockStatic(SettingsIo.class); WorkDir workDir = mock(WorkDir.class); when(workDir.getConfigFile()).thenReturn(null); @@ -133,7 +177,6 @@ public void failBackendInitWithInternetButWithoutCourse() { @Test public void failBackendInitWithInternetButWithCorruptedCourse() { mockStatic(CourseInfoIo.class); - mockStatic(SettingsIo.class); WorkDir workDir = mock(WorkDir.class); Path path = mock(Path.class); @@ -151,11 +194,8 @@ public void failBackendInitWithInternetButWithCorruptedCourse() { @Test public void backendInitWithoutInternet() { - mockStatic(SettingsIo.class); - WorkDir workDir = mock(WorkDir.class); when(workDir.getConfigFile()).thenReturn(null); - when(SettingsIo.load()).thenReturn(null); CliContext ctx = new CliContext(io, null, workDir); assertTrue(ctx.loadBackendWithoutLogin()); @@ -165,14 +205,13 @@ public void backendInitWithoutInternet() { @Test public void backendInitWithoutInternetWithCourse() { mockStatic(CourseInfoIo.class); - mockStatic(SettingsIo.class); WorkDir workDir = mock(WorkDir.class); CourseInfo info = mock(CourseInfo.class); Path path = mock(Path.class); + list.addAccount(new Account()); when(CourseInfoIo.load(eq(path))).thenReturn(info); - when(SettingsIo.load(anyString(), anyString())).thenReturn(new Settings()); when(workDir.getConfigFile()).thenReturn(path); CliContext ctx = new CliContext(io, null, workDir); diff --git a/src/test/java/fi/helsinki/cs/tmc/cli/command/core/CommandAnnotationProcessorTest.java b/src/test/java/fi/helsinki/cs/tmc/cli/core/CommandAnnotationProcessorTest.java similarity index 97% rename from src/test/java/fi/helsinki/cs/tmc/cli/command/core/CommandAnnotationProcessorTest.java rename to src/test/java/fi/helsinki/cs/tmc/cli/core/CommandAnnotationProcessorTest.java index 66abcfe9..4ee927c7 100644 --- a/src/test/java/fi/helsinki/cs/tmc/cli/command/core/CommandAnnotationProcessorTest.java +++ b/src/test/java/fi/helsinki/cs/tmc/cli/core/CommandAnnotationProcessorTest.java @@ -1,4 +1,4 @@ -package fi.helsinki.cs.tmc.cli.command.core; +package fi.helsinki.cs.tmc.cli.core; import static org.hamcrest.CoreMatchers.not; import static org.junit.Assert.assertFalse; @@ -11,8 +11,6 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -import fi.helsinki.cs.tmc.cli.io.Io; - import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.Options; import org.junit.Test; @@ -41,6 +39,7 @@ import javax.tools.JavaFileObject; public class CommandAnnotationProcessorTest { + CommandAnnotationProcessor processor; RoundEnvironment roundEnv; StringWriter stringWriter; @@ -50,7 +49,7 @@ public CommandAnnotationProcessorTest() throws IOException { final JavaFileObject fileObject = mock(JavaFileObject.class); final Filer mockedFiler = mock(Filer.class); when(mockedFiler.createSourceFile(anyString())).thenReturn(fileObject); - + stringWriter = new StringWriter(); when(fileObject.openWriter()).thenReturn(stringWriter); roundEnv = mock(RoundEnvironment.class); @@ -92,7 +91,6 @@ public SourceVersion getSourceVersion() { public Locale getLocale() { throw new UnsupportedOperationException(); } - }; processor = new CommandAnnotationProcessor(); processor.init(processingEnv); @@ -106,7 +104,7 @@ public void getOptions(Options options) { } @Override - public void run(CommandLine args, Io io) { + public void run(CliContext ctx, CommandLine args) { throw new UnsupportedOperationException(); } } @@ -119,7 +117,7 @@ public void getOptions(Options options) { } @Override - public void run(CommandLine args, Io io) { + public void run(CliContext ctx, CommandLine args) { throw new UnsupportedOperationException(); } } diff --git a/src/test/java/fi/helsinki/cs/tmc/cli/command/core/CommandFactoryTest.java b/src/test/java/fi/helsinki/cs/tmc/cli/core/CommandFactoryTest.java similarity index 85% rename from src/test/java/fi/helsinki/cs/tmc/cli/command/core/CommandFactoryTest.java rename to src/test/java/fi/helsinki/cs/tmc/cli/core/CommandFactoryTest.java index a1372ead..3a214681 100644 --- a/src/test/java/fi/helsinki/cs/tmc/cli/command/core/CommandFactoryTest.java +++ b/src/test/java/fi/helsinki/cs/tmc/cli/core/CommandFactoryTest.java @@ -1,12 +1,10 @@ -package fi.helsinki.cs.tmc.cli.command.core; +package fi.helsinki.cs.tmc.cli.core; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import fi.helsinki.cs.tmc.cli.Application; -import fi.helsinki.cs.tmc.cli.CliContext; -import fi.helsinki.cs.tmc.cli.io.Io; import fi.helsinki.cs.tmc.cli.io.TestIo; import org.apache.commons.cli.CommandLine; @@ -38,12 +36,12 @@ public void constructorAddsCommands() { @Test public void createCommandWorksWithRealCommand() { - assertNotNull(CommandFactory.createCommand(ctx, "help")); + assertNotNull(CommandFactory.createCommand("help")); } @Test public void createCommandWorksWithBadCommand() { - assertNull(CommandFactory.createCommand(ctx, "foobar")); + assertNull(CommandFactory.createCommand("foobar")); } @Command(name = "good", desc = "test") @@ -55,7 +53,7 @@ public void getOptions(Options options) { } @Override - public void run(CommandLine args, Io io) { + public void run(CliContext context, CommandLine args) { throw new UnsupportedOperationException(); } } @@ -64,7 +62,7 @@ public void run(CommandLine args, Io io) { public void addGoodCommand() { CommandFactory.addCommand(GoodCommand.class); //TODO check the all the stuff in the command - assertNotNull(CommandFactory.createCommand(ctx, "good")); + assertNotNull(CommandFactory.createCommand("good")); } public static class BadCommand extends AbstractCommand { @@ -75,7 +73,7 @@ public void getOptions(Options options) { } @Override - public void run(CommandLine args, Io io) { + public void run(CliContext context, CommandLine args) { throw new UnsupportedOperationException(); } } diff --git a/src/test/java/fi/helsinki/cs/tmc/cli/io/TmcCliProgressObserverTest.java b/src/test/java/fi/helsinki/cs/tmc/cli/io/CliProgressObserverTest.java similarity index 81% rename from src/test/java/fi/helsinki/cs/tmc/cli/io/TmcCliProgressObserverTest.java rename to src/test/java/fi/helsinki/cs/tmc/cli/io/CliProgressObserverTest.java index e316c3a3..71d7acc1 100644 --- a/src/test/java/fi/helsinki/cs/tmc/cli/io/TmcCliProgressObserverTest.java +++ b/src/test/java/fi/helsinki/cs/tmc/cli/io/CliProgressObserverTest.java @@ -13,7 +13,7 @@ @RunWith(PowerMockRunner.class) @PrepareForTest(EnvironmentUtil.class) -public class TmcCliProgressObserverTest { +public class CliProgressObserverTest { private TestIo io; @@ -26,7 +26,7 @@ public void setup() { @Test public void progressMessageWorks() { - TmcCliProgressObserver progobs = new TmcCliProgressObserver(io); + CliProgressObserver progobs = new CliProgressObserver(io); progobs.progress(0, "Hello, world!"); assertTrue("Prints message", io.out().contains( "Hello, world! ")); @@ -34,7 +34,7 @@ public void progressMessageWorks() { @Test public void progressBarWorks() { - TmcCliProgressObserver progobs = new TmcCliProgressObserver(io); + CliProgressObserver progobs = new CliProgressObserver(io); progobs.progress(0, 0.5, "Hello, world!"); assertTrue("Prints message", io.out().contains("Hello, world!")); assertTrue("Prints the start of the progress bar", io.out().contains( @@ -49,8 +49,8 @@ public void progressBarWorks() { @Test public void testResultBarWorks() { - String string = TmcCliProgressObserver.getPassedTestsBar(1, 2, - Color.AnsiColor.ANSI_NONE, Color.AnsiColor.ANSI_NONE); + String string = CliProgressObserver.getPassedTestsBar(1, 2, + Color.NONE, Color.NONE); assertTrue("Prints the start of the progress bar", string.contains( " 50%[")); assertTrue("Prints the first part of the progress bar", string.contains( @@ -63,7 +63,7 @@ public void testResultBarWorks() { @Test public void shortensLongMessages() { - TmcCliProgressObserver progobs = new TmcCliProgressObserver(io); + CliProgressObserver progobs = new CliProgressObserver(io); progobs.progress(0, "fooooooooooooooooooooooooooooooooooooooooooooooooobar"); assertTrue("Prints what it's supposed to", @@ -74,8 +74,8 @@ public void shortensLongMessages() { @Test public void percentagesWork() { - assertEquals(" 6%", TmcCliProgressObserver.percentage(0.06)); - assertEquals(" 20%", TmcCliProgressObserver.percentage(0.2)); - assertEquals("100%", TmcCliProgressObserver.percentage(1.0)); + assertEquals(" 6%", CliProgressObserver.percentage(0.06)); + assertEquals(" 20%", CliProgressObserver.percentage(0.2)); + assertEquals("100%", CliProgressObserver.percentage(1.0)); } } diff --git a/src/test/java/fi/helsinki/cs/tmc/cli/io/ColorTest.java b/src/test/java/fi/helsinki/cs/tmc/cli/io/ColorTest.java index 1749e5e3..67a9179a 100644 --- a/src/test/java/fi/helsinki/cs/tmc/cli/io/ColorTest.java +++ b/src/test/java/fi/helsinki/cs/tmc/cli/io/ColorTest.java @@ -22,20 +22,62 @@ public void setup() { @Test public void colorsWorkInNonWindows() { when(EnvironmentUtil.isWindows()).thenReturn(false); - String string = Color.colorString("foobar", Color.AnsiColor.ANSI_BLACK); + String string = ColorUtil.colorString("foobar", Color.BLACK); assertEquals("\u001B[30mfoobar\u001B[0m", string); } @Test public void colorsWorkInWindows() { when(EnvironmentUtil.isWindows()).thenReturn(true); - String string = Color.colorString("foobar", Color.AnsiColor.ANSI_BLACK); + String string = ColorUtil.colorString("foobar", Color.BLACK); assertEquals("foobar", string); } @Test public void noColorWorks() { - String string = Color.colorString("foobar", Color.AnsiColor.ANSI_NONE); + String string = ColorUtil.colorString("foobar", Color.NONE); assertEquals("foobar", string); } + + @Test + public void getLowerCaseGreenColor() { + Color color = ColorUtil.getColor("green"); + assertEquals(Color.GREEN, color); + } + + @Test + public void getCamelCaseGreenColor() { + Color color = ColorUtil.getColor("Green"); + assertEquals(Color.GREEN, color); + } + + @Test + public void getUpperCaseGreenColor() { + Color color = ColorUtil.getColor("GREEN"); + assertEquals(Color.GREEN, color); + } + + @Test + public void getGreenWithSpecialCharColor() { + Color color = ColorUtil.getColor("green$"); + assertEquals(null, color); + } + + @Test + public void getInvalidColor() { + Color color = ColorUtil.getColor("xgrewsg"); + assertEquals(null, color); + } + + @Test + public void getResetColor() { + Color color = ColorUtil.getColor("reset"); + assertEquals(null, color); + } + + @Test + public void getNullAsColor() { + Color color = ColorUtil.getColor(null); + assertEquals(null, color); + } } diff --git a/src/test/java/fi/helsinki/cs/tmc/cli/io/ShutdownHandlerTest.java b/src/test/java/fi/helsinki/cs/tmc/cli/io/ShutdownHandlerTest.java index 2b8518c1..f1a5f3ac 100644 --- a/src/test/java/fi/helsinki/cs/tmc/cli/io/ShutdownHandlerTest.java +++ b/src/test/java/fi/helsinki/cs/tmc/cli/io/ShutdownHandlerTest.java @@ -33,7 +33,7 @@ public void setUp() { @Test public void printsAnsiResetAtRun() { shutdownHandler.run(); - io.assertEquals(Color.AnsiColor.ANSI_RESET.toString() + "\n"); + io.assertEquals(Color.RESET.toString() + "\n"); } @Test diff --git a/src/test/java/fi/helsinki/cs/tmc/cli/tmcstuff/WorkDirTest.java b/src/test/java/fi/helsinki/cs/tmc/cli/io/WorkDirTest.java similarity index 97% rename from src/test/java/fi/helsinki/cs/tmc/cli/tmcstuff/WorkDirTest.java rename to src/test/java/fi/helsinki/cs/tmc/cli/io/WorkDirTest.java index 57d5a10a..b6e71a7a 100644 --- a/src/test/java/fi/helsinki/cs/tmc/cli/tmcstuff/WorkDirTest.java +++ b/src/test/java/fi/helsinki/cs/tmc/cli/io/WorkDirTest.java @@ -1,4 +1,4 @@ -package fi.helsinki.cs.tmc.cli.tmcstuff; +package fi.helsinki.cs.tmc.cli.io; import static junit.framework.Assert.assertNotNull; import static junit.framework.Assert.assertNull; @@ -7,6 +7,10 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import fi.helsinki.cs.tmc.cli.backend.Account; +import fi.helsinki.cs.tmc.cli.backend.CourseInfo; +import fi.helsinki.cs.tmc.cli.backend.CourseInfoIo; + import fi.helsinki.cs.tmc.core.domain.Course; import fi.helsinki.cs.tmc.core.domain.Exercise; @@ -53,7 +57,7 @@ public static void setup() { exercises.get(1).setCompleted(true); exercises.add(new Exercise("viikko2-teht3")); exercises.add(new Exercise("viikko3-nonexistent")); - CourseInfo info = new CourseInfo(new Settings(), new Course("dirUtilTest")); + CourseInfo info = new CourseInfo(new Account(), new Course("dirUtilTest")); info.getLocalCompletedExercises().add("viikko1-teht1"); info.setExercises(exercises); CourseInfoIo.save(info, tempDir.resolve(CourseInfoIo.COURSE_CONFIG)); diff --git a/src/test/java/fi/helsinki/cs/tmc/cli/tmcstuff/ExerciseUpdaterTest.java b/src/test/java/fi/helsinki/cs/tmc/cli/shared/ExerciseUpdaterTest.java similarity index 95% rename from src/test/java/fi/helsinki/cs/tmc/cli/tmcstuff/ExerciseUpdaterTest.java rename to src/test/java/fi/helsinki/cs/tmc/cli/shared/ExerciseUpdaterTest.java index 07650fbe..93644139 100644 --- a/src/test/java/fi/helsinki/cs/tmc/cli/tmcstuff/ExerciseUpdaterTest.java +++ b/src/test/java/fi/helsinki/cs/tmc/cli/shared/ExerciseUpdaterTest.java @@ -1,4 +1,4 @@ -package fi.helsinki.cs.tmc.cli.tmcstuff; +package fi.helsinki.cs.tmc.cli.shared; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -8,7 +8,8 @@ import static org.mockito.Mockito.when; import static org.powermock.api.mockito.PowerMockito.mockStatic; -import fi.helsinki.cs.tmc.cli.CliContext; +import fi.helsinki.cs.tmc.cli.backend.TmcUtil; +import fi.helsinki.cs.tmc.cli.core.CliContext; import fi.helsinki.cs.tmc.cli.io.TestIo; import fi.helsinki.cs.tmc.core.TmcCore; diff --git a/src/test/java/fi/helsinki/cs/tmc/cli/tmcstuff/FeedbackHandlerTest.java b/src/test/java/fi/helsinki/cs/tmc/cli/shared/FeedbackHandlerTest.java similarity index 96% rename from src/test/java/fi/helsinki/cs/tmc/cli/tmcstuff/FeedbackHandlerTest.java rename to src/test/java/fi/helsinki/cs/tmc/cli/shared/FeedbackHandlerTest.java index 251c7512..abddb1d1 100644 --- a/src/test/java/fi/helsinki/cs/tmc/cli/tmcstuff/FeedbackHandlerTest.java +++ b/src/test/java/fi/helsinki/cs/tmc/cli/shared/FeedbackHandlerTest.java @@ -1,4 +1,4 @@ -package fi.helsinki.cs.tmc.cli.tmcstuff; +package fi.helsinki.cs.tmc.cli.shared; import static com.google.common.truth.Truth.assertThat; import static org.mockito.Matchers.any; @@ -9,7 +9,8 @@ import static org.powermock.api.mockito.PowerMockito.verifyStatic; import static org.powermock.api.mockito.PowerMockito.when; -import fi.helsinki.cs.tmc.cli.CliContext; +import fi.helsinki.cs.tmc.cli.backend.TmcUtil; +import fi.helsinki.cs.tmc.cli.core.CliContext; import fi.helsinki.cs.tmc.cli.io.ExternalsUtil; import fi.helsinki.cs.tmc.cli.io.TestIo; import fi.helsinki.cs.tmc.core.domain.submission.FeedbackAnswer; diff --git a/src/test/java/fi/helsinki/cs/tmc/cli/io/ResultPrinterTest.java b/src/test/java/fi/helsinki/cs/tmc/cli/shared/ResultPrinterTest.java similarity index 97% rename from src/test/java/fi/helsinki/cs/tmc/cli/io/ResultPrinterTest.java rename to src/test/java/fi/helsinki/cs/tmc/cli/shared/ResultPrinterTest.java index 1bca573b..2040df77 100644 --- a/src/test/java/fi/helsinki/cs/tmc/cli/io/ResultPrinterTest.java +++ b/src/test/java/fi/helsinki/cs/tmc/cli/shared/ResultPrinterTest.java @@ -1,8 +1,11 @@ -package fi.helsinki.cs.tmc.cli.io; +package fi.helsinki.cs.tmc.cli.shared; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import fi.helsinki.cs.tmc.cli.io.Color; +import fi.helsinki.cs.tmc.cli.io.TestIo; + import fi.helsinki.cs.tmc.core.domain.submission.SubmissionResult; import fi.helsinki.cs.tmc.core.domain.submission.SubmissionResult.TestResultStatus; import fi.helsinki.cs.tmc.core.domain.submission.ValidationErrorImpl; @@ -37,7 +40,7 @@ public class ResultPrinterTest { public void setUp() { io = new TestIo(); printer = new ResultPrinter(io, true, true, - Color.AnsiColor.ANSI_GREEN, Color.AnsiColor.ANSI_RED); + Color.GREEN, Color.RED); mockSubResult = mock(SubmissionResult.class); logs = ImmutableMap.of(); } diff --git a/src/test/java/fi/helsinki/cs/tmc/cli/tmcstuff/SettingsIoTest.java b/src/test/java/fi/helsinki/cs/tmc/cli/tmcstuff/SettingsIoTest.java deleted file mode 100644 index 6317c9b7..00000000 --- a/src/test/java/fi/helsinki/cs/tmc/cli/tmcstuff/SettingsIoTest.java +++ /dev/null @@ -1,159 +0,0 @@ -package fi.helsinki.cs.tmc.cli.tmcstuff; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; - -import fi.helsinki.cs.tmc.core.configuration.TmcSettings; - -import org.apache.commons.io.FileUtils; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.HashMap; - -public class SettingsIoTest { - - private Settings settings; - private Path tempDir; - - @Before - public void setUp() { - tempDir = Paths.get(System.getProperty("java.io.tmpdir")).resolve(SettingsIo.CONFIG_DIR); - this.settings = new Settings("testserver", "testuser", "testpassword"); - try { - FileUtils.deleteDirectory(tempDir.toFile()); - } catch (Exception e) { } - } - - @After - public void cleanUp() { - try { - FileUtils.deleteDirectory(tempDir.toFile()); - } catch (Exception e) { } - } - - @Test - public void correctConfigPath() { - Path path = SettingsIo.getDefaultConfigRoot(); - String fs = System.getProperty("file.separator"); - assertTrue(path.toString().contains(SettingsIo.CONFIG_DIR)); - assertTrue(path.toString().contains(fs)); - assertTrue(!path.toString().contains(fs + fs)); - assertTrue(path.toString().contains(System.getProperty("user.home"))); - } - - @Test - public void savingToFileWorks() { - Boolean success = SettingsIo.saveTo(settings, tempDir); - assertTrue(success); - Path path = tempDir - .resolve(SettingsIo.ACCOUNTS_CONFIG); - assertTrue(Files.exists(path)); - } - - @Test - public void loadingFromFileWorks() { - SettingsIo.saveTo(this.settings, tempDir); - TmcSettings loadedSettings; - loadedSettings = SettingsIo.loadFrom(tempDir); - assertNotNull(loadedSettings); - assertEquals(settings.getUsername(), loadedSettings.getUsername()); - assertEquals(settings.getPassword(), loadedSettings.getPassword()); - assertEquals(settings.getServerAddress(), loadedSettings.getServerAddress()); - } - - @Test - public void loadingWhenNoFilePresentReturnsNull() { - Path path = tempDir.getParent(); - TmcSettings loadedSettings = SettingsIo.loadFrom(path); - assertEquals(null, loadedSettings); - } - - @Test - public void newHolderIsEmpty() { - SettingsHolder holder = new SettingsHolder(); - assertEquals(0, holder.settingsCount()); - } - - @Test - public void addingSettingsIncreasesHolderCount() { - SettingsHolder holder = new SettingsHolder(); - holder.addSettings(new Settings("eee", "aaa", "ooo")); - assertEquals(1, holder.settingsCount()); - } - - @Test - public void loadingFromHolderWorks() { - SettingsHolder holder = new SettingsHolder(); - holder.addSettings(this.settings); - Settings loaded = holder.getSettings(); - assertSame(this.settings, loaded); - } - - @Test - public void addingMoreThanOneSettingWorks() { - SettingsHolder holder = new SettingsHolder(); - holder.addSettings(this.settings); - holder.addSettings(new Settings("1", "2", "e")); - holder.addSettings(new Settings(":", "-", "D")); - assertEquals(3, holder.settingsCount()); - } - - @Test - public void loadingLatestSettingsWorks() { - SettingsHolder holder = new SettingsHolder(); - holder.addSettings(new Settings(":", "-", "D")); - holder.addSettings(new Settings("1", "2", "e")); - holder.addSettings(this.settings); - Settings latest = holder.getSettings(); - assertSame(this.settings, latest); - } - - @Test - public void gettingSettingsByNameAndServerWorks() { - SettingsHolder holder = new SettingsHolder(); - Settings wanted = new Settings("1", "2", "e"); - holder.addSettings(new Settings(":", "-", "D")); - holder.addSettings(wanted); - holder.addSettings(new Settings("344", "wc", "fffssshhhh aaahhh")); - Settings get = holder.getSettings("2", "1"); - assertSame(wanted, get); - } - - @Test - public void gettingLatestSettingsSetsItToTheTop() { - SettingsHolder holder = new SettingsHolder(); - Settings wanted = new Settings("1", "2", "e"); - holder.addSettings(wanted); - holder.addSettings(new Settings(":", "-", "D")); - holder.getSettings("2", "1"); - Settings get = holder.getSettings(); - assertSame(wanted, get); - } - - @Test - public void savingPropertiesWorks() { - HashMap props = new HashMap<>(); - props.put("lastupdated", "1970-01-01"); - props.put("nextupdate", "2038-01-20"); - SettingsIo.savePropertiesTo(props, tempDir); - assertTrue("Properties file exists", - Files.exists(tempDir.resolve(SettingsIo.PROPERTIES_CONFIG))); - } - - @Test - public void loadingPropertiesWorks() { - HashMap props = new HashMap<>(); - props.put("lastupdated", "1970-01-01"); - props.put("nextupdate", "2038-01-20"); - SettingsIo.savePropertiesTo(props, tempDir); - HashMap loadedProps = SettingsIo.loadPropertiesFrom(tempDir); - assertEquals(props, loadedProps); - } -} diff --git a/src/test/java/fi/helsinki/cs/tmc/cli/updater/TmcCliUpdaterTest.java b/src/test/java/fi/helsinki/cs/tmc/cli/updater/AutoUpdaterTest.java similarity index 88% rename from src/test/java/fi/helsinki/cs/tmc/cli/updater/TmcCliUpdaterTest.java rename to src/test/java/fi/helsinki/cs/tmc/cli/updater/AutoUpdaterTest.java index 611bf460..e20011ee 100644 --- a/src/test/java/fi/helsinki/cs/tmc/cli/updater/TmcCliUpdaterTest.java +++ b/src/test/java/fi/helsinki/cs/tmc/cli/updater/AutoUpdaterTest.java @@ -6,7 +6,6 @@ import static org.junit.Assert.assertThat; import static org.junit.matchers.JUnitMatchers.containsString; import static org.mockito.Matchers.any; -import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; @@ -25,7 +24,7 @@ import java.io.InputStream; import java.io.IOException; -public class TmcCliUpdaterTest { +public class AutoUpdaterTest { private static String latestJson; private static String apiLimitExeededJson; @@ -61,7 +60,7 @@ public void stub() { @Test public void doNothingIfReleaseEqualsCurrentVersion() { - TmcCliUpdater updater = spy(new TmcCliUpdater(io, "0.1.1", false)); + AutoUpdater updater = spy(new AutoUpdater(io, "0.1.1", false)); doReturn(latestJson).when(updater).fetchLatestReleaseJson(); //when(updater.fetchLatestReleaseJson()).thenReturn(latestJson); updater.run(); @@ -71,7 +70,7 @@ public void doNothingIfReleaseEqualsCurrentVersion() { @Test public void doNothingIfFetchingReleaseJsonFails() { - TmcCliUpdater updater = spy(new TmcCliUpdater(io, "0.1.0", false)); + AutoUpdater updater = spy(new AutoUpdater(io, "0.1.0", false)); doReturn(null).when(updater).fetchLatestReleaseJson(); //when(updater.fetchLatestReleaseJson()).thenReturn(null); updater.run(); @@ -81,7 +80,7 @@ public void doNothingIfFetchingReleaseJsonFails() { @Test public void doNothingIfFetchedJsonIsApiRateLimitExceeded() { - TmcCliUpdater updater = spy(new TmcCliUpdater(io, "0.1.0", false)); + AutoUpdater updater = spy(new AutoUpdater(io, "0.1.0", false)); doReturn(apiLimitExeededJson).when(updater).fetchLatestReleaseJson(); //when(updater.fetchLatestReleaseJson()).thenReturn(apiLimitExeededJson); updater.run(); @@ -92,7 +91,7 @@ public void doNothingIfFetchedJsonIsApiRateLimitExceeded() { @Test public void doNothingIfUserDoesntWantToUpdate() { io.addConfirmationPrompt(false); - TmcCliUpdater updater = spy(new TmcCliUpdater(io, "0.1.0", false)); + AutoUpdater updater = spy(new AutoUpdater(io, "0.1.0", false)); doReturn(latestJson).when(updater).fetchLatestReleaseJson(); //when(updater.fetchLatestReleaseJson()).thenReturn(latestJson); updater.run(); @@ -104,7 +103,7 @@ public void doNothingIfUserDoesntWantToUpdate() { @Test public void downloadsAndRunsNewBinaryIfOk() { io.addConfirmationPrompt(true); - TmcCliUpdater updater = spy(new TmcCliUpdater(io, "0.1.0", false)); + AutoUpdater updater = spy(new AutoUpdater(io, "0.1.0", false)); doReturn(latestJson).when(updater).fetchLatestReleaseJson(); //when(updater.fetchLatestReleaseJson()).thenReturn(latestJson); doReturn(true).when(updater).fetchTmcCliBinary(any(String.class), any(File.class)); @@ -120,7 +119,7 @@ public void downloadsAndRunsNewBinaryIfOk() { // Expected to fail once autoupdater is properly implemented on Windows. @Test public void newReleaseShowsDownloadLinkOnWindows() { - TmcCliUpdater updater = spy(new TmcCliUpdater(io, "0.1.0", true)); + AutoUpdater updater = spy(new AutoUpdater(io, "0.1.0", true)); doReturn(latestJson).when(updater).fetchLatestReleaseJson(); //when(updater.fetchLatestReleaseJson()).thenReturn(latestJson); updater.run(); @@ -131,7 +130,7 @@ public void newReleaseShowsDownloadLinkOnWindows() { @Test public void doNothingIfJsonIsMalformed() { - TmcCliUpdater updater = spy(new TmcCliUpdater(io, "0.1.0", false)); + AutoUpdater updater = spy(new AutoUpdater(io, "0.1.0", false)); doReturn(malformedJson).when(updater).fetchLatestReleaseJson(); //when(updater.fetchLatestReleaseJson()).thenReturn(malformedJson); updater.run(); @@ -141,7 +140,7 @@ public void doNothingIfJsonIsMalformed() { @Test public void abortIfJsonDoesNotContainNecessaryInfo() { - TmcCliUpdater updater = spy(new TmcCliUpdater(io, "0.1.0", false)); + AutoUpdater updater = spy(new AutoUpdater(io, "0.1.0", false)); doReturn(changedJson).when(updater).fetchLatestReleaseJson(); //when(updater.fetchLatestReleaseJson()).thenReturn(changedJson); updater.run(); @@ -150,7 +149,7 @@ public void abortIfJsonDoesNotContainNecessaryInfo() { } private static String readResource(String resourceName) throws IOException { - InputStream inputStream = TmcCliUpdaterTest.class.getClassLoader() + InputStream inputStream = AutoUpdaterTest.class.getClassLoader() .getResourceAsStream(resourceName); if (inputStream == null) { return null;