Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .idea/dictionaries/project.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions .idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file modified IlluminatedCloud/Apexkit/OfflineSymbolTable.zip
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/**
* @description A test-only helper for manipulating users' permissions, permission sets and permission set groups
*
* Note: This class does *no* error handling. Because it's used in the setup and preparation of test data,
* it's on the developer to ensure the methods are called with existing, valid data like permission set names.
* If, for instance, a developer fat-fingers a permission set name, the query on ~ line 74 will fail, and throw
* an exception.
*/

@IsTest
public class PermissionsHelper {
/**
* @description creates and inserts a permission set assignment record
* @param userToAssignTo User the user whom the permission set will be applied to
* @param permSetId Id The Id of the permission set to assign to the user.
*/
public static void assignPermissionSetToUser(
User userToAssignTo,
Id permSetId
) {
PermissionSetAssignment permissionSetAssignment = new PermissionSetAssignment(
AssigneeId = userToAssignTo.Id,
PermissionSetId = permSetId
);
insert permissionSetAssignment;
}

/**
* @description Assigns a permission set to a given user.
* @param userToAssignTo User to assign the permission set to.
* @param permSetName String name of the permission set.
*/
public static void assignPermSetToUser(
User userToAssignTo,
String permSetName
) {
assignPermissionSetToUser(
userToAssignTo,
UserFactoryHelper.fetchPermissionSetIdByName(permSetName)
);
}

/**
* @description Generates a test permission set record - no permissions are added to it
* @param permSetName String what to call your perm set
* @param doInsert Boolean true if you want this to insert your perm set record.
* @return PermissionSet the created permission set.
*/
public static PermissionSet createPermissionSet(
String permSetName,
Boolean doInsert
) {
PermissionSet newPermSet = new PermissionSet(
Name = permSetName,
Label = 'Test Permission Set'
);
if (doInsert) {
insert newPermSet;
}
return newPermSet;
}

/**
* @description Enables a custom permission using a permission set
* @param permissionName String name of the custom permission you want created
* @param forUserId Id user to assign the custom permission to.
*/
public static void enableCustomPermission(
String permissionName,
Id forUserId
) {
PermissionSet permSet = createPermissionSet('TestPermSet', true);

Id customPermissionId = [
SELECT Id
FROM CustomPermission
WHERE DeveloperName = :permissionName
WITH SYSTEM_MODE
LIMIT 1
]
.Id;

SetupEntityAccess permSetPermission = new SetupEntityAccess(
ParentId = permSet.Id,
SetupEntityId = customPermissionId
);

PermissionSetAssignment permSetAssignment = new PermissionSetAssignment(
AssigneeId = forUserId,
PermissionSetId = permSet.Id
);

insert new List<SObject>{ permSetPermission, permSetAssignment };
}
}
Comment on lines +1 to +95
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Image description CodeRabbit

The code looks good overall, but there's a potential issue with the enableCustomPermission method. If the custom permission with the provided name doesn't exist, the query on line 74 will return no results and an attempt to access the .Id property on line 81 will result in a NullPointerException. To avoid this, you should check if the query returned any results before trying to access the Id.

-       Id customPermissionId = [
-           SELECT Id
-           FROM CustomPermission
-           WHERE DeveloperName = :permissionName
-           WITH SYSTEM_MODE
-           LIMIT 1
-       ]
-       .Id;
+       List<CustomPermission> permissions = [
+           SELECT Id
+           FROM CustomPermission
+           WHERE DeveloperName = :permissionName
+           WITH SYSTEM_MODE
+           LIMIT 1
+       ];
+
+       if (permissions.isEmpty()) {
+           throw new CustomPermissionNotFoundException('Custom permission ' + permissionName + ' not found');
+       }
+
+       Id customPermissionId = permissions[0].Id;

In this fix, I've added a check for an empty list after the query. If the list is empty, it throws a CustomPermissionNotFoundException, which is a custom exception that you would need to define. This way, the error message can be more specific about what went wrong.

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>63.0</apiVersion>
<status>Active</status>
</ApexClass>
197 changes: 197 additions & 0 deletions force-app/main/default/classes/test utilities/SObjectFactory.cls
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
/**
* @description a factory class for generating test data.
* This class auto populates required fields and, by default, generates a plausible but fake ID for the record.
* You can use this class directly, or use one of the associated builder classes for generating
* complex data structures.
*
* This class has the ability to set default values for fields in 3, hierarchical ways.
* 1. The default values passed into the SObjectFactory via the sObject prototype.
* 2. The default values defined by the custom default class specified by the usingDefaultsClassName parameter.
* 3. The default values found in the 'org-wide' defaults class defined in the SObjectFactoryDefaults' subclasses.
*
* It's important to note that *nothing* overwrites field values specified in the SObject prototype.
*
* Some profiling information:
* | Action | Avg of 10 test executions |
* |-----------|------------------------|
* | Create 10 Single SObject w/ fake Id | 58ms |
* | Create 10 Single SObjects w/ fake Id and Custom Defaults | 73ms |
* | Create 10 Single SObjects & insert them | 550ms |
* | Create list of 200 SObjects w/ fake Id | 115ms |
* | Create list of 200 SObjects & insert them | 1216ms |
*/
@IsTest
public with sharing class SObjectFactory {
/**
Comment on lines +23 to +25
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Image description CodeRabbit

The @IsTest annotation is used for test classes and methods. It seems like this class is not a test class but a utility class for creating test data. Consider removing the @IsTest annotation.

- @IsTest

* @description Use the FieldDefaults interface to set up field/value keys you want to routinely impose on your
* factory generated objects.
*/
public interface FieldDefaults {
/**
* @description Interface used by implementing classes to define defaults.
* @return `Map<Schema.SObjectField, Object>`
*/
Map<Schema.SObjectField, Object> getFieldDefaults();
}

/**
* @description convenience method allowing you to specify just the prototype
* @param prototype SObject any SObject
* @return A created SObject with required fields populated
*/
public static SObject createSObject(SObject prototype) {
return createSObject(prototype, null, false);
}

/**
* @description Convenience method for creating SObjects using just the prototype and a custom defaults class
* @param prototype SObject - any constructed SObject
* @param usingDefaultsClassName String - the name of the class to use for custom default values
* @return A created SObject with required fields populated
*/
public static SObject createSObject(
SObject prototype,
String usingDefaultsClassName
) {
return createSObject(prototype, usingDefaultsClassName, false);
}

/**
* @description Creates an SObject with the given prototype and forceInsert flag.
*
* @param prototype The prototype SObject.
* @param forceInsert Flag indicating whether to force insertion.
*
* @return The created SObject.
*/
public static SObject createSObject(SObject prototype, Boolean forceInsert) {
return createSObject(prototype, null, forceInsert);
}

/**
* @description Creates an SObject with the given prototype, using defaults from the specified class, and optionally inserts it into the database.
*
* @param prototype The prototype SObject to be created.
* @param usingDefaultsClassName The name of the class providing default values for the SObject.
* @param forceInsert Indicates whether to insert the SObject into the database.
*
* @return The created SObject.
*/
public static SObject createSObject(
SObject prototype,
String usingDefaultsClassName,
Boolean forceInsert
) {
prototype = internalCreateSObject(prototype, usingDefaultsClassName);
if (forceInsert) {
Database.insert(prototype, AccessLevel.SYSTEM_MODE);
} else {
prototype.Id = IdFactory.get(prototype);
}
return prototype;
}
Comment on lines +70 to +92
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Image description CodeRabbit

In line 87, you are using Database.insert(prototype, AccessLevel.SYSTEM_MODE);. This will bypass all custom security settings such as object-level, field-level, and record-level access permissions. Be sure that this is what you want to do. If not, consider using insert prototype; instead.

- Database.insert(prototype, AccessLevel.SYSTEM_MODE);
+ insert prototype;


private static SObject internalCreateSObject(
SObject prototype,
String usingDefaultsClassName
) {
// ensure the defaults class is not null
String functionalDefaultsClassName = String.isNotEmpty(
usingDefaultsClassName
)
? usingDefaultsClassName
: '';
// First the specified defaults class
prototype = SObjectFactoryHelper.applyCustomDefaults(
prototype,
functionalDefaultsClassName
);
// then the 'org-wide' defaults
prototype = SObjectFactoryHelper.applyOrgWideObjectDefaults(prototype);
return prototype;
}

/**
* @description Creates a list of SObjects based on the provided prototype and count.
*
* @param prototype The SObject prototype to base the created SObjects on.
* @param count The number of SObjects to create.
*
* @return A list of created SObjects.
*/
public static List<SObject> createSObjects(SObject prototype, Integer count) {
return createSObjects(prototype, count, null, false);
}

/**
* @description Creates a list of SObjects based on the provided prototype, count, and defaults class name.
*
* @param prototype The prototype SObject to base the new SObjects on.
* @param count The number of SObjects to create.
* @param usingDefaultsClassName The name of the class to use for default values.
*
* @return A list of created SObjects.
*/
public static List<SObject> createSObjects(
SObject prototype,
Integer count,
String usingDefaultsClassName
) {
return createSObjects(prototype, count, usingDefaultsClassName, false);
}

/**
* @description Creates a list of sObjects based on the provided prototype, count, and forceInsert flag.
*
* @param prototype The prototype SObject to base the created objects on.
* @param count The number of SObjects to create.
* @param forceInsert Flag indicating whether to force insertion of the created SObjects.
*
* @return List of created SObjects.
*/
public static List<SObject> createSObjects(
SObject prototype,
Integer count,
Boolean forceInsert
) {
return createSObjects(prototype, count, null, forceInsert);
}

/**
* @description Creates a list of SObjects based on a prototype, count, defaults class, and force insert flag.
*
* @param prototype The prototype SObject to clone.
* @param count The number of SObjects to create.
* @param usingDefaultsClassName The name of the defaults class to use.
* @param forceInsert Whether to force insert the created SObjects.
*
* @return A list of created SObjects.
*/
@SuppressWarnings('PMD.ExcessiveParameterList')
public static List<SObject> createSObjects(
SObject prototype,
Integer count,
String usingDefaultsClassName,
Boolean forceInsert
) {
List<SObject> createdSObjects = new List<SObject>();
SObject constructedFromPrototype = internalCreateSObject(
prototype,
usingDefaultsClassName
);
for (
Integer iterationCounter = 0; iterationCounter < count; iterationCounter++
) {
SObject clonedSObject = constructedFromPrototype.clone(false, true);
createdSObjects.add(
SObjectFactoryHelper.mutateCloneToRespectNameAndAutonumberRules(
clonedSObject,
!forceInsert,
iterationCounter
)
);
}
SObjectFactoryHelper.insertIfForced(createdSObjects, forceInsert);
return createdSObjects;
}
Comment on lines +159 to +196
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Image description CodeRabbit

In line 194, you are using SObjectFactoryHelper.insertIfForced(createdSObjects, forceInsert);. This method might be bypassing all custom security settings such as object-level, field-level, and record-level access permissions. Be sure that this is what you want to do. If not, consider using a simple insert createdSObjects; when forceInsert is true.

- SObjectFactoryHelper.insertIfForced(createdSObjects, forceInsert);
+ if (forceInsert) {
+     insert createdSObjects;
+ }

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>63.0</apiVersion>
<status>Active</status>
</ApexClass>
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
@IsTest
public class SObjectFactoryDefaults {
// To specify defaults for objects, use the naming convention [ObjectName]Defaults.
// For custom objects, omit the __c from the Object Name

/**
* @description Default values for Account object
*/
public class AccountDefaults implements SObjectFactory.FieldDefaults {
/**
* @description Returns a map of field defaults for the Account object.
*
* @return A map containing the default values for specific Account fields.
*/
public Map<Schema.SObjectField, Object> getFieldDefaults() {
return new Map<Schema.SObjectField, Object>{
Account.Name => 'Test Account'
};
}
Comment on lines +15 to +19

Check warning

Code scanning / PMD

Missing ApexDoc comment Warning test

Missing ApexDoc comment
}

/**
* @description This class provides default field values for Contact objects.
*/
public class ContactDefaults implements SObjectFactory.FieldDefaults {
/**
* @description Returns a map of field defaults for the Contact object.
*
* @return A map where keys are Schema.SObjectField representing Contact fields and values are the default values for those fields.
*/
public Map<Schema.SObjectField, Object> getFieldDefaults() {
return new Map<Schema.SObjectField, Object>{
Contact.FirstName => 'First',
Contact.LastName => 'Last'
};
}
Comment on lines +31 to +36

Check warning

Code scanning / PMD

Missing ApexDoc comment Warning test

Missing ApexDoc comment
}

/**
* @description This class provides default field values for Opportunity objects.
*/
public class OpportunityDefaults implements SObjectFactory.FieldDefaults {
/**
* @description Returns a map of default field values for Opportunity.
*
* @return Map<Schema.SObjectField, Object> A map containing default field values.
*/
public Map<Schema.SObjectField, Object> getFieldDefaults() {
return new Map<Schema.SObjectField, Object>{
Opportunity.Name => 'Test Opportunity',
Opportunity.StageName => 'Closed Won',
Opportunity.CloseDate => System.today()
};
}
Comment on lines +48 to +54

Check warning

Code scanning / PMD

Missing ApexDoc comment Warning test

Missing ApexDoc comment
}

/**
* @description Defaults for Case SObjectFactory
*/
public class CaseDefaults implements SObjectFactory.FieldDefaults {
/**
* @description Returns a map of field defaults for the Case object.
*
* @return A map where the key is the Schema.SObjectField and the value is the default value.
*/
public Map<Schema.SObjectField, Object> getFieldDefaults() {
return new Map<Schema.SObjectField, Object>{
Case.Subject => 'Test Case'
};
}
Comment on lines +66 to +70

Check warning

Code scanning / PMD

Missing ApexDoc comment Warning test

Missing ApexDoc comment
}
}
Loading
Loading