Increase code coverage

This commit is contained in:
Wim Velzeboer
2023-12-07 12:52:23 +00:00
parent fbed669ab8
commit 4ccaf7afb1
11 changed files with 248 additions and 148 deletions
@@ -33,14 +33,4 @@ public abstract class fflib_DynamicAppFactory
protected String packageName;
protected fflib_IAppBindingResolver resolver;
protected Map<Object, Object> mockImplByObjectType = new Map<Object, Object>();
protected void setMock(Object objectType, Object mock)
{
this.mockImplByObjectType.put(
objectType,
mock
);
}
}
@@ -1,121 +0,0 @@
/**
* File Name: fflib_SObjectShareSelector
*
* @description Abstract selector for SObject Shares
*
* @author architect ir. Wilhelmus G.J. Velzeboer
*
* Copyright (c), W.G.J. Velzeboer,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above author notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the author nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
public abstract inherited sharing class fflib_SObjectShareSelector
extends fflib_SObjectSelector
{
private String accessLevelFieldName
{
get
{
if (accessLevelFieldName == null)
{
accessLevelFieldName = fflib_SObjectShare.getAccessLevelFieldName(getSObjectType2());
}
return accessLevelFieldName;
}
private set;
}
private String parentIdFieldName
{
get
{
if (parentIdFieldName == null)
{
parentIdFieldName = fflib_SObjectShare.getParentIdFieldName(getSObjectType2());
}
return parentIdFieldName;
}
private set;
}
private String rowCauseFieldName = 'RowCause';
private String userOrGroupIdName = 'UserOrGroupId';
private List<Schema.SObjectField> sObjectFieldList
{
get
{
if (sObjectFieldList == null)
{
SObjectType sObjectType = getSObjectType2();
fflib_SObjectDescribe sObjectDescribe = fflib_SObjectDescribe.getDescribe(sObjectType);
sObjectFieldList = new List<Schema.SObjectField>
{
fflib_SObjectShare.getIdField(sObjectType),
fflib_SObjectShare.getAccessLevelField(sObjectType),
fflib_SObjectShare.getParentIdField(sObjectType),
fflib_SObjectShare.getRowCauseField(sObjectType),
fflib_SObjectShare.getUserOrGroupIdField(sObjectType)
};
}
return sObjectFieldList;
}
private set;
}
public List<Schema.SObjectField> getSObjectFieldList()
{
return sObjectFieldList;
}
protected List<SObject> selectShareByParentId(Set<Id> parentIds)
{
return Database.query(
newQueryFactory()
.setCondition(parentIdFieldName + ' IN :parentIds')
.toSOQL());
}
protected List<SObject> selectShareByParentId(Set<Id> parentIds, Set<Id> userOrGroupIds)
{
return Database.query(
newQueryFactory()
.setCondition(parentIdFieldName + ' IN :parentIds AND ' + userOrGroupIdName + ' IN :userOrGroupIds')
.toSOQL());
}
protected List<SObject> selectShareByParentId(Set<Id> parentIds, Set<Id> userOrGroupIds, Set<String> accessLevels)
{
return Database.query(
newQueryFactory()
.setCondition(parentIdFieldName + ' IN :parentIds AND '
+ userOrGroupIdName + ' IN :userOrGroupIds AND '
+ accessLevelFieldName + ' IN :accessLevels')
.toSOQL());
}
protected List<SObject> selectShareByParentId(Set<Id> parentIds, Set<String> rowCauses)
{
return Database.query(
newQueryFactory()
.setCondition(parentIdFieldName + ' IN :parentIds AND ' + rowCauseFieldName + ' IN :rowCauses')
.toSOQL());
}
}
@@ -42,9 +42,9 @@ public virtual with sharing class fflib_SObjectTriggerHandler
super(records, sObjectType);
}
public List<SObject> getChangedRecords(String fileName)
public List<SObject> getChangedRecords(String fieldName)
{
return getChangedRecords(new Set<String>{ fileName });
return getChangedRecords(new Set<String>{ fieldName });
}
public List<SObject> getChangedRecords(Schema.SObjectField fieldToken)
@@ -46,7 +46,7 @@ public with sharing class fflib_SObjectShare
Id parentId,
Id userOrGroupId)
{
return createShares(sObjectType, new Set<Id>{ parentId }, new Set<Id>{ userOrGroupId }, ACCESS_LEVEL_EDIT)
return createEditShares(sObjectType, parentId, new Set<Id>{ userOrGroupId })
.get(0);
}
@@ -64,7 +64,7 @@ public with sharing class fflib_SObjectShare
Id parentId,
Set<Id> userOrGroupIds)
{
return createShares(sObjectType, new Set<Id>{ parentId }, userOrGroupIds, ACCESS_LEVEL_EDIT);
return createEditShares(sObjectType, new Set<Id>{ parentId }, userOrGroupIds);
}
/**
@@ -98,7 +98,7 @@ public with sharing class fflib_SObjectShare
Id parentId,
Id userOrGroupId)
{
return createShares(sObjectType, new Set<Id>{ parentId }, new Set<Id>{ userOrGroupId }, ACCESS_LEVEL_READ)
return createReadShares(sObjectType, parentId, new Set<Id>{ userOrGroupId })
.get(0);
}
@@ -116,7 +116,7 @@ public with sharing class fflib_SObjectShare
Id parentId,
Set<Id> userOrGroupIds)
{
return createShares(sObjectType, new Set<Id>{ parentId }, userOrGroupIds, ACCESS_LEVEL_READ);
return createReadShares(sObjectType, new Set<Id>{ parentId }, userOrGroupIds);
}
/**
@@ -172,17 +172,6 @@ public with sharing class fflib_SObjectShare
return results;
}
/**
* Gets the SObjectField for the Id field of the given SObjectType
*
* @param sObjectType The SObjectType to get its Id field
*
* @return Returns the Id.SObjectField
*/
public static SObjectField getIdField(SObjectType sObjectType)
{
return getsObjectField(fflib_SObjectDescribe.getDescribe(sObjectType).getFields(), 'Id');
}
/**
* Gets the name of the AccessLevel field of the given SObjectType
@@ -44,6 +44,11 @@ public class fflib_DynamicDomainFactoryTest
fflib_DynamicSelectorFactoryTest.Selector,
PACKAGE_FORCE_APP);
private static final fflib_DynamicDomainFactory NonDomain =
new fflib_DynamicDomainFactory(
bindingResolver,
fflib_DynamicSelectorFactoryTest.Selector);
private static final fflib_DynamicDomainFactory OtherDomain =
new fflib_DynamicDomainFactory(
bindingResolver,
@@ -0,0 +1,28 @@
@IsTest(IsParallel=true)
private class fflib_SObjectTriggerHandlerTest
{
@IsTest
static void testNewRecords()
{
Account record = new Account(Name = 'Account');
List<Account> records = new List<Account> {record};
fflib_SObjectTriggerHandler handler = new fflib_SObjectTriggerHandler(records);
System.Assert.areEqual(0, handler.getChangedRecords('Name').size());
}
@IsTest
static void testUpdateRecords()
{
Account record = new Account(
Id = fflib_IDGenerator.generate(Schema.Account.SObjectType),
Name = 'Account');
Account existingRecord = new Account(
Id = record.Id,
Name = '');
List<Account> records = new List<Account> {record};
fflib_SObjectTriggerHandler handler = new fflib_SObjectTriggerHandler(records, Schema.Account.SObjectType);
handler.ExistingRecords = new Map<Id, SObject>{ record.Id => existingRecord};
System.Assert.areEqual(1, handler.getChangedRecords(Schema.Account.Name).size());
}
}
@@ -0,0 +1,141 @@
@IsTest(IsParallel=true)
private class fflib_SObjectUnitOfWork2Test
{
private static List<SObjectType> SOBJECT_LIST = new List<SObjectType> {Schema.Account.SObjectType};
@IsTest
static void testRegisterNewOfDomain()
{
Account parentRecord = new Account(
Id = fflib_IDGenerator.generate(Schema.Account.SObjectType),
Name = 'Parent');
Account record = new Account(Name = 'Child');
List<Account> records = new List<Account> {record};
TestDomain domain = new TestDomain(records);
TestDML testDML = new TestDML();
fflib_SObjectUnitOfWork2 unitOfWork = new fflib_SObjectUnitOfWork2(SOBJECT_LIST, testDML);
unitOfWork.registerNew(domain, Schema.Account.ParentId, parentRecord);
unitOfWork.commitWork();
System.Assert.areEqual(1, testDML.toInsert.size(), 'Expected one record to be inserted');
System.Assert.areEqual(parentRecord.Id, ((Account) testDML.toInsert.get(0)).ParentId, 'Expected the record to be linked to the parent');
}
@IsTest
static void testRegisterDirtyOfDomain()
{
Account parentRecord = new Account(
Id = fflib_IDGenerator.generate(Schema.Account.SObjectType),
Name = 'Parent');
Account record = new Account(
Id = fflib_IDGenerator.generate(Schema.Account.SObjectType),
Name = 'Child');
List<Account> records = new List<Account> {record};
TestDomain domain = new TestDomain(records);
TestDML testDML = new TestDML();
fflib_SObjectUnitOfWork2 unitOfWork = new fflib_SObjectUnitOfWork2(SOBJECT_LIST, testDML);
unitOfWork.registerDirty(domain, Schema.Account.ParentId, parentRecord);
unitOfWork.commitWork();
System.Assert.areEqual(1, testDML.toUpdate.size(), 'Expected one record to be inserted');
System.Assert.areEqual(parentRecord.Id, ((Account) testDML.toUpdate.get(0)).ParentId, 'Expected the record to be linked to the parent');
}
@IsTest
static void testRegisterNewOfDomain_failing_NotTheSameType()
{
Account parentRecord = new Account(
Id = fflib_IDGenerator.generate(Schema.Account.SObjectType),
Name = 'Parent');
Account accountRecord = new Account(Name = 'Account');
Contact contactRecord = new Contact(LastName = 'Contact');
List<SObject> records = new List<SObject> {accountRecord, contactRecord};
TestDML testDML = new TestDML();
try
{
fflib_SObjectUnitOfWork2 unitOfWork = new fflib_SObjectUnitOfWork2(SOBJECT_LIST, testDML);
unitOfWork.registerNew(records, Schema.Account.ParentId, parentRecord);
System.Assert.fail('The UnitOfWork should have thrown an exception');
}
catch (fflib_SObjectUnitOfWork.UnitOfWorkException e)
{
System.Assert.areEqual(e.getMessage(), 'All records should be of the same SObjectType');
}
}
@IsTest
static void testRegisterNewOfDomain_failing_NotSupportedType()
{
Account parentRecord = new Account(
Id = fflib_IDGenerator.generate(Schema.Account.SObjectType),
Name = 'Parent');
Contact contactRecord = new Contact(LastName = 'Contact');
List<SObject> records = new List<SObject> {contactRecord};
TestDML testDML = new TestDML();
try
{
fflib_SObjectUnitOfWork2 unitOfWork = new fflib_SObjectUnitOfWork2(SOBJECT_LIST, testDML);
unitOfWork.registerNew(records, Schema.Account.ParentId, parentRecord);
System.Assert.fail('The UnitOfWork should have thrown an exception');
}
catch (fflib_SObjectUnitOfWork.UnitOfWorkException e)
{
System.Assert.areEqual(e.getMessage(), 'SObject type Contact is not supported by this unit of work');
}
}
private class TestDomain extends fflib_SObjects
{
private TestDomain(List<SObject> records)
{
super(records);
}
private TestDomain(List<SObject> records, SObjectType sObjectType)
{
super(records, sObjectType);
}
public override SObjectType getSObjectType()
{
return Schema.Account.SObjectType;
}
}
private class TestDML implements fflib_SObjectUnitOfWork.IDML
{
public List<SObject> toDelete = new List<SObject>();
public List<SObject> toInsert = new List<SObject>();
public List<SObject> toUpdate = new List<SObject>();
public List<SObject> toEmptyRecycleBin = new List<SObject>();
public List<SObject> toPublish = new List<SObject>();
public void dmlDelete(List<SObject> objList)
{
this.toDelete.addAll(objList);
}
public void dmlInsert(List<SObject> objList)
{
this.toInsert.addAll(objList);
}
public void dmlUpdate(List<SObject> objList)
{
this.toUpdate.addAll(objList);
}
public void emptyRecycleBin(List<SObject> objList)
{
this.toEmptyRecycleBin.addAll(objList);
}
public void eventPublish(List<SObject> objList)
{
this.toPublish.addAll(objList);
}
}
}
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>57.0</apiVersion>
<status>Active</status>
</ApexClass>
@@ -0,0 +1,58 @@
@IsTest(IsParallel=true)
private class fflib_SObjectShareTest
{
@IsTest
static void testEditShareCreation_single()
{
Id accountId = fflib_IDGenerator.generate(Schema.Account.SObjectType);
Id groupId = fflib_IDGenerator.generate(Schema.Group.SObjectType);
SObject editShare = fflib_SObjectShare.createEditShare(Schema.Account.SObjectType, accountId, groupId);
System.Assert.areEqual(accountId, editShare.get('AccountId'));
System.Assert.areEqual(groupId, editShare.get('UserOrGroupId'));
System.Assert.areEqual('Edit', editShare.get('AccountAccessLevel'));
System.Assert.areEqual('Manual', editShare.get('RowCause'));
}
@IsTest
static void testReadShareCreation_single()
{
Id accountId = fflib_IDGenerator.generate(Schema.Account.SObjectType);
Id groupId = fflib_IDGenerator.generate(Schema.Group.SObjectType);
SObject editShare = fflib_SObjectShare.createReadShare(Schema.Account.SObjectType, accountId, groupId);
System.Assert.areEqual(accountId, editShare.get('AccountId'));
System.Assert.areEqual(groupId, editShare.get('UserOrGroupId'));
System.Assert.areEqual('Read', editShare.get('AccountAccessLevel'));
System.Assert.areEqual('Manual', editShare.get('RowCause'));
}
@IsTest
static void testAccessLevelField()
{
System.Assert.areEqual(
Schema.AccountShare.AccountAccessLevel,
fflib_SObjectShare.getAccessLevelField(Schema.AccountShare.SObjectType));
}
@IsTest
static void testParentIdField()
{
System.Assert.areEqual(
Schema.AccountShare.AccountId,
fflib_SObjectShare.getParentIdField(Schema.AccountShare.SObjectType));
}
@IsTest
static void testRowClauseField()
{
System.Assert.areEqual(
Schema.AccountShare.RowCause,
fflib_SObjectShare.getRowCauseField(Schema.AccountShare.SObjectType));
}
@IsTest
static void testUserOrGroupField()
{
System.Assert.areEqual(
Schema.AccountShare.UserOrGroupId,
fflib_SObjectShare.getUserOrGroupIdField(Schema.AccountShare.SObjectType));
}
}
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>57.0</apiVersion>
<status>Active</status>
</ApexClass>