diff --git a/.travis.yml b/.travis.yml index 8faab01..658d4f9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,8 +13,7 @@ addons: - mysql-client before_install: - - chmod +x pandamonium-theorem-prover/gradlew - - cd pandamonium-theorem-prover + - chmod +x gradlew before_script: - mysql_upgrade --force -uroot @@ -31,11 +30,19 @@ stages: jobs: include: - - stage: Load Database + - stage: "Load Database" script: ./gradlew loaddb - - stage: Build + - stage: "Build" script: ./gradlew build - - stage: Unit Tests + - stage: "Unit Tests" script: ./gradlew test - - stage: Integration Tests - script: ./gradlew integrationTest + - stage: "Integration Tests" + script: + - | + ./gradlew :persistence:startPersistenceApi & + APP_PID=$! + - | + ./gradlew integrationTest + - kill $APP_PID + - stage: "Sonar Analysis" + script: ./gradlew sonar diff --git a/README.md b/README.md index dc1251a..1f5edb6 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,54 @@ # Pandamonium Theorem Prover -This is the main repository for the Technical Software Project +This project contains several different modules for different parts of the system. + +* [persistence](persistence/README.md) +* [web-server](src/README.md) + +## Getting Started + +1. Clone the project. `git clone git@github.com:atusa17/tsp.git` +2. Open the `pandamonium-theorem-prover` folder with IntelliJ. Use auto-import for a Gradle project. +3. Individual Components have their own README. Continue there. + +## Running the Tests + +This project is unit tested with JUnit and Mockito. You can run the unit tests with IntelliJ or Gradle. To run them with IntelliJ, browse to any `*Test.java` file and use IntelliJ's built-in test runner to run or debug the test. To run all the unit tests with Gradle: + +* On a Linux or Macintosh machine: + + ```$ ./gradlew test``` + +* On a Windows machine: + + ```$ gradlew.bat test``` + +You can also test modules individually: + +* On a Linux or Macintosh machine: + + ```$ ./gradlew persistence:test``` + +* On a Windows machine: + + ```$ gradlew.bat persistence:test``` + +## Integration Tests + +To run the integration tests with IntelliJ, browse to any `*Test.java` file residing in any module name `integrationTest` and use IntelliJ's built-in test runner to run or debug the test. To run all the integration tests with Gradle: + +* On a Linux or Macintosh machine: + + ```$ ./gradlew integrationTest``` + +* On a Windows machine + + ```$ gradlew.bat integrationTest``` + +## Built with + +* [Spring Boot](https://projects.spring.io/spring-boot/) - Web framework +* [Spring Web Flow](https://projects.spring.io/spring-webflow/) - MVC framework +* [Gradle](https://gradle.org/) - Dependency management +* [JUnit](http://junit.org/junit4/) - Unit tests +* [Mockito](http://site.mockito.org/) - Mock objects library +* [Lombok](https://projectlombok.org/) - Boilerplate Code Generator diff --git a/build.gradle b/build.gradle index 6690226..1402ea7 100644 --- a/build.gradle +++ b/build.gradle @@ -70,7 +70,6 @@ subprojects { testCompile group: 'junit', name: 'junit', version: '4.11' testCompile group: 'junit', name: 'junit', version: '4.12' testCompile('org.mockito:mockito-core:1.10.19') {exclude(group: 'org.hamcrest')} - } test { @@ -107,7 +106,11 @@ dependencies { compile 'org.slf4j:slf4j-api:1.7.22' compile "joda-time:joda-time:2.2" compile group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: '2.0.5.RELEASE' + compile('org.springframework.boot:spring-boot-starter-web','org.apache.tomcat.embed:tomcat-embed-jasper' + ,'javax.servlet:jstl') + testCompile 'javax.el:javax.el-api:3.0.0' + testCompile group: 'org.springframework.boot', name: 'spring-boot-starter-test', version: '2.1.3.RELEASE' testCompile group: 'junit', name: 'junit', version: '4.12' testCompile "org.springframework:spring-test:5.0.9.RELEASE" testCompile('org.mockito:mockito-core:1.10.19') {exclude(group: 'org.hamcrest')} @@ -136,13 +139,6 @@ testSets { integrationTest } -compileKotlin { - kotlinOptions.jvmTarget = "1.8" -} -compileTestKotlin { - kotlinOptions.jvmTarget = "1.8" -} - wrapper { gradleVersion = '5.2.1' distributionType = Wrapper.DistributionType.ALL diff --git a/gradlew~Stashed changes b/gradlew~Stashed changes deleted file mode 100755 index 4453cce..0000000 --- a/gradlew~Stashed changes +++ /dev/null @@ -1,172 +0,0 @@ -#!/usr/bin/env sh - -############################################################################## -## -## Gradle start up script for UN*X -## -############################################################################## - -# Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null - -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" - -warn ( ) { - echo "$*" -} - -die ( ) { - echo - echo "$*" - echo - exit 1 -} - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi -fi - -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi - -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi - # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" - fi - i=$((i+1)) - done - case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac -fi - -# Escape application args -save ( ) { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=$(save "$@") - -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" - -# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong -if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then - cd "$(dirname "$0")" -fi - -exec "$JAVACMD" "$@" diff --git a/out/production/resources/application.properties b/out/production/resources/application.properties new file mode 100644 index 0000000..a8a0755 --- /dev/null +++ b/out/production/resources/application.properties @@ -0,0 +1,3 @@ +spring.mvc.view.prefix:/WEB-INF/jsp/ +spring.mvc.view.suffix:.jsp +server.port=8090 \ No newline at end of file diff --git a/persistence/README.md b/persistence/README.md new file mode 100644 index 0000000..4258ce9 --- /dev/null +++ b/persistence/README.md @@ -0,0 +1,61 @@ +## PTP Persistence API + +The PTP Persistence API is the web API for accessing the theorems database. + + + +## Running from IntelliJ + +* Create a new run configuration in IntelliJ. + + ``` + Name: "PTP Persistence API Tomcat" + Application Server: Tomcat (8.5.12) + HTTP Port: 8090 + JMX Port: 1090 + Deployment tabe: Deploy persistence-api.war (exploded) + ``` +## Running the Tests + +This project is unit tested with JUnit and Mockito. You can run the unit tests with IntelliJ or Gradle. To run them with IntelliJ, browse to any `*Test.java` file and use IntelliJ's built-in test runner to run or debug the test. To run all the unit tests with Gradle: + +* On a Linux or Macintosh machine: + + ```$ ./gradlew test``` + +* On a Windows machine: + + ```$ gradlew.bat test``` + +You can also test modules individually: + +* On a Linux or Macintosh machine: + + ```$ ./gradlew persistence:test``` + +* On a Windows machine: + + ```$ gradlew.bat persistence:test``` + +## Integration Tests + +To run the integration tests with IntelliJ, browse to any `*Test.java` file residing in any module name `integrationTest` and use IntelliJ's built-in test runner to run or debug the test. To run all the integration tests with Gradle: + +* On a Linux or Macintosh machine: + + ```$ ./gradlew integrationTest``` + +* On a Windows machine + + ```$ gradlew.bat integrationTest``` + +## Built with + +* [Spring Boot](https://projects.spring.io/spring-boot/) - Web framework +* [Spring Web Flow](https://projects.spring.io/spring-webflow/) - MVC framework +* [Spring Data](https://spring.io/projects/spring-data/) - Persistence framework +* [Gradle](https://gradle.org/) - Dependency management +* [JUnit](http://junit.org/junit4/) - Unit tests +* [Mockito](http://site.mockito.org/) - Mock objects library +* [Lombok](https://projectlombok.org/) - Boilerplate Code Generator +* [Hibernate ORM](http://hibernate.org/orm/) - Object/Relational Mapping diff --git a/persistence/build.gradle b/persistence/build.gradle index b832e7e..811725d 100644 --- a/persistence/build.gradle +++ b/persistence/build.gradle @@ -50,3 +50,11 @@ task loadDb(type: Exec, group: 'Verification', description: 'Reloads the local d commandLine=['cmd','/c','loaddb.bat'] } } + +task startPersistenceApi(type: JavaExec, description: 'Starts the Persistence API') { + dependsOn 'loadDb' + dependsOn 'build' + classpath = files('build/libs/persistence-1.0.jar') + classpath += sourceSets.main.runtimeClasspath + main = 'edu.msudenver.tsp.persistence.PersistenceApi' +} diff --git a/persistence/scripts/mysql/local_development.sql b/persistence/scripts/mysql/local_development.sql index 1f885cc..27005d4 100644 --- a/persistence/scripts/mysql/local_development.sql +++ b/persistence/scripts/mysql/local_development.sql @@ -22,4 +22,29 @@ name varchar(200) not null, definition json not null, notation json, version int default 1 +); +create table theorems ( +id int not null auto_increment primary key unique, +name varchar(512) not null, +theorem varchar(1024) not null, +theorem_type varchar(20) not null, +branch varchar(512) not null, +referenced_definitions json, +referenced_theorems json, +proven_status boolean default false, +version int default 1 +); +CREATE TABLE proofs +( + id INT NOT NULL AUTO_INCREMENT, + theorem_name VARCHAR(512) NOT NULL, + proof VARCHAR(4096) NOT NULL, + branch VARCHAR(512) NOT NULL, + theorem INT NOT NULL, + referenced_definitions JSON, + referenced_theorems JSON, + date_added DATE, + last_updated DATE, + version INT DEFAULT 1, + PRIMARY KEY (id) ); \ No newline at end of file diff --git a/persistence/src/integrationTest/java/edu/msudenver/tsp/persistence/AccountsIntegrationTest.java b/persistence/src/integrationTest/java/edu/msudenver/tsp/persistence/AccountsIntegrationTest.java index b30a252..42cce04 100644 --- a/persistence/src/integrationTest/java/edu/msudenver/tsp/persistence/AccountsIntegrationTest.java +++ b/persistence/src/integrationTest/java/edu/msudenver/tsp/persistence/AccountsIntegrationTest.java @@ -1,6 +1,6 @@ package edu.msudenver.tsp.persistence; -import edu.msudenver.tsp.persistence.dto.AccountDto; +import edu.msudenver.tsp.persistence.dto.Account; import edu.msudenver.tsp.persistence.repository.AccountsRepository; import org.junit.Test; import org.junit.runner.RunWith; @@ -19,8 +19,8 @@ public class AccountsIntegrationTest { @Test public void testCRUDFunctionality() { - final AccountDto accountDto = createAccount(); - final AccountDto savedAccount = accountsRepository.save(accountDto); + final Account account = createAccount(); + final Account savedAccount = accountsRepository.save(account); assertNotNull(savedAccount); assertEquals(Integer.valueOf(0), savedAccount.getVersion()); @@ -29,29 +29,29 @@ public class AccountsIntegrationTest { assertEquals("Test username", savedAccount.getUsername()); assertEquals("test password", savedAccount.getPassword()); - assertTrue(savedAccount.isAdministratorStatus()); + assertTrue(savedAccount.getAdministratorStatus()); savedAccount.setPassword("Test Update"); - final AccountDto updatedAccount = accountsRepository.save(savedAccount); + final Account updatedAccount = accountsRepository.save(savedAccount); assertEquals("Test username", savedAccount.getUsername()); assertEquals("Test Update", savedAccount.getPassword()); - assertTrue(savedAccount.isAdministratorStatus()); + assertTrue(savedAccount.getAdministratorStatus()); assertEquals(updatedAccount.getId(), id); - accountsRepository.delete(accountDto); - final Optional deletedAccount = accountsRepository.findById(id); + accountsRepository.delete(account); + final Optional deletedAccount = accountsRepository.findById(id); assertFalse(deletedAccount.isPresent()); } - private AccountDto createAccount() { - final AccountDto accountDto = new AccountDto(); - accountDto.setUsername("Test username"); - accountDto.setPassword("test password"); - accountDto.setAdministratorStatus(true); + private Account createAccount() { + final Account account = new Account(); + account.setUsername("Test username"); + account.setPassword("test password"); + account.setAdministratorStatus(true); - return accountDto; + return account; } } diff --git a/persistence/src/integrationTest/java/edu/msudenver/tsp/persistence/DefinitionsIntegrationTest.java b/persistence/src/integrationTest/java/edu/msudenver/tsp/persistence/DefinitionsIntegrationTest.java index 93db37e..2c91789 100644 --- a/persistence/src/integrationTest/java/edu/msudenver/tsp/persistence/DefinitionsIntegrationTest.java +++ b/persistence/src/integrationTest/java/edu/msudenver/tsp/persistence/DefinitionsIntegrationTest.java @@ -1,8 +1,6 @@ package edu.msudenver.tsp.persistence; import edu.msudenver.tsp.persistence.dto.Definition; -import edu.msudenver.tsp.persistence.dto.DefinitionDto; -import edu.msudenver.tsp.persistence.dto.Notation; import edu.msudenver.tsp.persistence.repository.DefinitionRepository; import org.junit.Test; import org.junit.runner.RunWith; @@ -23,8 +21,8 @@ public class DefinitionsIntegrationTest { @Test public void testCRUDFunctionality() { - final DefinitionDto definitionDto = createDefinition(); - final DefinitionDto savedDefinition = definitionRepository.save(definitionDto); + final Definition definition = createDefinition(); + final Definition savedDefinition = definitionRepository.save(definition); assertNotNull(savedDefinition); assertEquals(Integer.valueOf(0), savedDefinition.getVersion()); @@ -35,8 +33,8 @@ public class DefinitionsIntegrationTest { assertNotNull(savedDefinition.getDefinition()); assertNotNull(savedDefinition.getNotation()); - final List definitionsList = savedDefinition.getDefinition().getDefinitions(); - final List notationList = savedDefinition.getNotation().getNotations(); + final List definitionsList = savedDefinition.getDefinition(); + final List notationList = savedDefinition.getNotation(); assertEquals(2, definitionsList.size()); assertEquals(1, notationList.size()); @@ -46,14 +44,14 @@ public class DefinitionsIntegrationTest { savedDefinition.setName("Test Update"); - final DefinitionDto updatedDefinition = definitionRepository.save(savedDefinition); + final Definition updatedDefinition = definitionRepository.save(savedDefinition); assertEquals("Test Update", updatedDefinition.getName()); assertNotNull(updatedDefinition.getDefinition()); assertNotNull(updatedDefinition.getNotation()); - final List updatedDefinitionsList = updatedDefinition.getDefinition().getDefinitions(); - final List updatedNotationsList = updatedDefinition.getNotation().getNotations(); + final List updatedDefinitionsList = updatedDefinition.getDefinition(); + final List updatedNotationsList = updatedDefinition.getNotation(); assertEquals(2, updatedDefinitionsList.size()); assertEquals(1, updatedNotationsList.size()); @@ -63,29 +61,23 @@ public class DefinitionsIntegrationTest { assertEquals(id, updatedDefinition.getId()); definitionRepository.delete(updatedDefinition); - final Optional deletedDefinition = definitionRepository.findById(id); + final Optional deletedDefinition = definitionRepository.findById(id); assertFalse(deletedDefinition.isPresent()); } - private DefinitionDto createDefinition() { + private Definition createDefinition() { final List definitionList = new ArrayList<>(); definitionList.add("Test definition 1"); definitionList.add("Test definition 2"); - final Definition definition = new Definition(); - definition.setDefinitions(definitionList); - final List notationList = new ArrayList<>(); notationList.add("\\testLaTeX"); - final Notation notation = new Notation(); - notation.setNotations(notationList); + final Definition definition = new Definition(); + definition.setName("Test Name"); + definition.setDefinition(definitionList); + definition.setNotation(notationList); - final DefinitionDto definitionDto = new DefinitionDto(); - definitionDto.setName("Test Name"); - definitionDto.setDefinition(definition); - definitionDto.setNotation(notation); - - return definitionDto; + return definition; } } diff --git a/persistence/src/integrationTest/java/edu/msudenver/tsp/persistence/PersistenceTestConfig.java b/persistence/src/integrationTest/java/edu/msudenver/tsp/persistence/PersistenceTestConfig.java index 7427fa2..9680dbe 100644 --- a/persistence/src/integrationTest/java/edu/msudenver/tsp/persistence/PersistenceTestConfig.java +++ b/persistence/src/integrationTest/java/edu/msudenver/tsp/persistence/PersistenceTestConfig.java @@ -56,7 +56,7 @@ public class PersistenceTestConfig { .create() .username("panda") .password("secret") - .url("jdbc:mysql://127.0.0.1:3306/pandamonium?autoReconnect=true&useSSL=false") + .url("jdbc:mysql://127.0.0.1:3306/pandamonium?autoReconnect=true&useSSL=false&serverTimezone=UTC") .driverClassName("com.mysql.cj.jdbc.Driver") .build(); } diff --git a/persistence/src/integrationTest/java/edu/msudenver/tsp/persistence/ProofsIntegrationTest.java b/persistence/src/integrationTest/java/edu/msudenver/tsp/persistence/ProofsIntegrationTest.java new file mode 100644 index 0000000..b18c47d --- /dev/null +++ b/persistence/src/integrationTest/java/edu/msudenver/tsp/persistence/ProofsIntegrationTest.java @@ -0,0 +1,93 @@ +package edu.msudenver.tsp.persistence; + +import edu.msudenver.tsp.persistence.dto.Proof; +import edu.msudenver.tsp.persistence.repository.ProofRepository; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Optional; + +import static org.junit.Assert.*; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes = PersistenceTestConfig.class) +public class ProofsIntegrationTest { + @Autowired + private ProofRepository proofRepository; + + @Test + public void testCRUDFunctionality() { + final Proof proof = createProof(); + final Proof savedProof = proofRepository.save(proof); + + assertNotNull(savedProof); + assertEquals(Integer.valueOf(0), savedProof.getVersion()); + + final int id = savedProof.getId(); + + assertEquals("Test proof", savedProof.getTheoremName()); + assertEquals("Test branch", savedProof.getBranch()); + assertEquals("test", savedProof.getProof()); + assertEquals(Integer.valueOf(1), savedProof.getTheorem()); + assertNotNull(savedProof.getDateCreated()); + assertNotNull(savedProof.getLastUpdated()); + assertEquals(2, savedProof.getReferencedTheorems().size()); + assertEquals(2, savedProof.getReferencedDefinitions().size()); + assertEquals("test theorem 1", savedProof.getReferencedTheorems().get(0)); + assertEquals("test theorem 2", savedProof.getReferencedTheorems().get(1)); + assertEquals("test definition 1", savedProof.getReferencedDefinitions().get(0)); + assertEquals("test definition 2", savedProof.getReferencedDefinitions().get(1)); + + savedProof.setBranch("Test Update"); + + final Proof updatedProof = proofRepository.save(savedProof); + + assertNotNull(updatedProof); + assertEquals(Integer.valueOf(0), updatedProof.getVersion()); + assertEquals("Test proof", updatedProof.getTheoremName()); + assertEquals("Test Update", updatedProof.getBranch()); + assertEquals("test", updatedProof.getProof()); + assertEquals(Integer.valueOf(1), savedProof.getTheorem()); + assertNotNull(updatedProof.getLastUpdated()); + assertNotNull(updatedProof.getDateCreated()); + assertNotEquals(updatedProof.getDateCreated().toInstant(), updatedProof.getLastUpdated().toInstant()); + assertEquals(2, updatedProof.getReferencedTheorems().size()); + assertEquals(2, updatedProof.getReferencedDefinitions().size()); + assertEquals("test theorem 1", updatedProof.getReferencedTheorems().get(0)); + assertEquals("test theorem 2", updatedProof.getReferencedTheorems().get(1)); + assertEquals("test definition 1", updatedProof.getReferencedDefinitions().get(0)); + assertEquals("test definition 2", updatedProof.getReferencedDefinitions().get(1)); + assertEquals(updatedProof.getId(), id); + + proofRepository.delete(proof); + final Optional deletedProof = proofRepository.findById(id); + assertFalse(deletedProof.isPresent()); + } + + private Proof createProof() { + final List referencedTheoremsList = new ArrayList<>(); + referencedTheoremsList.add("test theorem 1"); + referencedTheoremsList.add("test theorem 2"); + + final List referencedDefinitionsList = new ArrayList<>(); + referencedDefinitionsList.add("test definition 1"); + referencedDefinitionsList.add("test definition 2"); + + final Proof proof = new Proof(); + proof.setTheoremName("Test proof"); + proof.setProof("test"); + proof.setTheorem(1); + proof.setBranch("Test branch"); + proof.setDateCreated(new Date()); + proof.setReferencedTheorems(referencedTheoremsList); + proof.setReferencedDefinitions(referencedDefinitionsList); + + return proof; + } +} diff --git a/persistence/src/integrationTest/java/edu/msudenver/tsp/persistence/TheoremsIntegrationTest.java b/persistence/src/integrationTest/java/edu/msudenver/tsp/persistence/TheoremsIntegrationTest.java new file mode 100644 index 0000000..7090456 --- /dev/null +++ b/persistence/src/integrationTest/java/edu/msudenver/tsp/persistence/TheoremsIntegrationTest.java @@ -0,0 +1,87 @@ +package edu.msudenver.tsp.persistence; + +import edu.msudenver.tsp.persistence.dto.Theorem; +import edu.msudenver.tsp.persistence.dto.TheoremType; +import edu.msudenver.tsp.persistence.repository.TheoremRepository; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import static org.junit.Assert.*; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes = PersistenceTestConfig.class) +public class TheoremsIntegrationTest { + @Autowired private TheoremRepository theoremRepository; + + @Test + public void testCRUDFunctionality() { + final Theorem theorem = createTheorem(); + final Theorem savedTheorem = theoremRepository.save(theorem); + + assertNotNull(savedTheorem); + assertEquals(Integer.valueOf(0), savedTheorem.getVersion()); + + final int id = savedTheorem.getId(); + + assertEquals("Test theorem", savedTheorem.getName()); + assertEquals("Test branch", savedTheorem.getBranch()); + assertEquals("test", savedTheorem.getTheorem()); + assertTrue(savedTheorem.getProvenStatus()); + assertEquals(2, savedTheorem.getReferencedTheorems().size()); + assertEquals(2, savedTheorem.getReferencedDefinitions().size()); + assertEquals("test theorem 1", savedTheorem.getReferencedTheorems().get(0)); + assertEquals("test theorem 2", savedTheorem.getReferencedTheorems().get(1)); + assertEquals("test definition 1", savedTheorem.getReferencedDefinitions().get(0)); + assertEquals("test definition 2", savedTheorem.getReferencedDefinitions().get(1)); + + savedTheorem.setBranch("Test Update"); + + final Theorem updatedTheorem = theoremRepository.save(savedTheorem); + + assertNotNull(updatedTheorem); + assertEquals(Integer.valueOf(0), updatedTheorem.getVersion()); + assertEquals("Test theorem", updatedTheorem.getName()); + assertEquals("Test Update", updatedTheorem.getBranch()); + assertEquals("test", updatedTheorem.getTheorem()); + assertTrue(updatedTheorem.getProvenStatus()); + assertEquals(2, updatedTheorem.getReferencedTheorems().size()); + assertEquals(2, updatedTheorem.getReferencedDefinitions().size()); + assertEquals("test theorem 1", updatedTheorem.getReferencedTheorems().get(0)); + assertEquals("test theorem 2", updatedTheorem.getReferencedTheorems().get(1)); + assertEquals("test definition 1", updatedTheorem.getReferencedDefinitions().get(0)); + assertEquals("test definition 2", updatedTheorem.getReferencedDefinitions().get(1)); + assertEquals(updatedTheorem.getId(), id); + + theoremRepository.delete(theorem); + final Optional deletedTheorem = theoremRepository.findById(id); + assertFalse(deletedTheorem.isPresent()); + } + + private Theorem createTheorem() { + final List referencedTheoremsList = new ArrayList<>(); + referencedTheoremsList.add("test theorem 1"); + referencedTheoremsList.add("test theorem 2"); + + final List referencedDefinitionsList = new ArrayList<>(); + referencedDefinitionsList.add("test definition 1"); + referencedDefinitionsList.add("test definition 2"); + + final Theorem theorem = new Theorem(); + theorem.setName("Test theorem"); + theorem.setTheorem("test"); + theorem.setBranch("Test branch"); + theorem.setProvenStatus(true); + theorem.setTheoremType(TheoremType.THEOREM); + theorem.setReferencedTheorems(referencedTheoremsList); + theorem.setReferencedDefinitions(referencedDefinitionsList); + + return theorem; + } +} diff --git a/persistence/src/main/java/edu/msudenver/tsp/persistence/PersistenceApi.java b/persistence/src/main/java/edu/msudenver/tsp/persistence/PersistenceApi.java index 39a3f11..f309965 100644 --- a/persistence/src/main/java/edu/msudenver/tsp/persistence/PersistenceApi.java +++ b/persistence/src/main/java/edu/msudenver/tsp/persistence/PersistenceApi.java @@ -105,5 +105,6 @@ public class PersistenceApi { properties.setProperty("hibernate.id.new_generator_mappings","false"); return properties; + } } diff --git a/persistence/src/main/java/edu/msudenver/tsp/persistence/controller/AccountController.java b/persistence/src/main/java/edu/msudenver/tsp/persistence/controller/AccountController.java index 25f5368..3301f65 100644 --- a/persistence/src/main/java/edu/msudenver/tsp/persistence/controller/AccountController.java +++ b/persistence/src/main/java/edu/msudenver/tsp/persistence/controller/AccountController.java @@ -1,6 +1,6 @@ package edu.msudenver.tsp.persistence.controller; -import edu.msudenver.tsp.persistence.dto.AccountDto; +import edu.msudenver.tsp.persistence.dto.Account; import edu.msudenver.tsp.persistence.repository.AccountsRepository; import edu.msudenver.tsp.utilities.PersistenceUtilities; import lombok.AllArgsConstructor; @@ -14,6 +14,8 @@ import org.springframework.web.bind.annotation.*; import javax.validation.Valid; import javax.validation.groups.Default; +import java.time.Duration; +import java.time.Instant; import java.util.List; import java.util.Optional; @@ -24,9 +26,9 @@ import java.util.Optional; public class AccountController { private final AccountsRepository accountsRepository; - @GetMapping("/") + @GetMapping({"","/"}) public @ResponseBody - ResponseEntity> getListOfAccounts() { + ResponseEntity> getListOfAccounts() { LOG.info("Received request to list all accounts"); LOG.debug("Querying for list of accounts"); @@ -34,49 +36,78 @@ public class AccountController { final StopWatch stopWatch = new StopWatch(); stopWatch.start(); - final List listOfAccounts = (List) accountsRepository.findAll(); + final List listOfAccounts = (List) accountsRepository.findAll(); stopWatch.stop(); - LOG.debug("Successfully completed query. Query took " + stopWatch.getTotalTimeMillis() + "ms to complete"); - LOG.info("Returning list of all accounts with size of " + listOfAccounts.size()); + LOG.debug("Successfully completed query. Query took {}ms to complete", stopWatch.getTotalTimeMillis()); + LOG.info("Returning list of all accounts with size of {}", listOfAccounts.size()); return new ResponseEntity<>(listOfAccounts, HttpStatus.OK); } - @GetMapping("/{id}") + @GetMapping("/id") public @ResponseBody - ResponseEntity getAccountById(@PathVariable("id") final Integer id) { - LOG.info("Received request to query for account with id " + id); + ResponseEntity getAccountById(@RequestParam("id") final Integer id) { + LOG.info("Received request to query for account with id {}", id); if (id == null) { LOG.error("ERROR: ID was null"); return new ResponseEntity<>(HttpStatus.BAD_REQUEST); } - LOG.debug("Querying for account with id " + id); + LOG.debug("Querying for account with id {}", id); final StopWatch stopWatch = new StopWatch(); stopWatch.start(); - final Optional account = accountsRepository.findById(id); + final Optional account = accountsRepository.findById(id); stopWatch.stop(); - LOG.debug("Received response from server: query took " + stopWatch.getTotalTimeMillis() + "ms to complete"); + LOG.debug("Received response from server: query took {}ms to complete", stopWatch.getTotalTimeMillis()); return account.map(accountDto -> { - LOG.info("Returning account with id " + id); + LOG.info("Returning account with id {}", id); return new ResponseEntity<>(accountDto, HttpStatus.OK); }).orElseGet( () -> { - LOG.warn("No account was found with id " + id); + LOG.warn("No account was found with id {}", id); return new ResponseEntity<>(HttpStatus.NOT_FOUND); } ); } - @PostMapping("/") - @Validated({AccountDto.Insert.class, Default.class}) - public @ResponseBody ResponseEntity insertAccount( - @Valid @RequestBody final AccountDto accountDto, final BindingResult bindingResult) { + @GetMapping("/username") + public @ResponseBody + ResponseEntity getAccountByUsername(@RequestParam("username") final String username) { + LOG.info("Received request to query for account with username {}", username); + if (username == null) { + LOG.error("ERROR: username was null"); + return new ResponseEntity<>(HttpStatus.BAD_REQUEST); + } + + LOG.debug("Querying for account with username {}", username); + final StopWatch stopWatch = new StopWatch(); + stopWatch.start(); + + final Optional account = accountsRepository.findByUsername(username); + + stopWatch.stop(); + + LOG.debug("Received response from server: query took {}ms to complete", stopWatch.getTotalTimeMillis()); + return account.map(accountDto -> { + LOG.info("Returning account with username {}", username); + return new ResponseEntity<>(accountDto, HttpStatus.OK); + }).orElseGet( + () -> { + LOG.warn("No account was found with username {}", username); + return new ResponseEntity<>(HttpStatus.NOT_FOUND); + } + ); + } + + @PostMapping({"","/"}) + @Validated({Account.Insert.class, Default.class}) + public @ResponseBody ResponseEntity insertAccount( + @Valid @RequestBody final Account account, final BindingResult bindingResult) { LOG.info("Received request to insert a new account"); if (bindingResult.hasErrors()) { @@ -84,29 +115,44 @@ public class AccountController { return new ResponseEntity<>(HttpStatus.UNPROCESSABLE_ENTITY); } - if (accountDto == null) { + if (account == null) { LOG.error("Passed account is unprocessable"); return new ResponseEntity<>(HttpStatus.BAD_REQUEST); } + LOG.info("Checking for any existing users with username {}", account.getUsername()); + + final Instant start = Instant.now(); + + LOG.debug("Querying for existing accounts"); + + final Optional existingAccount = accountsRepository.findByUsername(account.getUsername()); + + LOG.debug("Received response from the server: query took {} ms", Duration.between(start, Instant.now()).toMillis()); + + if (existingAccount.isPresent()) { + LOG.warn("An account already exists with username {}", account.getUsername()); + return new ResponseEntity<>(HttpStatus.CONFLICT); + } + LOG.debug("Saving new account"); final StopWatch stopWatch = new StopWatch(); stopWatch.start(); - final AccountDto savedAccount = accountsRepository.save(accountDto); + final Account savedAccount = accountsRepository.save(account); stopWatch.stop(); - LOG.debug("Received response from server: query took " + stopWatch.getTotalTimeMillis() + "ms to complete"); + LOG.debug("Received response from server: query took {}ms to complete", stopWatch.getTotalTimeMillis()); LOG.info("Returning the newly created account"); return new ResponseEntity<>(savedAccount, HttpStatus.CREATED); } @PatchMapping("/{id}") - public @ResponseBody ResponseEntity updateAccount( + public @ResponseBody ResponseEntity updateAccount( @PathVariable("id") final Integer id, - @RequestBody final AccountDto accountDto, final BindingResult bindingResult) { + @RequestBody final Account account, final BindingResult bindingResult) { LOG.info("Received request to update an account"); if (bindingResult.hasErrors()) { @@ -114,7 +160,7 @@ public class AccountController { return new ResponseEntity<>(HttpStatus.UNPROCESSABLE_ENTITY); } - if (accountDto == null) { + if (account == null) { LOG.error("Passed entity is null"); return new ResponseEntity<>(HttpStatus.BAD_REQUEST); } @@ -124,48 +170,48 @@ public class AccountController { return new ResponseEntity<>(HttpStatus.BAD_REQUEST); } - LOG.debug("Checking for existence of account with id " + id); + LOG.debug("Checking for existence of account with id {}", id); final StopWatch stopWatch = new StopWatch(); stopWatch.start(); - final Optional existingAccount = accountsRepository.findById(id); + final Optional existingAccount = accountsRepository.findById(id); stopWatch.stop(); - LOG.debug("Received response from server: query took " + stopWatch.getTotalTimeMillis() + "ms to complete"); + LOG.debug("Received response from server: query took {}ms to complete", stopWatch.getTotalTimeMillis()); if (!existingAccount.isPresent()) { - LOG.error("No account associated with id " + id); + LOG.error("No account associated with id {}", id); return new ResponseEntity<>(HttpStatus.BAD_REQUEST); } - PersistenceUtilities.copyNonNullProperties(accountDto, existingAccount.get()); + PersistenceUtilities.copyNonNullProperties(account, existingAccount.get()); existingAccount.get().setVersion(existingAccount.get().getVersion()+ 1); - LOG.info("Updating account with id " + id); - LOG.debug("Querying for account with ID " + id); + LOG.info("Updating account with id {}", id); + LOG.debug("Querying for account with id {}", id); stopWatch.start(); - final AccountDto updatedAccount = accountsRepository.save(existingAccount.get()); + final Account updatedAccount = accountsRepository.save(existingAccount.get()); stopWatch.stop(); - LOG.debug("Received response from server: query took " + stopWatch.getTotalTimeMillis() + "ms to complete"); + LOG.debug("Received response from server: query took {}ms to complete", stopWatch.getTotalTimeMillis()); return new ResponseEntity<>(updatedAccount, HttpStatus.OK); } @DeleteMapping("/{id}") public @ResponseBody ResponseEntity deleteAccountById(@PathVariable("id") final Integer id) { - LOG.info("Received request to delete account with id " + id); + LOG.info("Received request to delete account with id {}", id); if (id == null) { LOG.error("Specified Id is null"); return new ResponseEntity<>(HttpStatus.BAD_REQUEST); } - LOG.debug("Deleting account with id " + id); + LOG.debug("Deleting account with id {}", id); final StopWatch stopWatch = new StopWatch(); stopWatch.start(); @@ -174,7 +220,7 @@ public class AccountController { stopWatch.stop(); - LOG.debug("Received response from server: query took " + stopWatch.getTotalTimeMillis() + "ms to complete"); + LOG.debug("Received response from server: query took {}ms to complete", stopWatch.getTotalTimeMillis()); return new ResponseEntity<>(HttpStatus.NO_CONTENT); } diff --git a/persistence/src/main/java/edu/msudenver/tsp/persistence/controller/DefinitionController.java b/persistence/src/main/java/edu/msudenver/tsp/persistence/controller/DefinitionController.java index 3b788a5..720e5df 100644 --- a/persistence/src/main/java/edu/msudenver/tsp/persistence/controller/DefinitionController.java +++ b/persistence/src/main/java/edu/msudenver/tsp/persistence/controller/DefinitionController.java @@ -1,6 +1,6 @@ package edu.msudenver.tsp.persistence.controller; -import edu.msudenver.tsp.persistence.dto.DefinitionDto; +import edu.msudenver.tsp.persistence.dto.Definition; import edu.msudenver.tsp.persistence.repository.DefinitionRepository; import edu.msudenver.tsp.utilities.PersistenceUtilities; import lombok.AllArgsConstructor; @@ -20,63 +20,63 @@ import java.util.Optional; @Slf4j @RestController @AllArgsConstructor -@RequestMapping(path = "/definitions/") +@RequestMapping(path = "/definitions") public class DefinitionController { private final DefinitionRepository definitionRepository; - @GetMapping("/") + @GetMapping({"","/"}) public @ResponseBody - ResponseEntity> getAllDefinitions() { + ResponseEntity> getAllDefinitions() { LOG.info("Received request to list all definitions"); LOG.debug("Querying for list of all definitions"); final StopWatch stopWatch = new StopWatch(); stopWatch.start(); - final List listOfDefinitions = definitionRepository.findAll(); + final List listOfDefinitions = definitionRepository.findAll(); stopWatch.stop(); - LOG.debug("Successfully completed query. Query took " + stopWatch.getTotalTimeMillis() + "ms to complete"); - LOG.info("Returning list of all definition with size " + listOfDefinitions.size()); + LOG.debug("Successfully completed query. Query took {}ms to complete", stopWatch.getTotalTimeMillis()); + LOG.info("Returning list of all definition with size {}", listOfDefinitions.size()); return new ResponseEntity<>(listOfDefinitions, HttpStatus.OK); } @GetMapping("/{id}") public @ResponseBody - ResponseEntity getDefinitionById(@PathVariable("id") final Integer id) { - LOG.info("Received request to query for definition with id " + id); + ResponseEntity getDefinitionById(@PathVariable("id") final Integer id) { + LOG.info("Received request to query for definition with id {}", id); if (id == null) { LOG.error("ERROR: ID was null"); return new ResponseEntity<>(HttpStatus.BAD_REQUEST); } - LOG.debug("Querying for definition with id " + id); + LOG.debug("Querying for definition with id {}", id); final StopWatch stopWatch = new StopWatch(); stopWatch.start(); - final Optional definition = definitionRepository.findById(id); + final Optional definition = definitionRepository.findById(id); stopWatch.stop(); - LOG.debug("Received response from server: query took " + stopWatch.getTotalTimeMillis() + "ms to complete"); + LOG.debug("Received response from server: query took {}ms to complete", stopWatch.getTotalTimeMillis()); return definition.map(definitionDto -> { - LOG.info("Returning definition with id " + id); + LOG.info("Returning definition with id {}", id); return new ResponseEntity<>(definitionDto, HttpStatus.OK); }).orElseGet( () -> { - LOG.warn("No definition was found with id " + id); + LOG.warn("No definition was found with id {}",id); return new ResponseEntity<>(HttpStatus.NOT_FOUND); }); } - @PostMapping("/") - @Validated({DefinitionDto.Insert.class, Default.class}) - public @ResponseBody ResponseEntity insertDefinition( - @Valid @RequestBody final DefinitionDto definitionDto, + @PostMapping({"","/"}) + @Validated({Definition.Insert.class, Default.class}) + public @ResponseBody ResponseEntity insertDefinition( + @Valid @RequestBody final Definition definition, final BindingResult bindingResult) { LOG.info("Received request to insert a new definition"); if (bindingResult.hasErrors()) { @@ -84,8 +84,8 @@ public class DefinitionController { return new ResponseEntity<>(HttpStatus.UNPROCESSABLE_ENTITY); } - if (definitionDto == null) { - LOG.error("Passed entity is unprocessable"); + if (definition == null) { + LOG.error("Passed entity is null"); return new ResponseEntity<>(HttpStatus.BAD_REQUEST); } @@ -94,19 +94,19 @@ public class DefinitionController { final StopWatch stopWatch = new StopWatch(); stopWatch.start(); - final DefinitionDto savedDefinition = definitionRepository.save(definitionDto); + final Definition savedDefinition = definitionRepository.save(definition); stopWatch.stop(); - LOG.debug("Received response from server: query took " + stopWatch.getTotalTimeMillis() + "ms to complete"); + LOG.debug("Received response from server: query took {}ms to complete", stopWatch.getTotalTimeMillis()); - LOG.info("Returning the newly created definition with id " + savedDefinition.getId()); + LOG.info("Returning the newly created definition with id {}", savedDefinition.getId()); return new ResponseEntity<>(savedDefinition, HttpStatus.CREATED); } @PatchMapping("/{id}") - public @ResponseBody ResponseEntity updateDefinition( + public @ResponseBody ResponseEntity updateDefinition( @PathVariable("id") final Integer id, - @RequestBody final DefinitionDto definitionDto, final BindingResult bindingResult) { + @RequestBody final Definition definition, final BindingResult bindingResult) { LOG.info("Received request to update an account"); if (bindingResult.hasErrors()) { @@ -114,7 +114,7 @@ public class DefinitionController { return new ResponseEntity<>(HttpStatus.UNPROCESSABLE_ENTITY); } - if (definitionDto == null) { + if (definition == null) { LOG.error("Passed entity is null"); return new ResponseEntity<>(HttpStatus.BAD_REQUEST); } @@ -124,48 +124,48 @@ public class DefinitionController { return new ResponseEntity<>(HttpStatus.BAD_REQUEST); } - LOG.debug("Checking for existence of definition with id " + id); + LOG.debug("Checking for existence of definition with id {}", id); final StopWatch stopWatch = new StopWatch(); stopWatch.start(); - final Optional existingDefinition = definitionRepository.findById(id); + final Optional existingDefinition = definitionRepository.findById(id); stopWatch.stop(); - LOG.debug("Received response from server: query took " + stopWatch.getTotalTimeMillis() + "ms to complete"); + LOG.debug("Received response from server: query took {}ms to complete", stopWatch.getTotalTimeMillis()); if (!existingDefinition.isPresent()) { - LOG.error("No definition associated with id " + id); + LOG.error("No definition associated with id {}", id); return new ResponseEntity<>(HttpStatus.BAD_REQUEST); } - PersistenceUtilities.copyNonNullProperties(definitionDto, existingDefinition.get()); + PersistenceUtilities.copyNonNullProperties(definition, existingDefinition.get()); existingDefinition.get().setVersion(existingDefinition.get().getVersion()+ 1); - LOG.info("Updating definition with id " + id); - LOG.debug("Querying for definition with ID " + id); + LOG.info("Updating definition with id {}", id); + LOG.debug("Querying for definition with id {}", id); stopWatch.start(); - final DefinitionDto updatedDefinition = definitionRepository.save(existingDefinition.get()); + final Definition updatedDefinition = definitionRepository.save(existingDefinition.get()); stopWatch.stop(); - LOG.debug("Received response from server: query took " + stopWatch.getTotalTimeMillis() + "ms to complete"); + LOG.debug("Received response from server: query took {}ms to complete", stopWatch.getTotalTimeMillis()); return new ResponseEntity<>(updatedDefinition, HttpStatus.OK); } @DeleteMapping("/{id}") public @ResponseBody ResponseEntity deleteDefinitionById(@PathVariable("id") final Integer id) { - LOG.info("Received request to delete definition with id " + id); + LOG.info("Received request to delete definition with id {}", id); if (id == null) { LOG.error("Specified id is null"); return new ResponseEntity<>(HttpStatus.BAD_REQUEST); } - LOG.debug("Deleting definition with id " + id); + LOG.debug("Deleting definition with id {}", id); final StopWatch stopWatch = new StopWatch(); stopWatch.start(); @@ -174,7 +174,7 @@ public class DefinitionController { stopWatch.stop(); - LOG.debug("Received response from server: query took " + stopWatch.getTotalTimeMillis() + "ms to complete"); + LOG.debug("Received response from server: query took {}ms to complete", stopWatch.getTotalTimeMillis()); return new ResponseEntity<>(HttpStatus.NO_CONTENT); } diff --git a/persistence/src/main/java/edu/msudenver/tsp/persistence/controller/NotationController.java b/persistence/src/main/java/edu/msudenver/tsp/persistence/controller/NotationController.java deleted file mode 100644 index 35b8a86..0000000 --- a/persistence/src/main/java/edu/msudenver/tsp/persistence/controller/NotationController.java +++ /dev/null @@ -1,11 +0,0 @@ -package edu.msudenver.tsp.persistence.controller; - -import edu.msudenver.tsp.persistence.repository.NotationRepository; -import lombok.AllArgsConstructor; -import org.springframework.stereotype.Component; - -@Component -@AllArgsConstructor -public class NotationController { - final private NotationRepository notationRepository; -} diff --git a/persistence/src/main/java/edu/msudenver/tsp/persistence/controller/ProofController.java b/persistence/src/main/java/edu/msudenver/tsp/persistence/controller/ProofController.java index 51e5d25..d682c32 100644 --- a/persistence/src/main/java/edu/msudenver/tsp/persistence/controller/ProofController.java +++ b/persistence/src/main/java/edu/msudenver/tsp/persistence/controller/ProofController.java @@ -1,11 +1,251 @@ package edu.msudenver.tsp.persistence.controller; +import edu.msudenver.tsp.persistence.dto.Proof; import edu.msudenver.tsp.persistence.repository.ProofRepository; +import edu.msudenver.tsp.utilities.PersistenceUtilities; import lombok.AllArgsConstructor; -import org.springframework.stereotype.Component; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.util.StopWatch; +import org.springframework.validation.BindingResult; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; -@Component +import javax.validation.Valid; +import javax.validation.groups.Default; +import java.util.List; +import java.util.Optional; + +@Slf4j +@RestController @AllArgsConstructor +@RequestMapping("/proofs") public class ProofController { - final private ProofRepository proofRepository; + private final ProofRepository proofRepository; + + @GetMapping({"","/"}) + public @ResponseBody + ResponseEntity> getAllProofs() { + LOG.info("Received request to list all theorems"); + + LOG.debug("Querying for list of all theorems"); + final StopWatch stopWatch = new StopWatch(); + stopWatch.start(); + + final List listOfProofs = proofRepository.findAll(); + + stopWatch.stop(); + + LOG.debug("Successfully completed query. Query took {}ms to complete", stopWatch.getTotalTimeMillis()); + LOG.info("Returning list of all theorems with size {}", listOfProofs.size()); + + return new ResponseEntity<>(listOfProofs, HttpStatus.OK); + } + + @GetMapping("/id") + public @ResponseBody + ResponseEntity getProofById(@RequestParam("id") final Integer id) { + LOG.info("Received request to query for proof with id {}", id); + if (id == null) { + LOG.error("ERROR: ID was null"); + return new ResponseEntity<>(HttpStatus.BAD_REQUEST); + } + + LOG.debug("Querying for proof with id {}", id); + + final StopWatch stopWatch = new StopWatch(); + stopWatch.start(); + + final Optional proof = proofRepository.findById(id); + + stopWatch.stop(); + + LOG.debug("Received response from server: query took {}ms to complete", stopWatch.getTotalTimeMillis()); + return proof.map(proofDto -> { + LOG.info("Returning proof with id {}", id); + return new ResponseEntity<>(proofDto, HttpStatus.OK); + }).orElseGet( + () -> { + LOG.warn("No proof was found with id {}", id); + return new ResponseEntity<>(HttpStatus.NOT_FOUND); + }); + + } + + @GetMapping("/branch") + public @ResponseBody + ResponseEntity> getAllProofsByBranch(@RequestParam("branch") String branch) { + LOG.info("Received request to query for proofs related to the {} branch of mathematics", branch); + if (branch == null) { + LOG.error("ERROR: branch was null"); + return new ResponseEntity<>(HttpStatus.BAD_REQUEST); + } + + if (branch.contains("_") || branch.contains("-")) { + branch = branch.replace("_"," "); + branch = branch.replace("-", " "); + } + + LOG.debug("Querying for proofs with branch {}", branch); + + final StopWatch stopWatch = new StopWatch(); + stopWatch.start(); + + final List listOfProofs = proofRepository.findByBranch(branch); + + stopWatch.stop(); + + LOG.debug("Received response from server: query took {}ms to complete", stopWatch.getTotalTimeMillis()); + LOG.info("Returning list of all proofs with size {}", listOfProofs.size()); + + if (listOfProofs.isEmpty()) { + LOG.warn("No proofs were found for branch {}", branch); + return new ResponseEntity<>(HttpStatus.NOT_FOUND); + } + + LOG.info("Returning list of proofs with branch {}", branch); + return new ResponseEntity<>(listOfProofs, HttpStatus.OK); + } + + @GetMapping("/theorem_name") + public @ResponseBody + ResponseEntity> getAllProofsByTheoremName(@RequestParam("theorem_name") String theoremName) { + LOG.info("Received request to query for proofs of the theorem {}", theoremName); + if (theoremName == null) { + LOG.error("ERROR: theorem name was null"); + return new ResponseEntity<>(HttpStatus.BAD_REQUEST); + } + + if (theoremName.contains("_") || theoremName.contains("-")) { + theoremName = theoremName.replace("_"," "); + theoremName = theoremName.replace("-", " "); + } + + LOG.debug("Querying for proofs of the theorem {}", theoremName); + + final StopWatch stopWatch = new StopWatch(); + stopWatch.start(); + + final List listOfProofs = proofRepository.findByTheoremName(theoremName); + + stopWatch.stop(); + + LOG.debug("Received response from server: query took {}ms to complete", stopWatch.getTotalTimeMillis()); + LOG.info("Returning list of all proofs with size {}", listOfProofs.size()); + + if (listOfProofs.isEmpty()) { + LOG.warn("No proofs were found of the theorem {}", theoremName); + return new ResponseEntity<>(HttpStatus.NOT_FOUND); + } + + LOG.info("Returning list of proofs for the theorem {}", theoremName); + return new ResponseEntity<>(listOfProofs, HttpStatus.OK); + } + + @PostMapping({"","/"}) + @Validated({Proof.Insert.class, Default.class}) + public @ResponseBody ResponseEntity insertProof( + @Valid @RequestBody final Proof proof, + final BindingResult bindingResult) { + LOG.info("Received request to insert a new proof"); + if (bindingResult.hasErrors()) { + LOG.error("Binding result is unprocessable"); + return new ResponseEntity<>(HttpStatus.UNPROCESSABLE_ENTITY); + } + + if (proof == null) { + LOG.error("Passed entity is null"); + return new ResponseEntity<>(HttpStatus.BAD_REQUEST); + } + + LOG.debug("Saving new proof"); + + final StopWatch stopWatch = new StopWatch(); + stopWatch.start(); + + final Proof savedProof = proofRepository.save(proof); + + stopWatch.stop(); + LOG.debug("Received response from server: query took {}ms to complete", stopWatch.getTotalTimeMillis()); + + LOG.info("Returning the newly created proof with id {}", savedProof.getId()); + return new ResponseEntity<>(savedProof, HttpStatus.CREATED); + } + + @PatchMapping("/{id}") + public @ResponseBody ResponseEntity updateProof( + @PathVariable("id") final Integer id, + @RequestBody final Proof proof, final BindingResult bindingResult) { + + LOG.info("Received request to update a proof"); + if (bindingResult.hasErrors()) { + LOG.error("Binding result is unprocessable"); + return new ResponseEntity<>(HttpStatus.UNPROCESSABLE_ENTITY); + } + + if (proof == null) { + LOG.error("Passed entity is null"); + return new ResponseEntity<>(HttpStatus.BAD_REQUEST); + } + + if (id == null) { + LOG.error("Proof ID must be specified"); + return new ResponseEntity<>(HttpStatus.BAD_REQUEST); + } + + LOG.debug("Checking for existence of proof with id {}", id); + + final StopWatch stopWatch = new StopWatch(); + stopWatch.start(); + + final Optional existingProof = proofRepository.findById(id); + + stopWatch.stop(); + + LOG.debug("Received response from server: query took {}ms to complete", stopWatch.getTotalTimeMillis()); + + if (!existingProof.isPresent()) { + LOG.error("No proof associated with id {}", id); + return new ResponseEntity<>(HttpStatus.BAD_REQUEST); + } + + PersistenceUtilities.copyNonNullProperties(proof, existingProof.get()); + existingProof.get().setVersion(existingProof.get().getVersion()+ 1); + + LOG.info("Updating proof with id {}", id); + LOG.debug("Querying for proof with ID {}", id); + + stopWatch.start(); + + final Proof updatedProof = proofRepository.save(existingProof.get()); + + stopWatch.stop(); + + LOG.debug("Received response from server: query took {}ms to complete", stopWatch.getTotalTimeMillis()); + + return new ResponseEntity<>(updatedProof, HttpStatus.OK); + } + + @DeleteMapping("/{id}") + public @ResponseBody ResponseEntity deleteProofById(@PathVariable("id") final Integer id) { + LOG.info("Received request to delete proof with id {}", id); + if (id == null) { + LOG.error("Specified id is null"); + return new ResponseEntity<>(HttpStatus.BAD_REQUEST); + } + + LOG.debug("Deleting proof with id {}", id); + + final StopWatch stopWatch = new StopWatch(); + stopWatch.start(); + + proofRepository.deleteById(id); + + stopWatch.stop(); + + LOG.debug("Received response from server: query took {}ms to complete", stopWatch.getTotalTimeMillis()); + + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } } diff --git a/persistence/src/main/java/edu/msudenver/tsp/persistence/controller/TheoremController.java b/persistence/src/main/java/edu/msudenver/tsp/persistence/controller/TheoremController.java index 080ed54..457ac10 100644 --- a/persistence/src/main/java/edu/msudenver/tsp/persistence/controller/TheoremController.java +++ b/persistence/src/main/java/edu/msudenver/tsp/persistence/controller/TheoremController.java @@ -1,11 +1,283 @@ package edu.msudenver.tsp.persistence.controller; +import edu.msudenver.tsp.persistence.dto.Theorem; import edu.msudenver.tsp.persistence.repository.TheoremRepository; +import edu.msudenver.tsp.utilities.PersistenceUtilities; import lombok.AllArgsConstructor; -import org.springframework.stereotype.Component; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.util.StopWatch; +import org.springframework.validation.BindingResult; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; -@Component +import javax.validation.Valid; +import javax.validation.groups.Default; +import java.util.List; +import java.util.Optional; + +@Slf4j +@RestController @AllArgsConstructor +@RequestMapping(path = "/theorems") public class TheoremController { - final private TheoremRepository theoremRepository; + private final TheoremRepository theoremRepository; + + @GetMapping({"","/"}) + public @ResponseBody + ResponseEntity> getAllTheorems() { + LOG.info("Received request to list all theorems"); + + LOG.debug("Querying for list of all theorems"); + final StopWatch stopWatch = new StopWatch(); + stopWatch.start(); + + final List listOfTheorems = theoremRepository.findAll(); + + stopWatch.stop(); + + LOG.debug("Successfully completed query. Query took {}ms to complete", stopWatch.getTotalTimeMillis()); + LOG.info("Returning list of all theorems with size {}", listOfTheorems.size()); + + return new ResponseEntity<>(listOfTheorems, HttpStatus.OK); + } + + @GetMapping("/branch") + public @ResponseBody + ResponseEntity> getAllTheoremsByBranch(@RequestParam("branch") String branch) { + LOG.info("Received request to query for theorems related to the {} branch of mathematics", branch); + if (branch == null) { + LOG.error("ERROR: branch was null"); + return new ResponseEntity<>(HttpStatus.BAD_REQUEST); + } + + if (branch.contains("_") || branch.contains("-")) { + branch = branch.replace("_", " "); + branch = branch.replace("-", " "); + } + + LOG.debug("Querying for theorems with branch {}", branch); + + final StopWatch stopWatch = new StopWatch(); + stopWatch.start(); + + final List listOfTheorems = theoremRepository.findByBranch(branch); + + stopWatch.stop(); + + LOG.debug("Received response from server: query took {}ms to complete", stopWatch.getTotalTimeMillis()); + LOG.info("Returning list of all theorems with size {}", listOfTheorems.size()); + + if (listOfTheorems.isEmpty()) { + LOG.warn("No theorems were found for branch {}", branch); + return new ResponseEntity<>(HttpStatus.NOT_FOUND); + } + + LOG.info("Returning list of theorems with branch {}", branch); + return new ResponseEntity<>(listOfTheorems, HttpStatus.OK); + } + + @GetMapping("/proven_status") + public @ResponseBody + ResponseEntity> getAllTheoremsByProvenStatus(@RequestParam("proven_status") final String provenStatus) { + LOG.info("Received request to query for theorems whose proven status is {}", provenStatus); + if (provenStatus == null) { + LOG.error("ERROR: status was null"); + return new ResponseEntity<>(HttpStatus.BAD_REQUEST); + } + + final Boolean isProven = Boolean.parseBoolean(provenStatus); + + LOG.debug("Querying for theorems with proven status {}", isProven); + + final StopWatch stopWatch = new StopWatch(); + stopWatch.start(); + + final List listOfTheorems = theoremRepository.findByProvenStatus(isProven); + + stopWatch.stop(); + + LOG.debug("Received response from server: query took {}ms to complete", stopWatch.getTotalTimeMillis()); + LOG.info("Returning list of all theorems with size {}", listOfTheorems.size()); + + if (listOfTheorems.isEmpty()) { + LOG.warn("No theorems were found for proven status {}", isProven); + return new ResponseEntity<>(HttpStatus.NOT_FOUND); + } + + LOG.info("Returning list of theorems with proven status {}", isProven); + return new ResponseEntity<>(listOfTheorems, HttpStatus.OK); + } + + @GetMapping("/name") + public @ResponseBody + ResponseEntity> getAllTheoremsByName(@RequestParam("name") String name) { + LOG.info("Received request to query for theorems whose name is {}", name); + if (name == null) { + LOG.error("ERROR: name was null"); + return new ResponseEntity<>(HttpStatus.BAD_REQUEST); + } + + if (name.contains("_") || name.contains("-")) { + name = name.replace("_", " "); + name = name.replace("-", " "); + } + + LOG.debug("Querying for theorems with name {}", name); + + final StopWatch stopWatch = new StopWatch(); + stopWatch.start(); + + final List listOfTheorems = theoremRepository.findByName(name); + + stopWatch.stop(); + + LOG.debug("Received response from server: query took {}ms to complete", stopWatch.getTotalTimeMillis()); + LOG.info("Returning list of all theorems with size {}", listOfTheorems.size()); + + if (listOfTheorems.isEmpty()) { + LOG.warn("No theorems were found with name {}", name); + return new ResponseEntity<>(HttpStatus.NOT_FOUND); + } + + LOG.info("Returning list of theorems with name {}", name); + return new ResponseEntity<>(listOfTheorems, HttpStatus.OK); + } + + @GetMapping("/id") + public @ResponseBody + ResponseEntity getTheoremById(@RequestParam("id") final Integer id) { + LOG.info("Received request to query for theorem with id {}", id); + if (id == null) { + LOG.error("ERROR: ID was null"); + return new ResponseEntity<>(HttpStatus.BAD_REQUEST); + } + + LOG.debug("Querying for theorem with id {}", id); + + final StopWatch stopWatch = new StopWatch(); + stopWatch.start(); + + final Optional theorem = theoremRepository.findById(id); + + stopWatch.stop(); + + LOG.debug("Received response from server: query took {}ms to complete", stopWatch.getTotalTimeMillis()); + return theorem.map(theoremDto -> { + LOG.info("Returning theorem with id {}", id); + return new ResponseEntity<>(theoremDto, HttpStatus.OK); + }).orElseGet( + () -> { + LOG.warn("No theorem was found with id {}", id); + return new ResponseEntity<>(HttpStatus.NOT_FOUND); + }); + + } + + @PostMapping({"","/"}) + @Validated({Theorem.Insert.class, Default.class}) + public @ResponseBody ResponseEntity insertTheorem( + @Valid @RequestBody final Theorem theorem, + final BindingResult bindingResult) { + LOG.info("Received request to insert a new theorem"); + if (bindingResult.hasErrors()) { + LOG.error("Binding result is unprocessable"); + return new ResponseEntity<>(HttpStatus.UNPROCESSABLE_ENTITY); + } + + if (theorem == null) { + LOG.error("Passed entity is null"); + return new ResponseEntity<>(HttpStatus.BAD_REQUEST); + } + + LOG.debug("Saving new theorem"); + + final StopWatch stopWatch = new StopWatch(); + stopWatch.start(); + + final Theorem savedTheorem = theoremRepository.save(theorem); + + stopWatch.stop(); + LOG.debug("Received response from server: query took {}ms to complete", stopWatch.getTotalTimeMillis()); + + LOG.info("Returning the newly created theorem with id {}", savedTheorem.getId()); + return new ResponseEntity<>(savedTheorem, HttpStatus.CREATED); + } + + @PatchMapping("/{id}") + public @ResponseBody ResponseEntity updateTheorem( + @PathVariable("id") final Integer id, + @RequestBody final Theorem theorem, final BindingResult bindingResult) { + + LOG.info("Received request to update a theorem"); + if (bindingResult.hasErrors()) { + LOG.error("Binding result is unprocessable"); + return new ResponseEntity<>(HttpStatus.UNPROCESSABLE_ENTITY); + } + + if (theorem == null) { + LOG.error("Passed entity is null"); + return new ResponseEntity<>(HttpStatus.BAD_REQUEST); + } + + if (id == null) { + LOG.error("Theorem ID must be specified"); + return new ResponseEntity<>(HttpStatus.BAD_REQUEST); + } + + LOG.debug("Checking for existence of theorem with id {}", id); + + final StopWatch stopWatch = new StopWatch(); + stopWatch.start(); + + final Optional existingTheorem = theoremRepository.findById(id); + + stopWatch.stop(); + + LOG.debug("Received response from server: query took {}ms to complete", stopWatch.getTotalTimeMillis()); + + if (!existingTheorem.isPresent()) { + LOG.error("No theorem associated with id {}", id); + return new ResponseEntity<>(HttpStatus.BAD_REQUEST); + } + + PersistenceUtilities.copyNonNullProperties(theorem, existingTheorem.get()); + existingTheorem.get().setVersion(existingTheorem.get().getVersion()+ 1); + + LOG.info("Updating theorem with id {}", id); + LOG.debug("Querying for theorem with id {}", id); + + stopWatch.start(); + + final Theorem updatedTheorem = theoremRepository.save(existingTheorem.get()); + + stopWatch.stop(); + + LOG.debug("Received response from server: query took {}ms to complete", stopWatch.getTotalTimeMillis()); + + return new ResponseEntity<>(updatedTheorem, HttpStatus.OK); + } + + @DeleteMapping("/{id}") + public @ResponseBody ResponseEntity deleteTheoremById(@PathVariable("id") final Integer id) { + LOG.info("Received request to delete theorem with id {}", id); + if (id == null) { + LOG.error("Specified id is null"); + return new ResponseEntity<>(HttpStatus.BAD_REQUEST); + } + + LOG.debug("Deleting theorem with id {}", id); + + final StopWatch stopWatch = new StopWatch(); + stopWatch.start(); + + theoremRepository.deleteById(id); + + stopWatch.stop(); + + LOG.debug("Received response from server: query took {}ms to complete", stopWatch.getTotalTimeMillis()); + + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } } diff --git a/persistence/src/main/java/edu/msudenver/tsp/persistence/dto/Account.java b/persistence/src/main/java/edu/msudenver/tsp/persistence/dto/Account.java new file mode 100644 index 0000000..a8fa430 --- /dev/null +++ b/persistence/src/main/java/edu/msudenver/tsp/persistence/dto/Account.java @@ -0,0 +1,53 @@ +package edu.msudenver.tsp.persistence.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +import javax.persistence.*; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.io.Serializable; +import java.util.Date; + +@Entity(name = "accounts") +@EntityListeners(AuditingEntityListener.class) +@Data +@EqualsAndHashCode(callSuper = true) +public class Account extends BaseDto implements Serializable { + @NotBlank(groups = Insert.class, message = "A username must be specified") @Size(max = 50) private String username; + @NotBlank(groups = Insert.class, message = "A password must be specified") @Size(max = 256) private String password; + @NotNull @Column(name = "administrator_status") private boolean administratorStatus; + @Temporal(TemporalType.DATE) @Column(name = "last_login") private Date lastLogin; + + private static final long serialVersionUID = 7095627971593953734L; + + @JsonProperty("administrator_status") + public boolean getAdministratorStatus() { + return administratorStatus; + } + + @JsonProperty("administrator_status") + public void setAdministratorStatus(final boolean administratorStatus) { + this.administratorStatus = administratorStatus; + } + + @JsonProperty("last_login") + public Date getLastLogin() { + return lastLogin; + } + + @JsonProperty("last_login") + public void setLastLogin(final Date lastLogin) { + this.lastLogin = lastLogin; + } + + public interface Insert {} + + @PrePersist + public void prePersist() { + lastLogin = new Date(); + } +} diff --git a/persistence/src/main/java/edu/msudenver/tsp/persistence/dto/AccountDto.java b/persistence/src/main/java/edu/msudenver/tsp/persistence/dto/AccountDto.java deleted file mode 100644 index 717bc64..0000000 --- a/persistence/src/main/java/edu/msudenver/tsp/persistence/dto/AccountDto.java +++ /dev/null @@ -1,31 +0,0 @@ -package edu.msudenver.tsp.persistence.dto; - -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Data; -import lombok.EqualsAndHashCode; -import org.springframework.data.jpa.domain.support.AuditingEntityListener; - -import javax.persistence.Entity; -import javax.persistence.EntityListeners; -import javax.persistence.Temporal; -import javax.persistence.TemporalType; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; -import java.io.Serializable; -import java.util.Date; - -@Entity(name = "accounts") -@EntityListeners(AuditingEntityListener.class) -@Data -@EqualsAndHashCode(callSuper = true) -public class AccountDto extends BaseDto implements Serializable { - @NotBlank(groups = Insert.class, message = "A username must be specified") @Size(max = 50) private String username; - @NotBlank(groups = Insert.class, message = "A password must be specified") @Size(max = 256) private String password; - @NotNull @JsonProperty("administrator_status") private boolean administratorStatus; - @Temporal(TemporalType.DATE) @JsonProperty("last_login") private Date lastLogin; - - public static final long serialVersionUID = 7095627971593953734L; - - public interface Insert {} -} diff --git a/persistence/src/main/java/edu/msudenver/tsp/persistence/dto/BaseDto.java b/persistence/src/main/java/edu/msudenver/tsp/persistence/dto/BaseDto.java index b718619..b6eb9ce 100644 --- a/persistence/src/main/java/edu/msudenver/tsp/persistence/dto/BaseDto.java +++ b/persistence/src/main/java/edu/msudenver/tsp/persistence/dto/BaseDto.java @@ -36,5 +36,5 @@ public class BaseDto implements Serializable { @Version private Integer version; - public static final long serialVersionUID = -1686252381978213945L; + private static final long serialVersionUID = -1686252381978213945L; } diff --git a/persistence/src/main/java/edu/msudenver/tsp/persistence/dto/Definition.java b/persistence/src/main/java/edu/msudenver/tsp/persistence/dto/Definition.java index e346772..b18d743 100644 --- a/persistence/src/main/java/edu/msudenver/tsp/persistence/dto/Definition.java +++ b/persistence/src/main/java/edu/msudenver/tsp/persistence/dto/Definition.java @@ -1,17 +1,35 @@ package edu.msudenver.tsp.persistence.dto; -import lombok.Getter; -import lombok.Setter; -import lombok.ToString; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.hibernate.annotations.Type; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.EntityListeners; +import javax.persistence.Table; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Size; import java.io.Serializable; import java.util.List; -@Getter -@Setter -@ToString -public class Definition implements Serializable { - private List definitions; +@Entity(name = "definitions") +@Table(name = "definitions") +@EntityListeners(AuditingEntityListener.class) +@Data +@EqualsAndHashCode(callSuper = true) +public class Definition extends BaseDto implements Serializable { + @NotBlank(groups = Insert.class, message = "A name must be specified") + @Size(min = 1, max = 200, message = "Must be between 1 and 200 characters") + private String name; - public static final long serialVersionUID = -2208496232532214840L; + @NotBlank(groups = Insert.class, message = "At least one (1) definition must be specified") + @Type(type = "json") @Column(columnDefinition = "jsonb") private List definition; + + @Type(type = "json") @Column(columnDefinition = "jsonb") private List notation; + + private static final long serialVersionUID = -5314619286352932857L; + + public interface Insert {} } diff --git a/persistence/src/main/java/edu/msudenver/tsp/persistence/dto/DefinitionDto.java b/persistence/src/main/java/edu/msudenver/tsp/persistence/dto/DefinitionDto.java deleted file mode 100644 index 806e84c..0000000 --- a/persistence/src/main/java/edu/msudenver/tsp/persistence/dto/DefinitionDto.java +++ /dev/null @@ -1,34 +0,0 @@ -package edu.msudenver.tsp.persistence.dto; - -import lombok.Data; -import lombok.EqualsAndHashCode; -import org.hibernate.annotations.Type; -import org.springframework.data.jpa.domain.support.AuditingEntityListener; - -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.EntityListeners; -import javax.persistence.Table; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.Size; -import java.io.Serializable; - -@Entity(name = "definitions") -@Table(name = "definitions") -@EntityListeners(AuditingEntityListener.class) -@Data -@EqualsAndHashCode(callSuper = true) -public class DefinitionDto extends BaseDto implements Serializable { - @NotBlank(groups = Insert.class, message = "A name must be specified") - @Size(min = 1, max = 200, message = "Must be between 1 and 200 characters") - private String name; - - @NotBlank(groups = Insert.class, message = "At least one (1) definition must be specified") - @Type(type = "json") @Column(columnDefinition = "jsonb") private Definition definition; - - @Type(type = "json") @Column(columnDefinition = "jsonb") private Notation notation; - - public static final long serialVersionUID = -5314619286352932857L; - - public interface Insert {} -} diff --git a/persistence/src/main/java/edu/msudenver/tsp/persistence/dto/Notation.java b/persistence/src/main/java/edu/msudenver/tsp/persistence/dto/Notation.java deleted file mode 100644 index 0545f3c..0000000 --- a/persistence/src/main/java/edu/msudenver/tsp/persistence/dto/Notation.java +++ /dev/null @@ -1,16 +0,0 @@ -package edu.msudenver.tsp.persistence.dto; - -import lombok.Getter; -import lombok.Setter; -import lombok.ToString; - -import java.io.Serializable; -import java.util.List; - -@Getter -@Setter -@ToString -public class Notation implements Serializable { - private List notations; - public static final long serialVersionUID = 2301438318932336121L; -} diff --git a/persistence/src/main/java/edu/msudenver/tsp/persistence/dto/NotationDto.java b/persistence/src/main/java/edu/msudenver/tsp/persistence/dto/NotationDto.java deleted file mode 100644 index feabde1..0000000 --- a/persistence/src/main/java/edu/msudenver/tsp/persistence/dto/NotationDto.java +++ /dev/null @@ -1,4 +0,0 @@ -package edu.msudenver.tsp.persistence.dto; - -public class NotationDto extends BaseDto { -} diff --git a/persistence/src/main/java/edu/msudenver/tsp/persistence/dto/Proof.java b/persistence/src/main/java/edu/msudenver/tsp/persistence/dto/Proof.java new file mode 100644 index 0000000..fba2b1a --- /dev/null +++ b/persistence/src/main/java/edu/msudenver/tsp/persistence/dto/Proof.java @@ -0,0 +1,97 @@ +package edu.msudenver.tsp.persistence.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.hibernate.annotations.Type; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +import javax.persistence.*; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +@Entity(name = "proofs") +@EntityListeners(AuditingEntityListener.class) +@Data +@EqualsAndHashCode(callSuper = true) +public class Proof extends BaseDto implements Serializable { + @NotBlank(groups = Insert.class) + @Size(min = 1, max = 512, message = "The name must be at least 1 character and at most 512 characters") + @Column(name = "theorem_name") + private String theoremName; + @NotNull(groups = Insert.class) + @Size(min = 1, max = 4096, message = "The proof must be at least 1 character and at most 4096 characters") + private String proof; + @NotNull(groups = Insert.class) + private Integer theorem; + @NotBlank(groups = Insert.class) + @Size(min = 1, max = 512, message = "The branch must be at least 1 character and at most 512 characters") + private String branch; + @Type(type = "json") @Column(name = "referenced_definitions", columnDefinition = "jsonb") private List referencedDefinitions; + @Type(type = "json") @Column(name = "referenced_theorems", columnDefinition = "jsonb") private List referencedTheorems; + @Temporal(TemporalType.DATE) @Column(name = "date_created") private Date dateCreated; + @Temporal(TemporalType.DATE) @Column(name = "last_updated") private Date lastUpdated; + + @JsonProperty("theorem_name") + public String getTheoremName() { + return theoremName; + } + + @JsonProperty("theorem_name") + public void setTheoremName(final String theoremName) { + this.theoremName = theoremName; + } + + @JsonProperty("referenced_definitions") + public List getReferencedDefinitions() { + return referencedDefinitions; + } + + @JsonProperty("referenced_definitions") + public void setReferencedDefinitions(final List referencedDefinitions) { + this.referencedDefinitions = referencedDefinitions; + } + + @JsonProperty("referenced_theorems") + public List getReferencedTheorems() { + return referencedTheorems; + } + + @JsonProperty("referenced_theorems") + public void setReferencedTheorems(final List referencedTheorems) { + this.referencedTheorems = referencedTheorems; + } + + @JsonProperty("date_created") + public Date getDateCreated() { + return dateCreated; + } + + @JsonProperty("date_created") + public void setDateCreated(final Date dateCreated) { + this.dateCreated = dateCreated; + } + + @JsonProperty("last_updated") + public Date getLastUpdated() { + return lastUpdated; + } + + @JsonProperty("last_updated") + public void setLastUpdated(final Date lastUpdated) { + this.lastUpdated = lastUpdated; + } + + @PrePersist + public void prePersist() { + lastUpdated = new Date(); + } + + private static final long serialVersionUID = -7731220940349760402L; + + public interface Insert {} +} diff --git a/persistence/src/main/java/edu/msudenver/tsp/persistence/dto/ProofDto.java b/persistence/src/main/java/edu/msudenver/tsp/persistence/dto/ProofDto.java deleted file mode 100644 index 195340e..0000000 --- a/persistence/src/main/java/edu/msudenver/tsp/persistence/dto/ProofDto.java +++ /dev/null @@ -1,4 +0,0 @@ -package edu.msudenver.tsp.persistence.dto; - -public class ProofDto extends BaseDto { -} diff --git a/persistence/src/main/java/edu/msudenver/tsp/persistence/dto/Theorem.java b/persistence/src/main/java/edu/msudenver/tsp/persistence/dto/Theorem.java new file mode 100644 index 0000000..5f0f2bf --- /dev/null +++ b/persistence/src/main/java/edu/msudenver/tsp/persistence/dto/Theorem.java @@ -0,0 +1,75 @@ +package edu.msudenver.tsp.persistence.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.hibernate.annotations.Type; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.EntityListeners; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.io.Serializable; +import java.util.List; + +@Entity(name = "theorems") +@EntityListeners(AuditingEntityListener.class) +@Data +@EqualsAndHashCode(callSuper = true) +public class Theorem extends BaseDto implements Serializable { + @NotBlank(groups = Insert.class) @Size(min = 1, max = 512, message = "theorem name must be between 1 and 512 characters") private String name; + @NotNull(groups = Insert.class) @Size(min = 1, max = 1024, message = "theorem must be between 1 and 1024 characters") private String theorem; + @NotNull(groups = Insert.class) @Column(name = "theorem_type") private TheoremType theoremType; + @NotNull(groups = Insert.class, message = "a branch of mathematics that this theorem is associated with must be specified") private String branch; + @Type(type = "json") @Column(name = "referenced_definitions", columnDefinition = "jsonb") private List referencedDefinitions; + @Type(type = "json") @Column(name = "referenced_theorems", columnDefinition = "jsonb") private List referencedTheorems; + @NotNull(groups = Insert.class) @Column(name = "proven_status") private boolean provenStatus; + + @JsonProperty("theorem_type") + public TheoremType getTheoremType() { + return theoremType; + } + + @JsonProperty("theorem_type") + public void setTheoremType(final TheoremType theoremType) { + this.theoremType = theoremType; + } + + @JsonProperty("referenced_definitions") + public List getReferencedDefinitions() { + return referencedDefinitions; + } + + @JsonProperty("referenced_definitions") + public void setReferencedDefinitions(final List referencedDefinitions) { + this.referencedDefinitions = referencedDefinitions; + } + + @JsonProperty("referenced_theorems") + public List getReferencedTheorems() { + return referencedTheorems; + } + + @JsonProperty("referenced_theorems") + public void setReferencedTheorems(final List referencedTheorems) { + this.referencedTheorems = referencedTheorems; + } + + @JsonProperty("proven_status") + public boolean getProvenStatus() { + return provenStatus; + } + + @JsonProperty("proven_status") + public void setProvenStatus(final boolean provenStatus) { + this.provenStatus = provenStatus; + } + + private static final long serialVersionUID = 1545568391140364425L; + + public interface Insert {} + +} diff --git a/persistence/src/main/java/edu/msudenver/tsp/persistence/dto/TheoremDto.java b/persistence/src/main/java/edu/msudenver/tsp/persistence/dto/TheoremDto.java deleted file mode 100644 index 0761432..0000000 --- a/persistence/src/main/java/edu/msudenver/tsp/persistence/dto/TheoremDto.java +++ /dev/null @@ -1,4 +0,0 @@ -package edu.msudenver.tsp.persistence.dto; - -public class TheoremDto extends BaseDto { -} diff --git a/persistence/src/main/java/edu/msudenver/tsp/persistence/dto/TheoremType.java b/persistence/src/main/java/edu/msudenver/tsp/persistence/dto/TheoremType.java new file mode 100644 index 0000000..c69b4e7 --- /dev/null +++ b/persistence/src/main/java/edu/msudenver/tsp/persistence/dto/TheoremType.java @@ -0,0 +1,5 @@ +package edu.msudenver.tsp.persistence.dto; + +public enum TheoremType { + THEOREM, PROPOSITION, LEMMA, COROLLARY +} diff --git a/persistence/src/main/java/edu/msudenver/tsp/persistence/repository/AccountsRepository.java b/persistence/src/main/java/edu/msudenver/tsp/persistence/repository/AccountsRepository.java index 454cd77..cfb0729 100644 --- a/persistence/src/main/java/edu/msudenver/tsp/persistence/repository/AccountsRepository.java +++ b/persistence/src/main/java/edu/msudenver/tsp/persistence/repository/AccountsRepository.java @@ -1,9 +1,12 @@ package edu.msudenver.tsp.persistence.repository; -import edu.msudenver.tsp.persistence.dto.AccountDto; +import edu.msudenver.tsp.persistence.dto.Account; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Repository; +import java.util.Optional; + @Repository -public interface AccountsRepository extends CrudRepository { +public interface AccountsRepository extends CrudRepository { + Optional findByUsername(String username); } diff --git a/persistence/src/main/java/edu/msudenver/tsp/persistence/repository/DefinitionRepository.java b/persistence/src/main/java/edu/msudenver/tsp/persistence/repository/DefinitionRepository.java index 1cda40a..1b90a38 100644 --- a/persistence/src/main/java/edu/msudenver/tsp/persistence/repository/DefinitionRepository.java +++ b/persistence/src/main/java/edu/msudenver/tsp/persistence/repository/DefinitionRepository.java @@ -1,11 +1,11 @@ package edu.msudenver.tsp.persistence.repository; -import edu.msudenver.tsp.persistence.dto.DefinitionDto; +import edu.msudenver.tsp.persistence.dto.Definition; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; @Repository -public interface DefinitionRepository extends JpaRepository { +public interface DefinitionRepository extends JpaRepository { } diff --git a/persistence/src/main/java/edu/msudenver/tsp/persistence/repository/NotationRepository.java b/persistence/src/main/java/edu/msudenver/tsp/persistence/repository/NotationRepository.java deleted file mode 100644 index 47f0904..0000000 --- a/persistence/src/main/java/edu/msudenver/tsp/persistence/repository/NotationRepository.java +++ /dev/null @@ -1,7 +0,0 @@ -package edu.msudenver.tsp.persistence.repository; - -import edu.msudenver.tsp.persistence.dto.BaseDto; -import org.springframework.data.repository.CrudRepository; - -public interface NotationRepository extends CrudRepository { -} diff --git a/persistence/src/main/java/edu/msudenver/tsp/persistence/repository/ProofRepository.java b/persistence/src/main/java/edu/msudenver/tsp/persistence/repository/ProofRepository.java index 8466bbb..040f740 100644 --- a/persistence/src/main/java/edu/msudenver/tsp/persistence/repository/ProofRepository.java +++ b/persistence/src/main/java/edu/msudenver/tsp/persistence/repository/ProofRepository.java @@ -1,7 +1,15 @@ package edu.msudenver.tsp.persistence.repository; -import edu.msudenver.tsp.persistence.dto.BaseDto; -import org.springframework.data.repository.CrudRepository; +import edu.msudenver.tsp.persistence.dto.Proof; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; -public interface ProofRepository extends CrudRepository { +import java.util.List; + +@Repository +public interface ProofRepository extends JpaRepository { + + List findByBranch(String branch); + + List findByTheoremName(String name); } diff --git a/persistence/src/main/java/edu/msudenver/tsp/persistence/repository/TheoremRepository.java b/persistence/src/main/java/edu/msudenver/tsp/persistence/repository/TheoremRepository.java index c4237ce..03a17db 100644 --- a/persistence/src/main/java/edu/msudenver/tsp/persistence/repository/TheoremRepository.java +++ b/persistence/src/main/java/edu/msudenver/tsp/persistence/repository/TheoremRepository.java @@ -1,7 +1,17 @@ package edu.msudenver.tsp.persistence.repository; -import edu.msudenver.tsp.persistence.dto.BaseDto; -import org.springframework.data.repository.CrudRepository; +import edu.msudenver.tsp.persistence.dto.Theorem; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; -public interface TheoremRepository extends CrudRepository { +import java.util.List; + +@Repository +public interface TheoremRepository extends JpaRepository { + + List findByBranch(String branch); + + List findByProvenStatus(Boolean provenStatus); + + List findByName(String name); } diff --git a/persistence/src/main/resources/application.properties b/persistence/src/main/resources/application.properties index 0068dff..c7ecc80 100644 --- a/persistence/src/main/resources/application.properties +++ b/persistence/src/main/resources/application.properties @@ -1,6 +1,6 @@ spring.jpa.hibernate.ddl-auto = none spring.jpa.database=mysql -spring.datasource.url=jdbc:mysql://127.0.0.1:3306/pandamonium?autoReconnect=true&useSSL=false +spring.datasource.url=jdbc:mysql://127.0.0.1:3306/pandamonium?autoReconnect=true&useSSL=false&serverTimezone=UTC spring.datasource.username=panda spring.datasource.password=secret spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver diff --git a/persistence/src/test/java/edu/msudenver/tsp/persistence/controller/AccountControllerTest.java b/persistence/src/test/java/edu/msudenver/tsp/persistence/controller/AccountControllerTest.java index 0b88630..503e2f6 100644 --- a/persistence/src/test/java/edu/msudenver/tsp/persistence/controller/AccountControllerTest.java +++ b/persistence/src/test/java/edu/msudenver/tsp/persistence/controller/AccountControllerTest.java @@ -1,6 +1,6 @@ package edu.msudenver.tsp.persistence.controller; -import edu.msudenver.tsp.persistence.dto.AccountDto; +import edu.msudenver.tsp.persistence.dto.Account; import edu.msudenver.tsp.persistence.repository.AccountsRepository; import org.junit.Test; import org.junit.runner.RunWith; @@ -33,35 +33,35 @@ public class AccountControllerTest { @Test public void testGetAllAccounts() { - final AccountDto accountDto = createAccount(); - final List accountDtoList = new ArrayList<>(); - accountDtoList.add(accountDto); - accountDtoList.add(accountDto); + final Account accountDto = createAccount(); + final List accountList = new ArrayList<>(); + accountList.add(accountDto); + accountList.add(accountDto); - when(accountsRepository.findAll()).thenReturn(accountDtoList); + when(accountsRepository.findAll()).thenReturn(accountList); - final ResponseEntity> responseEntity = accountController.getListOfAccounts(); + final ResponseEntity> responseEntity = accountController.getListOfAccounts(); assertNotNull(responseEntity); assertEquals(HttpStatus.OK, responseEntity.getStatusCode()); assertTrue(responseEntity.hasBody()); assertNotNull(responseEntity.getBody()); - responseEntity.getBody().forEach(account -> assertEquals(account, accountDto)); + responseEntity.getBody().forEach(account -> assertEquals(accountDto, account)); } @Test public void testGetAccountById() { - final AccountDto accountDto = createAccount(); - when(accountsRepository.findById(anyInt())).thenReturn(Optional.ofNullable(accountDto)); + final Account account = createAccount(); + when(accountsRepository.findById(anyInt())).thenReturn(Optional.ofNullable(account)); - final ResponseEntity responseEntity = accountController.getAccountById(1); + final ResponseEntity responseEntity = accountController.getAccountById(1); assertNotNull(responseEntity); assertTrue(responseEntity.hasBody()); assertNotNull(responseEntity.getBody()); assertEquals(HttpStatus.OK, responseEntity.getStatusCode()); - assertEquals(accountDto, responseEntity.getBody()); + assertEquals(account, responseEntity.getBody()); verify(accountsRepository).findById(anyInt()); } @@ -88,18 +88,70 @@ public class AccountControllerTest { } @Test - public void testInsertAccount() { - final AccountDto accountDto = createAccount(); - when(accountsRepository.save(any(AccountDto.class))).thenReturn(accountDto); + public void testGetAccountByUsername() { + final Account account = createAccount(); + when(accountsRepository.findByUsername(anyString())).thenReturn(Optional.ofNullable(account)); - final ResponseEntity responseEntity = accountController.insertAccount(accountDto, bindingResult); + final ResponseEntity responseEntity = accountController.getAccountByUsername("Test username"); + + assertNotNull(responseEntity); + assertTrue(responseEntity.hasBody()); + assertNotNull(responseEntity.getBody()); + assertEquals(HttpStatus.OK, responseEntity.getStatusCode()); + assertEquals(account, responseEntity.getBody()); + verify(accountsRepository).findByUsername(anyString()); + } + + @Test + public void testGetAccountById_nullUsername() { + final ResponseEntity responseEntity = accountController.getAccountByUsername(null); + + assertNotNull(responseEntity); + assertFalse(responseEntity.hasBody()); + assertEquals(HttpStatus.BAD_REQUEST, responseEntity.getStatusCode()); + verifyZeroInteractions(accountsRepository); + } + + @Test + public void testGetAccountByUsername_noAccountFound() { + when(accountsRepository.findByUsername(anyString())).thenReturn(Optional.empty()); + + final ResponseEntity responseEntity = accountController.getAccountByUsername("Test username"); + + assertNotNull(responseEntity); + assertFalse(responseEntity.hasBody()); + assertEquals(HttpStatus.NOT_FOUND, responseEntity.getStatusCode()); + verify(accountsRepository).findByUsername(anyString()); + } + + @Test + public void testInsertAccount() { + final Account account = createAccount(); + when(accountsRepository.save(any(Account.class))).thenReturn(account); + when(accountsRepository.findByUsername(anyString())).thenReturn(Optional.empty()); + + final ResponseEntity responseEntity = accountController.insertAccount(account, bindingResult); assertNotNull(responseEntity); assertTrue(responseEntity.hasBody()); assertNotNull(responseEntity.getBody()); assertEquals(HttpStatus.CREATED, responseEntity.getStatusCode()); - assertEquals(accountDto, responseEntity.getBody()); - verify(accountsRepository).save(any(AccountDto.class)); + assertEquals(account, responseEntity.getBody()); + verify(accountsRepository).save(any(Account.class)); + } + + @Test + public void testInsertAccount_usernameAlreadyExists() { + final Account account = createAccount(); + when(accountsRepository.findByUsername(anyString())).thenReturn(Optional.of(account)); + + final ResponseEntity responseEntity = accountController.insertAccount(account, bindingResult); + + assertNotNull(responseEntity); + assertFalse(responseEntity.hasBody()); + assertEquals(HttpStatus.CONFLICT, responseEntity.getStatusCode()); + verify(accountsRepository).findByUsername(anyString()); + verify(accountsRepository, times(0)).save(any(Account.class)); } @Test @@ -114,10 +166,10 @@ public class AccountControllerTest { @Test public void testInsertAccount_bindingResultHasErrors() { - final AccountDto definitionDto = createAccount(); + final Account account = createAccount(); when(bindingResult.hasErrors()).thenReturn(true); - final ResponseEntity responseEntity = accountController.insertAccount(definitionDto, bindingResult); + final ResponseEntity responseEntity = accountController.insertAccount(account, bindingResult); assertNotNull(responseEntity); assertFalse(responseEntity.hasBody()); @@ -127,31 +179,31 @@ public class AccountControllerTest { @Test public void testUpdateAccount() { - final AccountDto existingAccount = createAccount(); + final Account existingAccount = createAccount(); existingAccount.setId(1); existingAccount.setVersion(1); - final AccountDto accountUpdate = new AccountDto(); + final Account accountUpdate = new Account(); accountUpdate.setUsername("Test Update"); - final AccountDto updatedAccount = existingAccount; + final Account updatedAccount = existingAccount; updatedAccount.setUsername("Test Update"); when(accountsRepository.findById(anyInt())).thenReturn(Optional.of(existingAccount)); - when(accountsRepository.save(any(AccountDto.class))).thenReturn(updatedAccount); + when(accountsRepository.save(any(Account.class))).thenReturn(updatedAccount); - final ResponseEntity responseEntity = accountController.updateAccount(1, accountUpdate, bindingResult); + final ResponseEntity responseEntity = accountController.updateAccount(1, accountUpdate, bindingResult); assertNotNull(responseEntity); assertTrue(responseEntity.hasBody()); assertEquals(HttpStatus.OK, responseEntity.getStatusCode()); assertEquals(updatedAccount, responseEntity.getBody()); verify(accountsRepository).findById(anyInt()); - verify(accountsRepository).save(any(AccountDto.class)); + verify(accountsRepository).save(any(Account.class)); } @Test public void testUpdateAccount_bindingResultHasErrors() { when(bindingResult.hasErrors()).thenReturn(true); - final ResponseEntity responseEntity = accountController.updateAccount(1, createAccount(), bindingResult); + final ResponseEntity responseEntity = accountController.updateAccount(1, createAccount(), bindingResult); assertNotNull(responseEntity); assertFalse(responseEntity.hasBody()); @@ -161,7 +213,7 @@ public class AccountControllerTest { @Test public void testUpdateAccount_accountsDtoIsNull() { - final ResponseEntity responseEntity = accountController.updateAccount(1, null, bindingResult); + final ResponseEntity responseEntity = accountController.updateAccount(1, null, bindingResult); assertNotNull(responseEntity); assertFalse(responseEntity.hasBody()); @@ -171,7 +223,7 @@ public class AccountControllerTest { @Test public void testUpdateAccount_idIsNull() { - final ResponseEntity responseEntity = accountController.updateAccount(null, createAccount(), bindingResult); + final ResponseEntity responseEntity = accountController.updateAccount(null, createAccount(), bindingResult); assertNotNull(responseEntity); assertFalse(responseEntity.hasBody()); @@ -183,12 +235,12 @@ public class AccountControllerTest { public void testUpdateAccount_accountDoesNotExist() { when(accountsRepository.findById(anyInt())).thenReturn(Optional.empty()); - final ResponseEntity responseEntity = accountController.updateAccount(1, createAccount(), bindingResult); + final ResponseEntity responseEntity = accountController.updateAccount(1, createAccount(), bindingResult); assertNotNull(responseEntity); assertFalse(responseEntity.hasBody()); assertEquals(HttpStatus.BAD_REQUEST, responseEntity.getStatusCode()); - verify(accountsRepository, times(0)).save(any(AccountDto.class)); + verify(accountsRepository, times(0)).save(any(Account.class)); } @Test @@ -213,12 +265,12 @@ public class AccountControllerTest { verifyZeroInteractions(accountsRepository); } - private AccountDto createAccount() { - final AccountDto accountDto = new AccountDto(); - accountDto.setUsername("Test username"); - accountDto.setPassword("test password"); - accountDto.setAdministratorStatus(true); + private Account createAccount() { + final Account account = new Account(); + account.setUsername("Test username"); + account.setPassword("test password"); + account.setAdministratorStatus(true); - return accountDto; + return account; } } \ No newline at end of file diff --git a/persistence/src/test/java/edu/msudenver/tsp/persistence/controller/DefinitionControllerTest.java b/persistence/src/test/java/edu/msudenver/tsp/persistence/controller/DefinitionControllerTest.java index b24d508..4b7fa77 100644 --- a/persistence/src/test/java/edu/msudenver/tsp/persistence/controller/DefinitionControllerTest.java +++ b/persistence/src/test/java/edu/msudenver/tsp/persistence/controller/DefinitionControllerTest.java @@ -1,8 +1,6 @@ package edu.msudenver.tsp.persistence.controller; import edu.msudenver.tsp.persistence.dto.Definition; -import edu.msudenver.tsp.persistence.dto.DefinitionDto; -import edu.msudenver.tsp.persistence.dto.Notation; import edu.msudenver.tsp.persistence.repository.DefinitionRepository; import org.junit.Test; import org.junit.runner.RunWith; @@ -32,35 +30,35 @@ public class DefinitionControllerTest { @Test public void testGetAllDefinitions() { - final DefinitionDto definitionDto = createDefinition(); - final List definitionDtoList = new ArrayList<>(); - definitionDtoList.add(definitionDto); - definitionDtoList.add(definitionDto); + final Definition definitionDto = createDefinition(); + final List definitionList = new ArrayList<>(); + definitionList.add(definitionDto); + definitionList.add(definitionDto); - when(definitionRepository.findAll()).thenReturn(definitionDtoList); + when(definitionRepository.findAll()).thenReturn(definitionList); - final ResponseEntity> responseEntity = definitionController.getAllDefinitions(); + final ResponseEntity> responseEntity = definitionController.getAllDefinitions(); assertNotNull(responseEntity); assertEquals(HttpStatus.OK, responseEntity.getStatusCode()); assertTrue(responseEntity.hasBody()); assertNotNull(responseEntity.getBody()); - responseEntity.getBody().forEach(definition -> assertEquals(definition, definitionDto)); + responseEntity.getBody().forEach(definition -> assertEquals(definitionDto, definition)); } @Test public void testGetDefinitionsById() { - final DefinitionDto definitionDto = createDefinition(); - when(definitionRepository.findById(anyInt())).thenReturn(Optional.ofNullable(definitionDto)); + final Definition definition = createDefinition(); + when(definitionRepository.findById(anyInt())).thenReturn(Optional.ofNullable(definition)); - final ResponseEntity responseEntity = definitionController.getDefinitionById(1); + final ResponseEntity responseEntity = definitionController.getDefinitionById(1); assertNotNull(responseEntity); assertTrue(responseEntity.hasBody()); assertNotNull(responseEntity.getBody()); assertEquals(HttpStatus.OK, responseEntity.getStatusCode()); - assertEquals(definitionDto, responseEntity.getBody()); + assertEquals(definition, responseEntity.getBody()); verify(definitionRepository).findById(anyInt()); } @@ -88,17 +86,17 @@ public class DefinitionControllerTest { @Test public void testInsertDefinition() { - final DefinitionDto definitionDto = createDefinition(); - when(definitionRepository.save(any(DefinitionDto.class))).thenReturn(definitionDto); + final Definition definition = createDefinition(); + when(definitionRepository.save(any(Definition.class))).thenReturn(definition); - final ResponseEntity responseEntity = definitionController.insertDefinition(definitionDto, bindingResult); + final ResponseEntity responseEntity = definitionController.insertDefinition(definition, bindingResult); assertNotNull(responseEntity); assertTrue(responseEntity.hasBody()); assertNotNull(responseEntity.getBody()); assertEquals(HttpStatus.CREATED, responseEntity.getStatusCode()); - assertEquals(definitionDto, responseEntity.getBody()); - verify(definitionRepository).save(any(DefinitionDto.class)); + assertEquals(definition, responseEntity.getBody()); + verify(definitionRepository).save(any(Definition.class)); } @Test @@ -113,10 +111,10 @@ public class DefinitionControllerTest { @Test public void testInsertDefinition_bindingResultHasErrors() { - final DefinitionDto definitionDto = createDefinition(); + final Definition definition = createDefinition(); when(bindingResult.hasErrors()).thenReturn(true); - final ResponseEntity responseEntity = definitionController.insertDefinition(definitionDto, bindingResult); + final ResponseEntity responseEntity = definitionController.insertDefinition(definition, bindingResult); assertNotNull(responseEntity); assertFalse(responseEntity.hasBody()); @@ -126,31 +124,31 @@ public class DefinitionControllerTest { @Test public void testUpdateDefinition() { - final DefinitionDto existingDefinition = createDefinition(); + final Definition existingDefinition = createDefinition(); existingDefinition.setId(1); existingDefinition.setVersion(1); - final DefinitionDto definitionUpdate = new DefinitionDto(); + final Definition definitionUpdate = new Definition(); definitionUpdate.setName("Test Update"); - final DefinitionDto updatedDefinition = existingDefinition; + final Definition updatedDefinition = existingDefinition; updatedDefinition.setName("Test Update"); when(definitionRepository.findById(anyInt())).thenReturn(Optional.of(existingDefinition)); - when(definitionRepository.save(any(DefinitionDto.class))).thenReturn(updatedDefinition); + when(definitionRepository.save(any(Definition.class))).thenReturn(updatedDefinition); - final ResponseEntity responseEntity = definitionController.updateDefinition(1, definitionUpdate, bindingResult); + final ResponseEntity responseEntity = definitionController.updateDefinition(1, definitionUpdate, bindingResult); assertNotNull(responseEntity); assertTrue(responseEntity.hasBody()); assertEquals(HttpStatus.OK, responseEntity.getStatusCode()); assertEquals(updatedDefinition, responseEntity.getBody()); verify(definitionRepository).findById(anyInt()); - verify(definitionRepository).save(any(DefinitionDto.class)); + verify(definitionRepository).save(any(Definition.class)); } @Test public void testUpdateDefinition_bindingResultErrors() { when(bindingResult.hasErrors()).thenReturn(true); - final ResponseEntity responseEntity = definitionController.updateDefinition(1, createDefinition(), bindingResult); + final ResponseEntity responseEntity = definitionController.updateDefinition(1, createDefinition(), bindingResult); assertNotNull(responseEntity); assertFalse(responseEntity.hasBody()); @@ -160,7 +158,7 @@ public class DefinitionControllerTest { @Test public void testUpdateDefinition_definitionDtoIsNull() { - final ResponseEntity responseEntity = definitionController.updateDefinition(1, null, bindingResult); + final ResponseEntity responseEntity = definitionController.updateDefinition(1, null, bindingResult); assertNotNull(responseEntity); assertFalse(responseEntity.hasBody()); @@ -170,7 +168,7 @@ public class DefinitionControllerTest { @Test public void testUpdateDefinition_idIsNull() { - final ResponseEntity responseEntity = definitionController.updateDefinition(null, createDefinition(), bindingResult); + final ResponseEntity responseEntity = definitionController.updateDefinition(null, createDefinition(), bindingResult); assertNotNull(responseEntity); assertFalse(responseEntity.hasBody()); @@ -182,12 +180,12 @@ public class DefinitionControllerTest { public void testUpdateDefinition_definitionDoesntExist() { when(definitionRepository.findById(anyInt())).thenReturn(Optional.empty()); - final ResponseEntity responseEntity = definitionController.updateDefinition(1, createDefinition(), bindingResult); + final ResponseEntity responseEntity = definitionController.updateDefinition(1, createDefinition(), bindingResult); assertNotNull(responseEntity); assertFalse(responseEntity.hasBody()); assertEquals(HttpStatus.BAD_REQUEST, responseEntity.getStatusCode()); - verify(definitionRepository, times(0)).save(any(DefinitionDto.class)); + verify(definitionRepository, times(0)).save(any(Definition.class)); } @Test @@ -212,24 +210,18 @@ public class DefinitionControllerTest { verifyZeroInteractions(definitionRepository); } - private DefinitionDto createDefinition() { + private Definition createDefinition() { final List definitionList = new ArrayList<>(); definitionList.add("Test definition 1"); - final Definition definition = new Definition(); - definition.setDefinitions(definitionList); - final List notationList = new ArrayList<>(); notationList.add("\\testLaTeX"); - final Notation notation = new Notation(); - notation.setNotations(notationList); + final Definition definition = new Definition(); + definition.setName("Test Name"); + definition.setDefinition(definitionList); + definition.setNotation(notationList); - final DefinitionDto definitionDto = new DefinitionDto(); - definitionDto.setName("Test Name"); - definitionDto.setDefinition(definition); - definitionDto.setNotation(notation); - - return definitionDto; + return definition; } } \ No newline at end of file diff --git a/persistence/src/test/java/edu/msudenver/tsp/persistence/controller/ProofControllerTest.java b/persistence/src/test/java/edu/msudenver/tsp/persistence/controller/ProofControllerTest.java new file mode 100644 index 0000000..14c2482 --- /dev/null +++ b/persistence/src/test/java/edu/msudenver/tsp/persistence/controller/ProofControllerTest.java @@ -0,0 +1,310 @@ +package edu.msudenver.tsp.persistence.controller; + +import edu.msudenver.tsp.persistence.dto.Proof; +import edu.msudenver.tsp.persistence.repository.ProofRepository; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.BindingResult; + +import java.util.*; + +import static junit.framework.TestCase.assertTrue; +import static org.junit.Assert.*; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.*; + +@RunWith(MockitoJUnitRunner.class) +public class ProofControllerTest { + @Mock private ProofRepository proofRepository; + @InjectMocks private ProofController proofController; + @Mock private BindingResult bindingResult; + + @Test + public void testGetAllProofs() { + final Proof proofDto = createProof(); + final List listOfProofs = new ArrayList<>(); + listOfProofs.add(proofDto); + listOfProofs.add(proofDto); + + when(proofRepository.findAll()).thenReturn(listOfProofs); + + final ResponseEntity> responseEntity = proofController.getAllProofs(); + + assertNotNull(responseEntity); + assertEquals(HttpStatus.OK, responseEntity.getStatusCode()); + assertTrue(responseEntity.hasBody()); + assertNotNull(responseEntity.getBody()); + + responseEntity.getBody().forEach(proof -> assertEquals(proofDto, proof)); + } + + @Test + public void testGetAllProofsByBranch() { + final Proof proofDto = createProof(); + final List listOfProofs = new ArrayList<>(); + listOfProofs.add(proofDto); + listOfProofs.add(proofDto); + + when(proofRepository.findByBranch(anyString())).thenReturn(listOfProofs); + + final ResponseEntity> responseEntity = proofController.getAllProofsByBranch("Test_branch"); + + assertNotNull(responseEntity); + assertEquals(HttpStatus.OK, responseEntity.getStatusCode()); + assertTrue(responseEntity.hasBody()); + assertNotNull(responseEntity.getBody()); + + responseEntity.getBody().forEach(proof -> assertEquals(proofDto, proof)); + } + + @Test + public void testGetAllProfsByBranch_nullBranch() { + final ResponseEntity> responseEntity = proofController.getAllProofsByBranch(null); + + assertNotNull(responseEntity); + assertFalse(responseEntity.hasBody()); + assertEquals(HttpStatus.BAD_REQUEST, responseEntity.getStatusCode()); + verifyZeroInteractions(proofRepository); + } + + @Test + public void testGetAllProofsByBranch_noProofsFound() { + when(proofRepository.findByBranch(anyString())).thenReturn(Collections.emptyList()); + + final ResponseEntity> responseEntity = proofController.getAllProofsByBranch("test-nonexistent-branch"); + + assertNotNull(responseEntity); + assertFalse(responseEntity.hasBody()); + assertEquals(HttpStatus.NOT_FOUND, responseEntity.getStatusCode()); + } + + @Test + public void testGetAllProofsByTheoremName() { + final Proof proofDto = createProof(); + final List listOfProofs = new ArrayList<>(); + listOfProofs.add(proofDto); + listOfProofs.add(proofDto); + + when(proofRepository.findByTheoremName(anyString())).thenReturn(listOfProofs); + + final ResponseEntity> responseEntity = proofController.getAllProofsByTheoremName("Test_proof"); + + assertNotNull(responseEntity); + assertEquals(HttpStatus.OK, responseEntity.getStatusCode()); + assertTrue(responseEntity.hasBody()); + assertNotNull(responseEntity.getBody()); + + responseEntity.getBody().forEach(proof -> assertEquals(proofDto, proof)); + } + + @Test + public void testGetAllProofsByTheoremName_nullTheoremName() { + final ResponseEntity> responseEntity = proofController.getAllProofsByTheoremName(null); + + assertNotNull(responseEntity); + assertFalse(responseEntity.hasBody()); + assertEquals(HttpStatus.BAD_REQUEST, responseEntity.getStatusCode()); + verifyZeroInteractions(proofRepository); + } + + @Test + public void testGetAllProofsByTheoremName_noProofsFound() { + when(proofRepository.findByTheoremName(anyString())).thenReturn(Collections.emptyList()); + + final ResponseEntity> responseEntity = proofController.getAllProofsByTheoremName("test-nonexistent-proof"); + + assertNotNull(responseEntity); + assertFalse(responseEntity.hasBody()); + assertEquals(HttpStatus.NOT_FOUND, responseEntity.getStatusCode()); + } + + @Test + public void testGetProofById() { + final Proof proof = createProof(); + when(proofRepository.findById(anyInt())).thenReturn(Optional.ofNullable(proof)); + + final ResponseEntity responseEntity = proofController.getProofById(1); + + assertNotNull(responseEntity); + assertTrue(responseEntity.hasBody()); + assertNotNull(responseEntity.getBody()); + assertEquals(HttpStatus.OK, responseEntity.getStatusCode()); + assertEquals(proof, responseEntity.getBody()); + verify(proofRepository).findById(anyInt()); + } + + @Test + public void testGetProofById_nullId() { + final ResponseEntity responseEntity = proofController.getProofById(null); + + assertNotNull(responseEntity); + assertFalse(responseEntity.hasBody()); + assertEquals(HttpStatus.BAD_REQUEST, responseEntity.getStatusCode()); + verifyZeroInteractions(proofRepository); + } + + @Test + public void testGetProofById_noProofFound() { + when(proofRepository.findById(anyInt())).thenReturn(Optional.empty()); + + final ResponseEntity responseEntity = proofController.getProofById(1); + + assertNotNull(responseEntity); + assertFalse(responseEntity.hasBody()); + assertEquals(HttpStatus.NOT_FOUND, responseEntity.getStatusCode()); + verify(proofRepository).findById(anyInt()); + } + + @Test + public void testInsertProof() { + final Proof proof = createProof(); + when(proofRepository.save(any(Proof.class))).thenReturn(proof); + + final ResponseEntity responseEntity = proofController.insertProof(proof, bindingResult); + + assertNotNull(responseEntity); + assertTrue(responseEntity.hasBody()); + assertNotNull(responseEntity.getBody()); + assertEquals(HttpStatus.CREATED, responseEntity.getStatusCode()); + assertEquals(proof, responseEntity.getBody()); + verify(proofRepository).save(any(Proof.class)); + } + + @Test + public void testInsertProof_proofDtoIsNull() { + final ResponseEntity responseEntity = proofController.insertProof(null, bindingResult); + + assertNotNull(responseEntity); + assertFalse(responseEntity.hasBody()); + assertEquals(HttpStatus.BAD_REQUEST, responseEntity.getStatusCode()); + verifyZeroInteractions(proofRepository); + } + + @Test + public void testInsertProof_bindingResultHasErrors() { + final Proof proof = createProof(); + when(bindingResult.hasErrors()).thenReturn(true); + + final ResponseEntity responseEntity = proofController.insertProof(proof, bindingResult); + + assertNotNull(responseEntity); + assertFalse(responseEntity.hasBody()); + assertEquals(HttpStatus.UNPROCESSABLE_ENTITY, responseEntity.getStatusCode()); + verifyZeroInteractions(proofRepository); + } + + @Test + public void testUpdateProof() { + final Proof existingProof = createProof(); + existingProof.setId(1); + existingProof.setVersion(1); + final Proof proofUpdate = new Proof(); + proofUpdate.setTheoremName("Test Update"); + final Proof updatedProof = existingProof; + updatedProof.setTheoremName("Test Update"); + when(proofRepository.findById(anyInt())).thenReturn(Optional.of(existingProof)); + when(proofRepository.save(any(Proof.class))).thenReturn(updatedProof); + + final ResponseEntity responseEntity = proofController.updateProof(1, proofUpdate, bindingResult); + + assertNotNull(responseEntity); + assertTrue(responseEntity.hasBody()); + assertEquals(HttpStatus.OK, responseEntity.getStatusCode()); + assertEquals(updatedProof, responseEntity.getBody()); + verify(proofRepository).findById(anyInt()); + verify(proofRepository).save(any(Proof.class)); + } + + @Test + public void testUpdateProof_bindingResultHasErrors() { + when(bindingResult.hasErrors()).thenReturn(true); + + final ResponseEntity responseEntity = proofController.updateProof(1, createProof(), bindingResult); + + assertNotNull(responseEntity); + assertFalse(responseEntity.hasBody()); + assertEquals(HttpStatus.UNPROCESSABLE_ENTITY, responseEntity.getStatusCode()); + verifyZeroInteractions(proofRepository); + } + + @Test + public void testUpdateProof_proofDtoIsNull() { + final ResponseEntity responseEntity = proofController.updateProof(1, null, bindingResult); + + assertNotNull(responseEntity); + assertFalse(responseEntity.hasBody()); + assertEquals(HttpStatus.BAD_REQUEST, responseEntity.getStatusCode()); + verifyZeroInteractions(proofRepository); + } + + @Test + public void testUpdateProof_idIsNull() { + final ResponseEntity responseEntity = proofController.updateProof(null, createProof(), bindingResult); + + assertNotNull(responseEntity); + assertFalse(responseEntity.hasBody()); + assertEquals(HttpStatus.BAD_REQUEST, responseEntity.getStatusCode()); + verifyZeroInteractions(proofRepository); + } + + @Test + public void testUpdateProof_theoremDoesNotExist() { + when(proofRepository.findById(anyInt())).thenReturn(Optional.empty()); + + final ResponseEntity responseEntity = proofController.updateProof(1, createProof(), bindingResult); + + assertNotNull(responseEntity); + assertFalse(responseEntity.hasBody()); + assertEquals(HttpStatus.BAD_REQUEST, responseEntity.getStatusCode()); + verify(proofRepository, times(0)).save(any(Proof.class)); + } + + @Test + public void testDeleteProofById() { + doNothing().when(proofRepository).deleteById(anyInt()); + + final ResponseEntity responseEntity = proofController.deleteProofById(1); + + assertNotNull(responseEntity); + assertFalse(responseEntity.hasBody()); + assertEquals(HttpStatus.NO_CONTENT, responseEntity.getStatusCode()); + verify(proofRepository).deleteById(anyInt()); + } + + @Test + public void testDeleteProofById_idIsNull() { + final ResponseEntity responseEntity = proofController.deleteProofById(null); + + assertNotNull(responseEntity); + assertFalse(responseEntity.hasBody()); + assertEquals(HttpStatus.BAD_REQUEST, responseEntity.getStatusCode()); + verifyZeroInteractions(proofRepository); + } + + private Proof createProof() { + final List referencedTheoremsList = new ArrayList<>(); + referencedTheoremsList.add("test theorem 1"); + referencedTheoremsList.add("test theorem 2"); + + final List referencedDefinitionsList = new ArrayList<>(); + referencedDefinitionsList.add("test definition 1"); + referencedDefinitionsList.add("test definition 2"); + + final Proof proof = new Proof(); + proof.setTheoremName("Test proof"); + proof.setTheorem(1); + proof.setBranch("Test branch"); + proof.setProof("test proof"); + proof.setDateCreated(new Date()); + proof.setReferencedTheorems(referencedTheoremsList); + proof.setReferencedDefinitions(referencedDefinitionsList); + + return proof; + } +} \ No newline at end of file diff --git a/persistence/src/test/java/edu/msudenver/tsp/persistence/controller/TheoremControllerTest.java b/persistence/src/test/java/edu/msudenver/tsp/persistence/controller/TheoremControllerTest.java new file mode 100644 index 0000000..a667d0a --- /dev/null +++ b/persistence/src/test/java/edu/msudenver/tsp/persistence/controller/TheoremControllerTest.java @@ -0,0 +1,364 @@ +package edu.msudenver.tsp.persistence.controller; + +import edu.msudenver.tsp.persistence.dto.Theorem; +import edu.msudenver.tsp.persistence.dto.TheoremType; +import edu.msudenver.tsp.persistence.repository.TheoremRepository; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.BindingResult; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Optional; + +import static junit.framework.TestCase.assertTrue; +import static org.junit.Assert.*; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Mockito.*; + +@RunWith(MockitoJUnitRunner.class) +@WebMvcTest(controllers = TheoremController.class) +public class TheoremControllerTest { + @Mock private TheoremRepository theoremRepository; + @InjectMocks private TheoremController theoremController; + @Mock private BindingResult bindingResult; + + @Test + public void testGetAllTheorems() { + final Theorem theoremDto = createTheorem(); + final List listOfTheorems = new ArrayList<>(); + listOfTheorems.add(theoremDto); + listOfTheorems.add(theoremDto); + + when(theoremRepository.findAll()).thenReturn(listOfTheorems); + + final ResponseEntity> responseEntity = theoremController.getAllTheorems(); + + assertNotNull(responseEntity); + assertEquals(HttpStatus.OK, responseEntity.getStatusCode()); + assertTrue(responseEntity.hasBody()); + assertNotNull(responseEntity.getBody()); + + responseEntity.getBody().forEach(theorem -> assertEquals(theoremDto, theorem)); + } + + @Test + public void testGetTheoremById() { + final Theorem theorem = createTheorem(); + when(theoremRepository.findById(anyInt())).thenReturn(Optional.ofNullable(theorem)); + + final ResponseEntity responseEntity = theoremController.getTheoremById(1); + + assertNotNull(responseEntity); + assertTrue(responseEntity.hasBody()); + assertNotNull(responseEntity.getBody()); + assertEquals(HttpStatus.OK, responseEntity.getStatusCode()); + assertEquals(theorem, responseEntity.getBody()); + verify(theoremRepository).findById(anyInt()); + } + + @Test + public void testGetTheoremById_nullId() { + final ResponseEntity responseEntity = theoremController.getTheoremById(null); + + assertNotNull(responseEntity); + assertFalse(responseEntity.hasBody()); + assertEquals(HttpStatus.BAD_REQUEST, responseEntity.getStatusCode()); + verifyZeroInteractions(theoremRepository); + } + + @Test + public void testGetTheoremById_noTheoremFound() { + when(theoremRepository.findById(anyInt())).thenReturn(Optional.empty()); + + final ResponseEntity responseEntity = theoremController.getTheoremById(1); + + assertNotNull(responseEntity); + assertFalse(responseEntity.hasBody()); + assertEquals(HttpStatus.NOT_FOUND, responseEntity.getStatusCode()); + verify(theoremRepository).findById(anyInt()); + } + + @Test + public void testGetAllTheoremsByBranch() { + final Theorem theoremDto = createTheorem(); + final List listOfTheorems = new ArrayList<>(); + listOfTheorems.add(theoremDto); + listOfTheorems.add(theoremDto); + + when(theoremRepository.findByBranch(anyString())).thenReturn(listOfTheorems); + + final ResponseEntity> responseEntity = theoremController.getAllTheoremsByBranch("test-branch"); + + assertNotNull(responseEntity); + assertEquals(HttpStatus.OK, responseEntity.getStatusCode()); + assertTrue(responseEntity.hasBody()); + assertNotNull(responseEntity.getBody()); + + responseEntity.getBody().forEach(theorem -> assertEquals(theoremDto, theorem)); + } + + @Test + public void testGetAllTheoremsByBranch_nullBranch() { + final ResponseEntity> responseEntity = theoremController.getAllTheoremsByBranch(null); + + assertNotNull(responseEntity); + assertFalse(responseEntity.hasBody()); + assertEquals(HttpStatus.BAD_REQUEST, responseEntity.getStatusCode()); + verifyZeroInteractions(theoremRepository); + } + + @Test + public void testGetAllTheoremsByBranch_noTheoremsFound() { + when(theoremRepository.findByBranch(anyString())).thenReturn(Collections.emptyList()); + + final ResponseEntity> responseEntity = theoremController.getAllTheoremsByBranch("test_nonexistent_branch"); + + assertNotNull(responseEntity); + assertFalse(responseEntity.hasBody()); + assertEquals(HttpStatus.NOT_FOUND, responseEntity.getStatusCode()); + } + + @Test + public void testGetAllTheoremsByProvenStatus() { + final Theorem theoremDto = createTheorem(); + final List listOfTheorems = new ArrayList<>(); + listOfTheorems.add(theoremDto); + listOfTheorems.add(theoremDto); + + when(theoremRepository.findByProvenStatus(anyBoolean())).thenReturn(listOfTheorems); + + final ResponseEntity> responseEntity = theoremController.getAllTheoremsByProvenStatus("true"); + + assertNotNull(responseEntity); + assertEquals(HttpStatus.OK, responseEntity.getStatusCode()); + assertTrue(responseEntity.hasBody()); + assertNotNull(responseEntity.getBody()); + + responseEntity.getBody().forEach(theorem -> assertEquals(theoremDto, theorem)); + } + + @Test + public void testGetAllTheoremsByProvenStatus_nullProvenStatus() { + final ResponseEntity> responseEntity = theoremController.getAllTheoremsByProvenStatus(null); + + assertNotNull(responseEntity); + assertFalse(responseEntity.hasBody()); + assertEquals(HttpStatus.BAD_REQUEST, responseEntity.getStatusCode()); + verifyZeroInteractions(theoremRepository); + } + + @Test + public void testGetAllTheoremsByProvenStatus_invalidProvenStatus() { + final ResponseEntity> responseEntity = theoremController.getAllTheoremsByProvenStatus("test"); + + assertNotNull(responseEntity); + assertFalse(responseEntity.hasBody()); + assertEquals(HttpStatus.NOT_FOUND, responseEntity.getStatusCode()); + } + + @Test + public void testGetAllTheoremsByProvenStatus_noTheoremsFound() { + when(theoremRepository.findByProvenStatus(anyBoolean())).thenReturn(Collections.emptyList()); + + final ResponseEntity> responseEntity = theoremController.getAllTheoremsByProvenStatus("false"); + + assertNotNull(responseEntity); + assertFalse(responseEntity.hasBody()); + assertEquals(HttpStatus.NOT_FOUND, responseEntity.getStatusCode()); + } + + @Test + public void testGetAllTheoremsByName() { + final Theorem theoremDto = createTheorem(); + final List listOfTheorems = new ArrayList<>(); + listOfTheorems.add(theoremDto); + listOfTheorems.add(theoremDto); + + when(theoremRepository.findByName(anyString())).thenReturn(listOfTheorems); + + final ResponseEntity> responseEntity = theoremController.getAllTheoremsByName("Test_Theorem"); + + assertNotNull(responseEntity); + assertEquals(HttpStatus.OK, responseEntity.getStatusCode()); + assertTrue(responseEntity.hasBody()); + assertNotNull(responseEntity.getBody()); + + responseEntity.getBody().forEach(theorem -> assertEquals(theoremDto, theorem)); + } + + @Test + public void testGetAllTheoremsByName_nullName() { + final ResponseEntity> responseEntity = theoremController.getAllTheoremsByName(null); + + assertNotNull(responseEntity); + assertFalse(responseEntity.hasBody()); + assertEquals(HttpStatus.BAD_REQUEST, responseEntity.getStatusCode()); + verifyZeroInteractions(theoremRepository); + } + + @Test + public void testGetAllTheoremsByName_noNameFound() { + when(theoremRepository.findByName(anyString())).thenReturn(Collections.emptyList()); + + final ResponseEntity> responseEntity = theoremController.getAllTheoremsByName("No-name"); + + assertNotNull(responseEntity); + assertFalse(responseEntity.hasBody()); + assertEquals(HttpStatus.NOT_FOUND, responseEntity.getStatusCode()); + } + + @Test + public void testInsertTheorem() { + final Theorem theorem = createTheorem(); + when(theoremRepository.save(any(Theorem.class))).thenReturn(theorem); + + final ResponseEntity responseEntity = theoremController.insertTheorem(theorem, bindingResult); + + assertNotNull(responseEntity); + assertTrue(responseEntity.hasBody()); + assertNotNull(responseEntity.getBody()); + assertEquals(HttpStatus.CREATED, responseEntity.getStatusCode()); + assertEquals(theorem, responseEntity.getBody()); + verify(theoremRepository).save(any(Theorem.class)); + } + + @Test + public void testInsertTheorem_theoremDtoIsNull() { + final ResponseEntity responseEntity = theoremController.insertTheorem(null, bindingResult); + + assertNotNull(responseEntity); + assertFalse(responseEntity.hasBody()); + assertEquals(HttpStatus.BAD_REQUEST, responseEntity.getStatusCode()); + verifyZeroInteractions(theoremRepository); + } + + @Test + public void testInsertTheorem_bindingResultHasErrors() { + final Theorem theorem = createTheorem(); + when(bindingResult.hasErrors()).thenReturn(true); + + final ResponseEntity responseEntity = theoremController.insertTheorem(theorem, bindingResult); + + assertNotNull(responseEntity); + assertFalse(responseEntity.hasBody()); + assertEquals(HttpStatus.UNPROCESSABLE_ENTITY, responseEntity.getStatusCode()); + verifyZeroInteractions(theoremRepository); + } + + @Test + public void testUpdateTheorem() { + final Theorem existingTheorem = createTheorem(); + existingTheorem.setId(1); + existingTheorem.setVersion(1); + final Theorem theoremUpdate = new Theorem(); + theoremUpdate.setName("Test Update"); + final Theorem updatedTheorem = existingTheorem; + updatedTheorem.setName("Test Update"); + when(theoremRepository.findById(anyInt())).thenReturn(Optional.of(existingTheorem)); + when(theoremRepository.save(any(Theorem.class))).thenReturn(updatedTheorem); + + final ResponseEntity responseEntity = theoremController.updateTheorem(1, theoremUpdate, bindingResult); + + assertNotNull(responseEntity); + assertTrue(responseEntity.hasBody()); + assertEquals(HttpStatus.OK, responseEntity.getStatusCode()); + assertEquals(updatedTheorem, responseEntity.getBody()); + verify(theoremRepository).findById(anyInt()); + verify(theoremRepository).save(any(Theorem.class)); + } + + @Test + public void testUpdateTheorem_bindingResultHasErrors() { + when(bindingResult.hasErrors()).thenReturn(true); + + final ResponseEntity responseEntity = theoremController.updateTheorem(1, createTheorem(), bindingResult); + + assertNotNull(responseEntity); + assertFalse(responseEntity.hasBody()); + assertEquals(HttpStatus.UNPROCESSABLE_ENTITY, responseEntity.getStatusCode()); + verifyZeroInteractions(theoremRepository); + } + + @Test + public void testUpdateTheorem_theoremDtoIsNull() { + final ResponseEntity responseEntity = theoremController.updateTheorem(1, null, bindingResult); + + assertNotNull(responseEntity); + assertFalse(responseEntity.hasBody()); + assertEquals(HttpStatus.BAD_REQUEST, responseEntity.getStatusCode()); + verifyZeroInteractions(theoremRepository); + } + + @Test + public void testUpdateTheorem_idIsNull() { + final ResponseEntity responseEntity = theoremController.updateTheorem(null, createTheorem(), bindingResult); + + assertNotNull(responseEntity); + assertFalse(responseEntity.hasBody()); + assertEquals(HttpStatus.BAD_REQUEST, responseEntity.getStatusCode()); + verifyZeroInteractions(theoremRepository); + } + + @Test + public void testUpdateTheorem_theoremDoesNotExist() { + when(theoremRepository.findById(anyInt())).thenReturn(Optional.empty()); + + final ResponseEntity responseEntity = theoremController.updateTheorem(1, createTheorem(), bindingResult); + + assertNotNull(responseEntity); + assertFalse(responseEntity.hasBody()); + assertEquals(HttpStatus.BAD_REQUEST, responseEntity.getStatusCode()); + verify(theoremRepository, times(0)).save(any(Theorem.class)); + } + + @Test + public void testDeleteTheoremById() { + doNothing().when(theoremRepository).deleteById(anyInt()); + + final ResponseEntity responseEntity = theoremController.deleteTheoremById(1); + + assertNotNull(responseEntity); + assertFalse(responseEntity.hasBody()); + assertEquals(HttpStatus.NO_CONTENT, responseEntity.getStatusCode()); + verify(theoremRepository).deleteById(anyInt()); + } + + @Test + public void testDeleteTheoremById_idIsNull() { + final ResponseEntity responseEntity = theoremController.deleteTheoremById(null); + + assertNotNull(responseEntity); + assertFalse(responseEntity.hasBody()); + assertEquals(HttpStatus.BAD_REQUEST, responseEntity.getStatusCode()); + verifyZeroInteractions(theoremRepository); + } + + private Theorem createTheorem() { + final List referencedTheoremsList = new ArrayList<>(); + referencedTheoremsList.add("test theorem 1"); + referencedTheoremsList.add("test theorem 2"); + + final List referencedDefinitionsList = new ArrayList<>(); + referencedDefinitionsList.add("test definition 1"); + referencedDefinitionsList.add("test definition 2"); + + final Theorem theorem = new Theorem(); + theorem.setName("Test theorem"); + theorem.setTheorem("test theorem thing here"); + theorem.setBranch("Test branch"); + theorem.setProvenStatus(true); + theorem.setTheoremType(TheoremType.THEOREM); + theorem.setReferencedTheorems(referencedTheoremsList); + theorem.setReferencedDefinitions(referencedDefinitionsList); + + return theorem; + } +} \ No newline at end of file diff --git a/services/build.gradle b/services/build.gradle index a53319f..551f2b2 100644 --- a/services/build.gradle +++ b/services/build.gradle @@ -19,6 +19,11 @@ repositories { dependencies { compile project(':persistence') - testCompile group: 'junit', name: 'junit', version: '4.12' + compile group: 'org.apache.httpcomponents', name: 'httpcore', version: '4.4.11' + compile group: 'org.apache.httpcomponents', name: 'fluent-hc', version: '4.5.7' + compile group: 'com.google.code.gson', name: 'gson', version: '2.7' compile fileTree(dir: 'lib', include: '**/*.jar') + + testCompile "org.springframework:spring-test:5.0.9.RELEASE" + testCompile group: 'junit', name: 'junit', version: '4.12' } diff --git a/services/src/main/java/edu/msudenver/tsp/services/RestService.java b/services/src/main/java/edu/msudenver/tsp/services/RestService.java new file mode 100644 index 0000000..67d2ef0 --- /dev/null +++ b/services/src/main/java/edu/msudenver/tsp/services/RestService.java @@ -0,0 +1,105 @@ +package edu.msudenver.tsp.services; + +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import edu.msudenver.tsp.services.factory.RequestFactory; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.apache.http.HttpResponse; +import org.apache.http.client.fluent.Request; +import org.apache.http.util.EntityUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Optional; + +@Slf4j +@Service +public class RestService { + private static final Gson GSON = new Gson(); + private final RequestFactory requestFactory; + + @Autowired + public RestService(final RequestFactory requestFactory) { + this.requestFactory = requestFactory; + } + + public boolean delete(final String uri, final Integer connectionTimeout, final Integer socketTimeout, final HttpStatus httpStatus) { + LOG.info("Sending DELETE {}", uri); + final Optional response = send(requestFactory.delete(uri), null, connectionTimeout, socketTimeout); + + return response.isPresent() && response.get().getStatusLine().getStatusCode() == httpStatus.value(); + } + + Optional get(final String uri, final TypeToken type, final Integer connectionTimeout, final Integer socketTimeout, final String auth) { + LOG.info("Sending GET {}", uri); + return send(requestFactory.get(uri), auth, connectionTimeout, socketTimeout, type); + } + + Optional post(final String uri, final String requestJson, final TypeToken type, final Integer connectionTimeout, final Integer socketTimeout) { + LOG.info("Sending POST {} with body: {}", uri, requestJson); + return send(requestFactory.post(uri, requestJson), null, connectionTimeout, socketTimeout, type); + } + + Optional post(final String uri, final String requestJson, final Integer connectionTimeout, final Integer socketTimeout) { + LOG.info("Sending POST {} with body: {}", uri, requestJson); + return send(requestFactory.post(uri, requestJson), null, connectionTimeout, socketTimeout); + } + + Optional put(final String uri, final String requestJson, final TypeToken type, final Integer connectionTimeout, final Integer socketTimeout, final String auth) { + LOG.info("Sending PUT {} with body: {}", uri, requestJson); + return send(requestFactory.put(uri, requestJson), auth, connectionTimeout, socketTimeout, type); + } + + Optional patch(final String uri, final String requestJson, final TypeToken type, final Integer connectionTimeout, final Integer socketTimeout) { + LOG.info("Sending PATCH {} with body: {}", uri, requestJson); + return send(requestFactory.patch(uri, requestJson), null, connectionTimeout, socketTimeout, type); + } + + private Optional send(final Request request, final String auth, final Integer connectionTimeout, final Integer socketTimeout, final TypeToken type) { + try { + final Optional optionalHttpResponse = send(request, auth, connectionTimeout, socketTimeout); + if (optionalHttpResponse.isPresent()) { + final HttpResponse httpResponse = optionalHttpResponse.get(); + LOG.info("Received {} response", httpResponse.getStatusLine().getStatusCode()); + + final String jsonResponse = httpResponse.getEntity() == null ? null : EntityUtils.toString(httpResponse.getEntity()); + if (StringUtils.isNotBlank(jsonResponse)) { + final T responses = GSON.fromJson(jsonResponse, type.getType()); + if (responses instanceof List) { + LOG.info("Found {} responses.", ((List) responses).size()); + if (((List) responses).isEmpty()) { + return Optional.empty(); + } + } + + return Optional.ofNullable(responses); + } + } + } catch (final Exception e) { + LOG.error("Could not send request", e); + } + + return Optional.empty(); + } + + private Optional send(final Request request, final String auth, final Integer connectionTimeout, final Integer socketTimeout) { + if (StringUtils.isNotBlank(auth)) { + request.addHeader("Authorization", "Basic " + auth); + } + + try { + return Optional.ofNullable(request.connectTimeout(connectionTimeout) + .socketTimeout(socketTimeout) + .execute() + .returnResponse()); + } catch (final Exception e) { + LOG.error("Could not send request", e); + return Optional.empty(); + } + } +} + + diff --git a/services/src/main/java/edu/msudenver/tsp/services/UserService.java b/services/src/main/java/edu/msudenver/tsp/services/UserService.java new file mode 100644 index 0000000..f119441 --- /dev/null +++ b/services/src/main/java/edu/msudenver/tsp/services/UserService.java @@ -0,0 +1,57 @@ +package edu.msudenver.tsp.services; + +import com.google.gson.GsonBuilder; +import com.google.gson.reflect.TypeToken; +import edu.msudenver.tsp.services.dto.Account; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import java.time.Duration; +import java.time.Instant; +import java.util.Optional; + +@Slf4j +@Service +public class UserService { + private final RestService restService; + @Value("${persistence.api.connection.timeout.milliseconds}") private int connectionTimeoutMilliseconds; + @Value("${persistence.api.socket.timeout.milliseconds}") private int socketTimeoutMilliseconds; + @Value("${persistence.api.base.url}") private String persistenceApiBaseUrl; + + @Autowired + public UserService(final RestService restService) { + this.restService = restService; + } + + public Optional createNewAccount(final Account account) { + if (account == null) { + LOG.error("Given null account, returning {}"); + return Optional.empty(); + } + final Instant start = Instant.now(); + + try { + final TypeToken typeToken = new TypeToken() {}; + final Optional persistenceApiResponse = restService.post(persistenceApiBaseUrl + "/accounts/", + new GsonBuilder().create().toJson(account), + typeToken, + connectionTimeoutMilliseconds, + socketTimeoutMilliseconds); + + if (persistenceApiResponse.isPresent()) { + LOG.info("Returning {}", persistenceApiResponse.get()); + } else { + LOG.info("Unable to create new account {}", account.toString()); + } + + return persistenceApiResponse; + } catch (final Exception e) { + LOG.error("Error creating new account {}", e); + return Optional.empty(); + } finally { + LOG.info("Create new account request took {} ms", Duration.between(start, Instant.now()).toMillis()); + } + } +} diff --git a/services/src/main/java/edu/msudenver/tsp/services/dto/Account.java b/services/src/main/java/edu/msudenver/tsp/services/dto/Account.java new file mode 100644 index 0000000..139cd41 --- /dev/null +++ b/services/src/main/java/edu/msudenver/tsp/services/dto/Account.java @@ -0,0 +1,25 @@ +package edu.msudenver.tsp.services.dto; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import javax.persistence.Temporal; +import javax.persistence.TemporalType; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.io.Serializable; +import java.util.Date; + +@Data +@EqualsAndHashCode(callSuper = true) +public class Account extends BaseDto implements Serializable { + @NotBlank(groups = edu.msudenver.tsp.persistence.dto.Account.Insert.class, message = "A username must be specified") @Size(max = 50) private String username; + @NotBlank(groups = edu.msudenver.tsp.persistence.dto.Account.Insert.class, message = "A password must be specified") @Size(max = 256) private String password; + @NotNull @SerializedName("administrator_status") private boolean administratorStatus; + @Temporal(TemporalType.DATE) @SerializedName("last_login") private Date lastLogin; + + private static final long serialVersionUID = 7095627971593953734L; + +} diff --git a/services/src/main/java/edu/msudenver/tsp/services/dto/BaseDto.java b/services/src/main/java/edu/msudenver/tsp/services/dto/BaseDto.java new file mode 100644 index 0000000..4dc5dfd --- /dev/null +++ b/services/src/main/java/edu/msudenver/tsp/services/dto/BaseDto.java @@ -0,0 +1,13 @@ +package edu.msudenver.tsp.services.dto; + +import lombok.Data; + +import java.io.Serializable; + +@Data +public class BaseDto implements Serializable { + private int id; + private Integer version; + + private static final long serialVersionUID = 5343705942114910963L; +} diff --git a/services/src/main/java/edu/msudenver/tsp/services/factory/RequestFactory.java b/services/src/main/java/edu/msudenver/tsp/services/factory/RequestFactory.java new file mode 100644 index 0000000..eb4933d --- /dev/null +++ b/services/src/main/java/edu/msudenver/tsp/services/factory/RequestFactory.java @@ -0,0 +1,29 @@ +package edu.msudenver.tsp.services.factory; + +import org.apache.commons.lang3.StringUtils; +import org.apache.http.client.fluent.Request; +import org.apache.http.entity.ContentType; +import org.springframework.stereotype.Service; + +@Service +public class RequestFactory { + public Request delete(final String uri) { + return Request.Delete(uri); + } + + public Request get(final String uri) { + return Request.Get(uri); + } + + public Request post(final String uri, final String requestJson) { + return StringUtils.isNotBlank(requestJson) ? Request.Post(uri).bodyString(requestJson, ContentType.APPLICATION_JSON) : Request.Post(uri); + } + + public Request put(final String uri, final String requestJson) { + return StringUtils.isNotBlank(requestJson) ? Request.Put(uri).bodyString(requestJson, ContentType.APPLICATION_JSON) : Request.Put(uri); + } + + public Request patch(final String uri, final String requestJson) { + return StringUtils.isNotBlank(requestJson) ? Request.Put(uri).bodyString(requestJson, ContentType.APPLICATION_JSON) : Request.Patch(uri); + } +} \ No newline at end of file diff --git a/services/src/main/java/edu/msudenver/tsp/services/parser/Node.java b/services/src/main/java/edu/msudenver/tsp/services/parser/Node.java new file mode 100644 index 0000000..2b92dec --- /dev/null +++ b/services/src/main/java/edu/msudenver/tsp/services/parser/Node.java @@ -0,0 +1,43 @@ +package edu.msudenver.tsp.services.parser; + +import lombok.Getter; +import lombok.Setter; + +public class Node +{ + @Getter private final String statement; + @Getter @Setter private Node left; + @Getter @Setter private Node right; + @Getter @Setter private Node center; + @Getter private final Node parent; + @Getter private final int depth; + + public Node(final String statement, final Node parent) + { + this.statement = statement + "\n"; + left = null; + right = null; + center = null; + this.parent = parent; + if(parent != null) + { + depth = parent.depth + 1; + } + else + { + depth = 0; + } + } + + @Override + public String toString() + { + String returnVal = this.depth + ": " + this.statement; + + if(this.left != null) returnVal += "... " + this.left.toString(); + if(this.center != null) returnVal += "... " + this.center.toString(); + if(this.right != null) returnVal += "... " + this.right.toString(); + + return returnVal; + } +} \ No newline at end of file diff --git a/services/src/main/java/edu/msudenver/tsp/services/parser/ParserConfig.java b/services/src/main/java/edu/msudenver/tsp/services/parser/ParserConfig.java deleted file mode 100644 index eb1c4f2..0000000 --- a/services/src/main/java/edu/msudenver/tsp/services/parser/ParserConfig.java +++ /dev/null @@ -1,11 +0,0 @@ -package edu.msudenver.tsp.services.parser; - -import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.Configuration; - -@Configuration -@ComponentScan -//@PropertySource("classpath:development.properties") -public class ParserConfig { - -} diff --git a/services/src/main/java/edu/msudenver/tsp/services/parser/ParserService.java b/services/src/main/java/edu/msudenver/tsp/services/parser/ParserService.java index 747521d..c3f37e1 100644 --- a/services/src/main/java/edu/msudenver/tsp/services/parser/ParserService.java +++ b/services/src/main/java/edu/msudenver/tsp/services/parser/ParserService.java @@ -1,26 +1,126 @@ package edu.msudenver.tsp.services.parser; -import edu.msudenver.tsp.persistence.controller.DefinitionController; -import edu.msudenver.tsp.persistence.controller.NotationController; -import edu.msudenver.tsp.persistence.controller.ProofController; -import edu.msudenver.tsp.persistence.controller.TheoremController; -import org.springframework.beans.factory.annotation.Autowired; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; +import java.util.ArrayList; +import java.util.List; + +@Slf4j @Service class ParserService { - private final DefinitionController definitionController; - private final TheoremController theoremController; - private final NotationController notationController; - private final ProofController proofController; - @Autowired - public ParserService(final DefinitionController definitionController, final TheoremController theoremController, - final NotationController notationController, final ProofController proofController) { - this.definitionController = definitionController; - this.theoremController = theoremController; - this.notationController = notationController; - this.proofController = proofController; + public boolean parseUserInput(final String userInput) + { + try { + final Node tree = parseRawInput(userInput); + retrieveStatements(tree); + + return true; + } catch(final Exception e) { + LOG.error(e.getMessage()); + } + return false; } + public Node parseRawInput(String input) + { + input = input.toLowerCase(); + + final Node root = new Node(input, null); + + if(input.equals("")) + { + return root; + } + + recurse(root); + + return root; + } + + private void recurse(final Node current) + { + int startIndex; + int endIndex; + final String statement; + + if (current != null) { + statement = current.getStatement(); + } else { + return; + } + + String nextStatement; + + if(statement.contains("let")) + { + current.setLeft(new Node("let", current)); + + startIndex = statement.indexOf("let")+"let".length(); + + if(statement.contains("if")){ + endIndex = statement.indexOf("if"); + } else if(statement.contains("then")){ + endIndex = statement.indexOf("then"); + } else { + endIndex = statement.length(); + } + + nextStatement = statement.substring(startIndex, endIndex); + + current.getLeft().setCenter(new Node(nextStatement, current.getLeft())); + recurse(current.getLeft().getCenter()); + } + + + if(statement.contains("if")) + { + current.setCenter(new Node("if", current)); + + startIndex = statement.indexOf("if")+"if".length(); + endIndex = (statement.contains("then") ? statement.indexOf("then") : statement.length()); + nextStatement = statement.substring(startIndex, endIndex); + + current.getCenter().setCenter(new Node(nextStatement, current.getCenter())); + recurse(current.getCenter().getCenter()); + } + + + if(current.getStatement().contains("then")) + { + current.setRight(new Node("then", current)); + + startIndex = statement.indexOf("then")+"then".length(); + nextStatement = statement.substring(startIndex); + + current.getRight().setCenter(new Node(nextStatement, current.getRight())); + recurse(current.getRight().getCenter()); + } + } + + public List retrieveStatements(final Node parsedTree) + { + return populateStatementList(parsedTree, new ArrayList<>()); + } + + private ArrayList populateStatementList(final Node node, final ArrayList statementList) + { + if(node == null) + { + return statementList; + } + + final String statement = node.getStatement().trim(); + if(!(statement.contains("let") || statement.contains("if") || statement.contains("then"))) + { + statementList.add(statement); + } + + populateStatementList(node.getLeft(), statementList); + populateStatementList(node.getCenter(), statementList); + populateStatementList(node.getRight(), statementList); + + return statementList; + } } diff --git a/services/src/main/java/edu/msudenver/tsp/services/scoring/ScoringConfig.java b/services/src/main/java/edu/msudenver/tsp/services/scoring/ScoringConfig.java deleted file mode 100644 index 3a4aa63..0000000 --- a/services/src/main/java/edu/msudenver/tsp/services/scoring/ScoringConfig.java +++ /dev/null @@ -1,16 +0,0 @@ -package edu.msudenver.tsp.services.scoring; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.Configuration; - -@Configuration -@ComponentScan -//@PropertySource("classpath:development.properties") -public class ScoringConfig { - - @Bean - public TheoremScoringService theoremScoringService() { - return new TheoremScoringService(); - } -} diff --git a/services/src/main/java/edu/msudenver/tsp/services/scoring/TheoremScoringService.java b/services/src/main/java/edu/msudenver/tsp/services/scoring/TheoremScoringService.java deleted file mode 100644 index 6dad106..0000000 --- a/services/src/main/java/edu/msudenver/tsp/services/scoring/TheoremScoringService.java +++ /dev/null @@ -1,8 +0,0 @@ -package edu.msudenver.tsp.services.scoring; - -import org.springframework.stereotype.Service; - -@Service -class TheoremScoringService { - -} diff --git a/services/src/main/resources/application.properties b/services/src/main/resources/application.properties new file mode 100644 index 0000000..ff86c7e --- /dev/null +++ b/services/src/main/resources/application.properties @@ -0,0 +1,3 @@ +persistence.api.connection.timeout.milliseconds = 5000 +persistence.api.socket.timeout.milliseconds = 10000 +persistence.api.base.url = http://localhost:8090/ \ No newline at end of file diff --git a/services/src/test/java/edu/msudenver/tsp/services/factory/RequestFactoryTest.java b/services/src/test/java/edu/msudenver/tsp/services/factory/RequestFactoryTest.java new file mode 100644 index 0000000..1f21b28 --- /dev/null +++ b/services/src/test/java/edu/msudenver/tsp/services/factory/RequestFactoryTest.java @@ -0,0 +1,66 @@ +package edu.msudenver.tsp.services.factory; + +import org.apache.http.client.fluent.Request; +import org.junit.Test; + +import static org.junit.Assert.assertNotNull; + +public class RequestFactoryTest { + private final RequestFactory requestFactory = new RequestFactory(); + + @Test + public void testDelete() { + final Request testRequest = requestFactory.delete("testUri"); + + assertNotNull(testRequest); + } + + @Test + public void testGet() { + final Request testRequest = requestFactory.get("testUri"); + + assertNotNull(testRequest); + } + + @Test + public void testPost() { + final Request testRequest = requestFactory.post("testUri", "testJson"); + + assertNotNull(testRequest); + } + + @Test + public void testPost_blankRequestJson() { + final Request testRequest = requestFactory.post("testUri", null); + + assertNotNull(testRequest); + } + + @Test + public void testPut() { + final Request testRequest = requestFactory.put("testUri", "testJson"); + + assertNotNull(testRequest); + } + + @Test + public void testPut_blankRequestJson() { + final Request testRequest = requestFactory.put("testUri", null); + + assertNotNull(testRequest); + } + + @Test + public void testPatch() { + final Request testRequest = requestFactory.patch("testUri", "testJson"); + + assertNotNull(testRequest); + } + + @Test + public void testPatch_blankRequestJson() { + final Request testRequest = requestFactory.patch("testUri", null); + + assertNotNull(testRequest); + } +} \ No newline at end of file diff --git a/services/src/test/java/edu/msudenver/tsp/services/parser/ParserServiceTest.java b/services/src/test/java/edu/msudenver/tsp/services/parser/ParserServiceTest.java index 1ae6e5e..fdfecf0 100644 --- a/services/src/test/java/edu/msudenver/tsp/services/parser/ParserServiceTest.java +++ b/services/src/test/java/edu/msudenver/tsp/services/parser/ParserServiceTest.java @@ -2,16 +2,138 @@ package edu.msudenver.tsp.services.parser; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; +import java.util.ArrayList; +import java.util.List; + import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.when; @RunWith(MockitoJUnitRunner.class) public class ParserServiceTest { + @Mock private ParserService mockParserService; + + @InjectMocks private ParserService parserService; + @Test - public void test() { - assertEquals(3,3); + public void testEmptyStringEqualsEmptyString() { + final String expected = "0: \n"; + final String actual = parserService.parseRawInput("").toString(); + + assertEquals(expected, actual); } + @Test + public void testUselessStringEqualsUselessString() { + final String expected = "0: cat\n"; + final String actual = parserService.parseRawInput("cat").toString(); + + assertEquals(expected, actual); + } + + @Test + public void testSingleIfReturnsIfPlusEmptyString() { + final String expected = "0: if\n... 1: if\n... 2: \n\n"; + final String actual = parserService.parseRawInput("if").toString(); + + assertEquals(expected, actual); + } + + @Test + public void testBaseCaseIfXIsEvenThenXSquaredIsEven() { + final String expected = "0: if x is even then x^2 is even\n" + + "... 1: if\n" + + "... 2: x is even \n" + + "... 1: then\n" + + "... 2: x^2 is even\n\n"; + + final String actual = parserService.parseRawInput("if x is even then x^2 is even").toString(); + + assertEquals(expected, actual); + } + + @Test + public void testLetXBeEvenThenXSquaredIsEven() { + final String expected = "0: let x be even. then x^2 is even.\n" + + "... 1: let\n" + + "... 2: x be even. \n" + + "... 1: then\n" + + "... 2: x^2 is even.\n\n"; + + final String actual = parserService.parseRawInput("Let x be even. Then x^2 is even.").toString(); + + assertEquals(expected, actual); + } + + @Test + public void testLetIfThen() { + final String expected = "0: let a. if b, then c.\n" + + "... 1: let\n" + + "... 2: a. \n" + + "... 1: if\n" + + "... 2: b, \n" + + "... 1: then\n" + + "... 2: c.\n\n"; + + final String actual = parserService.parseRawInput("Let a. If b, then c.").toString(); + + assertEquals(expected, actual); + } + + @Test + public void testLetStatementWithoutAnyIfOrThenStatements() { + final String expected = "0: let a be equal to b.\n" + + "... 1: let\n" + + "... 2: a be equal to b.\n\n"; + + final String actual = parserService.parseRawInput("Let a be equal to b.").toString(); + + assertEquals(expected, actual); + } + + @Test + public void testEmptyStringReturnsEmptyList() { + final List expectedList = new ArrayList<>(); + expectedList.add(""); + + when(mockParserService.parseRawInput(anyString())).thenReturn(new Node("", null)); + final List actualList = parserService.retrieveStatements(mockParserService.parseRawInput("")); + + assertEquals(expectedList, actualList); + } + + @Test + public void testBaseCaseReturnsXIsEven() { + final List expectedList = new ArrayList<>(); + expectedList.add("x is even"); + expectedList.add("x^2 is even"); + + final Node testNode = new Node("if x is even then x^2 is even", null); + testNode.setCenter(new Node("if", testNode)); + testNode.getCenter().setCenter(new Node(" x is even ", testNode.getCenter())); + testNode.setRight(new Node("then", testNode)); + testNode.getRight().setCenter(new Node(" x^2 is even", testNode.getRight())); + + when(mockParserService.parseRawInput(anyString())).thenReturn(testNode); + final List actualList = parserService.retrieveStatements(mockParserService.parseRawInput("baseCase")); + + assertEquals(expectedList, actualList); + } + + @Test + public void testDriveParseUserInput() { + final Node testNode = new Node("", null); + when(mockParserService.parseRawInput(anyString())).thenReturn(testNode); + when(mockParserService.retrieveStatements(testNode)).thenReturn(new ArrayList<>()); + + final boolean successfulTestDrive = parserService.parseUserInput(""); + + assertTrue(successfulTestDrive); + } } \ No newline at end of file diff --git a/services/src/test/java/edu/msudenver/tsp/services/scoring/TheoremScoringServiceTest.java b/services/src/test/java/edu/msudenver/tsp/services/scoring/TheoremScoringServiceTest.java deleted file mode 100644 index f116fb6..0000000 --- a/services/src/test/java/edu/msudenver/tsp/services/scoring/TheoremScoringServiceTest.java +++ /dev/null @@ -1,16 +0,0 @@ -package edu.msudenver.tsp.services.scoring; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.runners.MockitoJUnitRunner; - -import static org.junit.Assert.assertEquals; - -@RunWith(MockitoJUnitRunner.class) -public class TheoremScoringServiceTest { - - @Test - public void test() { - assertEquals(3,3); - } -} \ No newline at end of file diff --git a/src/README.md b/src/README.md new file mode 100644 index 0000000..6ee4af6 --- /dev/null +++ b/src/README.md @@ -0,0 +1,58 @@ +## PTP Persistence API + +The PTP Persistence API is the web API for accessing the theorems database. + + + +## Running from IntelliJ + +* Create a new run configuration in IntelliJ. + + ``` + Name: "Pandamonium Theorem Prover Tomcat" + Application Server: Tomcat (8.5.12) + HTTP Port: 8080 + JMX Port: 1080 + Deployment tabe: Deploy pandamonium-theorem-prover.war (exploded) + ``` +## Running the Tests + +This project is unit tested with JUnit and Mockito. You can run the unit tests with IntelliJ or Gradle. To run them with IntelliJ, browse to any `*Test.java` file and use IntelliJ's built-in test runner to run or debug the test. To run all the unit tests with Gradle: + +* On a Linux or Macintosh machine: + + ```$ ./gradlew test``` + +* On a Windows machine: + + ```$ gradlew.bat test``` + +You can also test modules individually: + +* On a Linux or Macintosh machine: + + ```$ ./gradlew persistence:test``` + +* On a Windows machine: + + ```$ gradlew.bat persistence:test``` + +## Integration Tests + +To run the integration tests with IntelliJ, browse to any `*Test.java` file residing in any module name `integrationTest` and use IntelliJ's built-in test runner to run or debug the test. To run all the integration tests with Gradle: + +* On a Linux or Macintosh machine: + + ```$ ./gradlew integrationTest``` + +* On a Windows machine + + ```$ gradlew.bat integrationTest``` + +## Built with + +* [Spring Boot](https://projects.spring.io/spring-boot/) - Web framework +* [Gradle](https://gradle.org/) - Dependency management +* [JUnit](http://junit.org/junit4/) - Unit tests +* [Mockito](http://site.mockito.org/) - Mock objects library +* [Lombok](https://projectlombok.org/) - Boilerplate Code Generator diff --git a/src/main/java/edu/msudenver/tsp/website/Application.java b/src/main/java/edu/msudenver/tsp/website/Application.java index c8f0854..54da024 100644 --- a/src/main/java/edu/msudenver/tsp/website/Application.java +++ b/src/main/java/edu/msudenver/tsp/website/Application.java @@ -1,33 +1,12 @@ package edu.msudenver.tsp.website; -import lombok.extern.slf4j.Slf4j; -import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.context.ApplicationContext; -import org.springframework.context.annotation.Bean; -import java.util.Arrays; - -@Slf4j @SpringBootApplication public class Application { public static void main(final String[] args) { SpringApplication.run(Application.class, args); } - - @Bean - public CommandLineRunner commandLineRunner(final ApplicationContext ctx) { - return args -> { - - LOG.info("Beans provided by Spring Boot:"); - - final String[] beanNames = ctx.getBeanDefinitionNames(); - Arrays.sort(beanNames); - for (final String beanName : beanNames) { - LOG.info(beanName); - } - }; - } } diff --git a/src/main/java/edu/msudenver/tsp/website/ProofsDriver.java b/src/main/java/edu/msudenver/tsp/website/ProofsDriver.java deleted file mode 100644 index a6d4715..0000000 --- a/src/main/java/edu/msudenver/tsp/website/ProofsDriver.java +++ /dev/null @@ -1,4 +0,0 @@ -package edu.msudenver.tsp.website; - -public class ProofsDriver { -} diff --git a/src/main/java/edu/msudenver/tsp/website/controller/TheoremEntryController.java b/src/main/java/edu/msudenver/tsp/website/controller/TheoremEntryController.java new file mode 100644 index 0000000..2df1385 --- /dev/null +++ b/src/main/java/edu/msudenver/tsp/website/controller/TheoremEntryController.java @@ -0,0 +1,33 @@ +package edu.msudenver.tsp.website.controller; + +import edu.msudenver.tsp.website.forms.TheoremForm; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.servlet.ModelAndView; + +@Slf4j +@Controller +@AllArgsConstructor +@RequestMapping("/theorem") +public class TheoremEntryController { + @GetMapping({"/",""}) + public ModelAndView enterTheoremPage() { + LOG.info("Received request to display the theorem entry page: returning model with name 'Theorem'"); + return new ModelAndView("Theorem"); + } + + @PostMapping({"/",""}) + public String saveTheorem(@Validated final TheoremForm theoremForm, final Model model) { + model.addAttribute("theoremName", theoremForm.getTheoremName()); + model.addAttribute("theorem", theoremForm.getTheorem()); + LOG.info("Saving theorem {}...", theoremForm); + + return "success"; + } +} \ No newline at end of file diff --git a/src/main/java/edu/msudenver/tsp/website/forms/TheoremForm.java b/src/main/java/edu/msudenver/tsp/website/forms/TheoremForm.java new file mode 100644 index 0000000..8cfbd4b --- /dev/null +++ b/src/main/java/edu/msudenver/tsp/website/forms/TheoremForm.java @@ -0,0 +1,11 @@ +package edu.msudenver.tsp.website.forms; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class TheoremForm { + private String theoremName; + private String theorem; +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties new file mode 100644 index 0000000..f3ce324 --- /dev/null +++ b/src/main/resources/application.properties @@ -0,0 +1,2 @@ +spring.mvc.view.prefix:/WEB-INF/jsp/ +spring.mvc.view.suffix:.jsp \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/jsp/Theorem.jsp b/src/main/webapp/WEB-INF/jsp/Theorem.jsp new file mode 100644 index 0000000..95826da --- /dev/null +++ b/src/main/webapp/WEB-INF/jsp/Theorem.jsp @@ -0,0 +1,20 @@ +<%@ page contentType="text/html; charset=UTF-8" + pageEncoding="UTF-8"%> + + + + + Theorem Entry + + +
+ +

+ +
+ + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/jsp/success.jsp b/src/main/webapp/WEB-INF/jsp/success.jsp new file mode 100644 index 0000000..4a09232 --- /dev/null +++ b/src/main/webapp/WEB-INF/jsp/success.jsp @@ -0,0 +1,7 @@ + + +
Name: <%= request.getParameter("theoremName")%> +
Theorem: <%= request.getParameter("theorem")%> + + + \ No newline at end of file diff --git a/src/test/java/edu/msudenver/tsp/website/ProofsDriverTest.java b/src/test/java/edu/msudenver/tsp/website/ProofsDriverTest.java deleted file mode 100644 index 04a68e1..0000000 --- a/src/test/java/edu/msudenver/tsp/website/ProofsDriverTest.java +++ /dev/null @@ -1,5 +0,0 @@ -package edu.msudenver.tsp.website; - -public class ProofsDriverTest { - -} \ No newline at end of file diff --git a/src/test/java/edu/msudenver/tsp/website/controller/TheoremEntryControllerTest.java b/src/test/java/edu/msudenver/tsp/website/controller/TheoremEntryControllerTest.java new file mode 100644 index 0000000..2624c17 --- /dev/null +++ b/src/test/java/edu/msudenver/tsp/website/controller/TheoremEntryControllerTest.java @@ -0,0 +1,23 @@ +package edu.msudenver.tsp.website.controller; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; +import org.springframework.web.servlet.ModelAndView; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +@RunWith(MockitoJUnitRunner.class) +public class TheoremEntryControllerTest { + + private final TheoremEntryController theoremEntryController = new TheoremEntryController(); + + @Test + public void testEnterTheoremPage() { + final ModelAndView modelAndView = theoremEntryController.enterTheoremPage(); + + assertNotNull(modelAndView); + assertEquals("Theorem", modelAndView.getViewName()); + } +}