From b312097d0d23dc94e770f99ac2934ca75e7e786d Mon Sep 17 00:00:00 2001 From: Lucy Ciara Herud-Thomassen <86323303+LucyCiara@users.noreply.github.com> Date: Tue, 10 Mar 2026 15:41:43 +0100 Subject: [PATCH 1/7] feat[DbWrapper]: add methods for connecting to database --- pom.xml | 6 ++++ src/main/java/edu/group5/app/App.java | 9 +++++- .../edu/group5/app/control/DbWrapper.java | 30 +++++++++++++++++++ src/main/resources/init.sql | 23 ++++++++++++++ src/main/resources/test_init.sql | 23 ++++++++++++++ 5 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 src/main/java/edu/group5/app/control/DbWrapper.java create mode 100644 src/main/resources/init.sql create mode 100644 src/main/resources/test_init.sql diff --git a/pom.xml b/pom.xml index 7a55551..f9a8b88 100644 --- a/pom.xml +++ b/pom.xml @@ -62,6 +62,12 @@ slf4j-simple 2.0.9 + + com.h2database + h2 + 2.2.224 + runtime + diff --git a/src/main/java/edu/group5/app/App.java b/src/main/java/edu/group5/app/App.java index 887fe4d..8eae42a 100644 --- a/src/main/java/edu/group5/app/App.java +++ b/src/main/java/edu/group5/app/App.java @@ -1,10 +1,17 @@ package edu.group5.app; +import edu.group5.app.control.DbWrapper; + /** * Hello world! */ public class App { public static void main(String[] args) throws InterruptedException { - System.out.println("Hello World!"); + DbWrapper db = new DbWrapper("test_init.sql"); + try { + System.out.println(db.connect()); + } catch (Exception e) { + e.printStackTrace(); + } } } diff --git a/src/main/java/edu/group5/app/control/DbWrapper.java b/src/main/java/edu/group5/app/control/DbWrapper.java new file mode 100644 index 0000000..b767a49 --- /dev/null +++ b/src/main/java/edu/group5/app/control/DbWrapper.java @@ -0,0 +1,30 @@ +package edu.group5.app.control; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; + +public class DbWrapper { + protected Connection connection; + private static final String CONNECTION_TYPE = "jdbc:h2:"; + private static final String DB_SCRIPT = "INIT=RUNSCRIPT FROM 'classpath:"; + private String connectionString; + + public DbWrapper(String script) { + this(script, "mem:test;"); + } + + public DbWrapper(String script, String dbPath) { + this.connectionString = CONNECTION_TYPE + dbPath + DB_SCRIPT + script + "'"; + } + + public boolean connect() throws SQLException { + try { + this.connection = DriverManager.getConnection(this.connectionString); + } catch (SQLException SQLe) { + SQLe.printStackTrace(); + } + return connection.isValid(0); + } + +} diff --git a/src/main/resources/init.sql b/src/main/resources/init.sql new file mode 100644 index 0000000..ff37e31 --- /dev/null +++ b/src/main/resources/init.sql @@ -0,0 +1,23 @@ +CREATE TABLE IF NOT EXISTS +users ( + user_id int PRIMARY KEY, + first_name varchar(20), + last_name varchar(20), + email varchar(20), + password_hash varchar(72) +); + +CREATE TABLE IF NOT EXISTS +donations ( + donation_id int PRIMARY KEY, + user_id int NOT NULL, + organization_id int NOT NULL, + amount double NOT NULL, + dating timestamp NOT NULL, + payment_method varchar(20), + CONSTRAINT fk_user + FOREIGN KEY (user_id) + REFERENCES users(user_id) +); + + diff --git a/src/main/resources/test_init.sql b/src/main/resources/test_init.sql new file mode 100644 index 0000000..e1c1c43 --- /dev/null +++ b/src/main/resources/test_init.sql @@ -0,0 +1,23 @@ +DROP TABLE IF EXISTS users, donations; + +CREATE TABLE IF NOT EXISTS +users ( + user_id int PRIMARY KEY, + first_name varchar(20), + last_name varchar(20), + email varchar(20), + password_hash varchar(72) +); + +CREATE TABLE IF NOT EXISTS +donations ( + donation_id int PRIMARY KEY, + user_id int NOT NULL, + organization_id int NOT NULL, + amount double NOT NULL, + dating timestamp NOT NULL, + payment_method varchar(20), + CONSTRAINT fk_user + FOREIGN KEY (user_id) + REFERENCES users(user_id) +); From 1c56f3ca65b69233bfd49e50b3a3c649eec2c388 Mon Sep 17 00:00:00 2001 From: Lucy Ciara Herud-Thomassen <86323303+LucyCiara@users.noreply.github.com> Date: Tue, 10 Mar 2026 16:10:15 +0100 Subject: [PATCH 2/7] update[DbWrapper]: remove input for script and database paths remove input for scripts and database paths for ease of use --- src/main/java/edu/group5/app/App.java | 2 +- src/main/java/edu/group5/app/control/DbWrapper.java | 13 ++++++------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/main/java/edu/group5/app/App.java b/src/main/java/edu/group5/app/App.java index 8eae42a..dbd2319 100644 --- a/src/main/java/edu/group5/app/App.java +++ b/src/main/java/edu/group5/app/App.java @@ -7,7 +7,7 @@ */ public class App { public static void main(String[] args) throws InterruptedException { - DbWrapper db = new DbWrapper("test_init.sql"); + DbWrapper db = new DbWrapper(false); try { System.out.println(db.connect()); } catch (Exception e) { diff --git a/src/main/java/edu/group5/app/control/DbWrapper.java b/src/main/java/edu/group5/app/control/DbWrapper.java index b767a49..cafd03f 100644 --- a/src/main/java/edu/group5/app/control/DbWrapper.java +++ b/src/main/java/edu/group5/app/control/DbWrapper.java @@ -10,12 +10,12 @@ public class DbWrapper { private static final String DB_SCRIPT = "INIT=RUNSCRIPT FROM 'classpath:"; private String connectionString; - public DbWrapper(String script) { - this(script, "mem:test;"); - } - - public DbWrapper(String script, String dbPath) { - this.connectionString = CONNECTION_TYPE + dbPath + DB_SCRIPT + script + "'"; + public DbWrapper(boolean test) { + if (test) { + this.connectionString = CONNECTION_TYPE + "mem:test;" + DB_SCRIPT + "test_init.sql'"; + } else { + this.connectionString = CONNECTION_TYPE + "file:./help-me-help;" + DB_SCRIPT + "init.sql'"; + } } public boolean connect() throws SQLException { @@ -26,5 +26,4 @@ public boolean connect() throws SQLException { } return connection.isValid(0); } - } From bdd2284ad548e2036435d1e19fc4b1fb36664726 Mon Sep 17 00:00:00 2001 From: Lucy Ciara Herud-Thomassen <86323303+LucyCiara@users.noreply.github.com> Date: Thu, 12 Mar 2026 12:20:45 +0100 Subject: [PATCH 3/7] refactor[wrapper]&feat[DbWrapper]: move wrapper classes to its own folder, and add a class for database communication --- .../edu/group5/app/control/DbWrapper.java | 29 ----- .../group5/app/control/wrapper/DbWrapper.java | 113 ++++++++++++++++++ .../control/{ => wrapper}/OrgApiWrapper.java | 18 +-- .../app/control/{ => wrapper}/Wrapper.java | 15 ++- src/main/resources/init.sql | 23 ++-- src/main/resources/test_init.sql | 25 ++-- 6 files changed, 158 insertions(+), 65 deletions(-) delete mode 100644 src/main/java/edu/group5/app/control/DbWrapper.java create mode 100644 src/main/java/edu/group5/app/control/wrapper/DbWrapper.java rename src/main/java/edu/group5/app/control/{ => wrapper}/OrgApiWrapper.java (85%) rename src/main/java/edu/group5/app/control/{ => wrapper}/Wrapper.java (66%) diff --git a/src/main/java/edu/group5/app/control/DbWrapper.java b/src/main/java/edu/group5/app/control/DbWrapper.java deleted file mode 100644 index cafd03f..0000000 --- a/src/main/java/edu/group5/app/control/DbWrapper.java +++ /dev/null @@ -1,29 +0,0 @@ -package edu.group5.app.control; - -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.SQLException; - -public class DbWrapper { - protected Connection connection; - private static final String CONNECTION_TYPE = "jdbc:h2:"; - private static final String DB_SCRIPT = "INIT=RUNSCRIPT FROM 'classpath:"; - private String connectionString; - - public DbWrapper(boolean test) { - if (test) { - this.connectionString = CONNECTION_TYPE + "mem:test;" + DB_SCRIPT + "test_init.sql'"; - } else { - this.connectionString = CONNECTION_TYPE + "file:./help-me-help;" + DB_SCRIPT + "init.sql'"; - } - } - - public boolean connect() throws SQLException { - try { - this.connection = DriverManager.getConnection(this.connectionString); - } catch (SQLException SQLe) { - SQLe.printStackTrace(); - } - return connection.isValid(0); - } -} diff --git a/src/main/java/edu/group5/app/control/wrapper/DbWrapper.java b/src/main/java/edu/group5/app/control/wrapper/DbWrapper.java new file mode 100644 index 0000000..6eb673f --- /dev/null +++ b/src/main/java/edu/group5/app/control/wrapper/DbWrapper.java @@ -0,0 +1,113 @@ +package edu.group5.app.control.wrapper; + +import java.math.BigDecimal; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.List; + +public class DbWrapper { + protected Connection connection; + private static final String CONNECTION_TYPE = "jdbc:h2:"; + private static final String DB_SCRIPT = "INIT=RUNSCRIPT FROM 'classpath:"; + private String connectionString; + + public DbWrapper(boolean test) { + if (test) { + this.connectionString = CONNECTION_TYPE + "mem:test;" + DB_SCRIPT + "test_init.sql'"; + } else { + this.connectionString = CONNECTION_TYPE + "file:./help-me-help;" + DB_SCRIPT + "init.sql'"; + } + } + + public boolean connect() throws SQLException { + try { + this.connection = DriverManager.getConnection(this.connectionString); + } catch (SQLException SQLe) { + System.out.println(SQLe.getMessage()); + } + return connection.isValid(0); + } + + public List importUser() throws SQLException { + PreparedStatement ps = this.connection.prepareStatement("SELECT * FROM user"); + ResultSet results = ps.executeQuery(); + List data = new ArrayList(); + while (results.next()) { + data.add( + new Object[] { + results.getInt("user_id"), + results.getString("role"), + results.getString("first_name"), + results.getString("last_name"), + results.getString("email"), + results.getString("password_hash") + }); + } + return data; + } + + public int exportUser(List data) throws SQLException { + if (data == null) { + throw new IllegalArgumentException("data can't be null"); + } + if (data.get(0).length != 6) { + throw new IllegalArgumentException("data's arrays must have a length of 6"); + } + int rowsAffected = 0; + PreparedStatement ps = this.connection.prepareStatement( + "INSERT INTO user (user_id, role, first_name, last_name, email, password_hash) VALUES (?, ?, ?, ?, ?, ?)"); + for (Object[] row : data) { + ps.setInt(1, (int) row[0]); + for (int i = 1; i < row.length; i++) { + ps.setString(i + 1, (String) row[i]); + } + rowsAffected = ps.executeUpdate(); + } + return rowsAffected; + } + + public List importDonations(int user_id) throws SQLException { + PreparedStatement ps = this.connection.prepareStatement("SELECT * FROM donations WHERE user_id = ?"); + ps.setInt(1, user_id); + ResultSet results = ps.executeQuery(); + List data = new ArrayList(); + while (results.next()) { + data.add( + new Object[] { + results.getInt(1), + results.getInt(2), + results.getInt(3), + results.getBigDecimal(4), + results.getTimestamp(5), + results.getString(6) + }); + } + return data; + } + + public int exportDonations(List data) throws SQLException { + if (data == null) { + throw new IllegalArgumentException("data can't be null"); + } + if (data.get(0).length == 6) { + throw new IllegalArgumentException("data's arrays must have a length of 6"); + } + int rowsAffected = 0; + PreparedStatement ps = this.connection.prepareStatement( + "INSERT INTO donations (donation_id, user_id, organization_id, amount, dating, payment_method) VALUES (?, ?, ?, ?, ?, ?)"); + for (Object[] row : data) { + for (int i = 0; i < 3; i++) { + ps.setInt(i + 1, (int) row[i]); + } + ps.setBigDecimal(4, (BigDecimal) row[3]); + ps.setTimestamp(5, (Timestamp) row[4]); + rowsAffected = ps.executeUpdate(); + } + return rowsAffected; + } +} diff --git a/src/main/java/edu/group5/app/control/OrgApiWrapper.java b/src/main/java/edu/group5/app/control/wrapper/OrgApiWrapper.java similarity index 85% rename from src/main/java/edu/group5/app/control/OrgApiWrapper.java rename to src/main/java/edu/group5/app/control/wrapper/OrgApiWrapper.java index 24c82ee..39ac283 100644 --- a/src/main/java/edu/group5/app/control/OrgApiWrapper.java +++ b/src/main/java/edu/group5/app/control/wrapper/OrgApiWrapper.java @@ -1,4 +1,4 @@ -package edu.group5.app.control; +package edu.group5.app.control.wrapper; import java.io.IOException; import java.net.URI; @@ -17,7 +17,8 @@ public class OrgApiWrapper extends Wrapper { private HttpRequest request; /** - * The constructor, which takes a url String and constructs a URI and HttpRequest object from it. + * The constructor, which takes a url String and constructs a URI and + * HttpRequest object from it. * If the url is invalid, it will throw a fitting exception. * * @param urlString A string of the URL that's being connected to. @@ -44,11 +45,13 @@ public OrgApiWrapper(String urlString) { /** * A method for importing data from the wrapped API. * - * @return Returns a boolean, which indicates if the import was successful. Will be False if, for - * example, there is no internet connection. + * @return Returns a boolean, which indicates if the import was successful. Will + * be False if, for + * example, there is no internet connection. * - * @throws InterruptedException This exception is thrown whenever the program is interrupted, like - * by ctrl + c. + * @throws InterruptedException This exception is thrown whenever the program is + * interrupted, like + * by ctrl + c. */ @Override public boolean importData() throws InterruptedException { @@ -67,7 +70,8 @@ public boolean importData() throws InterruptedException { /** * A method for accessing the imported data. * - * @return Returns an array with HashMaps, which is how data is structured in the API. + * @return Returns an array with HashMaps, which is how data is structured in + * the API. */ @Override public Object[] getData() { diff --git a/src/main/java/edu/group5/app/control/Wrapper.java b/src/main/java/edu/group5/app/control/wrapper/Wrapper.java similarity index 66% rename from src/main/java/edu/group5/app/control/Wrapper.java rename to src/main/java/edu/group5/app/control/wrapper/Wrapper.java index ea55179..992b7a9 100644 --- a/src/main/java/edu/group5/app/control/Wrapper.java +++ b/src/main/java/edu/group5/app/control/wrapper/Wrapper.java @@ -1,4 +1,4 @@ -package edu.group5.app.control; +package edu.group5.app.control.wrapper; /** * An abstract class for all Wrappers of datasets. @@ -9,13 +9,16 @@ protected Wrapper() { } /** - * An abstract method for importing data from the dataset that child methods wrap. + * An abstract method for importing data from the dataset that child methods + * wrap. * - * @return Returns a boolean, which indicates if the import was successful. Will be False if, for - * example, there is no internet connection. + * @return Returns a boolean, which indicates if the import was successful. Will + * be False if, for + * example, there is no internet connection. * - * @throws InterruptedException This exception is thrown whenever the program is interrupted, like - * by ctrl + c. + * @throws InterruptedException This exception is thrown whenever the program is + * interrupted, like + * by ctrl + c. */ public abstract boolean importData() throws InterruptedException; diff --git a/src/main/resources/init.sql b/src/main/resources/init.sql index ff37e31..90e8421 100644 --- a/src/main/resources/init.sql +++ b/src/main/resources/init.sql @@ -1,20 +1,21 @@ CREATE TABLE IF NOT EXISTS users ( - user_id int PRIMARY KEY, - first_name varchar(20), - last_name varchar(20), - email varchar(20), - password_hash varchar(72) + user_id INT PRIMARY KEY, + role VARCHAR(20), + first_name VARCHAR(20), + last_name VARCHAR(20), + email VARCHAR(20), + password_hash VARCHAR(72) ); CREATE TABLE IF NOT EXISTS donations ( - donation_id int PRIMARY KEY, - user_id int NOT NULL, - organization_id int NOT NULL, - amount double NOT NULL, - dating timestamp NOT NULL, - payment_method varchar(20), + donation_id INT PRIMARY KEY, + user_id INT NOT NULL, + organization_id INT NOT NULL, + amount DECIMAL NOT NULL, + dating TIMESTAMP NOT NULL, + payment_method VARCHAR(20), CONSTRAINT fk_user FOREIGN KEY (user_id) REFERENCES users(user_id) diff --git a/src/main/resources/test_init.sql b/src/main/resources/test_init.sql index e1c1c43..40a8460 100644 --- a/src/main/resources/test_init.sql +++ b/src/main/resources/test_init.sql @@ -2,22 +2,23 @@ DROP TABLE IF EXISTS users, donations; CREATE TABLE IF NOT EXISTS users ( - user_id int PRIMARY KEY, - first_name varchar(20), - last_name varchar(20), - email varchar(20), - password_hash varchar(72) + user_id INT PRIMARY KEY, + role VARCHAR(20), + first_name VARCHAR(20), + last_name VARCHAR(20), + email VARCHAR(20), + password_hash VARCHAR(72) ); CREATE TABLE IF NOT EXISTS donations ( - donation_id int PRIMARY KEY, - user_id int NOT NULL, - organization_id int NOT NULL, - amount double NOT NULL, - dating timestamp NOT NULL, - payment_method varchar(20), + donation_id INT PRIMARY KEY, + user_id INT NOT NULL, + organization_id INT NOT NULL, + amount DECIMAL NOT NULL, + dating TIMESTAMP NOT NULL, + payment_method VARCHAR(20), CONSTRAINT fk_user FOREIGN KEY (user_id) REFERENCES users(user_id) -); +);; From fe39dd0a7757171272337abad096c8c9c67db667 Mon Sep 17 00:00:00 2001 From: Lucy Ciara Herud-Thomassen <86323303+LucyCiara@users.noreply.github.com> Date: Thu, 12 Mar 2026 12:27:01 +0100 Subject: [PATCH 4/7] refactor[wrapper-tests]: move wrapper tests to a wrapper subfolder --- src/main/java/edu/group5/app/App.java | 4 ++-- .../java/edu/group5/app/control/WrapperTest.java | 5 ----- .../control/{ => wrapper}/OrgApiWrapperTest.java | 15 +++++++++------ .../group5/app/control/wrapper/WrapperTest.java | 5 +++++ 4 files changed, 16 insertions(+), 13 deletions(-) delete mode 100644 src/test/java/edu/group5/app/control/WrapperTest.java rename src/test/java/edu/group5/app/control/{ => wrapper}/OrgApiWrapperTest.java (92%) create mode 100644 src/test/java/edu/group5/app/control/wrapper/WrapperTest.java diff --git a/src/main/java/edu/group5/app/App.java b/src/main/java/edu/group5/app/App.java index dbd2319..1eba2e5 100644 --- a/src/main/java/edu/group5/app/App.java +++ b/src/main/java/edu/group5/app/App.java @@ -1,6 +1,6 @@ package edu.group5.app; -import edu.group5.app.control.DbWrapper; +import edu.group5.app.control.wrapper.DbWrapper; /** * Hello world! @@ -11,7 +11,7 @@ public static void main(String[] args) throws InterruptedException { try { System.out.println(db.connect()); } catch (Exception e) { - e.printStackTrace(); + e.getMessage(); } } } diff --git a/src/test/java/edu/group5/app/control/WrapperTest.java b/src/test/java/edu/group5/app/control/WrapperTest.java deleted file mode 100644 index d626fd7..0000000 --- a/src/test/java/edu/group5/app/control/WrapperTest.java +++ /dev/null @@ -1,5 +0,0 @@ -package edu.group5.app.control; - -public class WrapperTest { - -} diff --git a/src/test/java/edu/group5/app/control/OrgApiWrapperTest.java b/src/test/java/edu/group5/app/control/wrapper/OrgApiWrapperTest.java similarity index 92% rename from src/test/java/edu/group5/app/control/OrgApiWrapperTest.java rename to src/test/java/edu/group5/app/control/wrapper/OrgApiWrapperTest.java index 53f08d7..23b30ec 100644 --- a/src/test/java/edu/group5/app/control/OrgApiWrapperTest.java +++ b/src/test/java/edu/group5/app/control/wrapper/OrgApiWrapperTest.java @@ -1,4 +1,4 @@ -package edu.group5.app.control; +package edu.group5.app.control.wrapper; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -30,7 +30,8 @@ void init() { } /** - * Checks if inputting null as the urlString throws the expected exception during construction. + * Checks if inputting null as the urlString throws the expected exception + * during construction. */ @Test public void nullUrlThrowsException() { @@ -40,7 +41,8 @@ public void nullUrlThrowsException() { } /** - * Checks if inputting an empty urlString throws the expected exception during construction. + * Checks if inputting an empty urlString throws the expected exception during + * construction. */ @Test public void emptyUrlThrowsException() { @@ -50,7 +52,8 @@ public void emptyUrlThrowsException() { } /** - * Checks if an invalid urlString throws the expected exception during construction. + * Checks if an invalid urlString throws the expected exception during + * construction. */ @Test public void faultyUrlThrowsException() { @@ -60,8 +63,8 @@ public void faultyUrlThrowsException() { } // /** - // * Checks if import returns False when there's no internet connection. - // */ + // * Checks if import returns False when there's no internet connection. + // */ // @Test // public void noConnectionReturnsFalseImport() { // assertDoesNotThrow(() -> { diff --git a/src/test/java/edu/group5/app/control/wrapper/WrapperTest.java b/src/test/java/edu/group5/app/control/wrapper/WrapperTest.java new file mode 100644 index 0000000..cfec876 --- /dev/null +++ b/src/test/java/edu/group5/app/control/wrapper/WrapperTest.java @@ -0,0 +1,5 @@ +package edu.group5.app.control.wrapper; + +public class WrapperTest { + +} From c0556a13d480ce1e02d628ef5ce38c7aec09d9d2 Mon Sep 17 00:00:00 2001 From: Lucy Ciara Herud-Thomassen <86323303+LucyCiara@users.noreply.github.com> Date: Thu, 12 Mar 2026 14:46:30 +0100 Subject: [PATCH 5/7] update[DbWrapper]: add exception-throwing to export methods --- src/main/java/edu/group5/app/App.java | 9 +++- .../group5/app/control/wrapper/DbWrapper.java | 44 +++++++++++++------ src/main/resources/init.sql | 10 ++--- 3 files changed, 44 insertions(+), 19 deletions(-) diff --git a/src/main/java/edu/group5/app/App.java b/src/main/java/edu/group5/app/App.java index 1eba2e5..1f76250 100644 --- a/src/main/java/edu/group5/app/App.java +++ b/src/main/java/edu/group5/app/App.java @@ -1,5 +1,8 @@ package edu.group5.app; +import java.util.ArrayList; +import java.util.List; + import edu.group5.app.control.wrapper.DbWrapper; /** @@ -10,8 +13,12 @@ public static void main(String[] args) throws InterruptedException { DbWrapper db = new DbWrapper(false); try { System.out.println(db.connect()); + List data = new ArrayList(); + data.add(new Object[] { 2, 4, "Bernt", "Berntson", "berntberntson123@outlook.com", "wawawa" }); + System.out.println(db.importUsers().toString()); + System.out.println(db.exportUsers(data)); } catch (Exception e) { - e.getMessage(); + System.out.println(e.getMessage()); } } } diff --git a/src/main/java/edu/group5/app/control/wrapper/DbWrapper.java b/src/main/java/edu/group5/app/control/wrapper/DbWrapper.java index 6eb673f..b546c63 100644 --- a/src/main/java/edu/group5/app/control/wrapper/DbWrapper.java +++ b/src/main/java/edu/group5/app/control/wrapper/DbWrapper.java @@ -15,6 +15,8 @@ public class DbWrapper { private static final String CONNECTION_TYPE = "jdbc:h2:"; private static final String DB_SCRIPT = "INIT=RUNSCRIPT FROM 'classpath:"; private String connectionString; + private List users; + private List donations; public DbWrapper(boolean test) { if (test) { @@ -33,8 +35,8 @@ public boolean connect() throws SQLException { return connection.isValid(0); } - public List importUser() throws SQLException { - PreparedStatement ps = this.connection.prepareStatement("SELECT * FROM user"); + public List importUsers() throws SQLException { + PreparedStatement ps = this.connection.prepareStatement("SELECT * FROM users"); ResultSet results = ps.executeQuery(); List data = new ArrayList(); while (results.next()) { @@ -48,23 +50,31 @@ public List importUser() throws SQLException { results.getString("password_hash") }); } - return data; + this.users = data; + return this.users; } - public int exportUser(List data) throws SQLException { + public int exportUsers(List data) throws SQLException { if (data == null) { throw new IllegalArgumentException("data can't be null"); } if (data.get(0).length != 6) { throw new IllegalArgumentException("data's arrays must have a length of 6"); } + if ((int) data.getLast()[0] <= (int) this.users.getLast()[0]) { + throw new IllegalArgumentException("data can't contain existing rows"); + } int rowsAffected = 0; PreparedStatement ps = this.connection.prepareStatement( - "INSERT INTO user (user_id, role, first_name, last_name, email, password_hash) VALUES (?, ?, ?, ?, ?, ?)"); + "INSERT INTO users (user_id, role, first_name, last_name, email, password_hash) VALUES (?, ?, ?, ?, ?, ?)"); for (Object[] row : data) { - ps.setInt(1, (int) row[0]); - for (int i = 1; i < row.length; i++) { - ps.setString(i + 1, (String) row[i]); + try { + ps.setInt(1, (int) row[0]); + for (int i = 1; i < row.length; i++) { + ps.setString(i + 1, (String) row[i]); + } + } catch (Exception e) { + throw new IllegalArgumentException("One or more rows in data contains a wrong datatype"); } rowsAffected = ps.executeUpdate(); } @@ -87,7 +97,8 @@ public List importDonations(int user_id) throws SQLException { results.getString(6) }); } - return data; + this.donations = data; + return this.donations; } public int exportDonations(List data) throws SQLException { @@ -97,15 +108,22 @@ public int exportDonations(List data) throws SQLException { if (data.get(0).length == 6) { throw new IllegalArgumentException("data's arrays must have a length of 6"); } + if ((int) data.getLast()[0] <= (int) this.donations.getLast()[0]) { + throw new IllegalArgumentException("data can't contain existing rows"); + } int rowsAffected = 0; PreparedStatement ps = this.connection.prepareStatement( "INSERT INTO donations (donation_id, user_id, organization_id, amount, dating, payment_method) VALUES (?, ?, ?, ?, ?, ?)"); for (Object[] row : data) { - for (int i = 0; i < 3; i++) { - ps.setInt(i + 1, (int) row[i]); + try { + for (int i = 0; i < 3; i++) { + ps.setInt(i + 1, (int) row[i]); + } + ps.setBigDecimal(4, (BigDecimal) row[3]); + ps.setTimestamp(5, (Timestamp) row[4]); + } catch (Exception e) { + throw new IllegalArgumentException("One or more rows in data contains a wrong datatype"); } - ps.setBigDecimal(4, (BigDecimal) row[3]); - ps.setTimestamp(5, (Timestamp) row[4]); rowsAffected = ps.executeUpdate(); } return rowsAffected; diff --git a/src/main/resources/init.sql b/src/main/resources/init.sql index 90e8421..26a48d6 100644 --- a/src/main/resources/init.sql +++ b/src/main/resources/init.sql @@ -1,10 +1,10 @@ CREATE TABLE IF NOT EXISTS users ( user_id INT PRIMARY KEY, - role VARCHAR(20), - first_name VARCHAR(20), - last_name VARCHAR(20), - email VARCHAR(20), + role VARCHAR(32), + first_name VARCHAR(32), + last_name VARCHAR(32), + email VARCHAR(32), password_hash VARCHAR(72) ); @@ -15,7 +15,7 @@ donations ( organization_id INT NOT NULL, amount DECIMAL NOT NULL, dating TIMESTAMP NOT NULL, - payment_method VARCHAR(20), + payment_method VARCHAR(32), CONSTRAINT fk_user FOREIGN KEY (user_id) REFERENCES users(user_id) From 24229ee84810fe5c32b3397cd866a35d9e48a89c Mon Sep 17 00:00:00 2001 From: Lucy Ciara Herud-Thomassen <86323303+LucyCiara@users.noreply.github.com> Date: Sun, 15 Mar 2026 12:42:01 +0100 Subject: [PATCH 6/7] update[DbWrapper]: change excpetion handling and implement logging --- src/main/java/edu/group5/app/App.java | 19 +- .../group5/app/control/wrapper/DbWrapper.java | 229 +++++++++++++----- src/main/resources/init.sql | 15 +- src/main/resources/test_init.sql | 16 +- 4 files changed, 195 insertions(+), 84 deletions(-) diff --git a/src/main/java/edu/group5/app/App.java b/src/main/java/edu/group5/app/App.java index 1f76250..6b74c18 100644 --- a/src/main/java/edu/group5/app/App.java +++ b/src/main/java/edu/group5/app/App.java @@ -1,6 +1,10 @@ package edu.group5.app; +import java.math.BigDecimal; +import java.sql.Timestamp; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; import java.util.List; import edu.group5.app.control.wrapper.DbWrapper; @@ -12,11 +16,18 @@ public class App { public static void main(String[] args) throws InterruptedException { DbWrapper db = new DbWrapper(false); try { - System.out.println(db.connect()); + Object[] john = new Object[] {1, "Customer", "John", "Doe", "mail", "password"}; + List users = new ArrayList(); + users.add(john); + Object[] row = new Object[] { 1, 1, 39, new BigDecimal(20.0204), new Timestamp(new Date().getTime()), + "Paypal" }; + List data = new ArrayList(); - data.add(new Object[] { 2, 4, "Bernt", "Berntson", "berntberntson123@outlook.com", "wawawa" }); - System.out.println(db.importUsers().toString()); - System.out.println(db.exportUsers(data)); + data.add(row); + db.connect(); + db.exportUsers(users); + db.exportDonations(data); + System.out.println(Arrays.toString(db.importDonations(1).get(0))); } catch (Exception e) { System.out.println(e.getMessage()); } diff --git a/src/main/java/edu/group5/app/control/wrapper/DbWrapper.java b/src/main/java/edu/group5/app/control/wrapper/DbWrapper.java index b546c63..65196dc 100644 --- a/src/main/java/edu/group5/app/control/wrapper/DbWrapper.java +++ b/src/main/java/edu/group5/app/control/wrapper/DbWrapper.java @@ -8,7 +8,12 @@ import java.sql.SQLException; import java.sql.Timestamp; import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; import java.util.List; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; public class DbWrapper { protected Connection connection; @@ -17,6 +22,7 @@ public class DbWrapper { private String connectionString; private List users; private List donations; + private Logger logger = Logger.getLogger(DbWrapper.class.getName()); public DbWrapper(boolean test) { if (test) { @@ -24,108 +30,203 @@ public DbWrapper(boolean test) { } else { this.connectionString = CONNECTION_TYPE + "file:./help-me-help;" + DB_SCRIPT + "init.sql'"; } + this.logger.info("connectionString constructed"); } - public boolean connect() throws SQLException { + public boolean connect() { try { this.connection = DriverManager.getConnection(this.connectionString); - } catch (SQLException SQLe) { - System.out.println(SQLe.getMessage()); + if (this.connection.isValid(0)) { + this.logger.info("Database connected"); + return true; + } else { + this.logger.warning("Failed to connect to database"); + return false; + } + } catch (SQLException e) { + this.logger.log(Level.SEVERE, "Failed to connect to database due to exception", e); + return false; } - return connection.isValid(0); } - public List importUsers() throws SQLException { - PreparedStatement ps = this.connection.prepareStatement("SELECT * FROM users"); - ResultSet results = ps.executeQuery(); - List data = new ArrayList(); - while (results.next()) { - data.add( - new Object[] { - results.getInt("user_id"), - results.getString("role"), - results.getString("first_name"), - results.getString("last_name"), - results.getString("email"), - results.getString("password_hash") - }); - } - this.users = data; + public boolean disconnect() { + try{ this.connection.close(); } catch (Exception e) {}; + try { + return this.connection.isClosed(); + } catch (Exception e) { + this.logger.log(Level.WARNING, "Failed to check if connection is closed due to exception", e); + return false; + } + } + + private void close(ResultSet results, PreparedStatement ps) { + try { results.close(); } catch (Exception e) {} + try { ps.close(); } catch (Exception e) {} + this.logger.info("results and ps closed"); + } + + public List importUsers() { + PreparedStatement ps = null; + ResultSet results = null; + try{ + ps = this.connection.prepareStatement("SELECT * FROM users"); + results = ps.executeQuery(); + List data = new ArrayList(); + while (results.next()) { + data.add( + new Object[] { + results.getInt("user_id"), + results.getString("role"), + results.getString("first_name"), + results.getString("last_name"), + results.getString("email"), + results.getString("password_hash") + }); + } + this.users = data; + this.logger.info("Users imported"); + } catch (SQLException e) { + this.logger.log(Level.SEVERE, "Unexpected SQL exception", e); + } finally { + this.close(results, ps); + } return this.users; } - public int exportUsers(List data) throws SQLException { + public int exportUsers(List data) { + this.importUsers(); + if (data == null) { throw new IllegalArgumentException("data can't be null"); } if (data.get(0).length != 6) { throw new IllegalArgumentException("data's arrays must have a length of 6"); } - if ((int) data.getLast()[0] <= (int) this.users.getLast()[0]) { - throw new IllegalArgumentException("data can't contain existing rows"); + if (data.stream().anyMatch(i -> Arrays.asList(i).contains(null))) { + throw new IllegalArgumentException("One or more rows in data contains null values"); + } + if (this.users.size() > 0) { + if ((int) data.getLast()[0] <= (int) this.users.getLast()[0]) { + throw new IllegalArgumentException("data can't contain existing rows"); + } } + Set ids = new HashSet<>(); + if (data.stream().anyMatch(i -> !ids.add(i[0]))) { + throw new IllegalArgumentException("data can't contain duplicate rows"); + } + + + PreparedStatement ps = null; int rowsAffected = 0; - PreparedStatement ps = this.connection.prepareStatement( - "INSERT INTO users (user_id, role, first_name, last_name, email, password_hash) VALUES (?, ?, ?, ?, ?, ?)"); - for (Object[] row : data) { - try { - ps.setInt(1, (int) row[0]); - for (int i = 1; i < row.length; i++) { - ps.setString(i + 1, (String) row[i]); + try { + ps = this.connection.prepareStatement( + "INSERT INTO users (user_id, role, first_name, last_name, email, password_hash) VALUES (?, ?, ?, ?, ?, ?)"); + for (Object[] row : data) { + try { + ps.setInt(1, (int) row[0]); + for (int i = 1; i < row.length; i++) { + ps.setString(i + 1, (String) row[i]); + } + } catch (Exception e) { + throw new IllegalArgumentException("One or more rows in data contains a wrong datatype"); } - } catch (Exception e) { - throw new IllegalArgumentException("One or more rows in data contains a wrong datatype"); + rowsAffected += ps.executeUpdate(); } - rowsAffected = ps.executeUpdate(); + this.logger.info("Users exported"); + } catch (SQLException e) { + this.logger.log(Level.SEVERE, "Unexpected SQL exception", e); + } finally { + this.close(null, ps); } return rowsAffected; } - public List importDonations(int user_id) throws SQLException { - PreparedStatement ps = this.connection.prepareStatement("SELECT * FROM donations WHERE user_id = ?"); - ps.setInt(1, user_id); - ResultSet results = ps.executeQuery(); - List data = new ArrayList(); - while (results.next()) { - data.add( - new Object[] { - results.getInt(1), - results.getInt(2), - results.getInt(3), - results.getBigDecimal(4), - results.getTimestamp(5), - results.getString(6) - }); - } - this.donations = data; + private List importDonations() { + return this.importDonations(0, true); + } + + public List importDonations(int user_id) { + return this.importDonations(user_id, false); + } + + private List importDonations(int user_id, boolean all) { + PreparedStatement ps = null; + ResultSet results = null; + try{ + if (all) { + ps = this.connection.prepareStatement("SELECT * FROM donations"); + } else { + ps = this.connection.prepareStatement("SELECT * FROM donations WHERE user_id = ?"); + ps.setInt(1, user_id); + } + results = ps.executeQuery(); + List data = new ArrayList(); + while (results.next()) { + data.add( + new Object[] { + results.getInt(1), + results.getInt(2), + results.getInt(3), + results.getBigDecimal(4), + results.getTimestamp(5), + results.getString(6) + }); + } + this.donations = data; + this.logger.info("Donations imported"); + } catch (SQLException e) { + this.logger.log(Level.SEVERE, "Unexpected SQL exception", e); + } finally { + this.close(results, ps); + } return this.donations; } - public int exportDonations(List data) throws SQLException { + public int exportDonations(List data) { + this.importDonations(); + if (data == null) { throw new IllegalArgumentException("data can't be null"); } - if (data.get(0).length == 6) { + if (data.get(0).length != 6) { throw new IllegalArgumentException("data's arrays must have a length of 6"); } - if ((int) data.getLast()[0] <= (int) this.donations.getLast()[0]) { + if (data.stream().anyMatch(i -> Arrays.asList(i).contains(null))) { + throw new IllegalArgumentException("One or more rows in data contains null values"); + } + if (this.donations.size() > 0 && (int) data.getLast()[0] <= (int) this.donations.getLast()[0]) { throw new IllegalArgumentException("data can't contain existing rows"); } + Set ids = new HashSet<>(); + if (data.stream().anyMatch(i -> !ids.add(i[0]))) { + throw new IllegalArgumentException("data can't contain duplicate rows"); + } + + PreparedStatement ps = null; int rowsAffected = 0; - PreparedStatement ps = this.connection.prepareStatement( - "INSERT INTO donations (donation_id, user_id, organization_id, amount, dating, payment_method) VALUES (?, ?, ?, ?, ?, ?)"); - for (Object[] row : data) { - try { - for (int i = 0; i < 3; i++) { - ps.setInt(i + 1, (int) row[i]); + try { + ps = this.connection.prepareStatement( + "INSERT INTO donations (donation_id, user_id, organization_id, amount, dating, payment_method) VALUES (?, (SELECT user_id FROM users WHERE user_id = ?), ?, ?, ?, ?)"); + for (Object[] row : data) { + try { + for (int i = 0; i < 3; i++) { + ps.setInt(i + 1, (int) row[i]); + } + ps.setBigDecimal(4, (BigDecimal) row[3]); + ps.setTimestamp(5, (Timestamp) row[4]); + ps.setString(6, (String) row[5]); + } catch (Exception e) { + throw new IllegalArgumentException("One or more rows in data contains a wrong datatype"); } - ps.setBigDecimal(4, (BigDecimal) row[3]); - ps.setTimestamp(5, (Timestamp) row[4]); - } catch (Exception e) { - throw new IllegalArgumentException("One or more rows in data contains a wrong datatype"); + rowsAffected += ps.executeUpdate(); } - rowsAffected = ps.executeUpdate(); + this.logger.info("Donations exported"); + } catch (SQLException e) { + this.logger.log(Level.SEVERE, "Unexpected SQL exception", e); + } finally { + this.close(null, ps); } return rowsAffected; } + } diff --git a/src/main/resources/init.sql b/src/main/resources/init.sql index 26a48d6..8b99314 100644 --- a/src/main/resources/init.sql +++ b/src/main/resources/init.sql @@ -1,11 +1,11 @@ CREATE TABLE IF NOT EXISTS users ( user_id INT PRIMARY KEY, - role VARCHAR(32), - first_name VARCHAR(32), - last_name VARCHAR(32), - email VARCHAR(32), - password_hash VARCHAR(72) + role VARCHAR(32) NOT NULL, + first_name VARCHAR(32) NOT NULL, + last_name VARCHAR(32) NOT NULL, + email VARCHAR(32) NOT NULL, + password_hash VARCHAR(72) NOT NULL ); CREATE TABLE IF NOT EXISTS @@ -13,12 +13,11 @@ donations ( donation_id INT PRIMARY KEY, user_id INT NOT NULL, organization_id INT NOT NULL, - amount DECIMAL NOT NULL, + amount DECIMAL(32, 16) NOT NULL, dating TIMESTAMP NOT NULL, - payment_method VARCHAR(32), + payment_method VARCHAR(32) NOT NULL, CONSTRAINT fk_user FOREIGN KEY (user_id) REFERENCES users(user_id) ); - diff --git a/src/main/resources/test_init.sql b/src/main/resources/test_init.sql index 40a8460..00670e8 100644 --- a/src/main/resources/test_init.sql +++ b/src/main/resources/test_init.sql @@ -3,11 +3,11 @@ DROP TABLE IF EXISTS users, donations; CREATE TABLE IF NOT EXISTS users ( user_id INT PRIMARY KEY, - role VARCHAR(20), - first_name VARCHAR(20), - last_name VARCHAR(20), - email VARCHAR(20), - password_hash VARCHAR(72) + role VARCHAR(32) NOT NULL, + first_name VARCHAR(32) NOT NULL, + last_name VARCHAR(32) NOT NULL, + email VARCHAR(32) NOT NULL, + password_hash VARCHAR(72) NOT NULL ); CREATE TABLE IF NOT EXISTS @@ -15,10 +15,10 @@ donations ( donation_id INT PRIMARY KEY, user_id INT NOT NULL, organization_id INT NOT NULL, - amount DECIMAL NOT NULL, + amount DECIMAL(32, 16) NOT NULL, dating TIMESTAMP NOT NULL, - payment_method VARCHAR(20), + payment_method VARCHAR(32) NOT NULL, CONSTRAINT fk_user FOREIGN KEY (user_id) REFERENCES users(user_id) -);; +); From f3a6e5a9b9ffd560084d6d6d75710f1fbe22c317 Mon Sep 17 00:00:00 2001 From: Lucy Ciara Herud-Thomassen <86323303+LucyCiara@users.noreply.github.com> Date: Sun, 15 Mar 2026 12:42:37 +0100 Subject: [PATCH 7/7] test[DbWrapper]: add tests for both users and donations --- .../wrapper/DbWrapperDonationsTest.java | 199 ++++++++++++++++++ .../control/wrapper/DbWrapperUserTest.java | 191 +++++++++++++++++ .../app/control/wrapper/WrapperTest.java | 5 - 3 files changed, 390 insertions(+), 5 deletions(-) create mode 100644 src/test/java/edu/group5/app/control/wrapper/DbWrapperDonationsTest.java create mode 100644 src/test/java/edu/group5/app/control/wrapper/DbWrapperUserTest.java delete mode 100644 src/test/java/edu/group5/app/control/wrapper/WrapperTest.java diff --git a/src/test/java/edu/group5/app/control/wrapper/DbWrapperDonationsTest.java b/src/test/java/edu/group5/app/control/wrapper/DbWrapperDonationsTest.java new file mode 100644 index 0000000..f31d57c --- /dev/null +++ b/src/test/java/edu/group5/app/control/wrapper/DbWrapperDonationsTest.java @@ -0,0 +1,199 @@ +package edu.group5.app.control.wrapper; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.List; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class DbWrapperDonationsTest { + private Object[] johnDonation; + private List users; + private Object[] janeDonation; + private Object[] cutoffDonation; + private Object[] freakyDonation; + private Object[] repeatingDonation; + private List donations; + private List donations2; + private List donations3; + private List repeatedDonations; + private List wrongFormatDonations; + private List wrongDatatypeDonations; + private List nullList; + + private static final int PRECISION = 5; + + private DbWrapper db; + + @BeforeEach + void init() { + this.db = new DbWrapper(true); + String[] firstNames = new String[] { "John", "Jane", "Cutoff", "Freaky", "Repeating" }; + String[] lastNames = new String[] { "Doe", "Doe", "Joh", "Bill", "JoeJoe" }; + this.users = new ArrayList(); + for (int i = 0; i < 5; i++) { + Object[] row = new Object[6]; + row[0] = i + 1; + row[1] = "Customer"; + row[2] = firstNames[i]; + row[3] = lastNames[i]; + row[4] = firstNames[i] + lastNames[i] + "@email.com"; + row[5] = "password"; + users.add(row); + } + + this.johnDonation = new Object[] { 1, 1, 39, new BigDecimal(20.02), new Timestamp(new Date().getTime()), + "Paypal" }; + this.donations = new ArrayList(); + this.donations.add(this.johnDonation); + + this.janeDonation = new Object[] { 2, 2, 39, new BigDecimal(20.00), new Timestamp(new Date().getTime()), + "Visa debit card" }; + this.donations2 = new ArrayList(); + this.donations2.add(this.johnDonation); + this.donations2.add(this.janeDonation); + + this.donations3 = new ArrayList(); + this.donations3.add(this.janeDonation); + + this.repeatingDonation = new Object[] { 3, 3, 333, new BigDecimal(18181818.18), + new Timestamp(new Date().getTime()), "Klarna installations payment" }; + this.repeatedDonations = new ArrayList(); + this.repeatedDonations.add(this.repeatingDonation); + this.repeatedDonations.add(this.repeatingDonation); + + this.cutoffDonation = new Object[] { 4, 4, 21 }; + this.wrongFormatDonations = new ArrayList(); + this.wrongFormatDonations.add(cutoffDonation); + + this.freakyDonation = new Object[] { 5, 5, "Freaks4Education", "lots", false, new String[6] }; + this.wrongDatatypeDonations = new ArrayList(); + this.wrongDatatypeDonations.add(freakyDonation); + + Object[] nullRow = new Object[] {null, null, null, null, null, null}; + this.nullList = new ArrayList(); + this.nullList.add(nullRow); + + this.db.connect(); + this.db.exportUsers(users); + } + + private static boolean donationEquals(Object[] array1, Object[] array2) { + Object[] tempArray1 = array1.clone(); + tempArray1[3] = ((BigDecimal) tempArray1[3]).setScale(2, RoundingMode.HALF_UP); + Object[] tempArray2 = array2.clone(); + tempArray2[3] = ((BigDecimal) tempArray2[3]).setScale(2, RoundingMode.HALF_UP); + return Arrays.equals(tempArray1, tempArray2); + } + + @Test + public void importDonationsIsOnlyExportDonationsTest() { + assertDoesNotThrow(() -> { + assertTrue(this.db.importDonations((int) this.users.get(0)[0]).size() == 0); + assertTrue(this.db.exportDonations(this.donations) == 1); + assertTrue(this.db.importDonations((int) this.users.get(0)[0]).size() == 1); + assertTrue(donationEquals(this.donations.get(0), this.db.importDonations((int) this.users.get(0)[0]).get(0))); + assertTrue(this.db.disconnect()); + }); + } + + @Test + public void nullDataInExportDonationsThrowsExpectedException() { + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { + this.db.exportDonations(null); + }); + assertTrue(this.db.disconnect()); + assertEquals("data can't be null", exception.getMessage()); + } + + @Test + public void wronglyFormattedDonationsThrowsExpectedException() { + assertTrue(this.db.importDonations((int) this.users.get(2)[0]).size() == 0); + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { + this.db.exportDonations(this.wrongFormatDonations); + }); + assertTrue(this.db.importDonations((int) this.users.get(2)[0]).size() == 0); + assertTrue(this.db.disconnect()); + assertEquals("data's arrays must have a length of 6", exception.getMessage()); + } + + @Test + public void wronglyDatatypedDonationsThrowsExpectedException() { + assertTrue(this.db.importDonations((int) this.users.get(3)[0]).size() == 0); + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { + this.db.exportDonations(this.wrongDatatypeDonations); + }); + assertTrue(this.db.importDonations((int) this.users.get(3)[0]).size() == 0); + assertTrue(this.db.disconnect()); + assertEquals("One or more rows in data contains a wrong datatype", exception.getMessage()); + } + + @Test + public void addingSameDonationTwiceThrowsExpectedException() { + assertTrue(this.db.importDonations((int) this.users.get(0)[0]).size() == 0); + assertEquals(1, this.db.exportDonations(this.donations)); + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { + this.db.exportDonations(this.donations); + }); + assertTrue(this.db.importDonations((int) this.users.get(0)[0]).size() == 1); + assertTrue(this.db.disconnect()); + assertEquals("data can't contain existing rows", exception.getMessage()); + } + + @Test + public void addingSameDonationTwiceThrowsExpectedException2() { + assertTrue(this.db.importDonations((int) this.users.get(0)[0]).size() == 0); + assertTrue(this.db.importDonations((int) this.users.get(1)[0]).size() == 0); + assertEquals(2, this.db.exportDonations(this.donations2)); + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { + this.db.exportDonations(this.donations); + }); + assertTrue(this.db.importDonations((int) this.users.get(0)[0]).size() == 1); + assertTrue(this.db.importDonations((int) this.users.get(1)[0]).size() == 1); + assertTrue(this.db.disconnect()); + assertEquals("data can't contain existing rows", exception.getMessage()); + } + + @Test + public void addingDifferentDonationsThrowsNoException() { + assertDoesNotThrow(() -> { + assertTrue(this.db.importDonations((int) this.users.get(0)[0]).size() == 0); + assertTrue(this.db.importDonations((int) this.users.get(1)[0]).size() == 0); + assertEquals(1, this.db.exportDonations(this.donations)); + assertEquals(1, this.db.exportDonations(this.donations3)); + assertTrue(this.db.importDonations((int) this.users.get(0)[0]).size() == 1); + assertTrue(this.db.importDonations((int) this.users.get(1)[0]).size() == 1); + assertTrue(this.db.disconnect()); + }); + } + + @Test + public void addingDonationListWithDuplicateIdsThrowsExpectedException() { + assertTrue(this.db.importDonations((int) this.users.get(4)[0]).size() == 0); + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { + this.db.exportDonations(this.repeatedDonations); + }); + assertTrue(this.db.importDonations((int) this.users.get(4)[0]).size() == 0); + assertTrue(this.db.disconnect()); + assertEquals("data can't contain duplicate rows", exception.getMessage()); + } + + @Test + public void addingDonationListWithNullInRowThrowsExpectedException() { + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { + this.db.exportDonations(this.nullList); + }); + assertTrue(this.db.disconnect()); + assertEquals("One or more rows in data contains null values", exception.getMessage()); + } +} diff --git a/src/test/java/edu/group5/app/control/wrapper/DbWrapperUserTest.java b/src/test/java/edu/group5/app/control/wrapper/DbWrapperUserTest.java new file mode 100644 index 0000000..10c514f --- /dev/null +++ b/src/test/java/edu/group5/app/control/wrapper/DbWrapperUserTest.java @@ -0,0 +1,191 @@ +package edu.group5.app.control.wrapper; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.math.BigDecimal; +import java.util.Date; +import java.sql.SQLException; +import java.sql.Time; +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import javafx.util.converter.BigDecimalStringConverter; + +public class DbWrapperUserTest { + private Object[] johnDoe; + private Object[] janeDoe; + private Object[] cutoffJoh; + private Object[] freakyBill; + private Object[] repeatingJoeJoe; + private List users; + private List users2; + private List users3; + private List repeatedUsers; + private List wrongFormatUsers; + private List wrongDatatypeUsers; + private List nullList; + + private DbWrapper db; + + @BeforeEach + void init() { + this.db = new DbWrapper(true); + this.johnDoe = new Object[] { 1, "Customer", "John", "Doe", "johndoe@email.com", "password" }; + this.users = new ArrayList(); + this.users.add(this.johnDoe); + + this.janeDoe = new Object[] { 2, "Customer", "Jane", "Doe", "janedoe@email.com", "qwerty" }; + this.users2 = new ArrayList(); + this.users2.add(this.johnDoe); + this.users2.add(this.janeDoe); + + this.users3 = new ArrayList(); + this.users3.add(this.janeDoe); + + this.repeatingJoeJoe = new Object[] { 3, "Customer", "Repeating", "JoeJoe", "repeatingjjoe@email.com", + "passwordpassword" }; + this.repeatedUsers = new ArrayList(); + this.repeatedUsers.add(this.repeatingJoeJoe); + this.repeatedUsers.add(this.repeatingJoeJoe); + + this.cutoffJoh = new Object[] { 4, "Customer", "Cutoff", "Joh" }; + this.wrongFormatUsers = new ArrayList(); + this.wrongFormatUsers.add(cutoffJoh); + + this.freakyBill = new Object[] { 5, "Customer", 6.1805011125, "Bill", true, false }; + this.wrongDatatypeUsers = new ArrayList(); + this.wrongDatatypeUsers.add(freakyBill); + + Object[] nullRow = new Object[] {null, null, null, null, null, null}; + this.nullList = new ArrayList(); + this.nullList.add(nullRow); + } + + @Test + public void nonTestDbWrapperThrowsNoException() { + assertDoesNotThrow(() -> new DbWrapper(false)); + } + + @Test + public void importUsersIsOnlyExportUsersTest() { + assertDoesNotThrow(() -> { + assertTrue(this.db.connect()); + assertTrue(this.db.importUsers().size() == 0); + assertTrue(this.db.exportUsers(this.users) == 1); + assertTrue(this.db.importUsers().size() == 1); + assertTrue(Arrays.equals(this.db.importUsers().get(0), this.johnDoe)); + assertTrue(this.db.disconnect()); + }); + } + + @Test + public void nullDataInExportUsersThrowsExpectedException() { + assertTrue(this.db.connect()); + assertTrue(this.db.importUsers().size() == 0); + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { + this.db.exportUsers(null); + }); + assertTrue(this.db.importUsers().size() == 0); + assertTrue(this.db.disconnect()); + assertEquals("data can't be null", exception.getMessage()); + } + + @Test + public void wronglyFormattedUsersThrowsExpectedException() { + assertTrue(this.db.connect()); + assertTrue(this.db.importUsers().size() == 0); + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { + this.db.exportUsers(this.wrongFormatUsers); + }); + assertTrue(this.db.importUsers().size() == 0); + assertTrue(this.db.disconnect()); + assertEquals("data's arrays must have a length of 6", exception.getMessage()); + } + + @Test + public void wronglyDatatypedUsersThrowsExpectedException() { + assertTrue(this.db.connect()); + assertTrue(this.db.importUsers().size() == 0); + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { + this.db.exportUsers(this.wrongDatatypeUsers); + }); + assertTrue(this.db.importUsers().size() == 0); + assertTrue(this.db.disconnect()); + assertEquals("One or more rows in data contains a wrong datatype", exception.getMessage()); + } + + @Test + public void addingSameUserTwiceThrowsExpectedException() { + assertTrue(this.db.connect()); + assertTrue(this.db.importUsers().size() == 0); + assertEquals(1, this.db.exportUsers(this.users)); + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { + this.db.exportUsers(this.users); + }); + assertTrue(this.db.importUsers().size() == 1); + assertTrue(this.db.disconnect()); + assertEquals("data can't contain existing rows", exception.getMessage()); + } + + @Test + public void addingSameUserTwiceThrowsExpectedException2() { + assertTrue(this.db.connect()); + assertTrue(this.db.importUsers().size() == 0); + assertEquals(2, this.db.exportUsers(this.users2)); + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { + this.db.exportUsers(this.users); + }); + assertTrue(this.db.importUsers().size() == 2); + assertTrue(this.db.disconnect()); + assertEquals("data can't contain existing rows", exception.getMessage()); + } + + @Test + public void addingDifferentUsersThrowsNoException() { + assertDoesNotThrow(() -> { + assertTrue(this.db.connect()); + assertTrue(this.db.importUsers().size() == 0); + assertEquals(1, this.db.exportUsers(this.users)); + assertEquals(1, this.db.exportUsers(this.users3)); + assertTrue(this.db.importUsers().size() == 2); + assertTrue(this.db.disconnect()); + }); + } + + @Test + public void addingUserListWithDuplicateIdsThrowsExpectedException() { + assertTrue(this.db.connect()); + assertTrue(this.db.importUsers().size() == 0); + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { + this.db.exportUsers(this.repeatedUsers); + }); + assertTrue(this.db.importUsers().size() == 0); + assertTrue(this.db.disconnect()); + assertEquals("data can't contain duplicate rows", exception.getMessage()); + } + + @Test + public void addingUserListWithNullInRowThrowsExpectedException() { + assertTrue(this.db.connect()); + assertTrue(this.db.importUsers().size() == 0); + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { + this.db.exportUsers(this.nullList); + }); + assertTrue(this.db.importUsers().size() == 0); + assertTrue(this.db.disconnect()); + assertEquals("One or more rows in data contains null values", exception.getMessage()); + } + + +} diff --git a/src/test/java/edu/group5/app/control/wrapper/WrapperTest.java b/src/test/java/edu/group5/app/control/wrapper/WrapperTest.java deleted file mode 100644 index cfec876..0000000 --- a/src/test/java/edu/group5/app/control/wrapper/WrapperTest.java +++ /dev/null @@ -1,5 +0,0 @@ -package edu.group5.app.control.wrapper; - -public class WrapperTest { - -}