From 4c03fef8a8b38a064af4a9ee297e54a061a96f33 Mon Sep 17 00:00:00 2001 From: hengsin Date: Tue, 12 May 2020 23:17:36 +0800 Subject: [PATCH] IDEMPIERE-4289 Implement Support for JUnit5 Unit Testing (#53) Add JUnit5 unit testing project org.idempiere.test Add tycho sure fire test (skip by default) --- org.idempiere.parent/pom.xml | 5 + org.idempiere.test/.classpath | 11 + org.idempiere.test/.project | 34 ++ .../org.eclipse.core.resources.prefs | 2 + .../.settings/org.eclipse.jdt.core.prefs | 9 + .../.settings/org.eclipse.pde.core.prefs | 3 + org.idempiere.test/META-INF/MANIFEST.MF | 21 + org.idempiere.test/build.properties | 4 + org.idempiere.test/idempiere.unit.test.launch | 568 ++++++++++++++++++ org.idempiere.test/pom.xml | 50 ++ .../org/idempiere/test/AbstractTestCase.java | 191 ++++++ .../src/org/idempiere/test/LoginDetails.java | 114 ++++ .../src/org/idempiere/test/base/DBTest.java | 207 +++++++ .../test/base/EmailFormatValidatorTest.java | 84 +++ .../src/org/idempiere/test/base/POTest.java | 322 ++++++++++ .../org/idempiere/test/base/QueryTest.java | 326 ++++++++++ pom.xml | 1 + 17 files changed, 1952 insertions(+) create mode 100644 org.idempiere.test/.classpath create mode 100644 org.idempiere.test/.project create mode 100644 org.idempiere.test/.settings/org.eclipse.core.resources.prefs create mode 100644 org.idempiere.test/.settings/org.eclipse.jdt.core.prefs create mode 100644 org.idempiere.test/.settings/org.eclipse.pde.core.prefs create mode 100644 org.idempiere.test/META-INF/MANIFEST.MF create mode 100644 org.idempiere.test/build.properties create mode 100644 org.idempiere.test/idempiere.unit.test.launch create mode 100644 org.idempiere.test/pom.xml create mode 100644 org.idempiere.test/src/org/idempiere/test/AbstractTestCase.java create mode 100644 org.idempiere.test/src/org/idempiere/test/LoginDetails.java create mode 100644 org.idempiere.test/src/org/idempiere/test/base/DBTest.java create mode 100644 org.idempiere.test/src/org/idempiere/test/base/EmailFormatValidatorTest.java create mode 100644 org.idempiere.test/src/org/idempiere/test/base/POTest.java create mode 100644 org.idempiere.test/src/org/idempiere/test/base/QueryTest.java diff --git a/org.idempiere.parent/pom.xml b/org.idempiere.parent/pom.xml index 74803cff4c..725220d4a7 100644 --- a/org.idempiere.parent/pom.xml +++ b/org.idempiere.parent/pom.xml @@ -396,6 +396,11 @@ maven-dependency-plugin ${maven.dependency.version} + + org.eclipse.tycho + tycho-surefire-plugin + ${tycho.version} + diff --git a/org.idempiere.test/.classpath b/org.idempiere.test/.classpath new file mode 100644 index 0000000000..a621c21ac5 --- /dev/null +++ b/org.idempiere.test/.classpath @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/org.idempiere.test/.project b/org.idempiere.test/.project new file mode 100644 index 0000000000..3dd557a8f9 --- /dev/null +++ b/org.idempiere.test/.project @@ -0,0 +1,34 @@ + + + org.idempiere.test + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + org.eclipse.m2e.core.maven2Nature + + diff --git a/org.idempiere.test/.settings/org.eclipse.core.resources.prefs b/org.idempiere.test/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000000..99f26c0203 --- /dev/null +++ b/org.idempiere.test/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +encoding/=UTF-8 diff --git a/org.idempiere.test/.settings/org.eclipse.jdt.core.prefs b/org.idempiere.test/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000000..c9545f06a4 --- /dev/null +++ b/org.idempiere.test/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,9 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=11 +org.eclipse.jdt.core.compiler.compliance=11 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning +org.eclipse.jdt.core.compiler.release=enabled +org.eclipse.jdt.core.compiler.source=11 diff --git a/org.idempiere.test/.settings/org.eclipse.pde.core.prefs b/org.idempiere.test/.settings/org.eclipse.pde.core.prefs new file mode 100644 index 0000000000..f29e940a00 --- /dev/null +++ b/org.idempiere.test/.settings/org.eclipse.pde.core.prefs @@ -0,0 +1,3 @@ +eclipse.preferences.version=1 +pluginProject.extensions=false +resolve.requirebundle=false diff --git a/org.idempiere.test/META-INF/MANIFEST.MF b/org.idempiere.test/META-INF/MANIFEST.MF new file mode 100644 index 0000000000..a19064ea2a --- /dev/null +++ b/org.idempiere.test/META-INF/MANIFEST.MF @@ -0,0 +1,21 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: iDempiere Unit Testing +Bundle-SymbolicName: org.idempiere.test +Bundle-Version: 7.1.0.qualifier +Bundle-Vendor: iDempiere +Automatic-Module-Name: org.idempiere.test +Bundle-RequiredExecutionEnvironment: JavaSE-11 +Import-Package: org.junit.jupiter.api;version="5.6.0", + org.junit.jupiter.api.condition;version="5.6.0", + org.junit.jupiter.api.extension;version="5.6.0", + org.junit.jupiter.api.extension.support;version="5.6.0", + org.junit.jupiter.api.function;version="5.6.0", + org.junit.jupiter.api.io;version="5.6.0", + org.junit.jupiter.api.parallel;version="5.6.0", + org.junit.jupiter.params;version="5.6.0", + org.junit.jupiter.params.aggregator;version="5.6.0", + org.junit.jupiter.params.converter;version="5.6.0", + org.junit.jupiter.params.provider;version="5.6.0", + org.junit.jupiter.params.support;version="5.6.0" +Require-Bundle: org.adempiere.base;bundle-version="7.1.0" diff --git a/org.idempiere.test/build.properties b/org.idempiere.test/build.properties new file mode 100644 index 0000000000..56d7765555 --- /dev/null +++ b/org.idempiere.test/build.properties @@ -0,0 +1,4 @@ +source.. = src/ +output.. = target/classes/ +bin.includes = META-INF/,\ + . diff --git a/org.idempiere.test/idempiere.unit.test.launch b/org.idempiere.test/idempiere.unit.test.launch new file mode 100644 index 0000000000..c69862c945 --- /dev/null +++ b/org.idempiere.test/idempiere.unit.test.launch @@ -0,0 +1,568 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.idempiere.test/pom.xml b/org.idempiere.test/pom.xml new file mode 100644 index 0000000000..432838b7ba --- /dev/null +++ b/org.idempiere.test/pom.xml @@ -0,0 +1,50 @@ + + 4.0.0 + + org.idempiere + org.idempiere.parent + 7.1.0-SNAPSHOT + ../org.idempiere.parent/pom.xml + + org.idempiere.test + eclipse-test-plugin + + .. + true + + + + + + org.eclipse.tycho + tycho-surefire-plugin + + + -DIDEMPIERE_HOME=${idempiere.home} + + p2Installed + ${skipTests} + + + + org.eclipse.tycho + target-platform-configuration + ${tycho.version} + + + + + + p2-installable-unit + org.adempiere.server.product + 0.0.0 + + + + + + + + diff --git a/org.idempiere.test/src/org/idempiere/test/AbstractTestCase.java b/org.idempiere.test/src/org/idempiere/test/AbstractTestCase.java new file mode 100644 index 0000000000..d4dc3ae079 --- /dev/null +++ b/org.idempiere.test/src/org/idempiere/test/AbstractTestCase.java @@ -0,0 +1,191 @@ +/*********************************************************************** + * This file is part of iDempiere ERP Open Source * + * http://www.idempiere.org * + * * + * Copyright (C) Contributors * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * + * MA 02110-1301, USA. * + * * + * Contributors: * + * - hengsin * + **********************************************************************/ +package org.idempiere.test; + +import static org.junit.jupiter.api.Assertions.fail; + +import java.sql.SQLException; +import java.sql.Timestamp; + +import org.compiere.Adempiere; +import org.compiere.model.MAcctSchema; +import org.compiere.model.MClientInfo; +import org.compiere.model.MRole; +import org.compiere.util.Env; +import org.compiere.util.Language; +import org.compiere.util.Trx; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; + +/** + * @author hengsin + * + */ +public abstract class AbstractTestCase { + + private Trx trx; + private LoginDetails loginDetails; + + protected final int GARDEN_WORLD_CLIENT = 11; + protected final int GARDEN_WORLD_HQ_ORG = 11; + protected final int GARDEN_WORLD_ADMIN_USER = 101; + protected final int GARDEN_WORLD_ADMIN_ROLE = 102; + protected final int GARDEN_WORLD_HQ_WAREHOUSE = 103; + + @BeforeAll + static void setup() { + Adempiere.startup(false); + } + + @BeforeEach + protected void init() { + String trxName = Trx.createTrxName(getClass().getName()+"_"); + trx = Trx.get(trxName, true); + trx.start(); + + initContext(); + } + + protected LoginDetails newLoginDetails() { + return new LoginDetails(GARDEN_WORLD_CLIENT, GARDEN_WORLD_HQ_ORG, GARDEN_WORLD_ADMIN_USER, GARDEN_WORLD_ADMIN_ROLE, GARDEN_WORLD_HQ_WAREHOUSE, + new Timestamp(System.currentTimeMillis()), Language.getLanguage("en_US")); + } + + protected void initContext() { + loginDetails = newLoginDetails(); + + Env.setContext(Env.getCtx(), Env.AD_CLIENT_ID, loginDetails.getClientId()); + Env.setContext(Env.getCtx(), Env.AD_ORG_ID, loginDetails.getOrganizationId()); + Env.setContext(Env.getCtx(), Env.AD_USER_ID, loginDetails.getUserId()); + Env.setContext(Env.getCtx(), Env.AD_ROLE_ID, loginDetails.getRoleId()); + Env.setContext(Env.getCtx(), Env.M_WAREHOUSE_ID, loginDetails.getWarehouseId()); + Env.setContext(Env.getCtx(), "#LanguageName", loginDetails.getLoginLanguage().getName()); + Env.setContext(Env.getCtx(), "#Date", loginDetails.getLoginDate()); + + Env.verifyLanguage(Env.getCtx(), getLanguage()); + Env.setContext(Env.getCtx(), Env.LANGUAGE, getLanguage().getAD_Language()); + Env.setContext(Env.getCtx(), Env.LOCALE, getLanguage().getLocale().toString()); + + if (loginDetails.getRoleId() > 0) { + if (MRole.getDefault(Env.getCtx(), false).isShowAcct()) + Env.setContext(Env.getCtx(), "#ShowAcct", "Y"); + else + Env.setContext(Env.getCtx(), "#ShowAcct", "N"); + } + + /** Define AcctSchema , Currency, HasAlias **/ + if (loginDetails.getClientId() > 0) { + if (MClientInfo.get(Env.getCtx(), loginDetails.getClientId()).getC_AcctSchema1_ID() > 0) { + MAcctSchema primary = MAcctSchema.get(Env.getCtx(), MClientInfo.get(Env.getCtx(), loginDetails.getClientId()).getC_AcctSchema1_ID()); + Env.setContext(Env.getCtx(), "$C_AcctSchema_ID", primary.getC_AcctSchema_ID()); + Env.setContext(Env.getCtx(), "$C_Currency_ID", primary.getC_Currency_ID()); + Env.setContext(Env.getCtx(), "$HasAlias", primary.isHasAlias()); + } + + MAcctSchema[] ass = MAcctSchema.getClientAcctSchema(Env.getCtx(), loginDetails.getClientId()); + if(ass != null && ass.length > 1) { + for(MAcctSchema as : ass) { + if (as.getAD_OrgOnly_ID() != 0) { + if (as.isSkipOrg(loginDetails.getOrganizationId())) { + continue; + } else { + Env.setContext(Env.getCtx(), "$C_AcctSchema_ID", as.getC_AcctSchema_ID()); + Env.setContext(Env.getCtx(), "$C_Currency_ID", as.getC_Currency_ID()); + Env.setContext(Env.getCtx(), "$HasAlias", as.isHasAlias()); + break; + } + } + } + } + } + } + + @AfterEach + protected void tearDown() { + if (trx != null && trx.isActive()) { + trx.rollback(); + trx.close(); + } + } + + protected Trx getTrx() { + return trx; + } + + protected void commit() { + if (trx != null && trx.isActive()) { + try { + trx.commit(true); + } catch (SQLException e) { + fail(e.getMessage(), e); + } + } + } + + protected void rollback() { + if (trx != null && trx.isActive()) { + trx.rollback(); + } + } + + protected int getAD_Client_ID() { + return loginDetails.getClientId(); + } + + protected int getAD_Org_ID() { + return loginDetails.getOrganizationId(); + } + + protected int getAD_User_ID() { + return loginDetails.getUserId(); + } + + protected int getAD_Role_ID() { + return loginDetails.getRoleId(); + } + + protected int getM_Warehouse_ID() { + return loginDetails.getWarehouseId(); + } + + protected Language getLanguage() { + return loginDetails.getLoginLanguage(); + } + + protected Timestamp getLoginDate() { + return loginDetails.getLoginDate(); + } + + protected String getTrxName() { + return trx.getTrxName(); + } + + @AfterAll + static void shutdown() { + Adempiere.stop(); + } +} diff --git a/org.idempiere.test/src/org/idempiere/test/LoginDetails.java b/org.idempiere.test/src/org/idempiere/test/LoginDetails.java new file mode 100644 index 0000000000..8f0ad2ae29 --- /dev/null +++ b/org.idempiere.test/src/org/idempiere/test/LoginDetails.java @@ -0,0 +1,114 @@ +/*********************************************************************** + * This file is part of iDempiere ERP Open Source * + * http://www.idempiere.org * + * * + * Copyright (C) Contributors * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * + * MA 02110-1301, USA. * + * * + * Contributors: * + * - hengsin * + **********************************************************************/ +package org.idempiere.test; + +import java.sql.Timestamp; + +import org.compiere.util.Language; + +/** + * + * @author hengsin + * + */ +public class LoginDetails { + private int clientId; + private int organizationId; + private int userId; + private int roleId; + private int warehouseId; + private Timestamp loginDate; + private Language loginLanguage; + + public LoginDetails(int clientId, int organizationId, int userId, int roleId, int warehouseId, Timestamp loginDate, + Language loginLanguage) { + super(); + this.clientId = clientId; + this.organizationId = organizationId; + this.userId = userId; + this.roleId = roleId; + this.warehouseId = warehouseId; + this.loginDate = loginDate; + this.loginLanguage = loginLanguage; + } + + public int getClientId() { + return clientId; + } + + public void setClientId(int clientId) { + this.clientId = clientId; + } + + public int getOrganizationId() { + return organizationId; + } + + public void setOrganizationId(int organizationId) { + this.organizationId = organizationId; + } + + public int getUserId() { + return userId; + } + + public void setUserId(int userId) { + this.userId = userId; + } + + public int getRoleId() { + return roleId; + } + + public void setRoleId(int roleId) { + this.roleId = roleId; + } + + public int getWarehouseId() { + return warehouseId; + } + + public void setWarehouseId(int warehouseId) { + this.warehouseId = warehouseId; + } + + public Timestamp getLoginDate() { + return loginDate; + } + + public void setLoginDate(Timestamp loginDate) { + this.loginDate = loginDate; + } + + public Language getLoginLanguage() { + return loginLanguage; + } + + public void setLoginLanguage(Language loginLanguage) { + this.loginLanguage = loginLanguage; + } + + +} diff --git a/org.idempiere.test/src/org/idempiere/test/base/DBTest.java b/org.idempiere.test/src/org/idempiere/test/base/DBTest.java new file mode 100644 index 0000000000..966ccb6dff --- /dev/null +++ b/org.idempiere.test/src/org/idempiere/test/base/DBTest.java @@ -0,0 +1,207 @@ +/****************************************************************************** + * Product: Adempiere ERP & CRM Smart Business Solution * + * Copyright (C) 2008 SC ARHIPAC SERVICE SRL. All Rights Reserved. * + * This program is free software; you can redistribute it and/or modify it * + * under the terms version 2 of the GNU General Public License as published * + * by the Free Software Foundation. This program is distributed in the hope * + * that it will be useful, but WITHOUT ANY WARRANTY; without even the implied * + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + * See the GNU General Public License for more details. * + * You should have received a copy of the GNU General Public License along * + * with this program; if not, write to the Free Software Foundation, Inc., * + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. * + *****************************************************************************/ +package org.idempiere.test.base; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.math.BigDecimal; +import java.sql.Timestamp; +import java.util.ArrayList; + +import org.adempiere.exceptions.DBException; +import org.compiere.model.MTable; +import org.compiere.util.DB; +import org.compiere.util.KeyNamePair; +import org.compiere.util.TimeUtil; +import org.compiere.util.ValueNamePair; +import org.idempiere.test.AbstractTestCase; +import org.junit.jupiter.api.Test; + +/** + * Test {@link org.compiere.util.DB} class + * @author Teo Sarca, www.arhipac.ro + * @author hengsin + */ +public class DBTest extends AbstractTestCase +{ + @Test + public void test_getSQLValueEx() throws Exception + { + int result = DB.getSQLValueEx(null, "SELECT 10 FROM DUAL"); + assertEquals(10, result); + // + result = DB.getSQLValue(null, "SELECT 10 FROM AD_SYSTEM WHERE 1=2"); + assertEquals(-1, result, "No value should be returned"); + // + assertThrows(DBException.class, () -> { + DB.getSQLValueEx(null, "SELECT 10 FROM INEXISTENT_TABLE"); + }); + } + + @Test + public void test_getSQLValue() throws Exception + { + int result = DB.getSQLValue(null, "SELECT 10 FROM DUAL"); + assertEquals(10, result); + // + result = DB.getSQLValue(null, "SELECT 10 FROM AD_SYSTEM WHERE 1=2"); + assertEquals(-1, result, "No value should be returned"); + // + result = DB.getSQLValue(null, "SELECT 10 FROM INEXISTENT_TABLE"); + assertEquals(-1, result, "Error should be signaled"); + } + + @Test + public void test_getSQLValueBDEx() throws Exception + { + BigDecimal result = DB.getSQLValueBDEx(null, "SELECT 10 FROM DUAL"); + assertEquals(BigDecimal.TEN, result); + // + result = DB.getSQLValueBD(null, "SELECT 10 FROM AD_SYSTEM WHERE 1=2"); + assertNull(result, "No value should be returned"); + // + assertThrows(DBException.class, () -> { + DB.getSQLValueBDEx(null, "SELECT 10 FROM INEXISTENT_TABLE"); + }); + } + + @Test + public void test_getSQLValueBD() throws Exception + { + BigDecimal result = DB.getSQLValueBD(null, "SELECT 10 FROM DUAL"); + assertEquals(BigDecimal.TEN, result); + // + result = DB.getSQLValueBD(null, "SELECT 10 FROM AD_SYSTEM WHERE 1=2"); + assertNull(result, "No value should be returned"); + // + result = DB.getSQLValueBD(null, "SELECT 10 FROM INEXISTENT_TABLE"); + assertNull(result, "Error should be signaled"); + } + + @Test + public void test_getSQLValueStringEx() throws Exception + { + String result = DB.getSQLValueStringEx(null, "SELECT 'string' FROM DUAL"); + assertEquals("string", result); + // + result = DB.getSQLValueStringEx(null, "SELECT 10 FROM AD_SYSTEM WHERE 1=2"); + assertNull(result, "No value should be returned"); + // + assertThrows(DBException.class, () -> { + DB.getSQLValueStringEx(null, "SELECT 'string' FROM INEXISTENT_TABLE"); + }); + } + + @Test + public void test_getSQLValueString() throws Exception + { + String result = DB.getSQLValueString(null, "SELECT 'string' FROM DUAL"); + assertEquals("string", result); + // + result = DB.getSQLValueString(null, "SELECT 'string' FROM AD_SYSTEM WHERE 1=2"); + assertNull(result, "No value should be returned"); + // + result = DB.getSQLValueString(null, "SELECT 'string' FROM INEXISTENT_TABLE"); + assertNull(result, "Error should be signaled"); + } + + @Test + public void test_getSQLValueTSEx() throws Exception + { + final Timestamp target = TimeUtil.getDay(2008, 01, 01); + // + Timestamp result = DB.getSQLValueTSEx(null, "SELECT TO_DATE('2008-01-01','YYYY-MM-DD') FROM AD_SYSTEM"); + assertEquals(target, result); + // + result = DB.getSQLValueTSEx(null, "SELECT TO_DATE('2008-01-01','YYYY-MM-DD') FROM AD_SYSTEM WHERE 1=2"); + assertNull(result, "No value should be returned"); + // + assertThrows(DBException.class, () -> { + DB.getSQLValueTSEx(null, "SELECT TO_DATE('2008-01-01','YYYY-MM-DD') FROM INEXISTENT_TABLE"); + }); + } + + @Test + public void test_getSQLValueTS() throws Exception + { + final Timestamp target = TimeUtil.getDay(2008, 01, 01); + // + Timestamp result = DB.getSQLValueTS(null, "SELECT TO_DATE('2008-01-01','YYYY-MM-DD') FROM DUAL"); + assertEquals(target, result); + // + result = DB.getSQLValueTS(null, "SELECT TO_DATE('2008-01-01','YYYY-MM-DD') FROM AD_SYSTEM WHERE 1=2"); + assertNull(result, "No value should be returned"); + // + result = DB.getSQLValueTS(null, "SELECT TO_DATE('2008-01-01','YYYY-MM-DD') FROM INEXISTENT_TABLE"); + assertNull(result, "Error should be signaled"); + } + + @Test + public void test_getValueNamePairs() throws Exception + { + ArrayList params = new ArrayList(); + params.add(MTable.ACCESSLEVEL_AD_Reference_ID); + final String sql = "SELECT Value, Name FROM AD_Ref_List WHERE AD_Reference_ID=? ORDER BY Value"; + // Get (with optional item) + ValueNamePair[] arr = DB.getValueNamePairs(sql, true, params); + assertEquals(6+1, arr.length, "Invalid size"); + assertSame(ValueNamePair.EMPTY, arr[0], "First value should be EMPTY"); + assertEquals(arr[1].getValue(), "1"); + assertEquals(arr[2].getValue(), "2"); + assertEquals(arr[3].getValue(), "3"); + assertEquals(arr[4].getValue(), "4"); + assertEquals(arr[5].getValue(), "6"); + assertEquals(arr[6].getValue(), "7"); + // Get (NO optional item) + arr = DB.getValueNamePairs(sql, false, params); + assertEquals(6, arr.length, "Invalid size"); + assertEquals(arr[0].getValue(), "1"); + assertEquals(arr[1].getValue(), "2"); + assertEquals(arr[2].getValue(), "3"); + assertEquals(arr[3].getValue(), "4"); + assertEquals(arr[4].getValue(), "6"); + assertEquals(arr[5].getValue(), "7"); + } + + @Test + public void test_getKeyNamePairs() throws Exception + { + ArrayList params = new ArrayList(); + params.add(MTable.ACCESSLEVEL_AD_Reference_ID); + final String sql = "SELECT AD_Ref_List_ID, Value FROM AD_Ref_List WHERE AD_Reference_ID=? ORDER BY Value"; + // Get (with optional item) + KeyNamePair[] arr = DB.getKeyNamePairs(sql, true, params); + assertEquals(6+1, arr.length, "Invalid size"); + assertSame(KeyNamePair.EMPTY, arr[0], "First value should be EMPTY"); + assertEquals(arr[1].getName(), "1"); + assertEquals(arr[2].getName(), "2"); + assertEquals(arr[3].getName(), "3"); + assertEquals(arr[4].getName(), "4"); + assertEquals(arr[5].getName(), "6"); + assertEquals(arr[6].getName(), "7"); + // Get (NO optional item) + arr = DB.getKeyNamePairs(sql, false, params); + assertEquals(6, arr.length, "Invalid size"); + assertEquals(arr[0].getName(), "1"); + assertEquals(arr[1].getName(), "2"); + assertEquals(arr[2].getName(), "3"); + assertEquals(arr[3].getName(), "4"); + assertEquals(arr[4].getName(), "6"); + assertEquals(arr[5].getName(), "7"); + } + +} diff --git a/org.idempiere.test/src/org/idempiere/test/base/EmailFormatValidatorTest.java b/org.idempiere.test/src/org/idempiere/test/base/EmailFormatValidatorTest.java new file mode 100644 index 0000000000..2f02a788e7 --- /dev/null +++ b/org.idempiere.test/src/org/idempiere/test/base/EmailFormatValidatorTest.java @@ -0,0 +1,84 @@ +/********************************************************************** +* This file is part of iDempiere ERP Open Source * +* http://www.idempiere.org * +* * +* Copyright (C) Contributors * +* * +* This program is free software; you can redistribute it and/or * +* modify it under the terms of the GNU General Public License * +* as published by the Free Software Foundation; either version 2 * +* of the License, or (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program; if not, write to the Free Software * +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * +* MA 02110-1301, USA. * +* * +* Contributors: * +* - Carlos Ruiz - globalqss * +* - hengsin * +**********************************************************************/ +package org.idempiere.test.base; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.Arrays; +import java.util.Collection; + +import org.compiere.util.EMail; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +/* + * Unit test sample from http://examples.javacodegeeks.com/core-java/util/regex/matcher/validate-email-address-with-java-regular-expression-example/ + */ + +public class EmailFormatValidatorTest { + + public EmailFormatValidatorTest() { + } + + public static Collection data() { + Object[][] data = new Object[][] { + { "javacodegeeks@gmail.com.2j",true }, + { "java@java@oracle.com", false }, // you cannot have @ twice in the address + { "java!!!@example.com", true }, + { "mysite@.com", false }, // tld cannot start with a dot + { "javacodegees.com", false }, // must contain a @ character and a tld + { ".javacodegees.com@at.com", false }, + { "javacodegees..javacom@at.com", false }, + { "javacodegeeks@gmail.com",true }, + { "nikos+mylist@gmail.com", true }, + { "abc.efg-900@gmail-list.com", true }, + { "abc123@example.com.gr", true }, + { "username+detail@example.com", true }, + { "user@example.museum", true }, + { "myemail+sketchysite@gmail.com", true }, + { "micky.o'finnagan@wherever.com", true }, + { "exampleemail@testing.info", true }, + { "marcelo.calbucci%mandic@fapesp.com.br", true }, + { "customer/department=shipping@example.com", true }, + { "$A12345@example.com", true }, + { "!def!xyz%abc@example.com", true }, + { "_somename@example.com", true }, + { "nuñez@globalqss.com", true }, + { "name@tld", true }, + { "john@server.department.company.com", true } + }; + + return Arrays.asList(data); + } + + @ParameterizedTest + @MethodSource("data") + public void test(String arg, Boolean expectedValidation) { + Boolean res = EMail.validate(arg); + assertEquals(expectedValidation, res, "Result"); + } + +} \ No newline at end of file diff --git a/org.idempiere.test/src/org/idempiere/test/base/POTest.java b/org.idempiere.test/src/org/idempiere/test/base/POTest.java new file mode 100644 index 0000000000..28035b62fe --- /dev/null +++ b/org.idempiere.test/src/org/idempiere/test/base/POTest.java @@ -0,0 +1,322 @@ +/*********************************************************************** + * This file is part of iDempiere ERP Open Source * + * http://www.idempiere.org * + * * + * Copyright (C) Contributors * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * + * MA 02110-1301, USA. * + * * + * Contributors: * + * - teo sarca * + * - hengsin * + **********************************************************************/ +package org.idempiere.test.base; + +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.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.Properties; + +import org.adempiere.exceptions.DBException; +import org.compiere.model.MClient; +import org.compiere.model.MTest; +import org.compiere.model.POInfo; +import org.compiere.util.DB; +import org.compiere.util.Env; +import org.compiere.util.Trx; +import org.idempiere.test.AbstractTestCase; +import org.junit.jupiter.api.Test; + +/** + * Tests for {@link org.compiere.model.PO} class. + * @author Teo Sarca, SC ARHIPAC SERVICE SRL + * @author hengsin + */ +public class POTest extends AbstractTestCase +{ + public static class MyTestPO extends MTest + { + private static final long serialVersionUID = -6861171283806782985L; + protected boolean failOnSave = false; + + + private MyTestPO m_parent = null; + private MyTestPO m_dependentRecord = null; + + public static String getName(int Test_ID, String trxName) + { + String sql = "SELECT "+COLUMNNAME_Name+" FROM "+Table_Name + +" WHERE "+COLUMNNAME_Test_ID+"=?"; + return DB.getSQLValueStringEx(trxName, sql, Test_ID); + } + + public static boolean exists(int Test_ID, String trxName) + { + final String sql = "SELECT "+COLUMNNAME_Test_ID+" FROM "+Table_Name + +" WHERE "+COLUMNNAME_Test_ID+"=?"; + int id = DB.getSQLValueEx(trxName, sql, Test_ID); + return id > 0 && id == Test_ID; + } + + public MyTestPO(Properties ctx, boolean failOnSave, String trxName) + { + super(ctx, "Test_"+System.currentTimeMillis(), 10); + this.set_TrxName(trxName); + this.setDescription(""+getClass()); + this.failOnSave = failOnSave; + } + public MyTestPO(Properties ctx, int id, String trxName) + { + super(ctx, id, trxName); + } + @Override + protected boolean afterSave(boolean newRecord, boolean success) + { + if (m_parent == null) + { + m_dependentRecord = new MyTestPO(getCtx(), false, get_TrxName()); + m_dependentRecord.m_parent = this; + m_dependentRecord.setName("D_"+this.getName()); + m_dependentRecord.saveEx(); + } + + if (this.failOnSave) + throw new RuntimeException("Never save this object [trxName="+get_TrxName()+", success="+success+"]"); + return true; + } + + public int getDependent_ID() + { + return (m_dependentRecord != null ? m_dependentRecord.get_ID() : -1); + } + }; + + /** + * Tests the following methods: + *
    + *
  • {@link org.compiere.model.PO#is_Changed()} + *
  • {@link org.compiere.model.PO#is_ValueChanged(String)} + *
+ * Applies to following bugs: + *
    + *
  • [ 1704828 ] PO.is_Changed() and PO.is_ValueChanged are not consistent + *
+ */ + @Test + public void test_Changed() + { + String[] testStrings = new String[] { + "a", + "test", + }; + // Create the test PO and save + MTest testPO = new MTest(Env.getCtx(), getClass().getName(), 1); + testPO.set_TrxName(getTrxName()); + + for (String str : testStrings) + { + testPO.setHelp(str); + testPO.saveEx(); + String originalString = testPO.getHelp(); + String info = "testString=[" + str + "]" + ", originalString=[" + originalString + "]"; + + // Initial asserts (nothing changed) + assertFalse(testPO.is_ValueChanged(MTest.COLUMNNAME_Help), info); + assertFalse(testPO.is_Changed(), info); + // Set the same name + testPO.setHelp(originalString); + assertFalse(testPO.is_ValueChanged(MTest.COLUMNNAME_Help), info); + assertFalse(testPO.is_Changed(), info); + // Set a new name + testPO.setHelp(originalString+"-changed"); + assertTrue(testPO.is_ValueChanged(MTest.COLUMNNAME_Help), info); + assertTrue(testPO.is_Changed(), info); + // Set the original name back + testPO.setHelp(originalString); + assertFalse(testPO.is_ValueChanged(MTest.COLUMNNAME_Help), info); + assertFalse(testPO.is_Changed(), info); + } + + // Finally, delete the testPO + testPO.delete(true, getTrxName()); + } + + + /** + *
  • BF [ 1990856 ] PO.set_Value* : truncate string more than needed + */ + @Test + public void testTruncatedStrings() { + // + // Creating a huge string for testing: + StringBuilder sb = new StringBuilder(); + for (int i = 1; i <= 1000; i++) { + sb.append("0123456789"); + } + String bigString = sb.toString(); + // + // Create the test PO: + MTest testPO = new MTest(Env.getCtx(), getClass().getName(), 1); + testPO.set_TrxName(getTrxName()); + // + // Getting Max Length: + POInfo info = POInfo.getPOInfo(Env.getCtx(), MTest.Table_ID); + int maxLength = info.getFieldLength(info.getColumnIndex(MTest.COLUMNNAME_Name)); + // + // Test with a string that has less then maxLength + { + testPO.set_ValueOfColumn(MTest.COLUMNNAME_Name, bigString.substring(0, maxLength - 1)); + String resultString = (String) testPO.get_Value(MTest.COLUMNNAME_Name); + assertEquals(maxLength - 1, resultString.length(), "String was not truncated correctly (1)"); + // + testPO.setName(bigString.substring(0, maxLength - 1)); + assertEquals(maxLength - 1, testPO.getName().length(), "String was not truncated correctly (2)"); + } + // + // Test with a string that has maxLength + { + testPO.set_ValueOfColumn(MTest.COLUMNNAME_Name, bigString.substring(0, maxLength)); + String resultString = (String) testPO.get_Value(MTest.COLUMNNAME_Name); + assertEquals(maxLength, resultString.length(), "String was not truncated correctly (3)"); + // + testPO.setName(bigString.substring(0, maxLength)); + assertEquals(maxLength, testPO.getName().length(), "String was not truncated correctly (4)"); + } + // + // Test with a string that has more than maxLength + { + testPO.set_ValueOfColumn(MTest.COLUMNNAME_Name, bigString); + String resultString = (String) testPO.get_Value(MTest.COLUMNNAME_Name); + assertEquals(maxLength, resultString.length(), "String was not truncated correctly (5)"); + // + testPO.setName(bigString); + assertEquals(maxLength, testPO.getName().length(), "String was not truncated correctly (6)"); + } + } + + /** + * Object should NOT be saved if afterSave fails EVEN if is outside transaction (trxName=null) + */ + @Test + public void testAfterSaveError() + { + // + // Test for new objects + { + MyTestPO test = new MyTestPO(Env.getCtx(), true, null); + assertFalse(test.save(), "Object should not be saved -- "+test); + assertFalse(test.get_ID() <= 0, "Object should not be saved -- "+test); + assertFalse(MyTestPO.exists(test.get_ID(), null), "Object should not be saved(2) -- "+test); + } + // + // Test for old objects + { + MyTestPO test = new MyTestPO(Env.getCtx(), false, null); + assertTrue(test.save(), "Object *should* be saved -- "+test); + // + MyTestPO test2 = new MyTestPO(Env.getCtx(), test.get_ID(), null); + assertEquals(test2.get_ID(), test.get_ID(), "Object not found"); + test2.failOnSave = true; + test2.setName(test2.getName()+"_2"); + assertFalse(test2.save(), "Object should not be saved -- "+test2); + // + String name = MyTestPO.getName(test2.get_ID(), null); + assertEquals(test.getName(), name, "Object should not be modified(2) -- id="+test2); + } + } + + /** + * If one object fails on after save we should not revert all transaction. + * BF [ 2849122 ] PO.AfterSave is not rollback on error + * https://sourceforge.net/tracker/index.php?func=detail&aid=2849122&group_id=176962&atid=879332# + */ + @Test + public void testAfterSaveError_BF2849122() + { + assertNotNull(getTrxName(), "TrxName should not be null"); + + MyTestPO t1 = new MyTestPO(Env.getCtx(), false, getTrxName()); + t1.saveEx(); + assertTrue(MyTestPO.exists(t1.get_ID(), getTrxName()), "Object not found(1) - t1="+t1); + assertTrue(MyTestPO.exists(t1.getDependent_ID(), getTrxName()), "Object not found(1) - t1(dep)="+t1); + // + final MyTestPO t2 = new MyTestPO(Env.getCtx(), true, getTrxName()); + try + { + t2.saveEx(); + } + catch (Exception e){} + assertTrue(MyTestPO.exists(t1.get_ID(), getTrxName()), "Object not found(2) - t1="+t1); + assertTrue(MyTestPO.exists(t1.getDependent_ID(), getTrxName()), "Object not found(2) - t1(dep)="+t1); + assertFalse(MyTestPO.exists(t2.get_ID(), getTrxName()), "Object found(2) - t2="+t2); + assertFalse(MyTestPO.exists(t2.getDependent_ID(), getTrxName()), "Object found(2) - t2(dep)="+t2); + // + final MyTestPO t3 = new MyTestPO(Env.getCtx(), false, getTrxName()); + t3.saveEx(); + assertTrue(MyTestPO.exists(t1.get_ID(), getTrxName()), "Object not found(3) - t1="+t1); + assertTrue(MyTestPO.exists(t1.getDependent_ID(), getTrxName()), "Object not found(3) - t1(dep)="+t1); + assertFalse(MyTestPO.exists(t2.get_ID(), getTrxName()), "Object found(3) - t2="+t2); + assertFalse(MyTestPO.exists(t2.getDependent_ID(), getTrxName()), "Object found(3) - t2(dep)="+t2); + assertTrue(MyTestPO.exists(t3.get_ID(), getTrxName()), "Object not found(3) - t3="+t3); + assertTrue(MyTestPO.exists(t3.getDependent_ID(), getTrxName()), "Object not found(3) - t3(dep)="+t3); + } + + @Test + public void testForUpdate() + { + MClient client = new MClient(Env.getCtx(), Env.getAD_Client_ID(Env.getCtx()), getTrxName()); + assertDoesNotThrow(() -> { + boolean ok = DB.getDatabase().forUpdate(client, 5); + assertTrue(ok); + }); + + Trx trx2 = Trx.get(Trx.createTrxName(), true); + try { + trx2.start(); + MClient client2 = new MClient(Env.getCtx(), Env.getAD_Client_ID(Env.getCtx()), trx2.getTrxName()); + assertThrows(DBException.class, () -> { + DB.getDatabase().forUpdate(client2, 5); + }); + } finally { + trx2.close(); + } + + String description = client.getDescription(); + client.setDescription(client.getName()+".Description"); + assertDoesNotThrow(() -> { + client.saveEx(); + }); + rollback(); + client.load(getTrxName()); + assertEquals(description, client.getDescription()); + + Trx trx3 = Trx.get(Trx.createTrxName(), true); + try { + trx3.start(); + MClient client3 = new MClient(Env.getCtx(), Env.getAD_Client_ID(Env.getCtx()), trx3.getTrxName()); + assertDoesNotThrow(() -> { + boolean ok = DB.getDatabase().forUpdate(client3, 5); + assertTrue(ok); + }); + } finally { + trx3.close(); + } + } +} diff --git a/org.idempiere.test/src/org/idempiere/test/base/QueryTest.java b/org.idempiere.test/src/org/idempiere/test/base/QueryTest.java new file mode 100644 index 0000000000..47e46cc729 --- /dev/null +++ b/org.idempiere.test/src/org/idempiere/test/base/QueryTest.java @@ -0,0 +1,326 @@ +/*********************************************************************** + * This file is part of iDempiere ERP Open Source * + * http://www.idempiere.org * + * * + * Copyright (C) Contributors * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * + * MA 02110-1301, USA. * + * * + * Contributors: * + * - hengsin * + **********************************************************************/ +package org.idempiere.test.base; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.adempiere.exceptions.DBException; +import org.compiere.model.MTable; +import org.compiere.model.POResultSet; +import org.compiere.model.Query; +import org.compiere.model.X_AD_Element; +import org.compiere.util.DB; +import org.compiere.util.Env; +import org.compiere.util.KeyNamePair; +import org.idempiere.test.AbstractTestCase; +import org.junit.jupiter.api.Test; + +/** + * @author hengsin + * + */ + +public class QueryTest extends AbstractTestCase { + + /** + * + */ + public QueryTest() { + } + + @Test + public void testNoTable() { + assertThrows(IllegalArgumentException.class, () -> { + new Query(Env.getCtx(), "NO_TABLE_DEFINED", null, getTrxName()); + }); + } + + @Test + public void testList() throws Exception + { + List list = new Query(Env.getCtx(), "AD_Table", "TableName IN (?,?)", getTrxName()) + .setParameters(new Object[]{"C_Invoice", "M_InOut"}) + .setOrderBy("TableName") + .list(); + assertEquals(2, list.size(), "Invalid list size"); + assertEquals(list.get(0).getTableName(), "C_Invoice", "Invalid object 1"); + assertEquals(list.get(1).getTableName(), "M_InOut", "Invalid object 2"); + } + + @Test + public void testScroll() throws Exception + { + POResultSet rs = new Query(Env.getCtx(), "AD_Table", "TableName IN (?,?)", getTrxName()) + .setParameters(new Object[]{"C_Invoice", "M_InOut"}) + .setOrderBy("TableName") + .scroll(); + try + { + int i = 0; + while (rs.hasNext()) + { + MTable t = rs.next(); + if (i == 0) + { + assertEquals("C_Invoice", t.getTableName(), "Invalid object "+i); + } + else if (i == 1) + { + assertEquals("M_InOut", t.getTableName(), "Invalid object "+i); + } + else + { + fail("More objects retrived than expected"); + } + i++; + } + } + finally + { + DB.close(rs); + } + + } + + @Test + public void testIterate() throws Exception + { + Iterator it = new Query(Env.getCtx(), "AD_Table", "TableName IN (?,?)", getTrxName()) + .setParameters(new Object[]{"C_Invoice", "M_InOut"}) + .setOrderBy("TableName") + .iterate(); + int i = 0; + while(it.hasNext()) + { + MTable t = it.next(); + if (i == 0) + { + assertEquals("C_Invoice", t.getTableName(), "Invalid object "+i); + } + else if (i == 1) + { + assertEquals("M_InOut", t.getTableName(), "Invalid object "+i); + } + else + { + fail("More objects retrived than expected"); + } + i++; + } + + } + + @Test + public void testCount() throws Exception + { + int count = new Query(Env.getCtx(), "AD_Table", "TableName IN (?,?)", getTrxName()) + .setParameters(new Object[]{"C_Invoice", "M_InOut"}) + .setOrderBy("TableName") + .count(); + assertEquals(2, count, "Invalid count"); + } + + @Test + public void testCount_BadSQL() throws Exception + { + assertThrows(DBException.class, () -> { + new Query(Env.getCtx(), "AD_Table", "TableName IN (?,?) AND BAD_SQL", getTrxName()) + .setParameters(new Object[]{"C_Invoice", "M_InOut"}) + .setOrderBy("TableName") + .count(); + }); + } + + @Test + public void testCount_NoValues() throws Exception + { + int count = new Query(Env.getCtx(), "AD_Table", "1=2", getTrxName()).count(); + assertEquals(0, count, "Counter should be ZERO"); + } + + @Test + public void testFirst() throws Exception + { + MTable t = new Query(Env.getCtx(), "AD_Table", "TableName IN (?,?)", getTrxName()) + .setParameters(new Object[]{"C_Invoice", "M_InOut"}) + .setOrderBy("TableName") + .first(); + assertEquals("C_Invoice", t.getTableName(), "Invalid object"); + } + + @Test + public void testFirstId() throws Exception + { + int id = new Query(Env.getCtx(), "AD_Table", "TableName IN (?,?)", getTrxName()) + .setParameters(new Object[]{"C_Invoice", "M_InOut"}) + .setOrderBy("TableName") + .firstId(); + int expectedId = 318; // C_Invoice + assertEquals(expectedId, id, "Invalid ID"); + } + + @Test + public void testFirstOnly() throws Exception + { + MTable t = new Query(Env.getCtx(), "AD_Table", "AD_Table_ID=?", getTrxName()) + .setParameters(new Object[]{318}) + .firstOnly(); + assertEquals(318, t.get_ID(), "Invalid table ID"); + // + assertThrows(DBException.class, () -> { + new Query(Env.getCtx(), "AD_Table", "TableName IN (?,?)", getTrxName()) + .setParameters(new Object[]{"C_Invoice", "M_InOut"}) + .setOrderBy("TableName") + .firstOnly(); + }); + } + + @Test + public void testFirstIdOnly() throws Exception + { + int expectedId = 318; // C_Invoice + int id = new Query(Env.getCtx(), "AD_Table", "AD_Table_ID=?", getTrxName()) + .setParameters(new Object[]{expectedId}) + .firstIdOnly(); + assertEquals(expectedId, id, "Invalid table ID"); + // + assertThrows(DBException.class, () -> { + new Query(Env.getCtx(), "AD_Table", "TableName IN (?,?)", getTrxName()) + .setParameters(new Object[]{"C_Invoice", "M_InOut"}) + .setOrderBy("TableName") + .firstIdOnly(); + }); + } + + @Test + public void testSetClient_ID() throws Exception + { + int AD_Client_ID = Env.getAD_Client_ID(Env.getCtx()); + String sql = "SELECT COUNT(*) FROM C_Invoice WHERE IsActive='Y' AND AD_Client_ID="+AD_Client_ID; + int targetCount = DB.getSQLValue(null, sql); + // + int count = new Query(Env.getCtx(), "C_Invoice", "1=1", getTrxName()) + .setOnlyActiveRecords(true) + .setClient_ID() + .count(); + assertEquals(targetCount, count, "Invoice # not match"); + } + + @Test + public void testGet_IDs() throws Exception + { + final String whereClause = "AD_Element_ID IN (101, 102)"; + int[] ids = new Query(Env.getCtx(), "AD_Element", whereClause, getTrxName()) + .setOrderBy("AD_Element_ID") + .getIDs(); + assertNotNull(ids); + assertEquals(2, ids.length); + assertEquals(101, ids[0]); + assertEquals(102, ids[1]); + } + + @Test + public void testAggregate() throws Exception + { + final int AD_Client_ID = Env.getAD_Client_ID(Env.getCtx()); + final String sqlFrom = "FROM C_InvoiceLine WHERE IsActive='Y' AND AD_Client_ID="+AD_Client_ID; + final Query query = new Query(Env.getCtx(), "C_InvoiceLine", null, getTrxName()) + .setOnlyActiveRecords(true) + .setClient_ID(); + // + // Test COUNT: + assertEquals(DB.getSQLValueBDEx(getTrxName(), "SELECT COUNT(*) "+sqlFrom), + query.aggregate(null, Query.AGGREGATE_COUNT), "COUNT not match"); + // + // Test SUM: + assertEquals(DB.getSQLValueBDEx(getTrxName(), "SELECT SUM(LineNetAmt+TaxAmt) "+sqlFrom), + query.aggregate("LineNetAmt+TaxAmt", Query.AGGREGATE_SUM), "SUM not match"); + // + // Test MIN: + assertEquals(DB.getSQLValueBDEx(getTrxName(), "SELECT MIN(LineNetAmt) "+sqlFrom), + query.aggregate("LineNetAmt", Query.AGGREGATE_MIN), "MIN not match"); + // + // Test MAX: + assertEquals(DB.getSQLValueBDEx(getTrxName(), "SELECT MAX(LineNetAmt) "+sqlFrom), + query.aggregate("LineNetAmt", Query.AGGREGATE_MAX), "MAX not match"); + // + // Test aggregate (String) - FR [ 2726447 ] + assertEquals(DB.getSQLValueStringEx(getTrxName(), "SELECT MAX(Description) "+sqlFrom), + (String)query.aggregate("Description", Query.AGGREGATE_MAX, String.class), "MAX not match (String)"); + // + // Test aggregate (Timestamp) - FR [ 2726447 ] + assertEquals(DB.getSQLValueTSEx(getTrxName(), "SELECT MAX(Updated) "+sqlFrom), + (Timestamp)query.aggregate("Updated", Query.AGGREGATE_MAX, Timestamp.class), "MAX not match (Timestamp)"); + // + // Test Exception : No Aggregate Function defined + assertThrows(DBException.class, () -> { + query.aggregate("*", null); + }, + "No Aggregate Function defined" + ); + // + // Test Exception : No Expression defined + assertThrows(DBException.class, () -> { + query.aggregate(null, Query.AGGREGATE_SUM); + }, "No Expression defined"); + } + + @Test + public void testOnlySelection() throws Exception + { + // Get one AD_PInstance_ID + int AD_PInstance_ID = DB.getSQLValueEx(null, "SELECT MAX(AD_PInstance_ID) FROM AD_PInstance"); + assertTrue(AD_PInstance_ID > 0); + + // Create selection list + List elements = new ArrayList (); + elements.add(new KeyNamePair(102, null)); // AD_Element_ID=102 => AD_Client_ID + elements.add(new KeyNamePair(104, null)); // AD_Element_ID=104 => AD_Column_ID + DB.executeUpdateEx("DELETE FROM T_Selection WHERE AD_PInstance_ID="+AD_PInstance_ID, getTrxName()); + DB.createT_SelectionNew (AD_PInstance_ID, elements, getTrxName()); + + String whereClause = "1=1"; // some dummy where clause + int[] ids = new Query(Env.getCtx(), X_AD_Element.Table_Name, whereClause, getTrxName()) + .setOnlySelection(AD_PInstance_ID) + .setOrderBy(X_AD_Element.COLUMNNAME_AD_Element_ID) + .getIDs(); + assertEquals(elements.size(), ids.length, "Resulting number of elements differ"); + + for (int i = 0; i < elements.size(); i++) + { + int expected = elements.get(i).getKey(); + assertEquals(expected, ids[i], "Element "+i+" not equals"); + } + } +} diff --git a/pom.xml b/pom.xml index 96887af1f7..645f4e9433 100644 --- a/pom.xml +++ b/pom.xml @@ -53,6 +53,7 @@ org.idempiere.webservices.client-feature org.idempiere.p2 org.idempiere.javadoc + org.idempiere.test ${idempiere.target}