From 1293b88125d56dd1f647d0b9b775855f1dfdbfb8 Mon Sep 17 00:00:00 2001 From: "Damith C. Rajapakse" Date: Mon, 3 Oct 2016 11:34:40 +0800 Subject: [PATCH 001/754] Remove redundant comment lines in GuiTest --- src/test/java/guitests/AddressBookGuiTest.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/test/java/guitests/AddressBookGuiTest.java b/src/test/java/guitests/AddressBookGuiTest.java index b9cf9ca092eb..35734932f11c 100644 --- a/src/test/java/guitests/AddressBookGuiTest.java +++ b/src/test/java/guitests/AddressBookGuiTest.java @@ -83,7 +83,6 @@ protected AddressBook getInitialData() { /** * Override this in child classes to set the data file location. - * @return */ protected String getDataFileLocation() { return TestApp.SAVE_LOCATION_FOR_TESTING; @@ -111,7 +110,6 @@ protected void assertListSize(int size) { /** * Asserts the message shown in the Result Display area is same as the given string. - * @param expected */ protected void assertResultMessage(String expected) { assertEquals(expected, resultDisplay.getText()); From b550d0b7ca26f2851e9dc74a595a563118dcf218 Mon Sep 17 00:00:00 2001 From: "Damith C. Rajapakse" Date: Tue, 4 Oct 2016 14:44:08 +0800 Subject: [PATCH 002/754] Add LO-EventDriven etc. --- docs/LearningOutcomes.md | 115 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 111 insertions(+), 4 deletions(-) diff --git a/docs/LearningOutcomes.md b/docs/LearningOutcomes.md index 31f26a37b480..a7edbcc500d1 100644 --- a/docs/LearningOutcomes.md +++ b/docs/LearningOutcomes.md @@ -2,19 +2,126 @@ After studying this code and completing the corresponding exercises, you should be able to, 1. [Use High-Level Designs `[LO-HighLevelDesign]`](#use-high-level-designs-lo-highleveldesign) +1. [Use Event-Driven Programming `[LO-EventDriven]`](#use-event-driven-programming-lo-eventdriven`) +{more to be added} ------------------------------------------------------------------------------------------------------ ## Use High-Level Designs `[LO-HighLevelDesign]` -Note how the [Developer Guide](DeveloperGuide.md#design) describes the high-level design using an + +Note how the [Developer Guide](DeveloperGuide.md#architecture) describes the high-level design using an _Architecture Diagrams_ and high-level sequence diagrams. - -#### Exercise: Add more user stories -* ... +------------------------------------------------------------------------------------------------------ + +## Use Event-Driven Programming `[LO-EventDriven]` + +Note how the [Developer Guide](DeveloperGuide.md#architecture) uses events to communicate with components +without needing a direct coupling. Also note how the `EventsCenter` class acts as an event dispatcher to +facilitate communication between event creators and event consumers. ------------------------------------------------------------------------------------------------------ +## Use API Design `[LO-ApiDesign]` + +Note how components of AddressBook have well-defined APIs. For example, the API of the `Logic` component +is given in the [`Logic.java`](../src/main/java/seedu/address/logic/Logic.java) +
+ +**Resources** +* [A three-minutes video](https://www.youtube.com/watch?v=Un80XoRT1ME) of designing architecture of and + discovering component APIs for a Game of Tic-Tac-Toe. + +------------------------------------------------------------------------------------------------------ + +## Use Assertions `[LO-Assertions]` + +Note how the AddressBook app uses Java `assert`s to verify assumptions. + +**Resources** + * [Programming With Assertions](http://docs.oracle.com/javase/6/docs/technotes/guides/language/assert.html) - a + guide from Oracle. + * [How to enable assertions in Eclipse](http://stackoverflow.com/questions/5509082/eclipse-enable-assertions) + +#### Exercise: Add more assertions + * Make sure assertions are enabled in Eclipse by forcing an assertion failure (e.g. add `assert false;` somewhere in + the code and run the code to ensure the runtime reports an assertion failure). + + * Add more assertions to AddressBook as you see fit. + +------------------------------------------------------------------------------------------------------ + +## Use Logging `[LO-Logging]` + +Note [how the AddressBook app uses Java's `java.util.log` package to do logging](DeveloperGuide.md#logging). + +**Resources** + * Tutorials + * [Logging using java.util.logging](http://tutorials.jenkov.com/java-logging/index.html) - a tutorial by Jakob Jenkov + * [Logging tutorial](http://docs.oracle.com/javase/7/docs/technotes/guides/logging/overview.html) - a more detailed + tutorial from Oracle. + * Logging best practices + * [Apache Commons Logging guide](http://commons.apache.org/proper/commons-logging/guide.html#Message_PrioritiesLevels) + * [10 Tips for Proper Application Logging](https://www.javacodegeeks.com/2011/01/10-tips-proper-application-logging.html) + * [Base 22 Java Logging Standards and Guidelines](https://wiki.base22.com/display/btg/Java+Logging+Standards+and+Guidelines) + +#### Exercise: Add more logging + Add more logging to AddressBook as you see fit. + + ------------------------------------------------------------------------------------------------------ + + ## Use Defensive Coding `[LO-DefensiveCoding]` + Note how AddressBook uses the `ReadOnly*` interfaces to prevent objects being modified by clients who are not + supposed to modify them. + + #### Exercise: identify more places for defensive coding + Analyze the AddressBook code/design to identify, + * where defensive coding is used + * where the code can be more defensive + +------------------------------------------------------------------------------------------------------ + +## Use Build Automation `[LO-BuildAutomation]` + +Note [how the AddressBook app uses Gradle to automate build tasks](UsingGradle.md). + +**Resources** + * Tutorials + * [Getting started with Gradle (Java)](https://gradle.org/getting-started-gradle-java/) - a tutorial from the Gradle team + * [Another tutorial](http://www.tutorialspoint.com/gradle/) - from TutorialPoint + +#### Exercise: Use gradle to run tasks + * Use gradle to do these tasks (instructions are [here](UsingGradle.md)) + : Run all tests in headless mode, build the jar file. + +#### Exercise: Use gradle to manage dependencies + * Note how the build script `build.gradle` file manages third party dependencies such as ControlsFx.
+ Update that file to manage a third-party library dependency. + +------------------------------------------------------------------------------------------------------ + +## Use Continuous Integration `[LO-ContinuousIntegration]` + +Note [how the AddressBook app uses Travis to perform Continuous Integration](UsingTravis.md). + +**Resources** + * Tutorials + * [Getting started with Travis](https://docs.travis-ci.com/user/getting-started/) - a tutorial from the Travis team + +#### Exercise: Use Travis in your own project + * Set up Travis to perform CI on your own project. + +------------------------------------------------------------------------------------------------------ + {More to be added} +* Integration testing +* System testing +* Acceptance testing (+dogfooding) +* Equivalence classes +* Boundary value analysis +* Test input combination +* GUI test automation +* Design patterns + From 3092267187fba507bed344055c782e1c68c16efc Mon Sep 17 00:00:00 2001 From: "Damith C. Rajapakse" Date: Tue, 4 Oct 2016 14:50:39 +0800 Subject: [PATCH 003/754] Add ToC to new LOs --- docs/LearningOutcomes.md | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/docs/LearningOutcomes.md b/docs/LearningOutcomes.md index a7edbcc500d1..87b9c659adbd 100644 --- a/docs/LearningOutcomes.md +++ b/docs/LearningOutcomes.md @@ -3,8 +3,12 @@ After studying this code and completing the corresponding exercises, you should 1. [Use High-Level Designs `[LO-HighLevelDesign]`](#use-high-level-designs-lo-highleveldesign) 1. [Use Event-Driven Programming `[LO-EventDriven]`](#use-event-driven-programming-lo-eventdriven`) - -{more to be added} +1. [Use API Design `[LO-ApiDesign]`](#use-api-design-lo-apidesign) +1. [Use Assertions `[LO-Assertions]`](#use-assertions-lo-assertions) +1. [Use Logging `[LO-Logging]`](#use-logging-lo-logging) +1. [Use Defensive Coding `[LO-DefensiveCoding]`](#use-defensive-coding-lo-defensivedoding) +1. [Use Build Automation `[LO-BuildAutomation]`](#use-build-automation-lo-buildautomation) +1. [Use Continuous Integration `[LO-ContinuousIntegration]`](#use-continuous-integration-lo-continuousintegration) ------------------------------------------------------------------------------------------------------ @@ -69,9 +73,10 @@ Note [how the AddressBook app uses Java's `java.util.log` package to do logging] #### Exercise: Add more logging Add more logging to AddressBook as you see fit. - ------------------------------------------------------------------------------------------------------ +------------------------------------------------------------------------------------------------------ ## Use Defensive Coding `[LO-DefensiveCoding]` + Note how AddressBook uses the `ReadOnly*` interfaces to prevent objects being modified by clients who are not supposed to modify them. From 0184f84e138a6b2e41b719be12846e5715c6159e Mon Sep 17 00:00:00 2001 From: "Damith C. Rajapakse" Date: Tue, 4 Oct 2016 14:51:57 +0800 Subject: [PATCH 004/754] Remove extra spaces in LO-DefensiveCoding --- docs/LearningOutcomes.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/LearningOutcomes.md b/docs/LearningOutcomes.md index 87b9c659adbd..eb0964f56c5c 100644 --- a/docs/LearningOutcomes.md +++ b/docs/LearningOutcomes.md @@ -75,12 +75,12 @@ Note [how the AddressBook app uses Java's `java.util.log` package to do logging] ------------------------------------------------------------------------------------------------------ - ## Use Defensive Coding `[LO-DefensiveCoding]` +## Use Defensive Coding `[LO-DefensiveCoding]` Note how AddressBook uses the `ReadOnly*` interfaces to prevent objects being modified by clients who are not supposed to modify them. - #### Exercise: identify more places for defensive coding +#### Exercise: identify more places for defensive coding Analyze the AddressBook code/design to identify, * where defensive coding is used * where the code can be more defensive From 239bcc15a1d244a1655b06b9f68e645176e310e8 Mon Sep 17 00:00:00 2001 From: "Damith C. Rajapakse" Date: Wed, 5 Oct 2016 14:31:36 +0800 Subject: [PATCH 005/754] Add troubleshooting help to DevGuide --- docs/DeveloperGuide.md | 12 ++++++++++++ docs/LearningOutcomes.md | 3 +++ 2 files changed, 15 insertions(+) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index bc710ed45eb9..0c6554871330 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -41,6 +41,18 @@ > * Depending on your connection speed and server load, it can even take up to 30 minutes for the set up to finish (This is because Gradle downloads library files from servers during the project set up process) > * If Eclipse auto-changed any settings files during the import process, you can discard those changes. + +#### Troubleshooting + +**Problem: Eclipse reports compile errors after new commits are pulled from Git** +* Reason: Eclipse fails to recognize new files that appeared due to the Git pull. +* Solution: Refresh the project in Eclipse:
+ Right click on the project (in Eclipse package explorer), choose `Gradle` -> `Refresh Gradle Project`. + +**Problem: Eclipse reports some required libraries missing** +* Reason: Required libraries may not have been downloaded during the project import. +* Solution: [Run tests using Gardle](UsingGradle.md) once (to refresh the libraries). + ## Design diff --git a/docs/LearningOutcomes.md b/docs/LearningOutcomes.md index eb0964f56c5c..5ee57072a8d8 100644 --- a/docs/LearningOutcomes.md +++ b/docs/LearningOutcomes.md @@ -128,5 +128,8 @@ Note [how the AddressBook app uses Travis to perform Continuous Integration](Usi * Test input combination * GUI test automation * Design patterns +* Static analysis +* Code reviews +* Code coverage From 386c3c108ff4a554d43a8ad38b8be6d56f6d9fcc Mon Sep 17 00:00:00 2001 From: "Damith C. Rajapakse" Date: Wed, 5 Oct 2016 15:11:57 +0800 Subject: [PATCH 006/754] Add troubleshooting tips for tests --- docs/DeveloperGuide.md | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 0c6554871330..690b6d386627 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -42,7 +42,7 @@ (This is because Gradle downloads library files from servers during the project set up process) > * If Eclipse auto-changed any settings files during the import process, you can discard those changes. -#### Troubleshooting +#### Troubleshooting project setup **Problem: Eclipse reports compile errors after new commits are pulled from Git** * Reason: Eclipse fails to recognize new files that appeared due to the Git pull. @@ -198,9 +198,6 @@ Certain properties of the application can be controlled (e.g App name, logging l Tests can be found in the `./src/test/java` folder. **In Eclipse**: -> If you are not using a recent Eclipse version (i.e. _Neon_ or later), enable assertions in JUnit tests - as described [here](http://stackoverflow.com/questions/2522897/eclipse-junit-ea-vm-option). - * To run all tests, right-click on the `src/test/java` folder and choose `Run as` > `JUnit Test` * To run a subset of tests, you can right-click on a test package, test class, or a test and choose @@ -230,6 +227,14 @@ Thanks to the [TestFX](https://github.com/TestFX/TestFX) library we use, In the headless mode, GUI tests do not show up on the screen. That means the developer can do other things on the Computer while the tests are running.
See [UsingGradle.md](UsingGradle.md#running-tests) to learn how to run tests in headless mode. + +#### Troubleshooting tests + **Problem: Tests fail because NullPointException when AssertionError is expected** + * Reason: Assertions are not enabled for JUnit tests. + This can happen if you are not using a recent Eclipse version (i.e. _Neon_ or later) + * Solution: Enable assertions in JUnit tests as described + [here](http://stackoverflow.com/questions/2522897/eclipse-junit-ea-vm-option).
+ Delete run configurations created when you ran tests earlier. ## Dev Ops From 76463e67b1bd1bd644a5d9d98197eb5e59425fc1 Mon Sep 17 00:00:00 2001 From: "Damith C. Rajapakse" Date: Thu, 6 Oct 2016 19:10:09 +0800 Subject: [PATCH 007/754] Fix broken link in Dev Guide ToC --- docs/DeveloperGuide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 690b6d386627..64445e53e534 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -9,7 +9,7 @@ * [Appendix B: Use Cases](#appendix-b--use-cases) * [Appendix C: Non Functional Requirements](#appendix-c--non-functional-requirements) * [Appendix D: Glossary](#appendix-d--glossary) -* [Appendix E : Product Survey](#appendix-e-product-survey) +* [Appendix E : Product Survey](#appendix-e--product-survey) ## Setting up From ef2543e16c999b3b647731410bf0495513d83bec Mon Sep 17 00:00:00 2001 From: Joshua Lee Date: Fri, 7 Oct 2016 17:34:46 +0800 Subject: [PATCH 008/754] [95] Reduce duplication between ConfigUtil and JsonUserPrefsStorage --- src/main/java/seedu/address/MainApp.java | 3 +- .../address/commons/util/ConfigUtil.java | 45 +------------- .../seedu/address/commons/util/FileUtil.java | 11 +--- .../seedu/address/commons/util/JsonUtil.java | 62 +++++++++++++++++++ .../address/storage/JsonUserPrefsStorage.java | 47 +++----------- .../java/seedu/address/storage/Storage.java | 1 - .../seedu/address/storage/StorageManager.java | 1 - .../seedu/address/storage/XmlAdaptedTag.java | 1 - ...atConfig.json => NotJsonFormatConfig.json} | 0 .../address/commons/util/ConfigUtilTest.java | 16 ++--- .../address/commons/util/FileUtilTest.java | 26 -------- .../address/commons/util/JsonUtilTest.java | 33 ++++++++++ .../address/commons/util/StringUtilTest.java | 1 - .../storage/JsonUserPrefsStorageTest.java | 2 +- 14 files changed, 118 insertions(+), 131 deletions(-) rename src/test/data/ConfigUtilTest/{NotJasonFormatConfig.json => NotJsonFormatConfig.json} (100%) diff --git a/src/main/java/seedu/address/MainApp.java b/src/main/java/seedu/address/MainApp.java index 36dc72a74b7a..6a991eb7fdfb 100644 --- a/src/main/java/seedu/address/MainApp.java +++ b/src/main/java/seedu/address/MainApp.java @@ -10,17 +10,16 @@ import seedu.address.commons.core.Version; import seedu.address.commons.events.ui.ExitAppRequestEvent; import seedu.address.commons.exceptions.DataConversionException; +import seedu.address.commons.util.ConfigUtil; import seedu.address.commons.util.StringUtil; import seedu.address.logic.Logic; import seedu.address.logic.LogicManager; import seedu.address.model.*; -import seedu.address.commons.util.ConfigUtil; import seedu.address.storage.Storage; import seedu.address.storage.StorageManager; import seedu.address.ui.Ui; import seedu.address.ui.UiManager; -import java.io.FileNotFoundException; import java.io.IOException; import java.util.Map; import java.util.Optional; diff --git a/src/main/java/seedu/address/commons/util/ConfigUtil.java b/src/main/java/seedu/address/commons/util/ConfigUtil.java index af42e03df06c..10864187a3c8 100644 --- a/src/main/java/seedu/address/commons/util/ConfigUtil.java +++ b/src/main/java/seedu/address/commons/util/ConfigUtil.java @@ -1,62 +1,23 @@ package seedu.address.commons.util; import seedu.address.commons.core.Config; -import seedu.address.commons.core.LogsCenter; import seedu.address.commons.exceptions.DataConversionException; +import seedu.address.commons.util.JsonUtil; -import java.io.File; import java.io.IOException; import java.util.Optional; -import java.util.logging.Logger; /** * A class for accessing the Config File. */ public class ConfigUtil { - private static final Logger logger = LogsCenter.getLogger(ConfigUtil.class); - - /** - * Returns the Config object from the given file or {@code Optional.empty()} object if the file is not found. - * If any values are missing from the file, default values will be used, as long as the file is a valid json file. - * @param configFilePath cannot be null. - * @throws DataConversionException if the file format is not as expected. - */ public static Optional readConfig(String configFilePath) throws DataConversionException { - - assert configFilePath != null; - - File configFile = new File(configFilePath); - - if (!configFile.exists()) { - logger.info("Config file " + configFile + " not found"); - return Optional.empty(); - } - - Config config; - - try { - config = FileUtil.deserializeObjectFromJsonFile(configFile, Config.class); - } catch (IOException e) { - logger.warning("Error reading from config file " + configFile + ": " + e); - throw new DataConversionException(e); - } - - return Optional.of(config); + return JsonUtil.readJsonFile(configFilePath, Config.class); } - /** - * Saves the Config object to the specified file. - * Overwrites existing file if it exists, creates a new file if it doesn't. - * @param config cannot be null - * @param configFilePath cannot be null - * @throws IOException if there was an error during writing to the file - */ public static void saveConfig(Config config, String configFilePath) throws IOException { - assert config != null; - assert configFilePath != null; - - FileUtil.serializeObjectToJsonFile(new File(configFilePath), config); + JsonUtil.saveJsonFile(config, configFilePath); } } diff --git a/src/main/java/seedu/address/commons/util/FileUtil.java b/src/main/java/seedu/address/commons/util/FileUtil.java index ca8221250de4..3e1eb4d9ff6e 100644 --- a/src/main/java/seedu/address/commons/util/FileUtil.java +++ b/src/main/java/seedu/address/commons/util/FileUtil.java @@ -5,9 +5,10 @@ import java.nio.file.Files; /** - * Writes and reads file + * Writes and reads files */ public class FileUtil { + private static final String CHARSET = "UTF-8"; public static boolean isFileExists(File file) { @@ -84,12 +85,4 @@ public static String getPath(String pathWithForwardSlash) { return pathWithForwardSlash.replace("/", File.separator); } - public static void serializeObjectToJsonFile(File jsonFile, T objectToSerialize) throws IOException { - FileUtil.writeToFile(jsonFile, JsonUtil.toJsonString(objectToSerialize)); - } - - public static T deserializeObjectFromJsonFile(File jsonFile, Class classOfObjectToDeserialize) - throws IOException { - return JsonUtil.fromJsonString(FileUtil.readFromFile(jsonFile), classOfObjectToDeserialize); - } } diff --git a/src/main/java/seedu/address/commons/util/JsonUtil.java b/src/main/java/seedu/address/commons/util/JsonUtil.java index 80b67de5b7e8..b1c3ed3dbc93 100644 --- a/src/main/java/seedu/address/commons/util/JsonUtil.java +++ b/src/main/java/seedu/address/commons/util/JsonUtil.java @@ -10,14 +10,76 @@ import com.fasterxml.jackson.databind.deser.std.FromStringDeserializer; import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import seedu.address.commons.core.LogsCenter; +import seedu.address.commons.exceptions.DataConversionException; +import java.io.File; import java.io.IOException; +import java.util.Optional; import java.util.logging.Level; +import java.util.logging.Logger; /** * Converts a Java object instance to JSON and vice versa */ public class JsonUtil { + + private static final Logger logger = LogsCenter.getLogger(JsonUtil.class); + + static void serializeObjectToJsonFile(File jsonFile, T objectToSerialize) throws IOException { + FileUtil.writeToFile(jsonFile, toJsonString(objectToSerialize)); + } + + static T deserializeObjectFromJsonFile(File jsonFile, Class classOfObjectToDeserialize) + throws IOException { + return fromJsonString(FileUtil.readFromFile(jsonFile), classOfObjectToDeserialize); + } + + /** + * Returns the Json object from the given file or {@code Optional.empty()} object if the file is not found. + * If any values are missing from the file, default values will be used, as long as the file is a valid json file. + * @param filePath cannot be null. + * @param classOfObjectToDeserialize Json file has to correspond to the structure in the class given here. + * @throws DataConversionException if the file format is not as expected. + */ + public static Optional readJsonFile( + String filePath, Class classOfObjectToDeserialize) throws DataConversionException { + + assert filePath != null; + + File file = new File(filePath); + + if (!file.exists()) { + logger.info("Json file " + file + " not found"); + return Optional.empty(); + } + + T jsonFile; + + try { + jsonFile = deserializeObjectFromJsonFile(file, classOfObjectToDeserialize); + } catch (IOException e) { + logger.warning("Error reading from jsonFile file " + file + ": " + e); + throw new DataConversionException(e); + } + + return Optional.of(jsonFile); + } + + /** + * Saves the Json object to the specified file. + * Overwrites existing file if it exists, creates a new file if it doesn't. + * @param jsonFile cannot be null + * @param filePath cannot be null + * @throws IOException if there was an error during writing to the file + */ + public static void saveJsonFile(T jsonFile, String filePath) throws IOException { + assert jsonFile != null; + assert filePath != null; + + serializeObjectToJsonFile(new File(filePath), jsonFile); + } + private static class LevelDeserializer extends FromStringDeserializer { protected LevelDeserializer(Class vc) { diff --git a/src/main/java/seedu/address/storage/JsonUserPrefsStorage.java b/src/main/java/seedu/address/storage/JsonUserPrefsStorage.java index 1efa8288e4f6..10905d644168 100644 --- a/src/main/java/seedu/address/storage/JsonUserPrefsStorage.java +++ b/src/main/java/seedu/address/storage/JsonUserPrefsStorage.java @@ -1,21 +1,16 @@ package seedu.address.storage; -import seedu.address.commons.core.LogsCenter; import seedu.address.commons.exceptions.DataConversionException; -import seedu.address.commons.util.FileUtil; +import seedu.address.commons.util.JsonUtil; import seedu.address.model.UserPrefs; -import java.io.File; import java.io.IOException; import java.util.Optional; -import java.util.logging.Logger; /** * A class to access UserPrefs stored in the hard disk as a json file */ -public class JsonUserPrefsStorage implements UserPrefsStorage{ - - private static final Logger logger = LogsCenter.getLogger(JsonUserPrefsStorage.class); +public class JsonUserPrefsStorage implements UserPrefsStorage { private String filePath; @@ -28,46 +23,18 @@ public Optional readUserPrefs() throws DataConversionException, IOExc return readUserPrefs(filePath); } - @Override - public void saveUserPrefs(UserPrefs userPrefs) throws IOException { - saveUserPrefs(userPrefs, filePath); - } - /** * Similar to {@link #readUserPrefs()} * @param prefsFilePath location of the data. Cannot be null. * @throws DataConversionException if the file format is not as expected. */ public Optional readUserPrefs(String prefsFilePath) throws DataConversionException { - assert prefsFilePath != null; - - File prefsFile = new File(prefsFilePath); - - if (!prefsFile.exists()) { - logger.info("Prefs file " + prefsFile + " not found"); - return Optional.empty(); - } - - UserPrefs prefs; - - try { - prefs = FileUtil.deserializeObjectFromJsonFile(prefsFile, UserPrefs.class); - } catch (IOException e) { - logger.warning("Error reading from prefs file " + prefsFile + ": " + e); - throw new DataConversionException(e); - } - - return Optional.of(prefs); + return JsonUtil.readJsonFile(prefsFilePath, UserPrefs.class); } - /** - * Similar to {@link #saveUserPrefs(UserPrefs)} - * @param prefsFilePath location of the data. Cannot be null. - */ - public void saveUserPrefs(UserPrefs userPrefs, String prefsFilePath) throws IOException { - assert userPrefs != null; - assert prefsFilePath != null; - - FileUtil.serializeObjectToJsonFile(new File(prefsFilePath), userPrefs); + @Override + public void saveUserPrefs(UserPrefs userPrefs) throws IOException { + JsonUtil.saveJsonFile(userPrefs, filePath); } + } diff --git a/src/main/java/seedu/address/storage/Storage.java b/src/main/java/seedu/address/storage/Storage.java index 91002a8a821a..1d7f3113e95b 100644 --- a/src/main/java/seedu/address/storage/Storage.java +++ b/src/main/java/seedu/address/storage/Storage.java @@ -6,7 +6,6 @@ import seedu.address.model.ReadOnlyAddressBook; import seedu.address.model.UserPrefs; -import java.io.FileNotFoundException; import java.io.IOException; import java.util.Optional; diff --git a/src/main/java/seedu/address/storage/StorageManager.java b/src/main/java/seedu/address/storage/StorageManager.java index ba1f72f15c27..ad09c2defe89 100644 --- a/src/main/java/seedu/address/storage/StorageManager.java +++ b/src/main/java/seedu/address/storage/StorageManager.java @@ -9,7 +9,6 @@ import seedu.address.model.ReadOnlyAddressBook; import seedu.address.model.UserPrefs; -import java.io.FileNotFoundException; import java.io.IOException; import java.util.Optional; import java.util.logging.Logger; diff --git a/src/main/java/seedu/address/storage/XmlAdaptedTag.java b/src/main/java/seedu/address/storage/XmlAdaptedTag.java index b9723fafbc67..de199188c7e1 100644 --- a/src/main/java/seedu/address/storage/XmlAdaptedTag.java +++ b/src/main/java/seedu/address/storage/XmlAdaptedTag.java @@ -1,6 +1,5 @@ package seedu.address.storage; -import seedu.address.commons.util.CollectionUtil; import seedu.address.commons.exceptions.IllegalValueException; import seedu.address.model.tag.Tag; diff --git a/src/test/data/ConfigUtilTest/NotJasonFormatConfig.json b/src/test/data/ConfigUtilTest/NotJsonFormatConfig.json similarity index 100% rename from src/test/data/ConfigUtilTest/NotJasonFormatConfig.json rename to src/test/data/ConfigUtilTest/NotJsonFormatConfig.json diff --git a/src/test/java/seedu/address/commons/util/ConfigUtilTest.java b/src/test/java/seedu/address/commons/util/ConfigUtilTest.java index 6699343c4a82..1d4d35d0f864 100644 --- a/src/test/java/seedu/address/commons/util/ConfigUtilTest.java +++ b/src/test/java/seedu/address/commons/util/ConfigUtilTest.java @@ -7,6 +7,8 @@ import org.junit.rules.TemporaryFolder; import seedu.address.commons.core.Config; import seedu.address.commons.exceptions.DataConversionException; +import seedu.address.commons.util.ConfigUtil; +import seedu.address.commons.util.FileUtil; import java.io.File; import java.io.IOException; @@ -38,10 +40,10 @@ public void read_missingFile_emptyResult() throws DataConversionException { } @Test - public void read_notJasonFormat_exceptionThrown() throws DataConversionException { + public void read_notJsonFormat_exceptionThrown() throws DataConversionException { thrown.expect(DataConversionException.class); - read("NotJasonFormatConfig.json"); + read("NotJsonFormatConfig.json"); /* IMPORTANT: Any code below an exception-throwing line (like the one above) will be ignored. * That means you should not have more than one exception test in one method @@ -103,18 +105,18 @@ public void saveConfig_allInOrder_success() throws DataConversionException, IOEx Config original = getTypicalConfig(); String configFilePath = testFolder.getRoot() + File.separator + "TempConfig.json"; - ConfigUtil configStorage = new ConfigUtil(); + ConfigUtil configUtil = new ConfigUtil(); //Try writing when the file doesn't exist - configStorage.saveConfig(original, configFilePath); - Config readBack = configStorage.readConfig(configFilePath).get(); + configUtil.saveConfig(original, configFilePath); + Config readBack = configUtil.readConfig(configFilePath).get(); assertEquals(original, readBack); //Try saving when the file exists original.setAppTitle("Updated Title"); original.setLogLevel(Level.FINE); - configStorage.saveConfig(original, configFilePath); - readBack = configStorage.readConfig(configFilePath).get(); + configUtil.saveConfig(original, configFilePath); + readBack = configUtil.readConfig(configFilePath).get(); assertEquals(original, readBack); } diff --git a/src/test/java/seedu/address/commons/util/FileUtilTest.java b/src/test/java/seedu/address/commons/util/FileUtilTest.java index 8de2621799cf..564a35ada340 100644 --- a/src/test/java/seedu/address/commons/util/FileUtilTest.java +++ b/src/test/java/seedu/address/commons/util/FileUtilTest.java @@ -4,17 +4,12 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; -import seedu.address.testutil.SerializableTestClass; -import seedu.address.testutil.TestUtil; import java.io.File; -import java.io.IOException; import static org.junit.Assert.assertEquals; public class FileUtilTest { - private static final File SERIALIZATION_FILE = new File(TestUtil.getFilePathInSandboxFolder("serialize.json")); - @Rule public ExpectedException thrown = ExpectedException.none(); @@ -34,25 +29,4 @@ public void getPath(){ FileUtil.getPath("folder"); } - @Test - public void serializeObjectToJsonFile_noExceptionThrown() throws IOException { - SerializableTestClass serializableTestClass = new SerializableTestClass(); - serializableTestClass.setTestValues(); - - FileUtil.serializeObjectToJsonFile(SERIALIZATION_FILE, serializableTestClass); - - assertEquals(FileUtil.readFromFile(SERIALIZATION_FILE), SerializableTestClass.JSON_STRING_REPRESENTATION); - } - - @Test - public void deserializeObjectFromJsonFile_noExceptionThrown() throws IOException { - FileUtil.writeToFile(SERIALIZATION_FILE, SerializableTestClass.JSON_STRING_REPRESENTATION); - - SerializableTestClass serializableTestClass = FileUtil - .deserializeObjectFromJsonFile(SERIALIZATION_FILE, SerializableTestClass.class); - - assertEquals(serializableTestClass.getName(), SerializableTestClass.getNameTestValue()); - assertEquals(serializableTestClass.getListOfLocalDateTimes(), SerializableTestClass.getListTestValues()); - assertEquals(serializableTestClass.getMapOfIntegerToString(), SerializableTestClass.getHashMapTestValues()); - } } diff --git a/src/test/java/seedu/address/commons/util/JsonUtilTest.java b/src/test/java/seedu/address/commons/util/JsonUtilTest.java index fc3902188807..9607283a41c2 100644 --- a/src/test/java/seedu/address/commons/util/JsonUtilTest.java +++ b/src/test/java/seedu/address/commons/util/JsonUtilTest.java @@ -1,10 +1,43 @@ package seedu.address.commons.util; +import org.junit.Test; +import seedu.address.testutil.SerializableTestClass; +import seedu.address.testutil.TestUtil; + +import java.io.File; +import java.io.IOException; + +import static org.junit.Assert.assertEquals; + /** * Tests JSON Read and Write */ public class JsonUtilTest { + private static final File SERIALIZATION_FILE = new File(TestUtil.getFilePathInSandboxFolder("serialize.json")); + + @Test + public void serializeObjectToJsonFile_noExceptionThrown() throws IOException { + SerializableTestClass serializableTestClass = new SerializableTestClass(); + serializableTestClass.setTestValues(); + + JsonUtil.serializeObjectToJsonFile(SERIALIZATION_FILE, serializableTestClass); + + assertEquals(FileUtil.readFromFile(SERIALIZATION_FILE), SerializableTestClass.JSON_STRING_REPRESENTATION); + } + + @Test + public void deserializeObjectFromJsonFile_noExceptionThrown() throws IOException { + FileUtil.writeToFile(SERIALIZATION_FILE, SerializableTestClass.JSON_STRING_REPRESENTATION); + + SerializableTestClass serializableTestClass = JsonUtil + .deserializeObjectFromJsonFile(SERIALIZATION_FILE, SerializableTestClass.class); + + assertEquals(serializableTestClass.getName(), SerializableTestClass.getNameTestValue()); + assertEquals(serializableTestClass.getListOfLocalDateTimes(), SerializableTestClass.getListTestValues()); + assertEquals(serializableTestClass.getMapOfIntegerToString(), SerializableTestClass.getHashMapTestValues()); + } + //TODO: @Test jsonUtil_readJsonStringToObjectInstance_correctObject() //TODO: @Test jsonUtil_writeThenReadObjectToJson_correctObject() diff --git a/src/test/java/seedu/address/commons/util/StringUtilTest.java b/src/test/java/seedu/address/commons/util/StringUtilTest.java index 194dd71d2c3f..7c53c58e462a 100644 --- a/src/test/java/seedu/address/commons/util/StringUtilTest.java +++ b/src/test/java/seedu/address/commons/util/StringUtilTest.java @@ -8,7 +8,6 @@ import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; diff --git a/src/test/java/seedu/address/storage/JsonUserPrefsStorageTest.java b/src/test/java/seedu/address/storage/JsonUserPrefsStorageTest.java index 4e87203611be..c0d45080ef4f 100644 --- a/src/test/java/seedu/address/storage/JsonUserPrefsStorageTest.java +++ b/src/test/java/seedu/address/storage/JsonUserPrefsStorageTest.java @@ -43,7 +43,7 @@ public void readUserPrefs_missingFile_emptyResult() throws DataConversionExcepti } @Test - public void readUserPrefs_notJasonFormat_exceptionThrown() throws DataConversionException { + public void readUserPrefs_notJsonFormat_exceptionThrown() throws DataConversionException { thrown.expect(DataConversionException.class); readUserPrefs("NotJsonFormatUserPrefs.json"); From 7c481930df6a69fb6a08a036b9e4ee0bed6135bc Mon Sep 17 00:00:00 2001 From: "Damith C. Rajapakse" Date: Wed, 12 Oct 2016 14:22:02 +0800 Subject: [PATCH 009/754] Fix broken link to LO-DefensiveCoding --- docs/LearningOutcomes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/LearningOutcomes.md b/docs/LearningOutcomes.md index 5ee57072a8d8..0c27c3377524 100644 --- a/docs/LearningOutcomes.md +++ b/docs/LearningOutcomes.md @@ -6,7 +6,7 @@ After studying this code and completing the corresponding exercises, you should 1. [Use API Design `[LO-ApiDesign]`](#use-api-design-lo-apidesign) 1. [Use Assertions `[LO-Assertions]`](#use-assertions-lo-assertions) 1. [Use Logging `[LO-Logging]`](#use-logging-lo-logging) -1. [Use Defensive Coding `[LO-DefensiveCoding]`](#use-defensive-coding-lo-defensivedoding) +1. [Use Defensive Coding `[LO-DefensiveCoding]`](#use-defensive-coding-lo-defensivecoding) 1. [Use Build Automation `[LO-BuildAutomation]`](#use-build-automation-lo-buildautomation) 1. [Use Continuous Integration `[LO-ContinuousIntegration]`](#use-continuous-integration-lo-continuousintegration) From 4e2f1695f401f5e06f7652af54007fb51034b7a7 Mon Sep 17 00:00:00 2001 From: "Damith C. Rajapakse" Date: Wed, 12 Oct 2016 14:53:15 +0800 Subject: [PATCH 010/754] Add LO-CodeCoverage --- docs/LearningOutcomes.md | 15 ++++++++++++++- docs/UsingTravis.md | 2 +- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/docs/LearningOutcomes.md b/docs/LearningOutcomes.md index 0c27c3377524..eef949f387c5 100644 --- a/docs/LearningOutcomes.md +++ b/docs/LearningOutcomes.md @@ -9,6 +9,7 @@ After studying this code and completing the corresponding exercises, you should 1. [Use Defensive Coding `[LO-DefensiveCoding]`](#use-defensive-coding-lo-defensivecoding) 1. [Use Build Automation `[LO-BuildAutomation]`](#use-build-automation-lo-buildautomation) 1. [Use Continuous Integration `[LO-ContinuousIntegration]`](#use-continuous-integration-lo-continuousintegration) +1. [Use Code Coverage `[LO-CodeCoverage]`](#use-code-coverage-lo-codecoverage) ------------------------------------------------------------------------------------------------------ @@ -109,6 +110,7 @@ Note [how the AddressBook app uses Gradle to automate build tasks](UsingGradle.m ## Use Continuous Integration `[LO-ContinuousIntegration]` Note [how the AddressBook app uses Travis to perform Continuous Integration](UsingTravis.md). +([![Build Status](https://travis-ci.org/se-edu/addressbook-level4.svg?branch=master)](https://travis-ci.org/se-edu/addressbook-level4)) **Resources** * Tutorials @@ -119,6 +121,18 @@ Note [how the AddressBook app uses Travis to perform Continuous Integration](Usi ------------------------------------------------------------------------------------------------------ +## Use Code Coverage `[LO-CodeCoverage]` + +Note how our CI server [Travis uses Coveralls to report code coverage](UsingTravis.md). +([![Coverage Status](https://coveralls.io/repos/github/se-edu/addressbook-level4/badge.svg?branch=master)](https://coveralls.io/github/se-edu/addressbook-level4?branch=master)) + + +#### Exercise: Use EclEmma to measure coverage locally + * Install the [EclEmma Eclipse Plugin](http://www.eclemma.org/) in your computer and use that to find code that + is not covered by the tests. + +------------------------------------------------------------------------------------------------------ + {More to be added} * Integration testing * System testing @@ -130,6 +144,5 @@ Note [how the AddressBook app uses Travis to perform Continuous Integration](Usi * Design patterns * Static analysis * Code reviews -* Code coverage diff --git a/docs/UsingTravis.md b/docs/UsingTravis.md index 4844f0682f75..36677982a2c3 100644 --- a/docs/UsingTravis.md +++ b/docs/UsingTravis.md @@ -32,7 +32,7 @@ from [Travis CI Documentation](https://docs.travis-ci.com/). * If repository cannot be found, click `Sync account` 4. Activate the switch.
![Activate the switch](images/flick_repository_switch.png) -5. This repo comes with a [`.travis.yml`](.travis.yml) that tells Travis what to do. +5. This repo comes with a [`.travis.yml`](../.travis.yml) that tells Travis what to do. So there is no need for you to create one yourself. 6. To see the CI in action, push a commit to the master branch! * Go to the repository and see the pushed commit. There should be an icon which will link you to the Travis build.
From 831c819aacea622f5f2245a97beb4c1d53d75836 Mon Sep 17 00:00:00 2001 From: You Liang Date: Wed, 12 Oct 2016 16:36:29 +0800 Subject: [PATCH 011/754] [133] Add a GUI test to test the error dialog * Added test case for error dialog. * fix typo * fix typos * change to getNode * renamed method names and add in comments --- src/main/java/seedu/address/ui/UiManager.java | 3 ++- .../java/guitests/AddressBookGuiTest.java | 7 ++++++ .../java/guitests/ErrorDialogGuiTest.java | 23 ++++++++++++++++++ .../guihandles/AlertDialogHandle.java | 24 +++++++++++++++++++ .../java/guitests/guihandles/GuiHandle.java | 11 ++++++++- .../guitests/guihandles/MainGuiHandle.java | 4 ++++ 6 files changed, 70 insertions(+), 2 deletions(-) create mode 100644 src/test/java/guitests/ErrorDialogGuiTest.java create mode 100644 src/test/java/guitests/guihandles/AlertDialogHandle.java diff --git a/src/main/java/seedu/address/ui/UiManager.java b/src/main/java/seedu/address/ui/UiManager.java index 4a4dba3a2f6e..ee7665b26daa 100644 --- a/src/main/java/seedu/address/ui/UiManager.java +++ b/src/main/java/seedu/address/ui/UiManager.java @@ -26,6 +26,7 @@ public class UiManager extends ComponentManager implements Ui { private static final Logger logger = LogsCenter.getLogger(UiManager.class); private static final String ICON_APPLICATION = "/images/address_book_32.png"; + public static final String ALERT_DIALOG_PANE_FIELD_ID = "alertDialogPane"; private Logic logic; private Config config; @@ -86,7 +87,7 @@ private static void showAlertDialogAndWait(Stage owner, AlertType type, String t alert.setTitle(title); alert.setHeaderText(headerText); alert.setContentText(contentText); - + alert.getDialogPane().setId(ALERT_DIALOG_PANE_FIELD_ID); alert.showAndWait(); } diff --git a/src/test/java/guitests/AddressBookGuiTest.java b/src/test/java/guitests/AddressBookGuiTest.java index 35734932f11c..664ac48b66ba 100644 --- a/src/test/java/guitests/AddressBookGuiTest.java +++ b/src/test/java/guitests/AddressBookGuiTest.java @@ -1,6 +1,7 @@ package guitests; import guitests.guihandles.*; +import javafx.application.Platform; import javafx.stage.Stage; import org.junit.After; import org.junit.Before; @@ -10,6 +11,7 @@ import org.testfx.api.FxToolkit; import seedu.address.TestApp; import seedu.address.commons.core.EventsCenter; +import seedu.address.commons.events.BaseEvent; import seedu.address.model.AddressBook; import seedu.address.model.person.ReadOnlyPerson; import seedu.address.testutil.TestUtil; @@ -114,4 +116,9 @@ protected void assertListSize(int size) { protected void assertResultMessage(String expected) { assertEquals(expected, resultDisplay.getText()); } + + public void raise(BaseEvent e) { + //JUnit doesn't run its test cases on the UI thread. Platform.runLater is used to post event on the UI thread. + Platform.runLater(() -> EventsCenter.getInstance().post(e)); + } } diff --git a/src/test/java/guitests/ErrorDialogGuiTest.java b/src/test/java/guitests/ErrorDialogGuiTest.java new file mode 100644 index 000000000000..5b2341c758c1 --- /dev/null +++ b/src/test/java/guitests/ErrorDialogGuiTest.java @@ -0,0 +1,23 @@ +package guitests; + +import guitests.guihandles.AlertDialogHandle; +import org.junit.Test; +import seedu.address.commons.events.storage.DataSavingExceptionEvent; + +import java.io.IOException; + +import static junit.framework.TestCase.assertTrue; + +public class ErrorDialogGuiTest extends AddressBookGuiTest{ + + @Test + public void showErrorDialogs() throws InterruptedException { + //Test DataSavingExceptionEvent dialog + raise(new DataSavingExceptionEvent(new IOException("Stub"))); + AlertDialogHandle alertDialog = mainGui.getAlertDialog("File Op Error"); + assertTrue(alertDialog.isMatching("Could not save data", "Could not save data to file" + ":\n" + + "java.io.IOException: Stub")); + + } + +} diff --git a/src/test/java/guitests/guihandles/AlertDialogHandle.java b/src/test/java/guitests/guihandles/AlertDialogHandle.java new file mode 100644 index 000000000000..0b855c3e8b3d --- /dev/null +++ b/src/test/java/guitests/guihandles/AlertDialogHandle.java @@ -0,0 +1,24 @@ +package guitests.guihandles; + +import guitests.GuiRobot; +import javafx.scene.control.DialogPane; +import javafx.stage.Stage; +import seedu.address.ui.UiManager; + +/** + * A handle for the AlertDialog of the UI + */ +public class AlertDialogHandle extends GuiHandle { + + + public AlertDialogHandle(GuiRobot guiRobot, Stage primaryStage, String dialogTitle) { + super(guiRobot, primaryStage, dialogTitle); + } + + public boolean isMatching(String headerMessage, String contentMessage) { + assert intermediateStage.isPresent() : "Alert dialog is not present"; + DialogPane dialogPane = (DialogPane) getNode("#" + UiManager.ALERT_DIALOG_PANE_FIELD_ID); + boolean isMatching = dialogPane.getHeaderText().equals(headerMessage) && dialogPane.getContentText().equals(contentMessage); + return isMatching; + } +} diff --git a/src/test/java/guitests/guihandles/GuiHandle.java b/src/test/java/guitests/guihandles/GuiHandle.java index 5e7e0f6de911..5003c440951a 100644 --- a/src/test/java/guitests/guihandles/GuiHandle.java +++ b/src/test/java/guitests/guihandles/GuiHandle.java @@ -10,6 +10,7 @@ import seedu.address.TestApp; import seedu.address.commons.core.LogsCenter; +import java.util.Optional; import java.util.logging.Logger; /** @@ -18,6 +19,10 @@ public class GuiHandle { protected final GuiRobot guiRobot; protected final Stage primaryStage; + /** + * An optional stage that exists in the App other than the primaryStage, could be a alert dialog, popup window, etc. + */ + protected Optional intermediateStage = Optional.empty(); protected final String stageTitle; private final Logger logger = LogsCenter.getLogger(this.getClass()); @@ -39,7 +44,7 @@ public void focusOnWindow(String stageTitle) { logger.warning("Can't find stage " + stageTitle + ", Therefore, aborting focusing"); return; } - + intermediateStage = Optional.ofNullable((Stage) window.get()); guiRobot.targetWindow(window.get()); guiRobot.interact(() -> window.get().requestFocus()); logger.info("Finishing focus " + stageTitle); @@ -67,6 +72,10 @@ protected String getTextFromLabel(String fieldId, Node parentNode) { return ((Label) guiRobot.from(parentNode).lookup(fieldId).tryQuery().get()).getText(); } + protected String getTextFromLabel(String fieldId) { + return ((Label) guiRobot.lookup(fieldId).tryQuery().get()).getText(); + } + public void focusOnSelf() { if (stageTitle != null) { focusOnWindow(stageTitle); diff --git a/src/test/java/guitests/guihandles/MainGuiHandle.java b/src/test/java/guitests/guihandles/MainGuiHandle.java index 45802c5135c7..c92251158f4e 100644 --- a/src/test/java/guitests/guihandles/MainGuiHandle.java +++ b/src/test/java/guitests/guihandles/MainGuiHandle.java @@ -29,4 +29,8 @@ public MainMenuHandle getMainMenu() { return new MainMenuHandle(guiRobot, primaryStage); } + public AlertDialogHandle getAlertDialog(String title) { + guiRobot.sleep(1000); + return new AlertDialogHandle(guiRobot, primaryStage, title) ; + } } From 7359b0bc913aeaee57b5863a12d562a418f07e17 Mon Sep 17 00:00:00 2001 From: "Damith C. Rajapakse" Date: Wed, 12 Oct 2016 15:16:32 +0800 Subject: [PATCH 012/754] Add test case design info to StringUtilTest::isUnsignedPositiveInteger --- .../address/commons/util/StringUtilTest.java | 30 +++++++++++++------ 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/src/test/java/seedu/address/commons/util/StringUtilTest.java b/src/test/java/seedu/address/commons/util/StringUtilTest.java index 7c53c58e462a..ba54951c6b8e 100644 --- a/src/test/java/seedu/address/commons/util/StringUtilTest.java +++ b/src/test/java/seedu/address/commons/util/StringUtilTest.java @@ -18,20 +18,32 @@ public class StringUtilTest { @Test public void isUnsignedPositiveInteger() { + + // Equivalence partition: null assertFalse(StringUtil.isUnsignedInteger(null)); - assertFalse(StringUtil.isUnsignedInteger("")); + + // EP: empty strings + assertFalse(StringUtil.isUnsignedInteger("")); //boundary value + assertFalse(StringUtil.isUnsignedInteger(" ")); + + // EP: not a number assertFalse(StringUtil.isUnsignedInteger("a")); assertFalse(StringUtil.isUnsignedInteger("aaa")); - assertFalse(StringUtil.isUnsignedInteger(" ")); - assertFalse(StringUtil.isUnsignedInteger("-1")); + + // EP: zero assertFalse(StringUtil.isUnsignedInteger("0")); - assertFalse(StringUtil.isUnsignedInteger("+1")); //should be unsigned - assertFalse(StringUtil.isUnsignedInteger("-1")); //should be unsigned - assertFalse(StringUtil.isUnsignedInteger(" 10")); //should not contain whitespaces - assertFalse(StringUtil.isUnsignedInteger("10 ")); //should not contain whitespaces - assertFalse(StringUtil.isUnsignedInteger("1 0")); //should not contain whitespaces - assertTrue(StringUtil.isUnsignedInteger("1")); + // EP: signed numbers + assertFalse(StringUtil.isUnsignedInteger("-1")); + assertFalse(StringUtil.isUnsignedInteger("+1")); + + // EP: numbers with white space + assertFalse(StringUtil.isUnsignedInteger(" 10")); + assertFalse(StringUtil.isUnsignedInteger("10 ")); + assertFalse(StringUtil.isUnsignedInteger("1 0")); + + // EP: valid numbers, should return true + assertTrue(StringUtil.isUnsignedInteger("1")); //boundary value assertTrue(StringUtil.isUnsignedInteger("10")); } From 5a6f6498876b842202966249512e1a24d347311d Mon Sep 17 00:00:00 2001 From: Martin Choo Date: Wed, 12 Oct 2016 23:57:24 +0800 Subject: [PATCH 013/754] [50] Set up check style --- .travis.yml | 2 +- build.gradle | 9 +- .../checkstyle/checkstyle-noframes-sorted.xsl | 195 ------------------ config/checkstyle/checkstyle.xml | 120 +++-------- config/findbugs/excludeFilter.xml | 12 -- src/main/java/seedu/address/MainApp.java | 8 +- .../seedu/address/commons/core/Config.java | 2 +- .../address/commons/core/GuiSettings.java | 2 +- .../address/commons/core/LogsCenter.java | 6 +- .../address/commons/events/BaseEvent.java | 2 +- .../address/commons/util/ConfigUtil.java | 1 - .../address/commons/util/StringUtil.java | 3 +- .../seedu/address/logic/parser/Parser.java | 18 +- .../seedu/address/model/ModelManager.java | 4 +- .../java/seedu/address/model/UserPrefs.java | 6 +- .../seedu/address/model/person/Address.java | 2 +- .../storage/XmlAddressBookStorage.java | 3 +- .../java/seedu/address/ui/BrowserPanel.java | 3 +- .../java/seedu/address/ui/CommandBox.java | 6 +- .../java/seedu/address/ui/MainWindow.java | 8 +- .../java/seedu/address/ui/PersonCard.java | 8 +- .../seedu/address/ui/PersonListPanel.java | 13 +- src/main/java/seedu/address/ui/UiManager.java | 4 +- .../java/seedu/address/ui/UiPartLoader.java | 4 +- src/test/java/guitests/DeleteCommandTest.java | 6 +- src/test/java/guitests/FindCommandTest.java | 10 +- src/test/java/guitests/SelectCommandTest.java | 16 +- .../guihandles/AlertDialogHandle.java | 3 +- .../java/guitests/guihandles/GuiHandle.java | 4 +- .../guitests/guihandles/MainGuiHandle.java | 2 +- .../guitests/guihandles/PersonCardHandle.java | 7 +- .../guihandles/PersonListPanelHandle.java | 10 +- src/test/java/seedu/address/TestApp.java | 3 +- .../address/commons/util/ConfigUtilTest.java | 5 +- .../address/commons/util/JsonUtilTest.java | 1 - .../address/commons/util/XmlUtilTest.java | 7 +- .../seedu/address/logic/LogicManagerTest.java | 50 +++-- .../storage/JsonUserPrefsStorageTest.java | 6 +- .../address/storage/StorageManagerTest.java | 5 +- .../storage/XmlAddressBookStorageTest.java | 2 +- .../testutil/SerializableTestClass.java | 21 +- .../java/seedu/address/testutil/TestUtil.java | 64 +++--- .../address/testutil/TypicalTestPersons.java | 33 +-- 43 files changed, 225 insertions(+), 471 deletions(-) delete mode 100644 config/checkstyle/checkstyle-noframes-sorted.xsl delete mode 100644 config/findbugs/excludeFilter.xml diff --git a/.travis.yml b/.travis.yml index a9d9e9b47d87..5a47b040874d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,7 @@ language: java matrix: include: - jdk: oraclejdk8 -script: travis_retry ./gradlew clean headless allTests coverage coveralls -i +script: travis_retry ./gradlew clean checkstyleMain checkstyleTest headless allTests coverage coveralls -i before_install: - "export DISPLAY=:99.0" - "sh -e /etc/init.d/xvfb start" diff --git a/build.gradle b/build.gradle index 46b06c1e42ec..74669b84902c 100644 --- a/build.gradle +++ b/build.gradle @@ -14,6 +14,8 @@ allprojects { apply plugin: 'idea' apply plugin: 'java' apply plugin: 'jacoco' + apply plugin: 'checkstyle' + sourceCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8 @@ -35,10 +37,15 @@ allprojects { junitVersion = '4.12' testFxVersion = '4.0.+' monocleVersion = '1.8.0_20' + checkstyleVersion = '7.1.2' libDir = 'lib' } + checkstyle { + toolVersion = "$checkstyleVersion" + } + jacocoTestReport { reports { xml.enabled false @@ -72,7 +79,7 @@ allprojects { } } } - + shadowJar { archiveName = "addressbook.jar" diff --git a/config/checkstyle/checkstyle-noframes-sorted.xsl b/config/checkstyle/checkstyle-noframes-sorted.xsl deleted file mode 100644 index 9c0ac3054165..000000000000 --- a/config/checkstyle/checkstyle-noframes-sorted.xsl +++ /dev/null @@ -1,195 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -

CheckStyle Audit

Designed for use with CheckStyle and Ant.
-
- - - -
- - - -
- - - - -
- - - - -
- - - - -

Files

- - - - - - - - - - - - - - -
NameErrors
-
- - - - -

File

- - - - - - - - - - - - - - -
Error DescriptionLine
- Back to top -
- - - -

Summary

- - - - - - - - - - - - -
FilesErrors
-
- - - - a - b - - -
- - diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml index 3bab4e05bbae..032a3b1c4abb 100644 --- a/config/checkstyle/checkstyle.xml +++ b/config/checkstyle/checkstyle.xml @@ -4,53 +4,40 @@ "http://www.puppycrawl.com/dtds/configuration_1_3.dtd"> - + - + - + + + + + + + + + - + + @@ -58,67 +45,36 @@ - - - - - - - - - - - - - - - - + - + - + - - + @@ -140,35 +96,30 @@ - + - + - + - + @@ -220,7 +171,7 @@ + @@ -250,9 +202,7 @@ @@ -265,9 +215,7 @@ @@ -286,16 +234,12 @@ - + - + @@ -307,18 +251,14 @@ - + - + diff --git a/config/findbugs/excludeFilter.xml b/config/findbugs/excludeFilter.xml deleted file mode 100644 index 03c15ae4cc81..000000000000 --- a/config/findbugs/excludeFilter.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - diff --git a/src/main/java/seedu/address/MainApp.java b/src/main/java/seedu/address/MainApp.java index 6a991eb7fdfb..3dc209058ac7 100644 --- a/src/main/java/seedu/address/MainApp.java +++ b/src/main/java/seedu/address/MainApp.java @@ -73,7 +73,7 @@ private Model initModelManager(Storage storage, UserPrefs userPrefs) { ReadOnlyAddressBook initialData; try { addressBookOptional = storage.readAddressBook(); - if(!addressBookOptional.isPresent()){ + if (!addressBookOptional.isPresent()) { logger.info("Data file not found. Will be starting with an empty AddressBook"); } initialData = addressBookOptional.orElse(new AddressBook()); @@ -81,7 +81,7 @@ private Model initModelManager(Storage storage, UserPrefs userPrefs) { logger.warning("Data file not in the correct format. Will be starting with an empty AddressBook"); initialData = new AddressBook(); } catch (IOException e) { - logger.warning("Problem while reading from the file. . Will be starting with an empty AddressBook"); + logger.warning("Problem while reading from the file. Will be starting with an empty AddressBook"); initialData = new AddressBook(); } @@ -98,7 +98,7 @@ protected Config initConfig(String configFilePath) { configFilePathUsed = Config.DEFAULT_CONFIG_FILE; - if(configFilePath != null) { + if (configFilePath != null) { logger.info("Custom Config file specified " + configFilePath); configFilePathUsed = configFilePath; } @@ -138,7 +138,7 @@ protected UserPrefs initPrefs(Config config) { "Using default user prefs"); initializedPrefs = new UserPrefs(); } catch (IOException e) { - logger.warning("Problem while reading from the file. . Will be starting with an empty AddressBook"); + logger.warning("Problem while reading from the file. Will be starting with an empty AddressBook"); initializedPrefs = new UserPrefs(); } diff --git a/src/main/java/seedu/address/commons/core/Config.java b/src/main/java/seedu/address/commons/core/Config.java index 6441c9ef20f4..212415c26237 100644 --- a/src/main/java/seedu/address/commons/core/Config.java +++ b/src/main/java/seedu/address/commons/core/Config.java @@ -71,7 +71,7 @@ public boolean equals(Object other) { return false; } - Config o = (Config)other; + Config o = (Config) other; return Objects.equals(appTitle, o.appTitle) && Objects.equals(logLevel, o.logLevel) diff --git a/src/main/java/seedu/address/commons/core/GuiSettings.java b/src/main/java/seedu/address/commons/core/GuiSettings.java index e157ac8b8679..561606aebba0 100644 --- a/src/main/java/seedu/address/commons/core/GuiSettings.java +++ b/src/main/java/seedu/address/commons/core/GuiSettings.java @@ -49,7 +49,7 @@ public boolean equals(Object other) { return false; } - GuiSettings o = (GuiSettings)other; + GuiSettings o = (GuiSettings) other; return Objects.equals(windowWidth, o.windowWidth) && Objects.equals(windowHeight, o.windowHeight) diff --git a/src/main/java/seedu/address/commons/core/LogsCenter.java b/src/main/java/seedu/address/commons/core/LogsCenter.java index 17939bab4975..d72bf52eff93 100644 --- a/src/main/java/seedu/address/commons/core/LogsCenter.java +++ b/src/main/java/seedu/address/commons/core/LogsCenter.java @@ -24,8 +24,8 @@ public class LogsCenter { /** * Initializes with a custom log level (specified in the {@code config} object) * Loggers obtained *AFTER* this initialization will have their logging level changed
- * Logging levels for existing loggers will only be updated if the logger with the same name is requested again - * from the LogsCenter. + * Logging levels for existing loggers will only be updated if the logger with the same name + * is requested again from the LogsCenter. */ public static void init(Config config) { currentLogLevel = config.getLogLevel(); @@ -99,6 +99,6 @@ public static String getEventHandlingLogMessage(BaseEvent e, String message) { * @see #getEventHandlingLogMessage(BaseEvent, String) */ public static String getEventHandlingLogMessage(BaseEvent e) { - return getEventHandlingLogMessage(e,""); + return getEventHandlingLogMessage(e, ""); } } diff --git a/src/main/java/seedu/address/commons/events/BaseEvent.java b/src/main/java/seedu/address/commons/events/BaseEvent.java index 723a9c69fbd5..daf9144f95c9 100644 --- a/src/main/java/seedu/address/commons/events/BaseEvent.java +++ b/src/main/java/seedu/address/commons/events/BaseEvent.java @@ -6,7 +6,7 @@ public abstract class BaseEvent { * All Events should have a clear unambiguous custom toString message so that feedback message creation * stays consistent and reusable. * - * For example the event manager post method will call any posted event's toString and print it in the console. + * For example, the event manager post method will call any posted event's toString and print it in the console. */ public abstract String toString(); diff --git a/src/main/java/seedu/address/commons/util/ConfigUtil.java b/src/main/java/seedu/address/commons/util/ConfigUtil.java index 10864187a3c8..c53e46e12d32 100644 --- a/src/main/java/seedu/address/commons/util/ConfigUtil.java +++ b/src/main/java/seedu/address/commons/util/ConfigUtil.java @@ -2,7 +2,6 @@ import seedu.address.commons.core.Config; import seedu.address.commons.exceptions.DataConversionException; -import seedu.address.commons.util.JsonUtil; import java.io.IOException; import java.util.Optional; diff --git a/src/main/java/seedu/address/commons/util/StringUtil.java b/src/main/java/seedu/address/commons/util/StringUtil.java index 2e94740456a6..13ad8bfd83d5 100644 --- a/src/main/java/seedu/address/commons/util/StringUtil.java +++ b/src/main/java/seedu/address/commons/util/StringUtil.java @@ -27,7 +27,8 @@ public static String getDetails(Throwable t){ /** * Returns true if s represents an unsigned integer e.g. 1, 2, 3, ...
- * Will return false for null, empty string, "-1", "0", "+1", and " 2 " (untrimmed) "3 0" (contains whitespace). + * Will return false if the string is: + * null, empty string, "-1", "0", "+1", and " 2 " (untrimmed) "3 0" (contains whitespace). * @param s Should be trimmed. */ public static boolean isUnsignedInteger(String s){ diff --git a/src/main/java/seedu/address/logic/parser/Parser.java b/src/main/java/seedu/address/logic/parser/Parser.java index 959b2cd0383c..e593fbd02166 100644 --- a/src/main/java/seedu/address/logic/parser/Parser.java +++ b/src/main/java/seedu/address/logic/parser/Parser.java @@ -26,8 +26,8 @@ public class Parser { private static final Pattern KEYWORDS_ARGS_FORMAT = Pattern.compile("(?\\S+(?:\\s+\\S+)*)"); // one or more keywords separated by whitespace - private static final Pattern PERSON_DATA_ARGS_FORMAT = // '/' forward slashes are reserved for delimiter prefixes - Pattern.compile("(?[^/]+)" + private static final Pattern PERSON_DATA_ARGS_FORMAT = + Pattern.compile("(?[^/]+)" // '/' forward slashes are reserved for delimiter prefixes + " (?p?)p/(?[^/]+)" + " (?p?)e/(?[^/]+)" + " (?p?)a/(?
[^/]+)" @@ -86,7 +86,7 @@ public Command parseCommand(String userInput) { * @param args full command args string * @return the prepared command */ - private Command prepareAdd(String args){ + private Command prepareAdd(String args) { final Matcher matcher = PERSON_DATA_ARGS_FORMAT.matcher(args.trim()); // Validate arg string format if (!matcher.matches()) { @@ -128,7 +128,7 @@ private static Set getTagsFromArgs(String tagArguments) throws IllegalVa private Command prepareDelete(String args) { Optional index = parseIndex(args); - if(!index.isPresent()){ + if (!index.isPresent()) { return new IncorrectCommand( String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteCommand.MESSAGE_USAGE)); } @@ -144,7 +144,7 @@ private Command prepareDelete(String args) { */ private Command prepareSelect(String args) { Optional index = parseIndex(args); - if(!index.isPresent()){ + if (!index.isPresent()) { return new IncorrectCommand( String.format(MESSAGE_INVALID_COMMAND_FORMAT, SelectCommand.MESSAGE_USAGE)); } @@ -153,8 +153,8 @@ private Command prepareSelect(String args) { } /** - * Returns the specified index in the {@code command} IF a positive unsigned integer is given as the index. - * Returns an {@code Optional.empty()} otherwise. + * Returns the specified index in the {@code command} if it is a positive unsigned integer + * Returns an {@code Optional.empty()} otherwise. */ private Optional parseIndex(String command) { final Matcher matcher = PERSON_INDEX_ARGS_FORMAT.matcher(command.trim()); @@ -163,7 +163,7 @@ private Optional parseIndex(String command) { } String index = matcher.group("targetIndex"); - if(!StringUtil.isUnsignedInteger(index)){ + if (!StringUtil.isUnsignedInteger(index)) { return Optional.empty(); } return Optional.of(Integer.parseInt(index)); @@ -189,4 +189,4 @@ private Command prepareFind(String args) { return new FindCommand(keywordSet); } -} \ No newline at end of file +} diff --git a/src/main/java/seedu/address/model/ModelManager.java b/src/main/java/seedu/address/model/ModelManager.java index 869226d02bf1..da5f472f6d87 100644 --- a/src/main/java/seedu/address/model/ModelManager.java +++ b/src/main/java/seedu/address/model/ModelManager.java @@ -77,7 +77,7 @@ public synchronized void addPerson(Person person) throws UniquePersonList.Duplic indicateAddressBookChanged(); } - //=========== Filtered Person List Accessors =============================================================== + //=========== Filtered Person List Accessors ============================================================= @Override public UnmodifiableObservableList getFilteredPersonList() { @@ -98,7 +98,7 @@ private void updateFilteredPersonList(Expression expression) { filteredPersons.setPredicate(expression::satisfies); } - //========== Inner classes/interfaces used for filtering ================================================== + //========== Inner classes/interfaces used for filtering ================================================= interface Expression { boolean satisfies(ReadOnlyPerson person); diff --git a/src/main/java/seedu/address/model/UserPrefs.java b/src/main/java/seedu/address/model/UserPrefs.java index da9c8037f495..0cbf893ad026 100644 --- a/src/main/java/seedu/address/model/UserPrefs.java +++ b/src/main/java/seedu/address/model/UserPrefs.java @@ -29,14 +29,14 @@ public void setGuiSettings(double width, double height, int x, int y) { @Override public boolean equals(Object other) { - if (other == this){ + if (other == this) { return true; } - if (!(other instanceof UserPrefs)){ //this handles null as well. + if (!(other instanceof UserPrefs)) { //this handles null as well. return false; } - UserPrefs o = (UserPrefs)other; + UserPrefs o = (UserPrefs) other; return Objects.equals(guiSettings, o.guiSettings); } diff --git a/src/main/java/seedu/address/model/person/Address.java b/src/main/java/seedu/address/model/person/Address.java index a2bd109c005e..30099e36bc40 100644 --- a/src/main/java/seedu/address/model/person/Address.java +++ b/src/main/java/seedu/address/model/person/Address.java @@ -51,4 +51,4 @@ public int hashCode() { return value.hashCode(); } -} \ No newline at end of file +} diff --git a/src/main/java/seedu/address/storage/XmlAddressBookStorage.java b/src/main/java/seedu/address/storage/XmlAddressBookStorage.java index 30cb00270cc4..bfeda7b006a8 100644 --- a/src/main/java/seedu/address/storage/XmlAddressBookStorage.java +++ b/src/main/java/seedu/address/storage/XmlAddressBookStorage.java @@ -33,7 +33,8 @@ public String getAddressBookFilePath(){ * @param filePath location of the data. Cannot be null * @throws DataConversionException if the file is not in the correct format. */ - public Optional readAddressBook(String filePath) throws DataConversionException, FileNotFoundException { + public Optional readAddressBook(String filePath) throws DataConversionException, + FileNotFoundException { assert filePath != null; File addressBookFile = new File(filePath); diff --git a/src/main/java/seedu/address/ui/BrowserPanel.java b/src/main/java/seedu/address/ui/BrowserPanel.java index 54b88318019b..cdd192a615df 100644 --- a/src/main/java/seedu/address/ui/BrowserPanel.java +++ b/src/main/java/seedu/address/ui/BrowserPanel.java @@ -44,7 +44,8 @@ public static BrowserPanel load(AnchorPane placeholder){ logger.info("Initializing browser"); BrowserPanel browserPanel = new BrowserPanel(); browserPanel.browser = new WebView(); - placeholder.setOnKeyPressed(Event::consume); // To prevent triggering events for typing inside the loaded Web page. + placeholder.setOnKeyPressed(Event::consume); // To prevent triggering events for typing inside the + // loaded Web page. FxViewUtil.applyAnchorBoundaryParameters(browserPanel.browser, 0.0, 0.0, 0.0, 0.0); placeholder.getChildren().add(browserPanel.browser); return browserPanel; diff --git a/src/main/java/seedu/address/ui/CommandBox.java b/src/main/java/seedu/address/ui/CommandBox.java index 2e1409a3016c..9a19db8be521 100644 --- a/src/main/java/seedu/address/ui/CommandBox.java +++ b/src/main/java/seedu/address/ui/CommandBox.java @@ -30,8 +30,8 @@ public class CommandBox extends UiPart { private TextField commandTextField; private CommandResult mostRecentResult; - public static CommandBox load(Stage primaryStage, AnchorPane commandBoxPlaceholder, - ResultDisplay resultDisplay, Logic logic) { + public static CommandBox load(Stage primaryStage, AnchorPane commandBoxPlaceholder, ResultDisplay resultDisplay, + Logic logic) { CommandBox commandBox = UiPartLoader.loadUiPart(primaryStage, commandBoxPlaceholder, new CommandBox()); commandBox.configure(resultDisplay, logic); commandBox.addToPlaceholder(); @@ -92,7 +92,7 @@ private void setStyleToIndicateCorrectCommand() { @Subscribe private void handleIncorrectCommandAttempted(IncorrectCommandAttemptedEvent event){ - logger.info(LogsCenter.getEventHandlingLogMessage(event,"Invalid command: " + previousCommandTest)); + logger.info(LogsCenter.getEventHandlingLogMessage(event, "Invalid command: " + previousCommandTest)); setStyleToIndicateIncorrectCommand(); restoreCommandText(); } diff --git a/src/main/java/seedu/address/ui/MainWindow.java b/src/main/java/seedu/address/ui/MainWindow.java index 2c76aced3b04..f9a802b14441 100644 --- a/src/main/java/seedu/address/ui/MainWindow.java +++ b/src/main/java/seedu/address/ui/MainWindow.java @@ -77,7 +77,6 @@ public String getFxmlPath() { } public static MainWindow load(Stage primaryStage, Config config, UserPrefs prefs, Logic logic) { - MainWindow mainWindow = UiPartLoader.loadUiPart(primaryStage, new MainWindow()); mainWindow.configure(config.getAppTitle(), config.getAddressBookName(), config, prefs, logic); return mainWindow; @@ -86,13 +85,13 @@ public static MainWindow load(Stage primaryStage, Config config, UserPrefs prefs private void configure(String appTitle, String addressBookName, Config config, UserPrefs prefs, Logic logic) { - //Set dependencies + // Set dependencies this.logic = logic; this.addressBookName = addressBookName; this.config = config; this.userPrefs = prefs; - //Configure the UI + // Configure the UI setTitle(appTitle); setIcon(ICON); setWindowMinSize(); @@ -111,7 +110,8 @@ void fillInnerParts() { browserPanel = BrowserPanel.load(browserPlaceholder); personListPanel = PersonListPanel.load(primaryStage, getPersonListPlaceholder(), logic.getFilteredPersonList()); resultDisplay = ResultDisplay.load(primaryStage, getResultDisplayPlaceholder()); - statusBarFooter = StatusBarFooter.load(primaryStage, getStatusbarPlaceholder(), config.getAddressBookFilePath()); + statusBarFooter = StatusBarFooter.load(primaryStage, getStatusbarPlaceholder(), + config.getAddressBookFilePath()); commandBox = CommandBox.load(primaryStage, getCommandBoxPlaceholder(), resultDisplay, logic); } diff --git a/src/main/java/seedu/address/ui/PersonCard.java b/src/main/java/seedu/address/ui/PersonCard.java index 259e9ad0d333..e8ef7408be6d 100644 --- a/src/main/java/seedu/address/ui/PersonCard.java +++ b/src/main/java/seedu/address/ui/PersonCard.java @@ -6,7 +6,7 @@ import javafx.scene.layout.HBox; import seedu.address.model.person.ReadOnlyPerson; -public class PersonCard extends UiPart{ +public class PersonCard extends UiPart { private static final String FXML = "PersonListCard.fxml"; @@ -28,11 +28,11 @@ public class PersonCard extends UiPart{ private ReadOnlyPerson person; private int displayedIndex; - public PersonCard(){ + public PersonCard() { } - public static PersonCard load(ReadOnlyPerson person, int displayedIndex){ + public static PersonCard load(ReadOnlyPerson person, int displayedIndex) { PersonCard card = new PersonCard(); card.person = person; card.displayedIndex = displayedIndex; @@ -55,7 +55,7 @@ public HBox getLayout() { @Override public void setNode(Node node) { - cardPane = (HBox)node; + cardPane = (HBox) node; } @Override diff --git a/src/main/java/seedu/address/ui/PersonListPanel.java b/src/main/java/seedu/address/ui/PersonListPanel.java index 27d9381c47b5..7b0b622d238d 100644 --- a/src/main/java/seedu/address/ui/PersonListPanel.java +++ b/src/main/java/seedu/address/ui/PersonListPanel.java @@ -72,12 +72,13 @@ private void addToPlaceholder() { } private void setEventHandlerForSelectionChangeEvent() { - personListView.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> { - if (newValue != null) { - logger.fine("Selection in person list panel changed to : '" + newValue + "'"); - raise(new PersonPanelSelectionChangedEvent(newValue)); - } - }); + personListView.getSelectionModel().selectedItemProperty() + .addListener((observable, oldValue, newValue) -> { + if (newValue != null) { + logger.fine("Selection in person list panel changed to : '" + newValue + "'"); + raise(new PersonPanelSelectionChangedEvent(newValue)); + } + }); } public void scrollTo(int index) { diff --git a/src/main/java/seedu/address/ui/UiManager.java b/src/main/java/seedu/address/ui/UiManager.java index ee7665b26daa..1177bf2add76 100644 --- a/src/main/java/seedu/address/ui/UiManager.java +++ b/src/main/java/seedu/address/ui/UiManager.java @@ -98,7 +98,7 @@ private void showFatalErrorDialogAndShutdown(String title, Throwable e) { System.exit(1); } - //==================== Event Handling Code ================================================================= + //==================== Event Handling Code =============================================================== @Subscribe private void handleDataSavingExceptionEvent(DataSavingExceptionEvent event) { @@ -119,7 +119,7 @@ private void handleJumpToListRequestEvent(JumpToListRequestEvent event) { } @Subscribe - private void handlePersonPanelSelectionChangedEvent(PersonPanelSelectionChangedEvent event){ + private void handlePersonPanelSelectionChangedEvent(PersonPanelSelectionChangedEvent event) { logger.info(LogsCenter.getEventHandlingLogMessage(event)); mainWindow.loadPersonPage(event.getNewSelection()); } diff --git a/src/main/java/seedu/address/ui/UiPartLoader.java b/src/main/java/seedu/address/ui/UiPartLoader.java index f880685a5b15..86e0182846eb 100644 --- a/src/main/java/seedu/address/ui/UiPartLoader.java +++ b/src/main/java/seedu/address/ui/UiPartLoader.java @@ -10,7 +10,7 @@ * A utility class to load UiParts from FXML files. */ public class UiPartLoader { - private final static String FXML_FILE_FOLDER = "/view/"; + private static final String FXML_FILE_FOLDER = "/view/"; public static T loadUiPart(Stage primaryStage, T controllerSeed) { return loadUiPart(primaryStage, null, controllerSeed); @@ -32,7 +32,7 @@ public static T loadUiPart(Stage primaryStage, AnchorPane pla controller.setStage(primaryStage); controller.setPlaceholder(placeholder); controller.setNode(mainNode); - return (T)controller; + return (T) controller; } /** diff --git a/src/test/java/guitests/DeleteCommandTest.java b/src/test/java/guitests/DeleteCommandTest.java index 10c7b9e0dbea..45750e0b0915 100644 --- a/src/test/java/guitests/DeleteCommandTest.java +++ b/src/test/java/guitests/DeleteCommandTest.java @@ -24,7 +24,7 @@ public void delete() { //delete from the middle of the list currentList = TestUtil.removePersonFromList(currentList, targetIndex); - targetIndex = currentList.length/2; + targetIndex = currentList.length / 2; assertDeleteSuccess(targetIndex, currentList); //invalid index @@ -35,11 +35,11 @@ public void delete() { /** * Runs the delete command to delete the person at specified index and confirms the result is correct. - * @param targetIndexOneIndexed e.g. to delete the first person in the list, 1 should be given as the target index. + * @param targetIndexOneIndexed e.g. index 1 to delete the first person in the list, * @param currentList A copy of the current list of persons (before deletion). */ private void assertDeleteSuccess(int targetIndexOneIndexed, final TestPerson[] currentList) { - TestPerson personToDelete = currentList[targetIndexOneIndexed-1]; //-1 because array uses zero indexing + TestPerson personToDelete = currentList[targetIndexOneIndexed - 1]; // -1 as array uses zero indexing TestPerson[] expectedRemainder = TestUtil.removePersonFromList(currentList, targetIndexOneIndexed); commandBox.runCommand("delete " + targetIndexOneIndexed); diff --git a/src/test/java/guitests/FindCommandTest.java b/src/test/java/guitests/FindCommandTest.java index 441a6dbed666..a4504ae94fff 100644 --- a/src/test/java/guitests/FindCommandTest.java +++ b/src/test/java/guitests/FindCommandTest.java @@ -10,18 +10,18 @@ public class FindCommandTest extends AddressBookGuiTest { @Test public void find_nonEmptyList() { - assertFindResult("find Mark"); //no results - assertFindResult("find Meier", td.benson, td.daniel); //multiple results + assertFindResult("find Mark"); // no results + assertFindResult("find Meier", td.benson, td.daniel); // multiple results //find after deleting one result commandBox.runCommand("delete 1"); - assertFindResult("find Meier",td.daniel); + assertFindResult("find Meier", td.daniel); } @Test public void find_emptyList(){ commandBox.runCommand("clear"); - assertFindResult("find Jean"); //no results + assertFindResult("find Jean"); // no results } @Test @@ -30,7 +30,7 @@ public void find_invalidCommand_fail() { assertResultMessage(Messages.MESSAGE_UNKNOWN_COMMAND); } - private void assertFindResult(String command, TestPerson... expectedHits ) { + private void assertFindResult(String command, TestPerson... expectedHits) { commandBox.runCommand(command); assertListSize(expectedHits.length); assertResultMessage(expectedHits.length + " persons listed!"); diff --git a/src/test/java/guitests/SelectCommandTest.java b/src/test/java/guitests/SelectCommandTest.java index 5273552056ce..91a8d50c3b57 100644 --- a/src/test/java/guitests/SelectCommandTest.java +++ b/src/test/java/guitests/SelectCommandTest.java @@ -11,17 +11,17 @@ public class SelectCommandTest extends AddressBookGuiTest { @Test public void selectPerson_nonEmptyList() { - assertSelectionInvalid(10); //invalid index + assertSelectionInvalid(10); // invalid index assertNoPersonSelected(); - assertSelectionSuccess(1); //first person in the list + assertSelectionSuccess(1); // first person in the list int personCount = td.getTypicalPersons().length; - assertSelectionSuccess(personCount); //last person in the list + assertSelectionSuccess(personCount); // last person in the list int middleIndex = personCount / 2; - assertSelectionSuccess(middleIndex); //a person in the middle of the list + assertSelectionSuccess(middleIndex); // a person in the middle of the list - assertSelectionInvalid(personCount + 1); //invalid index - assertPersonSelected(middleIndex); //assert previous selection remains + assertSelectionInvalid(personCount + 1); // invalid index + assertPersonSelected(middleIndex); // assert previous selection remains /* Testing other invalid indexes such as -1 should be done when testing the SelectCommand */ } @@ -40,14 +40,14 @@ private void assertSelectionInvalid(int index) { private void assertSelectionSuccess(int index) { commandBox.runCommand("select " + index); - assertResultMessage("Selected Person: "+index); + assertResultMessage("Selected Person: " + index); assertPersonSelected(index); } private void assertPersonSelected(int index) { assertEquals(personListPanel.getSelectedPersons().size(), 1); ReadOnlyPerson selectedPerson = personListPanel.getSelectedPersons().get(0); - assertEquals(personListPanel.getPerson(index-1), selectedPerson); + assertEquals(personListPanel.getPerson(index - 1), selectedPerson); //TODO: confirm the correct page is loaded in the Browser Panel } diff --git a/src/test/java/guitests/guihandles/AlertDialogHandle.java b/src/test/java/guitests/guihandles/AlertDialogHandle.java index 0b855c3e8b3d..f4e52df234db 100644 --- a/src/test/java/guitests/guihandles/AlertDialogHandle.java +++ b/src/test/java/guitests/guihandles/AlertDialogHandle.java @@ -18,7 +18,8 @@ public AlertDialogHandle(GuiRobot guiRobot, Stage primaryStage, String dialogTit public boolean isMatching(String headerMessage, String contentMessage) { assert intermediateStage.isPresent() : "Alert dialog is not present"; DialogPane dialogPane = (DialogPane) getNode("#" + UiManager.ALERT_DIALOG_PANE_FIELD_ID); - boolean isMatching = dialogPane.getHeaderText().equals(headerMessage) && dialogPane.getContentText().equals(contentMessage); + boolean isMatching = dialogPane.getHeaderText().equals(headerMessage) + && dialogPane.getContentText().equals(contentMessage); return isMatching; } } diff --git a/src/test/java/guitests/guihandles/GuiHandle.java b/src/test/java/guitests/guihandles/GuiHandle.java index 5003c440951a..66e0c689349b 100644 --- a/src/test/java/guitests/guihandles/GuiHandle.java +++ b/src/test/java/guitests/guihandles/GuiHandle.java @@ -60,7 +60,7 @@ protected String getTextFieldText(String filedName) { protected void setTextField(String textFieldId, String newText) { guiRobot.clickOn(textFieldId); - ((TextField)guiRobot.lookup(textFieldId).tryQuery().get()).setText(newText); + ((TextField) guiRobot.lookup(textFieldId).tryQuery().get()).setText(newText); guiRobot.sleep(500); // so that the texts stays visible on the GUI for a short period } @@ -96,7 +96,7 @@ public void closeWindow() { } guiRobot.targetWindow(window.get()); - guiRobot.interact(() -> ((Stage)window.get()).close()); + guiRobot.interact(() -> ((Stage) window.get()).close()); focusOnMainApp(); } } diff --git a/src/test/java/guitests/guihandles/MainGuiHandle.java b/src/test/java/guitests/guihandles/MainGuiHandle.java index c92251158f4e..c3308d98de46 100644 --- a/src/test/java/guitests/guihandles/MainGuiHandle.java +++ b/src/test/java/guitests/guihandles/MainGuiHandle.java @@ -31,6 +31,6 @@ public MainMenuHandle getMainMenu() { public AlertDialogHandle getAlertDialog(String title) { guiRobot.sleep(1000); - return new AlertDialogHandle(guiRobot, primaryStage, title) ; + return new AlertDialogHandle(guiRobot, primaryStage, title); } } diff --git a/src/test/java/guitests/guihandles/PersonCardHandle.java b/src/test/java/guitests/guihandles/PersonCardHandle.java index fae22a45ae2f..a64d9b9ecd4e 100644 --- a/src/test/java/guitests/guihandles/PersonCardHandle.java +++ b/src/test/java/guitests/guihandles/PersonCardHandle.java @@ -41,14 +41,15 @@ public String getEmail() { return getTextFromLabel(EMAIL_FIELD_ID); } - public boolean isSamePerson(ReadOnlyPerson person){ + public boolean isSamePerson(ReadOnlyPerson person) { return getFullName().equals(person.getName().fullName) && getPhone().equals(person.getPhone().value) - && getEmail().equals(person.getEmail().value) && getAddress().equals(person.getAddress().value); + && getEmail().equals(person.getEmail().value) + && getAddress().equals(person.getAddress().value); } @Override public boolean equals(Object obj) { - if(obj instanceof PersonCardHandle) { + if (obj instanceof PersonCardHandle) { PersonCardHandle handle = (PersonCardHandle) obj; return getFullName().equals(handle.getFullName()) && getAddress().equals(handle.getAddress()); //TODO: compare the rest diff --git a/src/test/java/guitests/guihandles/PersonListPanelHandle.java b/src/test/java/guitests/guihandles/PersonListPanelHandle.java index 3451992cf735..755699841117 100644 --- a/src/test/java/guitests/guihandles/PersonListPanelHandle.java +++ b/src/test/java/guitests/guihandles/PersonListPanelHandle.java @@ -52,7 +52,7 @@ public boolean isListMatching(ReadOnlyPerson... persons) { * Clicks on the ListView. */ public void clickOnListView() { - Point2D point= TestUtil.getScreenMidPoint(getListView()); + Point2D point = TestUtil.getScreenMidPoint(getListView()); guiRobot.clickOn(point.getX(), point.getY()); } @@ -69,7 +69,7 @@ public boolean containsInOrder(int startPosition, ReadOnlyPerson... persons) { // Return false if any of the persons doesn't match for (int i = 0; i < persons.length; i++) { - if (!personsInList.get(startPosition + i).getName().fullName.equals(persons[i].getName().fullName)){ + if (!personsInList.get(startPosition + i).getName().fullName.equals(persons[i].getName().fullName)) { return false; } } @@ -102,7 +102,9 @@ public boolean isListMatching(int startPosition, ReadOnlyPerson... persons) thro public PersonCardHandle navigateToPerson(String name) { guiRobot.sleep(500); //Allow a bit of time for the list to be updated - final Optional person = getListView().getItems().stream().filter(p -> p.getName().fullName.equals(name)).findAny(); + final Optional person = getListView().getItems().stream() + .filter(p -> p.getName().fullName.equals(name)) + .findAny(); if (!person.isPresent()) { throw new IllegalStateException("Name not found: " + name); } @@ -132,7 +134,7 @@ public PersonCardHandle navigateToPerson(ReadOnlyPerson person) { public int getPersonIndex(ReadOnlyPerson targetPerson) { List personsInList = getListView().getItems(); for (int i = 0; i < personsInList.size(); i++) { - if(personsInList.get(i).getName().equals(targetPerson.getName())){ + if (personsInList.get(i).getName().equals(targetPerson.getName())) { return i; } } diff --git a/src/test/java/seedu/address/TestApp.java b/src/test/java/seedu/address/TestApp.java index 756642b6c180..b32cfe96cc48 100644 --- a/src/test/java/seedu/address/TestApp.java +++ b/src/test/java/seedu/address/TestApp.java @@ -18,7 +18,8 @@ public class TestApp extends MainApp { public static final String SAVE_LOCATION_FOR_TESTING = TestUtil.getFilePathInSandboxFolder("sampleData.xml"); - protected static final String DEFAULT_PREF_FILE_LOCATION_FOR_TESTING = TestUtil.getFilePathInSandboxFolder("pref_testing.json"); + protected static final String DEFAULT_PREF_FILE_LOCATION_FOR_TESTING = + TestUtil.getFilePathInSandboxFolder("pref_testing.json"); public static final String APP_TITLE = "Test App"; protected static final String ADDRESS_BOOK_NAME = "Test"; protected Supplier initialDataSupplier = () -> null; diff --git a/src/test/java/seedu/address/commons/util/ConfigUtilTest.java b/src/test/java/seedu/address/commons/util/ConfigUtilTest.java index 1d4d35d0f864..ed4a12c75fa6 100644 --- a/src/test/java/seedu/address/commons/util/ConfigUtilTest.java +++ b/src/test/java/seedu/address/commons/util/ConfigUtilTest.java @@ -1,14 +1,11 @@ package seedu.address.commons.util; - import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.junit.rules.TemporaryFolder; import seedu.address.commons.core.Config; import seedu.address.commons.exceptions.DataConversionException; -import seedu.address.commons.util.ConfigUtil; -import seedu.address.commons.util.FileUtil; import java.io.File; import java.io.IOException; @@ -20,7 +17,7 @@ public class ConfigUtilTest { - private static String TEST_DATA_FOLDER = FileUtil.getPath("./src/test/data/ConfigUtilTest/"); + private static final String TEST_DATA_FOLDER = FileUtil.getPath("./src/test/data/ConfigUtilTest/"); @Rule public ExpectedException thrown = ExpectedException.none(); diff --git a/src/test/java/seedu/address/commons/util/JsonUtilTest.java b/src/test/java/seedu/address/commons/util/JsonUtilTest.java index 9607283a41c2..5561a4237c5b 100644 --- a/src/test/java/seedu/address/commons/util/JsonUtilTest.java +++ b/src/test/java/seedu/address/commons/util/JsonUtilTest.java @@ -41,5 +41,4 @@ public void deserializeObjectFromJsonFile_noExceptionThrown() throws IOException //TODO: @Test jsonUtil_readJsonStringToObjectInstance_correctObject() //TODO: @Test jsonUtil_writeThenReadObjectToJson_correctObject() - } diff --git a/src/test/java/seedu/address/commons/util/XmlUtilTest.java b/src/test/java/seedu/address/commons/util/XmlUtilTest.java index dc4fd886c23e..7df48d5349a0 100644 --- a/src/test/java/seedu/address/commons/util/XmlUtilTest.java +++ b/src/test/java/seedu/address/commons/util/XmlUtilTest.java @@ -80,14 +80,15 @@ public void saveDataToFile_validFile_dataSaved() throws Exception { XmlSerializableAddressBook dataToWrite = new XmlSerializableAddressBook(new AddressBook()); XmlUtil.saveDataToFile(TEMP_FILE, dataToWrite); XmlSerializableAddressBook dataFromFile = XmlUtil.getDataFromFile(TEMP_FILE, XmlSerializableAddressBook.class); - assertEquals((new AddressBook(dataToWrite)).toString(),(new AddressBook(dataFromFile)).toString()); + assertEquals((new AddressBook(dataToWrite)).toString(), (new AddressBook(dataFromFile)).toString()); //TODO: use equality instead of string comparisons AddressBookBuilder builder = new AddressBookBuilder(new AddressBook()); - dataToWrite = new XmlSerializableAddressBook(builder.withPerson(TestUtil.generateSamplePersonData().get(0)).withTag("Friends").build()); + dataToWrite = new XmlSerializableAddressBook( + builder.withPerson(TestUtil.generateSamplePersonData().get(0)).withTag("Friends").build()); XmlUtil.saveDataToFile(TEMP_FILE, dataToWrite); dataFromFile = XmlUtil.getDataFromFile(TEMP_FILE, XmlSerializableAddressBook.class); - assertEquals((new AddressBook(dataToWrite)).toString(),(new AddressBook(dataFromFile)).toString()); + assertEquals((new AddressBook(dataToWrite)).toString(), (new AddressBook(dataFromFile)).toString()); } } diff --git a/src/test/java/seedu/address/logic/LogicManagerTest.java b/src/test/java/seedu/address/logic/LogicManagerTest.java index e1ee0cfb4051..5d7e4feaf23b 100644 --- a/src/test/java/seedu/address/logic/LogicManagerTest.java +++ b/src/test/java/seedu/address/logic/LogicManagerTest.java @@ -68,7 +68,7 @@ public void setup() { logic = new LogicManager(model, new StorageManager(tempAddressBookFile, tempPreferencesFile)); EventsCenter.getInstance().registerHandler(this); - latestSavedAddressBook = new AddressBook(model.getAddressBook()); // last saved assumed to be up to date before. + latestSavedAddressBook = new AddressBook(model.getAddressBook()); // last saved assumed to be up to date helpShown = false; targetedJumpIndex = -1; // non yet } @@ -149,26 +149,21 @@ public void execute_clear() throws Exception { @Test public void execute_add_invalidArgsFormat() throws Exception { String expectedMessage = String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddCommand.MESSAGE_USAGE); - assertCommandBehavior( - "add wrong args wrong args", expectedMessage); - assertCommandBehavior( - "add Valid Name 12345 e/valid@email.butNoPhonePrefix a/valid, address", expectedMessage); - assertCommandBehavior( - "add Valid Name p/12345 valid@email.butNoPrefix a/valid, address", expectedMessage); - assertCommandBehavior( - "add Valid Name p/12345 e/valid@email.butNoAddressPrefix valid, address", expectedMessage); + assertCommandBehavior("add wrong args wrong args", expectedMessage); + assertCommandBehavior("add Valid Name 12345 e/valid@email.butNoPhonePrefix a/valid, address", expectedMessage); + assertCommandBehavior("add Valid Name p/12345 valid@email.butNoPrefix a/valid, address", expectedMessage); + assertCommandBehavior("add Valid Name p/12345 e/valid@email.butNoAddressPrefix valid, address", + expectedMessage); } @Test public void execute_add_invalidPersonData() throws Exception { - assertCommandBehavior( - "add []\\[;] p/12345 e/valid@e.mail a/valid, address", Name.MESSAGE_NAME_CONSTRAINTS); - assertCommandBehavior( - "add Valid Name p/not_numbers e/valid@e.mail a/valid, address", Phone.MESSAGE_PHONE_CONSTRAINTS); - assertCommandBehavior( - "add Valid Name p/12345 e/notAnEmail a/valid, address", Email.MESSAGE_EMAIL_CONSTRAINTS); - assertCommandBehavior( - "add Valid Name p/12345 e/valid@e.mail a/valid, address t/invalid_-[.tag", Tag.MESSAGE_TAG_CONSTRAINTS); + assertCommandBehavior("add []\\[;] p/12345 e/valid@e.mail a/valid, address", Name.MESSAGE_NAME_CONSTRAINTS); + assertCommandBehavior("add Valid Name p/not_numbers e/valid@e.mail a/valid, address", + Phone.MESSAGE_PHONE_CONSTRAINTS); + assertCommandBehavior("add Valid Name p/12345 e/notAnEmail a/valid, address", Email.MESSAGE_EMAIL_CONSTRAINTS); + assertCommandBehavior("add Valid Name p/12345 e/valid@e.mail a/valid, address t/invalid_-[.tag", + Tag.MESSAGE_TAG_CONSTRAINTS); } @@ -229,9 +224,11 @@ public void execute_list_showsAllPersons() throws Exception { /** * Confirms the 'invalid argument index number behaviour' for the given command * targeting a single person in the shown list, using visible index. - * @param commandWord to test assuming it targets a single person in the last shown list based on visible index. + * @param commandWord to test assuming it targets a single person in the last shown list + * based on visible index. */ - private void assertIncorrectIndexFormatBehaviorForCommand(String commandWord, String expectedMessage) throws Exception { + private void assertIncorrectIndexFormatBehaviorForCommand(String commandWord, String expectedMessage) + throws Exception { assertCommandBehavior(commandWord , expectedMessage); //index missing assertCommandBehavior(commandWord + " +1", expectedMessage); //index should be unsigned assertCommandBehavior(commandWord + " -1", expectedMessage); //index should be unsigned @@ -242,7 +239,8 @@ private void assertIncorrectIndexFormatBehaviorForCommand(String commandWord, St /** * Confirms the 'invalid argument index number behaviour' for the given command * targeting a single person in the shown list, using visible index. - * @param commandWord to test assuming it targets a single person in the last shown list based on visible index. + * @param commandWord to test assuming it targets a single person in the last shown list + * based on visible index. */ private void assertIndexNotFoundBehaviorForCommand(String commandWord) throws Exception { String expectedMessage = MESSAGE_INVALID_PERSON_DISPLAYED_INDEX; @@ -422,7 +420,7 @@ String generateAddCommand(Person p) { cmd.append(" a/").append(p.getAddress()); UniqueTagList tags = p.getTags(); - for(Tag t: tags){ + for (Tag t: tags) { cmd.append(" t/").append(t.tagName); } @@ -451,15 +449,15 @@ AddressBook generateAddressBook(List persons) throws Exception{ * Adds auto-generated Person objects to the given AddressBook * @param addressBook The AddressBook to which the Persons will be added */ - void addToAddressBook(AddressBook addressBook, int numGenerated) throws Exception{ + void addToAddressBook(AddressBook addressBook, int numGenerated) throws Exception { addToAddressBook(addressBook, generatePersonList(numGenerated)); } /** * Adds the given list of Persons to the given AddressBook */ - void addToAddressBook(AddressBook addressBook, List personsToAdd) throws Exception{ - for(Person p: personsToAdd){ + void addToAddressBook(AddressBook addressBook, List personsToAdd) throws Exception { + for (Person p: personsToAdd) { addressBook.addPerson(p); } } @@ -476,7 +474,7 @@ void addToModel(Model model, int numGenerated) throws Exception{ * Adds the given list of Persons to the given model */ void addToModel(Model model, List personsToAdd) throws Exception{ - for(Person p: personsToAdd){ + for (Person p: personsToAdd) { model.addPerson(p); } } @@ -486,7 +484,7 @@ void addToModel(Model model, List personsToAdd) throws Exception{ */ List generatePersonList(int numGenerated) throws Exception{ List persons = new ArrayList<>(); - for(int i = 1; i <= numGenerated; i++){ + for (int i = 1; i <= numGenerated; i++) { persons.add(generatePerson(i)); } return persons; diff --git a/src/test/java/seedu/address/storage/JsonUserPrefsStorageTest.java b/src/test/java/seedu/address/storage/JsonUserPrefsStorageTest.java index c0d45080ef4f..7a40ee2bde71 100644 --- a/src/test/java/seedu/address/storage/JsonUserPrefsStorageTest.java +++ b/src/test/java/seedu/address/storage/JsonUserPrefsStorageTest.java @@ -18,7 +18,7 @@ public class JsonUserPrefsStorageTest { - private static String TEST_DATA_FOLDER = FileUtil.getPath("./src/test/data/JsonUserPrefsStorageTest/"); + private static final String TEST_DATA_FOLDER = FileUtil.getPath("./src/test/data/JsonUserPrefsStorageTest/"); @Rule public ExpectedException thrown = ExpectedException.none(); @@ -44,7 +44,6 @@ public void readUserPrefs_missingFile_emptyResult() throws DataConversionExcepti @Test public void readUserPrefs_notJsonFormat_exceptionThrown() throws DataConversionException { - thrown.expect(DataConversionException.class); readUserPrefs("NotJsonFormatUserPrefs.json"); @@ -95,7 +94,8 @@ public void saveUserPrefs_nullFilePath_assertionFailure() throws IOException { } private void saveUserPrefs(UserPrefs userPrefs, String prefsFileInTestDataFolder) throws IOException { - new JsonUserPrefsStorage(addToTestDataPathIfNotNull(prefsFileInTestDataFolder)).saveUserPrefs(userPrefs); + new JsonUserPrefsStorage(addToTestDataPathIfNotNull(prefsFileInTestDataFolder)) + .saveUserPrefs(userPrefs); } @Test diff --git a/src/test/java/seedu/address/storage/StorageManagerTest.java b/src/test/java/seedu/address/storage/StorageManagerTest.java index 6780feab6afc..0e8118fcdfd3 100644 --- a/src/test/java/seedu/address/storage/StorageManagerTest.java +++ b/src/test/java/seedu/address/storage/StorageManagerTest.java @@ -69,8 +69,9 @@ public void getAddressBookFilePath(){ @Test public void handleAddressBookChangedEvent_exceptionThrown_eventRaised() throws IOException { - //Create a StorageManager while injecting a stub that throws an exception when the save method is called - Storage storage = new StorageManager(new XmlAddressBookStorageExceptionThrowingStub("dummy"), new JsonUserPrefsStorage("dummy")); + // Create a StorageManager while injecting a stub that throws an exception when the save method is called + Storage storage = new StorageManager(new XmlAddressBookStorageExceptionThrowingStub("dummy"), + new JsonUserPrefsStorage("dummy")); EventsCollector eventCollector = new EventsCollector(); storage.handleAddressBookChangedEvent(new AddressBookChangedEvent(new AddressBook())); assertTrue(eventCollector.get(0) instanceof DataSavingExceptionEvent); diff --git a/src/test/java/seedu/address/storage/XmlAddressBookStorageTest.java b/src/test/java/seedu/address/storage/XmlAddressBookStorageTest.java index 04b0db1ce1c7..fa0ece2bfdef 100644 --- a/src/test/java/seedu/address/storage/XmlAddressBookStorageTest.java +++ b/src/test/java/seedu/address/storage/XmlAddressBookStorageTest.java @@ -18,7 +18,7 @@ import static org.junit.Assert.assertFalse; public class XmlAddressBookStorageTest { - private static String TEST_DATA_FOLDER = FileUtil.getPath("./src/test/data/XmlAddressBookStorageTest/"); + private static final String TEST_DATA_FOLDER = FileUtil.getPath("./src/test/data/XmlAddressBookStorageTest/"); @Rule public ExpectedException thrown = ExpectedException.none(); diff --git a/src/test/java/seedu/address/testutil/SerializableTestClass.java b/src/test/java/seedu/address/testutil/SerializableTestClass.java index ef58ef857179..0b423008bebd 100644 --- a/src/test/java/seedu/address/testutil/SerializableTestClass.java +++ b/src/test/java/seedu/address/testutil/SerializableTestClass.java @@ -9,16 +9,17 @@ * A class used to test serialization and deserialization */ public class SerializableTestClass { - public static final String JSON_STRING_REPRESENTATION = String.format("{%n" + - " \"name\" : \"This is a test class\",%n" + - " \"listOfLocalDateTimes\" : " + - "[ \"-999999999-01-01T00:00:00\", \"+999999999-12-31T23:59:59.999999999\", \"0001-01-01T01:01:00\" ],%n" + - " \"mapOfIntegerToString\" : {%n" + - " \"1\" : \"One\",%n" + - " \"2\" : \"Two\",%n" + - " \"3\" : \"Three\"%n" + - " }%n" + - "}"); + public static final String JSON_STRING_REPRESENTATION = String.format("{%n" + + " \"name\" : \"This is a test class\",%n" + + " \"listOfLocalDateTimes\" : " + + "[ \"-999999999-01-01T00:00:00\", \"+999999999-12-31T23:59:59.999999999\", " + + "\"0001-01-01T01:01:00\" ],%n" + + " \"mapOfIntegerToString\" : {%n" + + " \"1\" : \"One\",%n" + + " \"2\" : \"Two\",%n" + + " \"3\" : \"Three\"%n" + + " }%n" + + "}"); private static final String NAME_TEST_VALUE = "This is a test class"; diff --git a/src/test/java/seedu/address/testutil/TestUtil.java b/src/test/java/seedu/address/testutil/TestUtil.java index 17c92d66398a..87159154e98f 100644 --- a/src/test/java/seedu/address/testutil/TestUtil.java +++ b/src/test/java/seedu/address/testutil/TestUtil.java @@ -38,18 +38,18 @@ */ public class TestUtil { - public static String LS = System.lineSeparator(); + public static final String LS = System.lineSeparator(); public static void assertThrows(Class expected, Runnable executable) { try { executable.run(); - } - catch (Throwable actualException) { - if (!actualException.getClass().isAssignableFrom(expected)) { - String message = String.format("Expected thrown: %s, actual: %s", expected.getName(), - actualException.getClass().getName()); - throw new AssertionFailedError(message); - } else return; + } catch (Throwable actualException) { + if (actualException.getClass().isAssignableFrom(expected)) { + return; + } + String message = String.format("Expected thrown: %s, actual: %s", expected.getName(), + actualException.getClass().getName()); + throw new AssertionFailedError(message); } throw new AssertionFailedError( String.format("Expected %s to be thrown, but nothing was thrown.", expected.getName())); @@ -58,37 +58,39 @@ public static void assertThrows(Class expected, Runnable ex /** * Folder used for temp files created during testing. Ignored by Git. */ - public static String SANDBOX_FOLDER = FileUtil.getPath("./src/test/data/sandbox/"); + public static final String SANDBOX_FOLDER = FileUtil.getPath("./src/test/data/sandbox/"); - public static final Person[] samplePersonData = getSamplePersonData(); + public static final Person[] SAMPLE_PERSON_DATA = getSamplePersonData(); private static Person[] getSamplePersonData() { try { + //CHECKSTYLE.OFF: LineLength return new Person[]{ - new Person(new Name("Ali Muster"), new Phone("9482424"), new Email("hans@google.com"), new Address("4th street"), new UniqueTagList()), - new Person(new Name("Boris Mueller"), new Phone("87249245"), new Email("ruth@google.com"), new Address("81th street"), new UniqueTagList()), - new Person(new Name("Carl Kurz"), new Phone("95352563"), new Email("heinz@yahoo.com"), new Address("wall street"), new UniqueTagList()), - new Person(new Name("Daniel Meier"), new Phone("87652533"), new Email("cornelia@google.com"), new Address("10th street"), new UniqueTagList()), - new Person(new Name("Elle Meyer"), new Phone("9482224"), new Email("werner@gmail.com"), new Address("michegan ave"), new UniqueTagList()), - new Person(new Name("Fiona Kunz"), new Phone("9482427"), new Email("lydia@gmail.com"), new Address("little tokyo"), new UniqueTagList()), - new Person(new Name("George Best"), new Phone("9482442"), new Email("anna@google.com"), new Address("4th street"), new UniqueTagList()), - new Person(new Name("Hoon Meier"), new Phone("8482424"), new Email("stefan@mail.com"), new Address("little india"), new UniqueTagList()), - new Person(new Name("Ida Mueller"), new Phone("8482131"), new Email("hans@google.com"), new Address("chicago ave"), new UniqueTagList()) + new Person(new Name("Ali Muster"), new Phone("9482424"), new Email("hans@google.com"), new Address("4th street"), new UniqueTagList()), + new Person(new Name("Boris Mueller"), new Phone("87249245"), new Email("ruth@google.com"), new Address("81th street"), new UniqueTagList()), + new Person(new Name("Carl Kurz"), new Phone("95352563"), new Email("heinz@yahoo.com"), new Address("wall street"), new UniqueTagList()), + new Person(new Name("Daniel Meier"), new Phone("87652533"), new Email("cornelia@google.com"), new Address("10th street"), new UniqueTagList()), + new Person(new Name("Elle Meyer"), new Phone("9482224"), new Email("werner@gmail.com"), new Address("michegan ave"), new UniqueTagList()), + new Person(new Name("Fiona Kunz"), new Phone("9482427"), new Email("lydia@gmail.com"), new Address("little tokyo"), new UniqueTagList()), + new Person(new Name("George Best"), new Phone("9482442"), new Email("anna@google.com"), new Address("4th street"), new UniqueTagList()), + new Person(new Name("Hoon Meier"), new Phone("8482424"), new Email("stefan@mail.com"), new Address("little india"), new UniqueTagList()), + new Person(new Name("Ida Mueller"), new Phone("8482131"), new Email("hans@google.com"), new Address("chicago ave"), new UniqueTagList()) }; + //CHECKSTYLE.ON: LineLength } catch (IllegalValueException e) { assert false; - //not possible + // not possible return null; } } - public static final Tag[] sampleTagData = getSampleTagData(); + public static final Tag[] SAMPLE_TAG_DATA = getSampleTagData(); private static Tag[] getSampleTagData() { try { return new Tag[]{ - new Tag("relatives"), - new Tag("friends") + new Tag("relatives"), + new Tag("friends") }; } catch (IllegalValueException e) { assert false; @@ -98,7 +100,7 @@ private static Tag[] getSampleTagData() { } public static List generateSamplePersonData() { - return Arrays.asList(samplePersonData); + return Arrays.asList(SAMPLE_PERSON_DATA); } /** @@ -185,7 +187,8 @@ public static String descOnFail(Object... comparedObjects) { .collect(Collectors.joining("\n")); } - public static void setFinalStatic(Field field, Object newValue) throws NoSuchFieldException, IllegalAccessException{ + public static void setFinalStatic(Field field, Object newValue) throws NoSuchFieldException, + IllegalAccessException { field.setAccessible(true); // remove final modifier from field Field modifiersField = Field.class.getDeclaredField("modifiers"); @@ -233,7 +236,7 @@ public static void renameFile(File file, String newFileName) { public static Point2D getScreenMidPoint(Node node) { double x = getScreenPos(node).getMinX() + node.getLayoutBounds().getWidth() / 2; double y = getScreenPos(node).getMinY() + node.getLayoutBounds().getHeight() / 2; - return new Point2D(x,y); + return new Point2D(x, y); } /** @@ -244,7 +247,7 @@ public static Point2D getScreenMidPoint(Node node) { public static Point2D getSceneMidPoint(Node node) { double x = getScenePos(node).getMinX() + node.getLayoutBounds().getWidth() / 2; double y = getScenePos(node).getMinY() + node.getLayoutBounds().getHeight() / 2; - return new Point2D(x,y); + return new Point2D(x, y); } /** @@ -288,10 +291,10 @@ public static TestPerson[] removePersonsFromList(final TestPerson[] persons, Tes /** * Returns a copy of the list with the person at specified index removed. * @param list original list to copy from - * @param targetIndexInOneIndexedFormat e.g. if the first element to be removed, 1 should be given as index. + * @param targetIndexInOneIndexedFormat e.g. index 1 if the first element is to be removed */ public static TestPerson[] removePersonFromList(final TestPerson[] list, int targetIndexInOneIndexedFormat) { - return removePersonsFromList(list, list[targetIndexInOneIndexedFormat-1]); + return removePersonsFromList(list, list[targetIndexInOneIndexedFormat - 1]); } /** @@ -320,7 +323,7 @@ public static TestPerson[] addPersonsToList(final TestPerson[] persons, TestPers private static List asList(T[] objs) { List list = new ArrayList<>(); - for(T obj : objs) { + for (T obj : objs) { list.add(obj); } return list; @@ -331,7 +334,6 @@ public static boolean compareCardAndPerson(PersonCardHandle card, ReadOnlyPerson } public static Tag[] getTagList(String tags) { - if (tags.equals("")) { return new Tag[]{}; } diff --git a/src/test/java/seedu/address/testutil/TypicalTestPersons.java b/src/test/java/seedu/address/testutil/TypicalTestPersons.java index 773f64a98cc3..2fcb7f27bf39 100644 --- a/src/test/java/seedu/address/testutil/TypicalTestPersons.java +++ b/src/test/java/seedu/address/testutil/TypicalTestPersons.java @@ -13,21 +13,29 @@ public class TypicalTestPersons { public TypicalTestPersons() { try { - alice = new PersonBuilder().withName("Alice Pauline").withAddress("123, Jurong West Ave 6, #08-111") - .withEmail("alice@gmail.com").withPhone("85355255") + alice = new PersonBuilder().withName("Alice Pauline") + .withAddress("123, Jurong West Ave 6, #08-111").withEmail("alice@gmail.com") + .withPhone("85355255") .withTags("friends").build(); benson = new PersonBuilder().withName("Benson Meier").withAddress("311, Clementi Ave 2, #02-25") .withEmail("johnd@gmail.com").withPhone("98765432") .withTags("owesMoney", "friends").build(); - carl = new PersonBuilder().withName("Carl Kurz").withPhone("95352563").withEmail("heinz@yahoo.com").withAddress("wall street").build(); - daniel = new PersonBuilder().withName("Daniel Meier").withPhone("87652533").withEmail("cornelia@google.com").withAddress("10th street").build(); - elle = new PersonBuilder().withName("Elle Meyer").withPhone("9482224").withEmail("werner@gmail.com").withAddress("michegan ave").build(); - fiona = new PersonBuilder().withName("Fiona Kunz").withPhone("9482427").withEmail("lydia@gmail.com").withAddress("little tokyo").build(); - george = new PersonBuilder().withName("George Best").withPhone("9482442").withEmail("anna@google.com").withAddress("4th street").build(); - - //Manually added - hoon = new PersonBuilder().withName("Hoon Meier").withPhone("8482424").withEmail("stefan@mail.com").withAddress("little india").build(); - ida = new PersonBuilder().withName("Ida Mueller").withPhone("8482131").withEmail("hans@google.com").withAddress("chicago ave").build(); + carl = new PersonBuilder().withName("Carl Kurz").withPhone("95352563") + .withEmail("heinz@yahoo.com").withAddress("wall street").build(); + daniel = new PersonBuilder().withName("Daniel Meier").withPhone("87652533") + .withEmail("cornelia@google.com").withAddress("10th street").build(); + elle = new PersonBuilder().withName("Elle Meyer").withPhone("9482224") + .withEmail("werner@gmail.com").withAddress("michegan ave").build(); + fiona = new PersonBuilder().withName("Fiona Kunz").withPhone("9482427") + .withEmail("lydia@gmail.com").withAddress("little tokyo").build(); + george = new PersonBuilder().withName("George Best").withPhone("9482442") + .withEmail("anna@google.com").withAddress("4th street").build(); + + // Manually added + hoon = new PersonBuilder().withName("Hoon Meier").withPhone("8482424") + .withEmail("stefan@mail.com").withAddress("little india").build(); + ida = new PersonBuilder().withName("Ida Mueller").withPhone("8482131") + .withEmail("hans@google.com").withAddress("chicago ave").build(); } catch (IllegalValueException e) { e.printStackTrace(); assert false : "not possible"; @@ -35,7 +43,6 @@ public TypicalTestPersons() { } public static void loadAddressBookWithSampleData(AddressBook ab) { - try { ab.addPerson(new Person(alice)); ab.addPerson(new Person(benson)); @@ -53,7 +60,7 @@ public TestPerson[] getTypicalPersons() { return new TestPerson[]{alice, benson, carl, daniel, elle, fiona, george}; } - public AddressBook getTypicalAddressBook(){ + public AddressBook getTypicalAddressBook() { AddressBook ab = new AddressBook(); loadAddressBookWithSampleData(ab); return ab; From 38a5a4dd871a6f58c673131992d68b9675ff6fba Mon Sep 17 00:00:00 2001 From: "Damith C. Rajapakse" Date: Thu, 13 Oct 2016 09:53:08 +0800 Subject: [PATCH 014/754] Add tests for StringUtil::containsWordIgnoreCase --- .../address/commons/util/StringUtil.java | 33 +++++-- .../seedu/address/model/ModelManager.java | 2 +- .../address/commons/util/StringUtilTest.java | 86 +++++++++++++++++++ 3 files changed, 114 insertions(+), 7 deletions(-) diff --git a/src/main/java/seedu/address/commons/util/StringUtil.java b/src/main/java/seedu/address/commons/util/StringUtil.java index 13ad8bfd83d5..53e773c790b1 100644 --- a/src/main/java/seedu/address/commons/util/StringUtil.java +++ b/src/main/java/seedu/address/commons/util/StringUtil.java @@ -2,17 +2,38 @@ import java.io.PrintWriter; import java.io.StringWriter; -import java.util.Arrays; -import java.util.List; /** * Helper functions for handling strings. */ public class StringUtil { - public static boolean containsIgnoreCase(String source, String query) { - String[] split = source.toLowerCase().split("\\s+"); - List strings = Arrays.asList(split); - return strings.stream().filter(s -> s.equals(query.toLowerCase())).count() > 0; + + /** + * Returns true if the {@code sentence} contains the {@code word}. + * Ignores case, but a full word match is required. + *
examples:
+     *       containsWordIgnoreCase("ABc def", "abc") == true
+     *       containsWordIgnoreCase("ABc def", "DEF") == true
+     *       containsWordIgnoreCase("ABc def", "AB") == false //not a full word match
+     *       
+ * @param sentence cannot be null + * @param word cannot be null, cannot be empty, must be a single word + */ + public static boolean containsWordIgnoreCase(String sentence, String word) { + assert word != null : "Word parameter cannot be null"; + assert sentence != null : "Sentence parameter cannot be null"; + + String preppedWord = word.trim().toLowerCase(); + assert !preppedWord.isEmpty() : "Word parameter cannot be empty"; + assert preppedWord.split("\\s+").length == 1 : "Word parameter should be a single word"; + + String preppedSentence = sentence.toLowerCase(); + String[] wordsInPreppedSentence = preppedSentence.split("\\s+"); + + for(String wordInSentence: wordsInPreppedSentence){ + if (wordInSentence.equals(preppedWord)) return true; + } + return false; } /** diff --git a/src/main/java/seedu/address/model/ModelManager.java b/src/main/java/seedu/address/model/ModelManager.java index da5f472f6d87..f77b3987c020 100644 --- a/src/main/java/seedu/address/model/ModelManager.java +++ b/src/main/java/seedu/address/model/ModelManager.java @@ -139,7 +139,7 @@ private class NameQualifier implements Qualifier { @Override public boolean run(ReadOnlyPerson person) { return nameKeyWords.stream() - .filter(keyword -> StringUtil.containsIgnoreCase(person.getName().fullName, keyword)) + .filter(keyword -> StringUtil.containsWordIgnoreCase(person.getName().fullName, keyword)) .findAny() .isPresent(); } diff --git a/src/test/java/seedu/address/commons/util/StringUtilTest.java b/src/test/java/seedu/address/commons/util/StringUtilTest.java index ba54951c6b8e..fddfa881b560 100644 --- a/src/test/java/seedu/address/commons/util/StringUtilTest.java +++ b/src/test/java/seedu/address/commons/util/StringUtilTest.java @@ -16,6 +16,8 @@ public class StringUtilTest { @Rule public ExpectedException thrown = ExpectedException.none(); + //---------------- Tests for isUnsignedPositiveInteger -------------------------------------- + @Test public void isUnsignedPositiveInteger() { @@ -47,6 +49,90 @@ public void isUnsignedPositiveInteger() { assertTrue(StringUtil.isUnsignedInteger("10")); } + + //---------------- Tests for containsWordIgnoreCase -------------------------------------- + + /* + * Invalid equivalence partitions for word: null, empty, multiple words + * Invalid equivalence partitions for sentence: null + * The four test cases below test one invalid input at a time. + */ + + @Test + public void containsWordIgnoreCase_nullWord_exceptionThrown(){ + assertExceptionThrown("typical sentence", null, "Word parameter cannot be null"); + } + + private void assertExceptionThrown(String sentence, String word, String errorMessage) { + thrown.expect(AssertionError.class); + thrown.expectMessage(errorMessage); + StringUtil.containsWordIgnoreCase(sentence, word); + } + + @Test + public void containsWordIgnoreCase_emptyWord_exceptionThrown(){ + assertExceptionThrown("typical sentence", " ", "Word parameter cannot be empty"); + } + + @Test + public void containsWordIgnoreCase_multipleWords_exceptionThrown(){ + assertExceptionThrown("typical sentence", "aaa BBB", "Word parameter should be a single word"); + } + + @Test + public void containsWordIgnoreCase_nullSentence_exceptionThrown(){ + assertExceptionThrown(null, "abc", "Sentence parameter cannot be null"); + } + + /* + * Valid equivalence partitions for word: + * - any word + * - word containing symbols/numbers + * - word with leading/trailing spaces + * + * Valid equivalence partitions for sentence: + * - empty string + * - one word + * - multiple words + * - sentence with extra spaces + * + * Possible scenarios returning true: + * - matches first word in sentence + * - last word in sentence + * - middle word in sentence + * - matches multiple words + * + * Possible scenarios returning false: + * - query word matches part of a sentence word + * - sentence word matches part of the query word + * + * The test method below tries to verify all above with a reasonably low number of test cases. + */ + + @Test + public void containsWordIgnoreCase_validInputs_correctResult(){ + + // Empty sentence + assertFalse(StringUtil.containsWordIgnoreCase("","abc")); //boundary case + assertFalse(StringUtil.containsWordIgnoreCase(" ","123")); + + // Matches a partial word only + assertFalse(StringUtil.containsWordIgnoreCase("aaa bbb ccc","bb")); // Sentence word bigger than query word + assertFalse(StringUtil.containsWordIgnoreCase("aaa bbb ccc","bbbb")); // Query word bigger than sentence word + + // Matches word in the sentence, different upper/lower case letters + assertTrue(StringUtil.containsWordIgnoreCase("aaa bBb ccc","Bbb")); // First word (boundary case) + assertTrue(StringUtil.containsWordIgnoreCase("aaa bBb ccc@1","CCc@1")); // Last word (boundary case) + assertTrue(StringUtil.containsWordIgnoreCase(" AAA bBb ccc ","aaa")); // Sentence has extra spaces + assertTrue(StringUtil.containsWordIgnoreCase("Aaa","aaa")); // Only one word in sentence (boundary case) + assertTrue(StringUtil.containsWordIgnoreCase("aaa bbb ccc"," ccc ")); // Leading/trailing spaces + + // Matches multiple words in sentence + assertTrue(StringUtil.containsWordIgnoreCase("AAA bBb ccc bbb","bbB")); + } + + //---------------- Tests for getDetails -------------------------------------- + @Test public void getDetails_exceptionGiven(){ assertThat(StringUtil.getDetails(new FileNotFoundException("file not found")), From 8dd845ff7ad1762b8cba9cf00c17731f4815f1f6 Mon Sep 17 00:00:00 2001 From: "Damith C. Rajapakse" Date: Thu, 13 Oct 2016 12:47:27 +0800 Subject: [PATCH 015/754] Optimize StringUtil::containsWordIgnoreCase --- .../seedu/address/commons/util/StringUtil.java | 6 +++--- .../address/commons/util/StringUtilTest.java | 15 +++++++++------ 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/main/java/seedu/address/commons/util/StringUtil.java b/src/main/java/seedu/address/commons/util/StringUtil.java index 53e773c790b1..1ba904dcd1c2 100644 --- a/src/main/java/seedu/address/commons/util/StringUtil.java +++ b/src/main/java/seedu/address/commons/util/StringUtil.java @@ -23,15 +23,15 @@ public static boolean containsWordIgnoreCase(String sentence, String word) { assert word != null : "Word parameter cannot be null"; assert sentence != null : "Sentence parameter cannot be null"; - String preppedWord = word.trim().toLowerCase(); + String preppedWord = word.trim(); assert !preppedWord.isEmpty() : "Word parameter cannot be empty"; assert preppedWord.split("\\s+").length == 1 : "Word parameter should be a single word"; - String preppedSentence = sentence.toLowerCase(); + String preppedSentence = sentence; String[] wordsInPreppedSentence = preppedSentence.split("\\s+"); for(String wordInSentence: wordsInPreppedSentence){ - if (wordInSentence.equals(preppedWord)) return true; + if (wordInSentence.equalsIgnoreCase(preppedWord)) return true; } return false; } diff --git a/src/test/java/seedu/address/commons/util/StringUtilTest.java b/src/test/java/seedu/address/commons/util/StringUtilTest.java index fddfa881b560..4deda21b20a9 100644 --- a/src/test/java/seedu/address/commons/util/StringUtilTest.java +++ b/src/test/java/seedu/address/commons/util/StringUtilTest.java @@ -25,7 +25,7 @@ public void isUnsignedPositiveInteger() { assertFalse(StringUtil.isUnsignedInteger(null)); // EP: empty strings - assertFalse(StringUtil.isUnsignedInteger("")); //boundary value + assertFalse(StringUtil.isUnsignedInteger("")); // Boundary value assertFalse(StringUtil.isUnsignedInteger(" ")); // EP: not a number @@ -40,12 +40,11 @@ public void isUnsignedPositiveInteger() { assertFalse(StringUtil.isUnsignedInteger("+1")); // EP: numbers with white space - assertFalse(StringUtil.isUnsignedInteger(" 10")); - assertFalse(StringUtil.isUnsignedInteger("10 ")); - assertFalse(StringUtil.isUnsignedInteger("1 0")); + assertFalse(StringUtil.isUnsignedInteger(" 10 ")); // Leading/trailing spaces + assertFalse(StringUtil.isUnsignedInteger("1 0")); // Spaces in the middle // EP: valid numbers, should return true - assertTrue(StringUtil.isUnsignedInteger("1")); //boundary value + assertTrue(StringUtil.isUnsignedInteger("1")); // Boundary value assertTrue(StringUtil.isUnsignedInteger("10")); } @@ -113,7 +112,7 @@ public void containsWordIgnoreCase_nullSentence_exceptionThrown(){ public void containsWordIgnoreCase_validInputs_correctResult(){ // Empty sentence - assertFalse(StringUtil.containsWordIgnoreCase("","abc")); //boundary case + assertFalse(StringUtil.containsWordIgnoreCase("","abc")); // Boundary case assertFalse(StringUtil.containsWordIgnoreCase(" ","123")); // Matches a partial word only @@ -133,6 +132,10 @@ public void containsWordIgnoreCase_validInputs_correctResult(){ //---------------- Tests for getDetails -------------------------------------- + /* + * Equivalence Partitions: null, valid throwable object + */ + @Test public void getDetails_exceptionGiven(){ assertThat(StringUtil.getDetails(new FileNotFoundException("file not found")), From 7b432582f6d4bd2cf8344bc8d8f01de80da0a474 Mon Sep 17 00:00:00 2001 From: "Damith C. Rajapakse" Date: Thu, 13 Oct 2016 13:08:52 +0800 Subject: [PATCH 016/754] Fix checkstyle problems --- .../address/commons/util/StringUtil.java | 2 +- .../address/commons/util/StringUtilTest.java | 20 +++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/main/java/seedu/address/commons/util/StringUtil.java b/src/main/java/seedu/address/commons/util/StringUtil.java index 1ba904dcd1c2..fd7fb71516cb 100644 --- a/src/main/java/seedu/address/commons/util/StringUtil.java +++ b/src/main/java/seedu/address/commons/util/StringUtil.java @@ -30,7 +30,7 @@ public static boolean containsWordIgnoreCase(String sentence, String word) { String preppedSentence = sentence; String[] wordsInPreppedSentence = preppedSentence.split("\\s+"); - for(String wordInSentence: wordsInPreppedSentence){ + for (String wordInSentence: wordsInPreppedSentence){ if (wordInSentence.equalsIgnoreCase(preppedWord)) return true; } return false; diff --git a/src/test/java/seedu/address/commons/util/StringUtilTest.java b/src/test/java/seedu/address/commons/util/StringUtilTest.java index 4deda21b20a9..cea531819726 100644 --- a/src/test/java/seedu/address/commons/util/StringUtilTest.java +++ b/src/test/java/seedu/address/commons/util/StringUtilTest.java @@ -112,22 +112,22 @@ public void containsWordIgnoreCase_nullSentence_exceptionThrown(){ public void containsWordIgnoreCase_validInputs_correctResult(){ // Empty sentence - assertFalse(StringUtil.containsWordIgnoreCase("","abc")); // Boundary case - assertFalse(StringUtil.containsWordIgnoreCase(" ","123")); + assertFalse(StringUtil.containsWordIgnoreCase("", "abc")); // Boundary case + assertFalse(StringUtil.containsWordIgnoreCase(" ", "123")); // Matches a partial word only - assertFalse(StringUtil.containsWordIgnoreCase("aaa bbb ccc","bb")); // Sentence word bigger than query word - assertFalse(StringUtil.containsWordIgnoreCase("aaa bbb ccc","bbbb")); // Query word bigger than sentence word + assertFalse(StringUtil.containsWordIgnoreCase("aaa bbb ccc", "bb")); // Sentence word bigger than query word + assertFalse(StringUtil.containsWordIgnoreCase("aaa bbb ccc", "bbbb")); // Query word bigger than sentence word // Matches word in the sentence, different upper/lower case letters - assertTrue(StringUtil.containsWordIgnoreCase("aaa bBb ccc","Bbb")); // First word (boundary case) - assertTrue(StringUtil.containsWordIgnoreCase("aaa bBb ccc@1","CCc@1")); // Last word (boundary case) - assertTrue(StringUtil.containsWordIgnoreCase(" AAA bBb ccc ","aaa")); // Sentence has extra spaces - assertTrue(StringUtil.containsWordIgnoreCase("Aaa","aaa")); // Only one word in sentence (boundary case) - assertTrue(StringUtil.containsWordIgnoreCase("aaa bbb ccc"," ccc ")); // Leading/trailing spaces + assertTrue(StringUtil.containsWordIgnoreCase("aaa bBb ccc", "Bbb")); // First word (boundary case) + assertTrue(StringUtil.containsWordIgnoreCase("aaa bBb ccc@1", "CCc@1")); // Last word (boundary case) + assertTrue(StringUtil.containsWordIgnoreCase(" AAA bBb ccc ", "aaa")); // Sentence has extra spaces + assertTrue(StringUtil.containsWordIgnoreCase("Aaa", "aaa")); // Only one word in sentence (boundary case) + assertTrue(StringUtil.containsWordIgnoreCase("aaa bbb ccc", " ccc ")); // Leading/trailing spaces // Matches multiple words in sentence - assertTrue(StringUtil.containsWordIgnoreCase("AAA bBb ccc bbb","bbB")); + assertTrue(StringUtil.containsWordIgnoreCase("AAA bBb ccc bbb", "bbB")); } //---------------- Tests for getDetails -------------------------------------- From 9941eabb4bec0b081212312ba86e64a4608c5010 Mon Sep 17 00:00:00 2001 From: "Damith C. Rajapakse" Date: Thu, 13 Oct 2016 14:14:36 +0800 Subject: [PATCH 017/754] Add LO-TestCaseDesignHeuristics --- docs/LearningOutcomes.md | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/docs/LearningOutcomes.md b/docs/LearningOutcomes.md index eef949f387c5..3687909d5ff7 100644 --- a/docs/LearningOutcomes.md +++ b/docs/LearningOutcomes.md @@ -10,6 +10,7 @@ After studying this code and completing the corresponding exercises, you should 1. [Use Build Automation `[LO-BuildAutomation]`](#use-build-automation-lo-buildautomation) 1. [Use Continuous Integration `[LO-ContinuousIntegration]`](#use-continuous-integration-lo-continuousintegration) 1. [Use Code Coverage `[LO-CodeCoverage]`](#use-code-coverage-lo-codecoverage) +1. [Apply Test Case Design Heuristics `[LO-TestCaseDesignHeuristics]`](#apply-test-case-design-heuristics-lo-testcasedesignheuristics) ------------------------------------------------------------------------------------------------------ @@ -133,13 +134,22 @@ Note how our CI server [Travis uses Coveralls to report code coverage](UsingTrav ------------------------------------------------------------------------------------------------------ +## Apply Test Case Design Heuristics `[LO-TestCaseDesignHeuristics]` + +The [`StringUtilTest.java`](..\src\test\java\seedu\address\commons\util\StringUtilTest.java) class gives some examples +of how to use _Equivalence Classes_, _Boundary Value Analysis_, and _Test Input Combination Heuristics_ to improve +the efficiency and effectiveness of test cases. + + +#### Exercise: Apply Test Case Design Heuristics to other places + * Use the test case design heuristics mentioned above to improve test cases in other places. + +------------------------------------------------------------------------------------------------------ + {More to be added} * Integration testing * System testing * Acceptance testing (+dogfooding) -* Equivalence classes -* Boundary value analysis -* Test input combination * GUI test automation * Design patterns * Static analysis From daa496f6efac093e566451e6a2401739fdfb38f6 Mon Sep 17 00:00:00 2001 From: "Damith C. Rajapakse" Date: Thu, 13 Oct 2016 14:17:31 +0800 Subject: [PATCH 018/754] Fix broken link in LOs --- docs/LearningOutcomes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/LearningOutcomes.md b/docs/LearningOutcomes.md index 3687909d5ff7..d835f13dc3e2 100644 --- a/docs/LearningOutcomes.md +++ b/docs/LearningOutcomes.md @@ -136,7 +136,7 @@ Note how our CI server [Travis uses Coveralls to report code coverage](UsingTrav ## Apply Test Case Design Heuristics `[LO-TestCaseDesignHeuristics]` -The [`StringUtilTest.java`](..\src\test\java\seedu\address\commons\util\StringUtilTest.java) class gives some examples +The [`StringUtilTest.java`](../src/test/java/seedu/address/commons/util/StringUtilTest.java) class gives some examples of how to use _Equivalence Classes_, _Boundary Value Analysis_, and _Test Input Combination Heuristics_ to improve the efficiency and effectiveness of test cases. From ba7205071e402ab4e7b2035f23f5ae1b502d3b5f Mon Sep 17 00:00:00 2001 From: "Damith C. Rajapakse" Date: Thu, 13 Oct 2016 15:16:46 +0800 Subject: [PATCH 019/754] Refine LO-TestCaseDesignHeuristics --- docs/LearningOutcomes.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/LearningOutcomes.md b/docs/LearningOutcomes.md index d835f13dc3e2..0e0d7560c687 100644 --- a/docs/LearningOutcomes.md +++ b/docs/LearningOutcomes.md @@ -138,7 +138,8 @@ Note how our CI server [Travis uses Coveralls to report code coverage](UsingTrav The [`StringUtilTest.java`](../src/test/java/seedu/address/commons/util/StringUtilTest.java) class gives some examples of how to use _Equivalence Classes_, _Boundary Value Analysis_, and _Test Input Combination Heuristics_ to improve -the efficiency and effectiveness of test cases. +the efficiency and effectiveness of test cases testing the +[`StringUtil.java`](../src/main/java/seedu/address/commons/util/StringUtilTest.java) class. #### Exercise: Apply Test Case Design Heuristics to other places From 1927239e91a307bea7821f9ca5b96c5debf95601 Mon Sep 17 00:00:00 2001 From: "Damith C. Rajapakse" Date: Thu, 13 Oct 2016 15:18:31 +0800 Subject: [PATCH 020/754] Fix link to StringUtil --- docs/LearningOutcomes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/LearningOutcomes.md b/docs/LearningOutcomes.md index 0e0d7560c687..571bf1b07840 100644 --- a/docs/LearningOutcomes.md +++ b/docs/LearningOutcomes.md @@ -139,7 +139,7 @@ Note how our CI server [Travis uses Coveralls to report code coverage](UsingTrav The [`StringUtilTest.java`](../src/test/java/seedu/address/commons/util/StringUtilTest.java) class gives some examples of how to use _Equivalence Classes_, _Boundary Value Analysis_, and _Test Input Combination Heuristics_ to improve the efficiency and effectiveness of test cases testing the -[`StringUtil.java`](../src/main/java/seedu/address/commons/util/StringUtilTest.java) class. +[`StringUtil.java`](../src/main/java/seedu/address/commons/util/StringUtil.java) class. #### Exercise: Apply Test Case Design Heuristics to other places From 2034f1740c8d85b01835ec7241743c5c507d9935 Mon Sep 17 00:00:00 2001 From: Joshua Lee Date: Sat, 15 Oct 2016 15:39:02 +0800 Subject: [PATCH 021/754] [91] Separate CommandBox and ResultsDisplay Separate CommandBox and ResultsDisplay #91 --- docs/diagrams/UiComponentClassDiagram.pptx | Bin 0 -> 59263 bytes docs/images/UiClassDiagram.png | Bin 38175 -> 38003 bytes .../events/ui/NewResultAvailableEvent.java | 21 ++++++++ .../java/seedu/address/ui/CommandBox.java | 29 +++++------ .../java/seedu/address/ui/MainWindow.java | 25 +++++----- .../java/seedu/address/ui/ResultDisplay.java | 45 ++++++++++-------- src/main/resources/view/ResultDisplay.fxml | 11 +++-- 7 files changed, 80 insertions(+), 51 deletions(-) create mode 100644 docs/diagrams/UiComponentClassDiagram.pptx create mode 100644 src/main/java/seedu/address/commons/events/ui/NewResultAvailableEvent.java diff --git a/docs/diagrams/UiComponentClassDiagram.pptx b/docs/diagrams/UiComponentClassDiagram.pptx new file mode 100644 index 0000000000000000000000000000000000000000..70f3e1e3b55f78e7b47f97f5d0dea33c8afeca1e GIT binary patch literal 59263 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 z z_3ExNMnCPrxS3AZoLRS{K#hPlFea(%Kg;p^9YhZ>==#Khn@B}dL+@<|>dN?ubkWXX za1XW0sexC^X%9zLDk`1R3v)s>Cd?owqMt^cTxDAf5K;|hKIpAMw{(e;V*+kT?DMKa zvU6sDKBve7zynN_k4G44eF2w-Bv2R9eUf>nF?)+AP8BX2>=3~ZD<&KJ1)-62u#kq0 zRJ7GKaDRXmc|~18pO#O7Oou%VcL#o0?y_p~chi<`!!rC{hqE@OLpwexNf8esOlp1! z#kqgQ+!0^y{a9{;zlNdlHM&piiA!S`mDp_^81+r{dSe|Bcz#FjF$0N%hns+z3n__>ImcEny#PiVHK5^__eVCo&Tz}(F4dl zVWq>J^l2I%_=nAXuETLc$Tb^R699jTplb8`U3lT^x1QR`58vlw?nNM;6e(HcpX!xx zperi(96dNKOV5hTCZCo#Y^MnhP1*P737_Bm^IcdFrn`ljQ& z#|Jy*vHKZn|0SQMIvdm{dl*-;><^(DxS&#?j>~MGvc1}?rtp&RVL@J*hWq6HBpX>S zcbmzc>$w}a7KJFX|D(cctS`4l;XC9)O@1}lO%nZ^C+;bqdY_+1W_>H6dlPH0i&ggp zj5uW4KxNtm{U$(IM}qjJHlJ(?^lE*uLlE>C z0VsIf(Ki3*KHec(z4a6~tVJ!v!QxxD@#2?d0F*;+65P?@CYFaTmxF?5r0m=WhO?)& z-(gYI03Uk(y>2fQ*cMK20qW3f74!tS#XI18la`W-O0Y$Z^s5YzrP%V)U zv-CvQ$=$4#GXTPbEZ&yW(RrHpgLw%@ux3O4Qs9?+p6h+bQ)>iYda~MnDQo*co5Bx? z6s`4duCvE>DncF{48ME@_%zVEdu65u^pjb)b}Ie`+@N^w!+Pg~_y?~$_X-M)`SrO_ z{Ks#^Qa5X+xrkctxe(}NB`v*0%>k~qA+8?%c6*pQ$Zz=emhT1Jfw3%e_aDz4WSLkc zd)JHtc|j~g3tZWah%$^-J9jQ9zghd3_q(h(^+NC>dWKl0oin>MYTynm+op5^fT8H> zIoY;kYVI!bpL7ITD^#yvf6jq)5m$Spb9~0B{RxFyF2~|D<13mGhtHtK%#`Jy57f9CeyjNTc6{K; z#NOXQORW&72jw)sDV?$Kk8J%V{jazVc!%LyV(AC2nqyBWT*%28t$LFw2V(2jmjr0t zXqsE?8R@L%*rp7x7O$9~H|MhBWbgW4w66qYwPF zKDz?S7<_#(wj~fwQF)vKQq>C(Q$=jZq$>V?Yt0#f1H8Mrdr!;zrp^l6%EpHQfp6*k z#g`^muR3Mwfuz^ZgBm2Mpyr%<4&|30ca$hlSWyY-|S#AYTE+G#8Bi9i*k8<7`fTHFwYx5@4@&x zXtqH)gyFO`-M`)`@xEBdp!Sj8T}0#}#&mV6LRGZidSdBIkz^7jTo`yUZw|0OTVX0I z^2boR#IW$0^m1k7N$g6mD{M`^=~-=$NUw0;VO&HH`BAp_HCz_PpqN zQjuknqzouu7I?|2j6^K$h@23XVn5OqdU3)J1aD9~gu^+^OM{6WsD|lj4sj(T?u;P` z);}8>K>luTz$y?76{_MLXTP@X!o(Q6 zL?#=NSKxn=1W**|9TSwM=I9>(Se`( zpPbUyG)HBDbaN5haNOd(j1e)~h<|w>i<(HVeKgG{#=m>vy!>U>|rNQ7UZmiz=+sk}EiAQcCC> z+zjNPtBkS@L}ioGgk)MwzL?m)d7Rqkj7sQC<@>CHdkr?_%0AQJ)aang`*@IDx=Bgq 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� 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 Cn!Jbr literal 38175 zcmaHT2RzjOA3rHa;n1+pXlNnXoE4(XCNeH7A$y&9bU35XqRfhn$S5J>tgMugadOrf z8E2f$8TbEu$oH%N@B9Bh9`*TtyL*4$@7I36UeDM2ePMb!>Wl|D4^mN4F<#M7y-r27 zA4WyBFM^I1_~crj<{I!HYS-)Pm-Z=D`qcvepm)+RbfuzVV+H?GTPObnUZLV}Q!{Y8 z;dsx@)6B(+O54W5#nBb`7oYCEdo~tUsA&mjDyrwnS5%d6B73I$yqvgK%*MSoU!=d+ z|LnZg%|`i@b8{O1oO0!b)UDjJpNV&PMV4jr%buK#QM-D3N-rkkxYv`TwXE(>o~kwK zwjCu3RB2wUHQKKfaD;wHAr#H$%uGekydpspz(>UzK*!9!;o;BdF^rS%b2W>cc_osi zV3n1gUYZUO8=P%YnDJif)Sul4P)$WO(>fZzd2glRalOyxr{u*){n^C1z9SB8#L~82 zId4})(QIA22{zMFZNVFPL;k^J*ViJ4?@^9Mql$hDSz+^B3l=}BD96B=F4lb4x6mIM zSkk9pE66L9%(Z+Uj>A@IGi_Y>-Xoj>A)#&Y>)t-;*vrU<)b0z!^_j=N=5!stKVDfl z$pE}>`6+)Qe&O(XDD$f~IH@IT2e}gdJAElq8-3Vcv#hW(823ZODefQOQkBi$H(sJ_ z`&TsUbYPE}%7+}h4x-so(44&9=?;F0q`|i1+%w$QYuU~Mg9Av^Ls|LfxT&iqj!w9A zqK26XRTd8Z5_6{zN#JDWCv~fs->x{+-I@^;X?;oGru=1fB#I6SoGuy)M`eiv3bMDmP&+m)hdOiI5Yn#Q!L%~=L6ltkE-aPL74Mj z-Fd(@QXiJ})1(_S!|0&g)8GeGSHzd$7NXTOgus;T5qxLv{jPKDE0I`oud@JWyse4} z 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 - + - - + + + +