From 1fc82c5f99e9457ef5f7e33c93d9a9d5ffbc34c2 Mon Sep 17 00:00:00 2001 From: bjanderson70 Date: Sat, 11 Jul 2020 11:25:09 -0400 Subject: [PATCH 1/9] updated unit tests for cache; fixed logic in cache --- force-di/main/classes/di_Binding.cls | 2 +- force-di/main/classes/di_BindingParam.cls | 68 ++-- force-di/main/classes/di_Injector.cls | 36 +- .../di_InjectorComponentController.cls | 8 +- force-di/main/classes/di_PlatformCache.cls | 329 ++++++++++++------ force-di/test/classes/di_BindingTest.cls | 1 + .../di_InjectorComponentControllerTest.cls | 33 +- .../test/classes/di_PlatformCacheTest.cls | 260 ++++++++++++++ .../classes/di_PlatformCacheTest.cls-meta.xml | 5 + 9 files changed, 570 insertions(+), 172 deletions(-) create mode 100644 force-di/test/classes/di_PlatformCacheTest.cls create mode 100644 force-di/test/classes/di_PlatformCacheTest.cls-meta.xml diff --git a/force-di/main/classes/di_Binding.cls b/force-di/main/classes/di_Binding.cls index 931613a..538a939 100644 --- a/force-di/main/classes/di_Binding.cls +++ b/force-di/main/classes/di_Binding.cls @@ -275,7 +275,7 @@ public abstract class di_Binding implements Comparable { { if ( this.bindings == null ) { - System.debug('// di_Binding.Resolver :: Loading Bindings //'); + //System.debug('// di_Binding.Resolver :: Loading Bindings //'); // Ask each module to configure and aggregate the resulting bindings this.bindings = new List(); for (di_Module module : modules) diff --git a/force-di/main/classes/di_BindingParam.cls b/force-di/main/classes/di_BindingParam.cls index fb224b9..fe8571a 100644 --- a/force-di/main/classes/di_BindingParam.cls +++ b/force-di/main/classes/di_BindingParam.cls @@ -22,7 +22,7 @@ * 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 with sharing class di_BindingParam { @@ -32,7 +32,7 @@ public with sharing class di_BindingParam { @InvocableMethod( label = 'Get Value' - ) + ) public static List invoke( List requests ) { List responses = new List(); @@ -177,18 +177,18 @@ public with sharing class di_BindingParam { } else { - System.debug( LoggingLevel.WARN, 'BindingParam.parameters.get("' + req + '") is null' ); + // System.debug( LoggingLevel.WARN, 'BindingParam.parameters.get("' + req + '") is null' ); } } else { - System.debug( LoggingLevel.WARN, 'BindingParam.parameters is null' ); + // System.debug( LoggingLevel.WARN, 'BindingParam.parameters is null' ); } - System.debug( 'paramName=' + req ); - System.debug( res ); + // System.debug( 'paramName=' + req ); + // System.debug( res ); responses.add( res ); @@ -214,8 +214,8 @@ public with sharing class di_BindingParam { private static Long toLongValue( Date value ) { return ( value == null ? null : toLongValue( - DateTime.newInstance( value.year(), value.month(), value.day(), 0, 0, 0 ) - )); + DateTime.newInstance( value.year(), value.month(), value.day(), 0, 0, 0 ) + )); } private static Long toLongValue( DateTime value ) { @@ -235,8 +235,8 @@ public with sharing class di_BindingParam { private static Decimal toDecimalValue( Date value ) { return ( value == null ? null : toDecimalValue( - DateTime.newInstance( value.year(), value.month(), value.day(), 0, 0, 0 ) - )); + DateTime.newInstance( value.year(), value.month(), value.day(), 0, 0, 0 ) + )); } private static Decimal toDecimalValue( DateTime value ) { @@ -333,8 +333,8 @@ public with sharing class di_BindingParam { @InvocableVariable( label = 'Parameter Name' - required = true - ) + required = true + ) public String paramName; } @@ -343,72 +343,72 @@ public with sharing class di_BindingParam { @InvocableVariable( label = 'Number' - description = 'Whole number (no decimals)' - ) + description = 'Whole number (no decimals)' + ) public Long longValue; @InvocableVariable( label = 'Decimal' - description = 'Number that may include decimal places' - ) + description = 'Number that may include decimal places' + ) public Decimal decimalValue; @InvocableVariable( label = 'Text' - description = 'Text value' - ) + description = 'Text value' + ) public String stringValue; @InvocableVariable( label = 'Boolean' - description = 'true/false' - ) + description = 'true/false' + ) public Boolean booleanValue; @InvocableVariable( label = 'Date' - ) + ) public Date dateValue; @InvocableVariable( label = 'Date/Time' - ) + ) public DateTime dateTimeValue; @InvocableVariable( label = 'Number Collection' - description = 'Collection of whole numbers' - ) + description = 'Collection of whole numbers' + ) public Long[] longValues = new Long[] {}; @InvocableVariable( label = 'Decimal Collection' - description = 'Collection of numbers that may include decimal places' - ) + description = 'Collection of numbers that may include decimal places' + ) public Decimal[] decimalValues = new Decimal[] {}; @InvocableVariable( label = 'Text Collection' - description = 'Collection of text values' - ) + description = 'Collection of text values' + ) public String[] stringValues = new String[] {}; @InvocableVariable( label = 'Boolean Collection' - description = 'Collection of true/false values' - ) + description = 'Collection of true/false values' + ) public Boolean[] booleanValues = new Boolean[] {}; @InvocableVariable( label = 'Date Collection' - description = 'Collection of date values' - ) + description = 'Collection of date values' + ) public Date[] dateValues = new Date[] {}; @InvocableVariable( label = 'Date/Time Collection' - description = 'Collection of date/time values' - ) + description = 'Collection of date/time values' + ) public DateTime[] dateTimeValues = new DateTime[] {}; } diff --git a/force-di/main/classes/di_Injector.cls b/force-di/main/classes/di_Injector.cls index 1028c75..8dc9c40 100644 --- a/force-di/main/classes/di_Injector.cls +++ b/force-di/main/classes/di_Injector.cls @@ -33,11 +33,13 @@ public class di_Injector { public static final di_Injector Org = new di_Injector( new List { - new CustomMetadataModule()}); + new CustomMetadataModule() + }); /** * Bindings visible to this Injector **/ + @TestVisible public di_Binding.Resolver Bindings {get; private set;} /** @@ -121,8 +123,8 @@ public class di_Injector { } List bindingsFound = this.Bindings.bySObject( bindingSObjectType ) - .byName( developerName.toLowerCase().trim() ) - .get(); + .byName( developerName.toLowerCase().trim() ) + .get(); if ( bindingsFound == null || bindingsFound.isEmpty() || bindingsFound[0] == null) { throw new InjectorException('Binding for "' + developerName + '" and SObjectType "' + bindingSObjectType + '" not found'); @@ -146,31 +148,31 @@ public class di_Injector { private List getDIBinding(){ List recordList = new List(); List bindingMDTRec = [SELECT QualifiedAPIName - , DeveloperName - , NamespacePrefix - , Type__c - , To__c - , BindingObject__c - , BindingObject__r.QualifiedApiName - , BindingObjectAlternate__c - , BindingSequence__c - FROM di_Binding__mdt]; - for(di_Binding__mdt records :bindingMDTRec){ + , DeveloperName + , NamespacePrefix + , Type__c + , To__c + , BindingObject__c + , BindingObject__r.QualifiedApiName + , BindingObjectAlternate__c + , BindingSequence__c + FROM di_Binding__mdt]; + for(di_Binding__mdt records :bindingMDTRec) { recordList.add(new di_BindingConfigWrapper(records)); } // When we want to mock data from metadata for injecting dependencies. - if(di_Injector.mock_BindingConfigurationWrappersOuter != null){ + if(di_Injector.mock_BindingConfigurationWrappersOuter != null) { recordList = di_Injector.mock_BindingConfigurationWrappersOuter; } return recordList; } public override void configure() { // TODO: Support Namespace - for(di_BindingConfigWrapper bindingConfig :getDIBinding()){ + for(di_BindingConfigWrapper bindingConfig :getDIBinding()) { bind(bindingConfig.DeveloperName); type(bindingConfig.Type); if( String.isNotBlank(bindingConfig.BindingObject) - || String.isNotBlank(bindingConfig.BindingObjectAlternate)){ + || String.isNotBlank(bindingConfig.BindingObjectAlternate)) { bindingObjectApiName = String.isNotBlank(bindingConfig.BindingObject) ? bindingConfig.bindingObjectQualifiedApiName.toLowerCase().trim() : bindingConfig.BindingObjectAlternate.toLowerCase().trim(); @@ -180,7 +182,7 @@ public class di_Injector { } bind(results[0].getSObjectType()); // if it is getting here, then it is finding a SObject to add to the binding } - if(bindingConfig.BindingSequence != null){ + if(bindingConfig.BindingSequence != null) { sequence(Integer.valueOf(bindingConfig.BindingSequence)); } data(bindingConfig); diff --git a/force-di/main/classes/di_InjectorComponentController.cls b/force-di/main/classes/di_InjectorComponentController.cls index 92e46bd..f336b1a 100644 --- a/force-di/main/classes/di_InjectorComponentController.cls +++ b/force-di/main/classes/di_InjectorComponentController.cls @@ -22,13 +22,13 @@ * 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 with sharing class di_InjectorComponentController { - public String BindingNameValue {set;get;} + public String BindingNameValue {set; get;} - public Object ParametersValue {set;get;} + public Object ParametersValue {set; get;} public ApexPages.Component getInject() { ApexPages.Component cmp = null; @@ -56,7 +56,7 @@ public with sharing class di_InjectorComponentController { return new Component.di_injectorFlowProxy( flowName = flowName, inputVariables = params - ); + ); } } \ No newline at end of file diff --git a/force-di/main/classes/di_PlatformCache.cls b/force-di/main/classes/di_PlatformCache.cls index 9e4dcf8..7dad92b 100644 --- a/force-di/main/classes/di_PlatformCache.cls +++ b/force-di/main/classes/di_PlatformCache.cls @@ -1,9 +1,40 @@ -public with sharing class di_PlatformCache +/* + * Modifications: + * B Anderson -- + * + Checked for Cache not enabled ( getPartition) + * + Re-aligned the code for readability + * + Add Tests + */ +public with sharing class di_PlatformCache { - private di_PlatformCache() { } - + ////////////////////////////////////////////////////////////////////////////////////////////// + // Data Members + ////////////////////////////////////////////////////////////////////////////////////////////// + // number of seconds for a 24 hour period + public static final Integer NUM_OF_SECS_IN24HR = 86400; + + @TestVisible + private static final String BINDING_KEY = 'bindingKeyIndex'; + @TestVisible private static di_PlatformCache instance; + @TestVisible + private Map > > cacheKeyIndexMap = new Map > >(); + @TestVisible + private static Map generatedKeyNames = new Map(); + // Used for turning on logging (if needed) + @TestVisible + private static Boolean DEBUGGING = false; + + ////////////////////////////////////////////////////////////////////////////////////////////// + // Ctors + ////////////////////////////////////////////////////////////////////////////////////////////// + // singleton + private di_PlatformCache() { + } + ////////////////////////////////////////////////////////////////////////////////////////////// + // Public Methods + ////////////////////////////////////////////////////////////////////////////////////////////// public static di_PlatformCache getInstance() { if ( instance == null ) @@ -14,48 +45,21 @@ public with sharing class di_PlatformCache return instance; } - private static di_Configurations__c getConfig() - { - di_Configurations__c config = di_Configurations__c.getInstance(); - - if ( config == null ) - { - config = new di_Configurations__c(); - config.SetupOwnerId = ConnectApi.Organization.getSettings().orgId; - insert config; - } - - return config; - } public static Boolean isStoringBindingInPlatformCache() { return getConfig().UsePlatformCacheToStoreBindings__c == null ? false : getConfig().UsePlatformCacheToStoreBindings__c; } - - private static String getPartitionName() - { - return getConfig().OrgCachePartitionName__c; - } - - private Integer getPartitionTTL() - { - return 86400; // number of seconds for a 24 hour period - } - - private static Cache.OrgPartition getPartition() - { - return Cache.Org.getPartition(getPartitionName()); - } - - private Map>> cacheKeyIndexMap = new Map>>(); - - public Map>> getCacheKeyIndexMap() + public Map > > getCacheKeyIndexMap() { if ( cacheKeyIndexMap.isEmpty() ) { try { - cacheKeyIndexMap = (Map>>) getPartition().get( getKeyIndexName() ); + // if there IS NO Partition created; let's not FAIL + Cache.OrgPartition orgPartition = getPartition(); + if ( orgPartition != null ) { + cacheKeyIndexMap = (Map > >) orgPartition.get( getKeyIndexName() ); + } } catch (Cache.Org.OrgCacheException ex) { // this indicates a potentially corrupt cache, so clear the map and let it rebuild @@ -64,40 +68,172 @@ public with sharing class di_PlatformCache if ( cacheKeyIndexMap == null ) { - cacheKeyIndexMap = new Map>>(); + cacheKeyIndexMap = new Map > >(); } - + /* - for(String key : cacheKeyIndexMap.keySet()) { - System.debug('Cache Key => ' + key); + for(String key : cacheKeyIndexMap.keySet()) { + log('Cache Key => ' + key); for (SObjectType subkey : cacheKeyIndexMap.get(key).keySet()) { - System.debug('Cache Key Index => ' + subkey); + log('Cache Key Index => ' + subkey); for(String item : cacheKeyIndexMap.get(key).get(subkey)) { - System.debug('Cache Key Index Item => ' + item); + log('Cache Key Index Item => ' + item); } } - } - */ + } + */ } return cacheKeyIndexMap; } - private void pushCacheKeyIndexMapToCache() + public Boolean addBindingToPlatformCache( di_Binding binding ) { - getPartition().put( getKeyIndexName(), this.cacheKeyIndexMap, getPartitionTTL(), Cache.Visibility.ALL, false); + Boolean result=false; + if ( isStoringBindingInPlatformCache() ) + { + // if there IS NO Partition created; let's not FAIL + Cache.OrgPartition orgPartition = getPartition(); + if ( orgPartition != null ) { + String theKeyName = getKeyName(binding); + // add the binding to the platform cache directly + orgPartition.put(theKeyName, binding, getPartitionTTL(), Cache.Visibility.ALL, false); + // add the binding's cache key name to the bindingKeyIndex + addBindingToKeyIndex(binding); + //log('Adding binding for hash => ' + theKeyName + ' && developerName => ' + binding.developerName + ' && object => ' + binding.bindingObject); + result = true; + } + } + return result; + } + + public list retrieveBindings(String developerName, Schema.SObjectType bindingSObjectType) + { + list bindings = new list(); + + if ( isStoringBindingInPlatformCache() + && string.isNotBlank(developerName) + && bindingSObjectType != null) + { + //log('Retrieving from Cache Key => ' + developerName + ' && Cache Key Index => ' + bindingSObjectType); + // if there IS NO Partition created; let's not FAIL + Cache.OrgPartition orgPartition = getPartition(); + Map > keyIndexBySObjectTypeMap = getCacheKeyIndexMap().get(developerName.toLowerCase().trim()); + if ( keyIndexBySObjectTypeMap != null && orgPartition != null ) + { + Set cacheKeys = keyIndexBySObjectTypeMap.get(bindingSObjectType); + if ( cacheKeys != null ) + { + Object cachedObject = null; + for ( String cacheKey : cacheKeys ) + { + cachedObject = orgPartition.get( cacheKey ); + if ( cachedObject != null ) + { + bindings.add( (di_Binding) cachedObject); + } + } + } + } + } + + return bindings; } + public static void clearCachedBindings() { + + Set keys =getPartitionKeys(); + + if ( keys != null ) { + String partitionKey = getPartitionName(); + Cache.OrgPartition partition = getPartition(); + // clear current bindings + for (String key : partition.getKeys() ) { + try { + partition.remove(key); + } catch (Exception ex) { + log('XX]> Unable to remove Platform Cache partition [' + partitionKey + '] key [' + key + ']'); + } + } + } + } + + /** + * getPartitionKeys get partition keys + * @return return Set partition keys + */ + public static Set getPartitionKeys() { + Set keys = null; + Cache.OrgPartition partition = getPartition(); + if ( partition != null ) { + // get partition keys + keys= partition.getKeys(); + } + return keys; + }// end of getPartitionKeys + ////////////////////////////////////////////////////////////////////////////////////////////// + // Private Methods + ////////////////////////////////////////////////////////////////////////////////////////////// + + @TestVisible + private static di_Configurations__c getConfig() + { + di_Configurations__c config = di_Configurations__c.getInstance(); + + if ( config == null ) + { + config = new di_Configurations__c(); + config.SetupOwnerId = ConnectApi.Organization.getSettings().orgId; + insert config; + } + + return config; + } + + @TestVisible + private static String getPartitionName() + { + return getConfig().OrgCachePartitionName__c; + } + @TestVisible + private Integer getPartitionTTL() + { + return NUM_OF_SECS_IN24HR; // number of seconds for a 24 hour period + } + @TestVisible + private static Cache.OrgPartition getPartition() + { + Cache.OrgPartition result=null; + try { + result=Cache.Org.getPartition(getPartitionName()); + } catch (Exception excp) { + log('ERROR: Is there Cache? Is the Cache Partition enabled : Exception:' + excp); + } + return result; + } + + @TestVisible + private boolean pushCacheKeyIndexMapToCache() + { + // if there IS NO Partition created; let's not FAIL + Cache.OrgPartition orgPartition = getPartition(); + if ( orgPartition != null ) { + orgPartition.put( getKeyIndexName(), this.cacheKeyIndexMap, getPartitionTTL(), Cache.Visibility.ALL, false); + + } + return orgPartition != null; + } + @TestVisible private void addBindingToKeyIndex(di_Binding binding) { String workingDeveloperName = binding.developerName.toLowerCase().trim(); - if ( ! getCacheKeyIndexMap().containsKey( workingDeveloperName ) ) + if ( !getCacheKeyIndexMap().containsKey( workingDeveloperName ) ) { - getCacheKeyIndexMap().put(workingDeveloperName, new Map>() ); + getCacheKeyIndexMap().put(workingDeveloperName, new Map >() ); } - if ( ! getCacheKeyIndexMap().get(workingDeveloperName).containsKey( binding.bindingObject) ) + if ( !getCacheKeyIndexMap().get(workingDeveloperName).containsKey( binding.bindingObject) ) { getCacheKeyIndexMap().get(workingDeveloperName).put( binding.bindingObject, new Set() ); } @@ -107,91 +243,62 @@ public with sharing class di_PlatformCache pushCacheKeyIndexMapToCache(); } - private static Map generatedKeyNames = new Map(); - + @TestVisible private String constructKeyName( Schema.SObjectType bindingSObjectType, String developerName ) { - String key = ( ( bindingSObjectType != null ) ? bindingSObjectType.getDescribe().getName().toLowerCase().replaceAll('__','') : '' ) - + ( String.isBlank(developerName) ? '' : developerName.toLowerCase().trim() ); + String key = ( ( bindingSObjectType != null ) ? bindingSObjectType.getDescribe().getName().toLowerCase().replaceAll('__','') : '' ) + + ( String.isBlank(developerName) ? '' : developerName.toLowerCase().trim() ); // put generated hash into a map on first pass, so that we do not perform hashcode() operation more than once per "key" // hashcode() is a more expensive operation than map.get() if (generatedKeyNames.containsKey(key)) { return generatedKeyNames.get(key); } String hash = String.valueOf( Math.abs( ( key ).hashcode() ) ); - //System.debug('Creating Hash For => ' + developerName + ' && ' + bindingSObjectType + ' := ' + hash); + //log('Creating Hash For => ' + developerName + ' && ' + bindingSObjectType + ' := ' + hash); generatedKeyNames.put(key, hash); return hash; } - + @TestVisible private String getKeyName( String developerName, Schema.SObjectType bindingSObjectType) { return constructKeyName( bindingSObjectType, developerName); } - + @TestVisible private String getKeyName( di_Binding binding ) { return constructKeyName( binding.bindingObject, binding.developerName); } - + @TestVisible private String getKeyIndexName() { - return 'bindingKeyIndex'; + return di_PlatformCache.BINDING_KEY; } - public void addBindingToPlatformCache( di_Binding binding ) - { - if ( isStoringBindingInPlatformCache() ) - { - String theKeyName = getKeyName(binding); - // add the binding to the platform cache directly - getPartition().put(theKeyName, binding, getPartitionTTL(), Cache.Visibility.ALL, false); - // add the binding's cache key name to the bindingKeyIndex - addBindingToKeyIndex(binding); - //System.debug('Adding binding for hash => ' + theKeyName + ' && developerName => ' + binding.developerName + ' && object => ' + binding.bindingObject); - } - } - - public list retrieveBindings(String developerName, Schema.SObjectType bindingSObjectType) - { - list bindings = new list(); - - if ( isStoringBindingInPlatformCache() ) - { - //System.debug('Retrieving from Cache Key => ' + developerName + ' && Cache Key Index => ' + bindingSObjectType); - - Map> keyIndexBySObjectTypeMap = getCacheKeyIndexMap().get(developerName.toLowerCase().trim()); - if ( keyIndexBySObjectTypeMap != null ) - { - Set cacheKeys = keyIndexBySObjectTypeMap.get(bindingSObjectType); - if ( cacheKeys != null ) - { - Object cachedObject = null; - for ( String cacheKey : cacheKeys ) - { - cachedObject = getPartition().get( cacheKey ); - if ( cachedObject != null ) - { - bindings.add( (di_Binding) getPartition().get( cacheKey ) ); - } - } - } - } + /** + * log centralize to encapsulate and refactor later + * @param excp to display in sink + */ + @TestVisible + private static Boolean log(Exception excp){ + Boolean before=DEBUGGING,result; + // always show exceptions + DEBUGGING=true; + result=log(excp.getMessage()); + DEBUGGING=before; + return result; + + }// end of log + /** + * log centralize to encapsulate and refactor later + * @param message message to display in sink + */ + @TestVisible + private static Boolean log(String message){ + Boolean doLog = DEBUGGING && string.isNotBlank(message); + if ( doLog ) { + system.debug('+++ di_PlatformCache.message: ' + message); } - - return bindings; - } + return doLog; + }// end of log - public static void clearCachedBindings() { - String partitionKey = getPartitionName(); - Cache.OrgPartition partition = getPartition(); - // clear current bindings - for (String key : partition.getKeys() ) { - try { - partition.remove(key); - } catch (Exception ex) { - System.debug('XX]> Unable to remove Platform Cache partition [' + partitionKey + '] key [' + key + ']'); - } - } - } } \ No newline at end of file diff --git a/force-di/test/classes/di_BindingTest.cls b/force-di/test/classes/di_BindingTest.cls index 5585c28..12ab11e 100644 --- a/force-di/test/classes/di_BindingTest.cls +++ b/force-di/test/classes/di_BindingTest.cls @@ -25,6 +25,7 @@ **/ @IsTest +@TestVisible private class di_BindingTest { @IsTest diff --git a/force-di/test/classes/di_InjectorComponentControllerTest.cls b/force-di/test/classes/di_InjectorComponentControllerTest.cls index 2911ccd..bdb42a2 100644 --- a/force-di/test/classes/di_InjectorComponentControllerTest.cls +++ b/force-di/test/classes/di_InjectorComponentControllerTest.cls @@ -22,7 +22,7 @@ * 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. -**/ + **/ @IsTest private class di_InjectorComponentControllerTest { @@ -34,9 +34,9 @@ private class di_InjectorComponentControllerTest { String BindingNameValue = 'flow_AccountRecord_VF'; Object ParametersValue = 'Account'; try { - //When - newObj.getInject(); - } catch(Exception e){ + //When + newObj.getInject(); + } catch(Exception e) { //Then System.assertEquals(e.getMessage().contains('List index out of bounds'), true, 'Correct exception is not thrown'); } @@ -45,7 +45,30 @@ private class di_InjectorComponentControllerTest { @isTest static void givenFlowNameWhenGetInjectorFlowProxyInstanceThenMethodCall(){ di_InjectorComponentController newObj = new di_InjectorComponentController(); - newObj.getInjectorFlowProxyInstance('HelloWorld', 'Account'); + Object result= newObj.getInjectorFlowProxyInstance('HelloWorld', 'Account'); + //Then + System.assertEquals(true, result instanceOf Component.di_injectorFlowProxy ); + + } + + @isTest + static void givenApexPageComponentGetInjectorIsValid() { + // Given + final String BINDING_NAME = 'myapexpage_cmp'; + di_InjectorComponentController newObj = new di_InjectorComponentController(); + newObj.BindingNameValue=BINDING_NAME; + Component.Apex.PageBlock pageBlk = new Component.Apex.PageBlock(); + di_Injector.Org.Bindings.set(new di_Module() + .visualforceComponent() + .bind(BINDING_NAME) + .toObject(pageBlk)); + //When + + Object result= newObj.getInject(); + //Then + System.assertNotEquals(null, result ); + System.assertEquals(true,result instanceOf Component.apex.pageblock); + } } diff --git a/force-di/test/classes/di_PlatformCacheTest.cls b/force-di/test/classes/di_PlatformCacheTest.cls new file mode 100644 index 0000000..cc2be13 --- /dev/null +++ b/force-di/test/classes/di_PlatformCacheTest.cls @@ -0,0 +1,260 @@ +/** + * + * 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 copyright 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 Andrew Fawcett, 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. + **/ +@isTest +private with sharing class di_PlatformCacheTest { + + static final String EXPECTED_PARTITION_NAME = 'diPartition'; + + @isTest + static void givenNoPlatformCacheInstanceThenCreate(){ + // Given/ When + di_PlatformCache cache = di_PlatformCache.getInstance(); + + //Then + System.assertEquals(true, cache == di_PlatformCache.instance); + + } + + @isTest + static void givenPlatformCacheConfigThenCreate(){ + // Given/ When + di_Configurations__c config = di_PlatformCache.getConfig(); + //Then + System.assertEquals(true, config!=null); + + } + + @isTest + static void givenStoringBindingIsTrueThenGet(){ + // Given/ When configuraiton is true + makeData(); + //Then + System.assertEquals(true,di_PlatformCache.isStoringBindingInPlatformCache()); + + } + + + @isTest + static void givenPartitionNameSetThenGetNonNull(){ + // Given/ When partition name is set + makeData(); + //Then + System.assertEquals(EXPECTED_PARTITION_NAME,di_PlatformCache.getPartitionName()); + + } + + @isTest + static void givenPartitionTTLSetThenGetSeconds(){ + // Given/ When partition name is set + di_PlatformCache cache = di_PlatformCache.getInstance(); + //Then + System.assertEquals(di_PlatformCache.NUM_OF_SECS_IN24HR,cache.getPartitionTTL()); + + } + + @isTest + static void givenNoDataInCachePartitionThenGetEmptyKeys(){ + // Given/ When partition name is set + makeData(); + di_PlatformCache cache = di_PlatformCache.getInstance(); + //Then + System.assertEquals(0,cache.getCacheKeyIndexMap().size()); + + } + @isTest + static void givenDataInCachePartitionIsNotEnabledThenGetEmptyKeys(){ + // Given when not storing ( ) + makeData(false); + di_PlatformCache cache = di_PlatformCache.getInstance(); + // create binding + di_Binding binding = di_Binding.newInstance( + di_Binding.BindingType.Apex, + di_BindingTest.Bob.class.getName(), null, null, di_BindingTest.Bob.class.getName(), null); + // When + cache.addBindingToPlatformCache(binding); + //Then + System.assertEquals(0,cache.getCacheKeyIndexMap().size()); + + } + + @isTest + static void givenDataInCachePartitionIsEnabledThenGetEmptyKeys(){ + // Given when storing ( ) + Integer expected=0; + makeData(true); + di_PlatformCache cache = di_PlatformCache.getInstance(); + // if there IS NO Partition created; let's not FAIL + Cache.OrgPartition orgPartition = di_PlatformCache.getPartition(); + // if we have cache informaiton, then we expect 1 + if ( orgPartition != null ) { + expected=1; + } + // create binding + di_Binding binding = di_Binding.newInstance( + di_Binding.BindingType.Apex, + di_BindingTest.Bob.class.getName(), null, null, di_BindingTest.Bob.class.getName(), null); + // When + cache.addBindingToPlatformCache(binding); + //Then + System.assertEquals(expected,cache.getCacheKeyIndexMap().size()); + + } + + @isTest + static void givenCachedBindingsClearThenGetEmpty(){ + // Given + makeData(true); + + // When + di_PlatformCache.clearCachedBindings(); + Set keys = di_PlatformCache.getPartitionKeys(); + //Then + System.assertEquals(true,keys == null || keys.size()==0); + + } + + @isTest + static void givenInvalidDeveloperNameThenGetEmptyKeys(){ + // Given + makeData(true); + di_PlatformCache cache = di_PlatformCache.getInstance(); + // when + list binding = cache.retrieveBindings(null,Account.sObjectType); + //Then + System.assertEquals(0,binding.size()); + } + @isTest + static void givenInvalidSObjectTypeThenGetEmptyKeys(){ + // Given + makeData(true); + di_PlatformCache cache = di_PlatformCache.getInstance(); + // when + list binding = cache.retrieveBindings('value',null); + //Then + System.assertEquals(0,binding.size()); + } + // + @isTest + static void givenCacheMapAddedThenGetKeys(){ + // Given + di_PlatformCache cache = di_PlatformCache.getInstance(); + // When + Cache.OrgPartition orgPartition = di_PlatformCache.getPartition(); + //Then + System.assertEquals(orgPartition != null,cache.pushCacheKeyIndexMapToCache()); + } + @isTest + static void givenLogMethodThenGetKeys(){ + // Given + di_PlatformCache.DEBUGGING = true; + // When + //Then + System.assertEquals(true,di_PlatformCache.log('test')); + System.assertEquals(true,di_PlatformCache.log(new NullPointerException())); + } + + @IsTest + static void givenValidBindingThenAddBinding(){ + // Given + di_PlatformCache cache = di_PlatformCache.getInstance(); + // create binding + di_Binding binding = di_Binding.newInstance( + di_Binding.BindingType.Apex, + di_BindingTest.Bob.class.getName(), null, null, di_BindingTest.Bob.class.getName(), null); + String workingDeveloperName = binding.developerName.toLowerCase().trim(); + + // When + cache.addBindingToKeyIndex(binding); + // Then + system.assertEquals(1, cache.getCacheKeyIndexMap().size()); + system.assertNotEquals(null,cache.getCacheKeyIndexMap().get(workingDeveloperName)); + } + + // + @IsTest + static void givenValidTSTypeAndNameThenHash(){ + // + // Given + di_PlatformCache cache = di_PlatformCache.getInstance(); + // When + String hash= cache.constructKeyName(Account.sObjectType,'test'); + // Then + system.assertEquals(true, hash != null); + + } + // + @IsTest + static void givenKeyIndexNameThenGetKey(){ + // + // Given + di_PlatformCache cache = di_PlatformCache.getInstance(); + // When + // Then + system.assertEquals(di_PlatformCache.BINDING_KEY, cache.getKeyIndexName()); + + } + // + @IsTest + static void givenValidSTypeAndNameThenHash(){ + // + // Given + di_PlatformCache cache = di_PlatformCache.getInstance(); + // When + String hash= cache.constructKeyName(Account.sObjectType,'test'); + // Then + system.assertEquals(true, hash != null); + + } + + // + @IsTest + static void givenDevNameAndSTypeThenGetHashAndKey(){ + // + // Given + di_PlatformCache cache = di_PlatformCache.getInstance(); + // When + String key= cache.getKeyName('test',Account.sObjectType), + hash= cache.constructKeyName(Account.sObjectType,'test'); + // Then + system.assertEquals(hash, key); + + } + // + /////////////////////////////////////////////////////////////////////////////// + // Private Helper + /////////////////////////////////////////////////////////////////////////////// + + + static void makeData(){ + makeData(true); + } + + static void makeData(Boolean isStoring){ + di_Configurations__c setting = new di_Configurations__c(SetupOwnerId=Userinfo.getUserId()); + + setting.OrgCachePartitionName__c = EXPECTED_PARTITION_NAME; + setting.UsePlatformCacheToStoreBindings__c = isStoring; + insert setting; + } +} diff --git a/force-di/test/classes/di_PlatformCacheTest.cls-meta.xml b/force-di/test/classes/di_PlatformCacheTest.cls-meta.xml new file mode 100644 index 0000000..db9bf8c --- /dev/null +++ b/force-di/test/classes/di_PlatformCacheTest.cls-meta.xml @@ -0,0 +1,5 @@ + + + 48.0 + Active + From 7d97e1166d994b16f894a8aa2008e1facd4641d3 Mon Sep 17 00:00:00 2001 From: bjanderson70 Date: Mon, 13 Jul 2020 12:53:58 -0400 Subject: [PATCH 2/9] updated tests to get code-coverage above 75%; added force-di test-suite for convience --- config/enterprise-project-scratch-def.json | 18 ++- config/project-scratch-def.json | 18 ++- force-di/main/classes/di_Injector.cls | 1 - .../classes/di_BindingConfigWrapperTest.cls | 81 ++++++++++++ .../di_BindingConfigWrapperTest.cls-meta.xml | 5 + .../di_InjectorCMPFlowProxyControllerTest.cls | 13 +- .../di_InjectorComponentControllerTest.cls | 9 +- force-di/test/classes/di_InjectorTest.cls | 118 ++++++++++++++++-- force-di/test/classes/di_ModuleTest.cls | 59 ++++++++- .../force_di_teststuite.testSuite-meta.xml | 12 ++ 10 files changed, 311 insertions(+), 23 deletions(-) create mode 100644 force-di/test/classes/di_BindingConfigWrapperTest.cls create mode 100644 force-di/test/classes/di_BindingConfigWrapperTest.cls-meta.xml create mode 100644 force-di/test/testSuites/force_di_teststuite.testSuite-meta.xml diff --git a/config/enterprise-project-scratch-def.json b/config/enterprise-project-scratch-def.json index f605b63..66c6888 100644 --- a/config/enterprise-project-scratch-def.json +++ b/config/enterprise-project-scratch-def.json @@ -1,9 +1,21 @@ { - "orgName": "Acme DF18 Enterprise Company", + "orgName": "force-di-scratch-ent", "edition": "Enterprise", + "features": ["MultiCurrency","AuthorApex"], "settings": { - "orgPreferenceSettings": { - "s1DesktopEnabled": true + "communitiesSettings": { + "enableNetworksEnabled": false + }, + "mobileSettings": { + "enableS1EncryptedStoragePref2": false + }, + "lightningExperienceSettings": { + "enableS1DesktopEnabled": true + }, + "securitySettings": { + "sessionSettings":{ + "sessionTimeout": "TwelveHours" + } } } } diff --git a/config/project-scratch-def.json b/config/project-scratch-def.json index 9337863..8096eea 100644 --- a/config/project-scratch-def.json +++ b/config/project-scratch-def.json @@ -1,9 +1,21 @@ { - "orgName": "force-di", + "orgName": "force-di-scratch-dev", "edition": "Developer", + "features": ["MultiCurrency","AuthorApex"], "settings": { - "orgPreferenceSettings": { - "s1DesktopEnabled": true + "communitiesSettings": { + "enableNetworksEnabled": false + }, + "mobileSettings": { + "enableS1EncryptedStoragePref2": false + }, + "lightningExperienceSettings": { + "enableS1DesktopEnabled": true + }, + "securitySettings": { + "sessionSettings":{ + "sessionTimeout": "TwelveHours" + } } } } diff --git a/force-di/main/classes/di_Injector.cls b/force-di/main/classes/di_Injector.cls index 8dc9c40..c7f36a0 100644 --- a/force-di/main/classes/di_Injector.cls +++ b/force-di/main/classes/di_Injector.cls @@ -86,7 +86,6 @@ public class di_Injector { if ( String.isBlank(developerName) ) { throw new InjectorException('Request for Binding cannot take "developerName" parameter of null'); } - List bindingsFound = this.Bindings.byName( developerName.toLowerCase().trim() ).get(); if ( bindingsFound == null || bindingsFound.isEmpty() ) { throw new InjectorException('Binding for "' + developerName + '" not found'); diff --git a/force-di/test/classes/di_BindingConfigWrapperTest.cls b/force-di/test/classes/di_BindingConfigWrapperTest.cls new file mode 100644 index 0000000..47589d1 --- /dev/null +++ b/force-di/test/classes/di_BindingConfigWrapperTest.cls @@ -0,0 +1,81 @@ +/** + * + * 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 copyright 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 Andrew Fawcett, 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. + **/ +/** + * Modifications: + * ============= + * B Anderson : Gettting the overall code-coverage > 75% + */ +@isTest +private with sharing class di_BindingConfigWrapperTest { + + @isTest + static void givenBindingWrapperThenExtractAndValidate(){ + // Given + di_BindingConfigWrapper wrapper = new di_BindingConfigWrapper( + 'QualifiedAPIName' + , 'DeveloperName' + , 'NamespacePrefix' + , 'Type' + , 'To' + , 'BindingObject' + , 'BindingObjectQualifiedApiName' + , 'BindingObjectAlternate' + , 10.10 + ); + // Then + system.assertEquals('QualifiedAPIName', wrapper.QualifiedAPIName); + system.assertEquals('DeveloperName', wrapper.DeveloperName); + system.assertEquals('NamespacePrefix', wrapper.NamespacePrefix); + system.assertEquals('Type', wrapper.Type); + system.assertEquals('To', wrapper.To); + system.assertEquals('BindingObject', wrapper.BindingObject); + system.assertEquals('BindingObjectQualifiedApiName', wrapper.BindingObjectQualifiedApiName); + system.assertEquals('BindingObjectAlternate', wrapper.BindingObjectAlternate); + system.assertEquals(10.10, wrapper.BindingSequence); + } + + @isTest + static void givenBindingWrapperWithMDTThenExtractAndValidate(){ + // Given + di_Binding__mdt bindingConfig = new di_Binding__mdt(); + bindingConfig.QualifiedApiName='QualifiedAPIName'; + bindingConfig.DeveloperName='DeveloperName'; + bindingConfig.NamespacePrefix='NamespacePrefix'; + bindingConfig.Type__c='Type'; + bindingConfig.To__c='To'; + bindingConfig.BindingObject__c='BindingObject'; + bindingConfig.BindingObjectAlternate__c='BindingObjectAlternate'; + bindingConfig.BindingSequence__c=10.10; + di_BindingConfigWrapper wrapper = new di_BindingConfigWrapper(bindingConfig); + // Then + system.assertEquals('QualifiedAPIName', wrapper.QualifiedAPIName); + system.assertEquals('DeveloperName', wrapper.DeveloperName); + system.assertEquals('NamespacePrefix', wrapper.NamespacePrefix); + system.assertEquals('Type', wrapper.Type); + system.assertEquals('To', wrapper.To); + system.assertEquals('BindingObject', wrapper.BindingObject); + system.assertEquals('BindingObjectAlternate', wrapper.BindingObjectAlternate); + system.assertEquals(10.10, wrapper.BindingSequence); + } +} diff --git a/force-di/test/classes/di_BindingConfigWrapperTest.cls-meta.xml b/force-di/test/classes/di_BindingConfigWrapperTest.cls-meta.xml new file mode 100644 index 0000000..db9bf8c --- /dev/null +++ b/force-di/test/classes/di_BindingConfigWrapperTest.cls-meta.xml @@ -0,0 +1,5 @@ + + + 48.0 + Active + diff --git a/force-di/test/classes/di_InjectorCMPFlowProxyControllerTest.cls b/force-di/test/classes/di_InjectorCMPFlowProxyControllerTest.cls index ee6d282..767e908 100644 --- a/force-di/test/classes/di_InjectorCMPFlowProxyControllerTest.cls +++ b/force-di/test/classes/di_InjectorCMPFlowProxyControllerTest.cls @@ -1,14 +1,17 @@ - @isTest +@isTest private with sharing class di_InjectorCMPFlowProxyControllerTest { @isTest private static void givenValueWhenGetInjectThenThrowException(){ - String FlowNameValue = 'AccountRecordFlow'; - Object InputVariablesValue = 'Account'; + di_InjectorComponentFlowProxyController newObj = new di_InjectorComponentFlowProxyController(); + newObj.FlowNameValue = 'AccountRecordFlow'; + newObj.InputVariablesValue = new Map { + 'Account'=>null + }; try { - newObj.getInject(); - } catch(Exception e){ + newObj.getInject(); + } catch(Exception e) { System.assertEquals(e.getMessage().contains('Invalid value for property name'), true, 'correct Exception is thrown'); } } diff --git a/force-di/test/classes/di_InjectorComponentControllerTest.cls b/force-di/test/classes/di_InjectorComponentControllerTest.cls index bdb42a2..d239d7a 100644 --- a/force-di/test/classes/di_InjectorComponentControllerTest.cls +++ b/force-di/test/classes/di_InjectorComponentControllerTest.cls @@ -23,7 +23,10 @@ * 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. **/ - +/** + * Modifications: + * B Anderson - Updated Unit Tests ( needing >75% overall) + */ @IsTest private class di_InjectorComponentControllerTest { @@ -31,8 +34,7 @@ private class di_InjectorComponentControllerTest { static void givenWrongBindingNameValueWhenGetInjectThenThrowException(){ //given di_InjectorComponentController newObj = new di_InjectorComponentController(); - String BindingNameValue = 'flow_AccountRecord_VF'; - Object ParametersValue = 'Account'; + try { //When newObj.getInject(); @@ -57,6 +59,7 @@ private class di_InjectorComponentControllerTest { final String BINDING_NAME = 'myapexpage_cmp'; di_InjectorComponentController newObj = new di_InjectorComponentController(); newObj.BindingNameValue=BINDING_NAME; + Component.Apex.PageBlock pageBlk = new Component.Apex.PageBlock(); di_Injector.Org.Bindings.set(new di_Module() .visualforceComponent() diff --git a/force-di/test/classes/di_InjectorTest.cls b/force-di/test/classes/di_InjectorTest.cls index 35111ca..4f7f39d 100644 --- a/force-di/test/classes/di_InjectorTest.cls +++ b/force-di/test/classes/di_InjectorTest.cls @@ -22,20 +22,124 @@ * 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. -**/ - + **/ +/** + * Modifications: + * ============= + * B Anderson : Gettting the overall code-coverage > 75% + */ @IsTest private class di_InjectorTest { - + //TODO @IsTest private static void test(){ di_module module = new di_module(); di_Injector injector = new di_Injector(module); - + di_Injector.Org.Bindings.byName( Contact.class.getName() ) - .bySObject( Account.sObjectType ) - .replaceBindingWith( null ); - + .bySObject( Account.sObjectType ) + .replaceBindingWith( null ); + + } + @IsTest + private static void givenListOfModulesBindThenGetCount(){ + // Given + List modules = new List { + }; + final Integer expected = 0; + // When + di_Injector injector = new di_Injector(modules); + // Then + system.assertEquals(expected, injector.Bindings.get().size()); + + } + + @isTest + static void givenInstanceThenGetThatInstance(){ + // Given + di_module module=new di_module(); + di_Binding bobBinding = di_Binding.newInstance( + di_Binding.BindingType.Apex, + di_BindingTest.Bob.class.getName(), null, null, + di_BindingTest.Bob.class.getName(), null); + + module.getBindings().add(bobBinding); + + di_Injector injector = new di_Injector(module); + // When + Object result=injector.getInstance(di_BindingTest.Bob.class); + Object resultNoParams=injector.getInstance(di_BindingTest.Bob.class,(Object)null); + Object resultByName=injector.getInstance(di_BindingTest.Bob.class.getName()); + // Then + system.assertEquals(true, result instanceof di_BindingTest.Bob); + system.assertEquals(true, resultByName instanceof di_BindingTest.Bob); + system.assertEquals(true, resultNoParams instanceof di_BindingTest.Bob); } + + @isTest + static void givenInstanceNameThenGetException(){ + // Given + di_module module=new di_module(); + di_Injector injector = new di_Injector(module); + Boolean hasException = false; + // When + try { + injector.getInstance((String)null); + } catch (di_Injector.InjectorException excp) { + hasException=true; + } + // Then + system.assertEquals(true, hasException); + // When + hasException=false; + try { + injector.getInstance(''); + } catch (di_Injector.InjectorException excp) { + hasException=true; + } + // Then + system.assertEquals(true, hasException); + + } + + @isTest + static void givenNullSTypeParamterInGetInstanceThenThrowException() + { + // + // Given + di_Module module= new di_Module(); + di_Injector injector = new di_Injector(module); + Schema.SObjectType sType = null; + Boolean hasException=false; + // Then + + try { + injector.getInstance(di_Module.class,sType); + } catch (di_Injector.InjectorException excp) { + hasException=true; + } + // Then + system.assertEquals(true, hasException); + } + @isTest + static void givenNullParamterInGetInstanceThenThrowException() + { + // + // Given + di_Module module= new di_Module(); + di_Injector injector = new di_Injector(module); + Schema.SObjectType sType = Account.getSObjectType(); + Boolean hasException=false; + // Then + + try { + injector.getInstance(Account.class,sType,null); + } catch (di_Injector.InjectorException excp) { + hasException=true; + } + // Then + system.assertEquals(true, hasException); + } + } \ No newline at end of file diff --git a/force-di/test/classes/di_ModuleTest.cls b/force-di/test/classes/di_ModuleTest.cls index 7b10c29..dad7309 100644 --- a/force-di/test/classes/di_ModuleTest.cls +++ b/force-di/test/classes/di_ModuleTest.cls @@ -22,8 +22,65 @@ * 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. -**/ + **/ + /** + * Modifications: + * -------------- + * B Anderson : Gettting the overall code-coverage > 75% + */ @IsTest private class di_ModuleTest { + + @isTest + static void givenBindingInModuleWhenSetTypeThenGetModule(){ + + // Given + di_Module module=new di_Module(); + di_Binding bobBinding = di_Binding.newInstance( + di_Binding.BindingType.Apex, + di_BindingTest.Bob.class.getName(), null, null, + di_BindingTest.Bob.class.getName(), null); + List bindings = new List { + bobBinding + }; + module.getBindings().add(bobBinding); + // Then + system.assertEquals(module, module.type(di_Binding.BindingType.Apex.name())); + // gt bindings + system.assertEquals(bindings, module.getBindings()); + } + + @isTest + static void givenBadBindingTypeThenGetModuleException(){ + + // Given + di_Module module=new di_Module(); + // Then + Boolean moduleExceptionThrown=false; + try { + module.type('not-valid'); + } catch(di_Module.ModuleException excp) { + moduleExceptionThrown=true; + + } + system.assertEquals(true,moduleExceptionThrown); + } + + @isTest + static void givenModuleWhenSettingValuesThenGet(){ + + // Given + di_Module module=new di_Module(); + // When + module.type(di_Binding.BindingType.Apex) + .data('test') + .sequence(1) + .bind(di_BindingTest.Bob.class); + List bindings = module.getBindings(); + // Then + system.assertEquals('test',(String)bindings[0].Data); + system.assertEquals('apex',(String)bindings[0].BindingTypeAsString.toLowerCase()); + system.assertEquals('1',(String)bindings[0].BindingTypeAsString); + } } diff --git a/force-di/test/testSuites/force_di_teststuite.testSuite-meta.xml b/force-di/test/testSuites/force_di_teststuite.testSuite-meta.xml new file mode 100644 index 0000000..ff24bb8 --- /dev/null +++ b/force-di/test/testSuites/force_di_teststuite.testSuite-meta.xml @@ -0,0 +1,12 @@ + + + di_BindingParamTest + di_BindingTest + di_FlowTest + di_InjectorCMPFlowProxyControllerTest + di_InjectorComponentControllerTest + di_InjectorControllerTest + di_InjectorTest + di_ModuleTest + di_PlatformCacheTest + From ff45d283103fa2228163446ba2e13e1fa7e1bcab Mon Sep 17 00:00:00 2001 From: bjanderson70 Date: Tue, 14 Jul 2020 09:35:41 -0400 Subject: [PATCH 3/9] check for creatable on custom setting if can insert; makes checkmarx happy; not problem as instance is created via getinstance() --- force-di/main/classes/di_PlatformCache.cls | 6 +- .../test/classes/di_PlatformCacheTest.cls | 57 +++++++++++++++++++ 2 files changed, 62 insertions(+), 1 deletion(-) diff --git a/force-di/main/classes/di_PlatformCache.cls b/force-di/main/classes/di_PlatformCache.cls index 7dad92b..926de87 100644 --- a/force-di/main/classes/di_PlatformCache.cls +++ b/force-di/main/classes/di_PlatformCache.cls @@ -184,7 +184,11 @@ public with sharing class di_PlatformCache { config = new di_Configurations__c(); config.SetupOwnerId = ConnectApi.Organization.getSettings().orgId; - insert config; + // make CheckMarx happy + if (di_Configurations__c.SObjectType.getDescribe().isCreateable() ) + { + insert config; + } } return config; diff --git a/force-di/test/classes/di_PlatformCacheTest.cls b/force-di/test/classes/di_PlatformCacheTest.cls index cc2be13..1cce713 100644 --- a/force-di/test/classes/di_PlatformCacheTest.cls +++ b/force-di/test/classes/di_PlatformCacheTest.cls @@ -240,6 +240,39 @@ private with sharing class di_PlatformCacheTest { system.assertEquals(hash, key); } + + @isTest + static void givenReadOnlyAccessThenGetInstance(){ + // Given + User ruser = di_PlatformCacheTest.setROTestUser(false,false,false,false); + System.runAs(ruser) { + // Then + di_Configurations__c config = di_PlatformCache.getConfig(); + system.assertEquals(true, config!=null); + system.assertEquals(false, config.UsePlatformCacheToStoreBindings__c); + system.assertEquals(null, config.OrgCachePartitionName__c); + } + } + + @isTest + static void givenANewConfigSettingThenGetThatInstance(){ + // Given + User ruser = di_PlatformCacheTest.setROTestUser(false,false,false,false); + final String PARTITION = 'test'; + di_Configurations__c usrConfig = new di_Configurations__c(); + usrConfig.SetupOwnerId = ruser.Id; + usrConfig.UsePlatformCacheToStoreBindings__c = true; + usrConfig.OrgCachePartitionName__c = PARTITION; + insert usrConfig; + + System.runAs(ruser) { + // Then + di_Configurations__c config = di_PlatformCache.getConfig(); + system.assertEquals(true, config!=null); + system.assertEquals(true, config.UsePlatformCacheToStoreBindings__c); + system.assertEquals(PARTITION, config.OrgCachePartitionName__c); + } + } // /////////////////////////////////////////////////////////////////////////////// // Private Helper @@ -257,4 +290,28 @@ private with sharing class di_PlatformCacheTest { setting.UsePlatformCacheToStoreBindings__c = isStoring; insert setting; } + + /** + * readonly user + */ + @TestVisible + private static User setROTestUser(Boolean read, Boolean create, Boolean edit, Boolean remove){ + Profile prof = [SELECT Id FROM Profile WHERE Name='Read Only']; + + User newUser = new User(Alias = 'readonly', + Email='standarduser@mytest.com', + EmailEncodingKey='UTF-8', + LastName='TestingReadOnly', + LanguageLocaleKey='en_US', + LocaleSidKey='en_US', + ProfileId = prof.Id, + TimeZoneSidKey='America/Los_Angeles', + UserName='readonly@mytest.com'); + + insert newUser; + + return newUser; + }// end of setTestUser + + } From 4bb307a7e48f1e4a00355089afc3fad5cf409b4b Mon Sep 17 00:00:00 2001 From: bjanderson70 Date: Thu, 23 Jul 2020 16:10:10 -0400 Subject: [PATCH 4/9] provide bindingId to set di-container aura:id so that we can navigate into injected components; ie. my_comp.find("my_item").find("di-component").callMyMethod() --- force-di/main/aura/di_injector/di_injector.cmp | 2 ++ .../aura/di_injector/di_injectorController.js | 17 +++++++++++++++++ .../classes/di_InjectorComponentController.cls | 3 ++- .../di_InjectorComponentControllerTest.cls | 16 ++++++++++++++++ 4 files changed, 37 insertions(+), 1 deletion(-) diff --git a/force-di/main/aura/di_injector/di_injector.cmp b/force-di/main/aura/di_injector/di_injector.cmp index 7b7aad7..0c2409b 100644 --- a/force-di/main/aura/di_injector/di_injector.cmp +++ b/force-di/main/aura/di_injector/di_injector.cmp @@ -28,6 +28,8 @@ + + {!v.body} diff --git a/force-di/main/aura/di_injector/di_injectorController.js b/force-di/main/aura/di_injector/di_injectorController.js index 96018c1..7a49fba 100644 --- a/force-di/main/aura/di_injector/di_injectorController.js +++ b/force-di/main/aura/di_injector/di_injectorController.js @@ -30,19 +30,35 @@ // Resolve the given binding var action = cmp.get("c.getBinding"); action.setParams({ bindingName : cmp.get("v.bindingName") }); + action.setCallback(this, function(response) { var state = response.getState(); if (state === "SUCCESS") { var bindingInfo = response.getReturnValue(); var injectAttrs = cmp.get("v.body"); + // Construct attributes to pass on to injected component var componentName = null; var componentAttrs = {}; + + if(bindingInfo.BindingTypeAsString == 'Flow') { componentName = 'c:di_injectorFlowProxy'; componentAttrs['flowName'] = bindingInfo.To; componentAttrs['injectorAttributes'] = injectAttrs; } else if(bindingInfo.BindingTypeAsString == 'LightningComponent') { + // BJA -- get container id, if any + let bindingId = cmp.get("v.bindingId"); + // BJA -- inject the user defined id, if any. This will allow + // the consumer to be able to reference into container + // (i.e. mycomponent.find('my-name').find('di_container').call-my-method() ) + // + if (typeof bindingId !== 'undefined' && bindingId) { + componentAttrs['aura:id'] = bindingId; + } else { + // bja -- default id + componentAttrs['aura:id'] = 'di_container'; + } componentName = bindingInfo.To; for (var attrIdx in injectAttrs) { var injectAttr = injectAttrs[attrIdx]; @@ -52,6 +68,7 @@ console.log("Binding type " + bindingInfo.BindingTypeAsString + ' not supported'); return; } + // Inject the component bound to the given binding $A.createComponent( componentName, diff --git a/force-di/main/classes/di_InjectorComponentController.cls b/force-di/main/classes/di_InjectorComponentController.cls index f336b1a..75da4e7 100644 --- a/force-di/main/classes/di_InjectorComponentController.cls +++ b/force-di/main/classes/di_InjectorComponentController.cls @@ -27,7 +27,8 @@ public with sharing class di_InjectorComponentController { public String BindingNameValue {set; get;} - + // BJA - container id for lightning-- allows consumers to reference into (optional) + public String BindingIdValue {set; get;} public Object ParametersValue {set; get;} public ApexPages.Component getInject() { diff --git a/force-di/test/classes/di_InjectorComponentControllerTest.cls b/force-di/test/classes/di_InjectorComponentControllerTest.cls index d239d7a..c8ceade 100644 --- a/force-di/test/classes/di_InjectorComponentControllerTest.cls +++ b/force-di/test/classes/di_InjectorComponentControllerTest.cls @@ -74,4 +74,20 @@ private class di_InjectorComponentControllerTest { } + @isTest + static void givenLightningComponentGetBindingId() { + // Given + final String BINDING_NAME = 'myapexpage_cmp'; + final String BINDING_ID = 'myapexpage_id'; + // When + di_InjectorComponentController newObj = new di_InjectorComponentController(); + newObj.BindingNameValue=BINDING_NAME; + newObj.BindingIdValue=BINDING_ID; + + //Then + System.assertEquals( BINDING_ID,newObj.BindingIdValue); + System.assertEquals( BINDING_NAME,newObj.BindingNameValue); + + } + } From 37472305df28addd1eae9cb5300d9f2ce1eeae62 Mon Sep 17 00:00:00 2001 From: bjanderson70 Date: Mon, 27 Jul 2020 10:10:19 -0400 Subject: [PATCH 5/9] allow container to have aura-id; allow dynamic values to alert contained component of change --- .../main/aura/di_injector/di_injector.cmp | 3 ++ .../aura/di_injector/di_injectorController.js | 43 ++++++++++++++----- .../di_injectorAttribute.cmp | 14 ++++++ .../di_injectorAttributeController.js | 11 +++++ .../di_injectorAttributeChangeEvent.evt | 8 ++++ ..._injectorAttributeChangeEvent.evt-meta.xml | 5 +++ 6 files changed, 73 insertions(+), 11 deletions(-) create mode 100644 force-di/main/aura/di_injectorAttribute/di_injectorAttributeController.js create mode 100644 force-di/main/aura/di_injectorAttributeChangeEvent/di_injectorAttributeChangeEvent.evt create mode 100644 force-di/main/aura/di_injectorAttributeChangeEvent/di_injectorAttributeChangeEvent.evt-meta.xml diff --git a/force-di/main/aura/di_injector/di_injector.cmp b/force-di/main/aura/di_injector/di_injector.cmp index 0c2409b..7f40a2a 100644 --- a/force-di/main/aura/di_injector/di_injector.cmp +++ b/force-di/main/aura/di_injector/di_injector.cmp @@ -31,5 +31,8 @@ + + + {!v.body} diff --git a/force-di/main/aura/di_injector/di_injectorController.js b/force-di/main/aura/di_injector/di_injectorController.js index 7a49fba..beea9b6 100644 --- a/force-di/main/aura/di_injector/di_injectorController.js +++ b/force-di/main/aura/di_injector/di_injectorController.js @@ -47,18 +47,12 @@ componentAttrs['flowName'] = bindingInfo.To; componentAttrs['injectorAttributes'] = injectAttrs; } else if(bindingInfo.BindingTypeAsString == 'LightningComponent') { - // BJA -- get container id, if any - let bindingId = cmp.get("v.bindingId"); - // BJA -- inject the user defined id, if any. This will allow - // the consumer to be able to reference into container - // (i.e. mycomponent.find('my-name').find('di_container').call-my-method() ) - // - if (typeof bindingId !== 'undefined' && bindingId) { - componentAttrs['aura:id'] = bindingId; - } else { - // bja -- default id - componentAttrs['aura:id'] = 'di_container'; + // Added by Leon Kempers: set aura:id + let bindingId = cmp.get('v.bindingId'); + if (typeof bindingId === 'undefined') { + cmp.set('v.bindingId', 'di_component'); } + componentAttrs['aura:id'] = cmp.get('v.bindingId'); componentName = bindingInfo.To; for (var attrIdx in injectAttrs) { var injectAttr = injectAttrs[attrIdx]; @@ -105,5 +99,32 @@ } }); $A.enqueueAction(action); + }, + + // Added by Leon Kempers: Listen to attribute value change + // + // added a handler to capture the di_injectorAttributeChangeEvent. When it comes in, + // the handleChangeEvent() function looks at the bindingId variable stored in the component, + // finds the component based on this ID, and changes the specified attribute to the 'newValue'. + // + // The only not-so-pretty thing here is that sometimes (e.g. in case of the spinner) the value + // changed while $A.createComponent was still running (i.e. the Lightning Component hadn't + // been put on the DOM yet). So in that case, we just wait 100ms and try again. + handleChangeEvent : function(component, event, helper) { + + let bindingId = component.get('v.bindingId'); + let auraCmp = component.find(bindingId); + + // Sometimes value will change while the Aura Component hasn't + // been added to the DOM yet; wait 100ms and try again + if (typeof(auraCmp) === undefined) { + setTimeout(function() { + this.handleChangeEvent(component, event, helper); + }, 100); + } else { + let name = event.getParam('name'); + let newValue = event.getParam('newValue'); + auraCmp.set('v.' + name, newValue); + } } }) diff --git a/force-di/main/aura/di_injectorAttribute/di_injectorAttribute.cmp b/force-di/main/aura/di_injectorAttribute/di_injectorAttribute.cmp index b197e78..9fca1a0 100644 --- a/force-di/main/aura/di_injectorAttribute/di_injectorAttribute.cmp +++ b/force-di/main/aura/di_injectorAttribute/di_injectorAttribute.cmp @@ -16,4 +16,18 @@ description="Specific data type the value represents. Helps when mapping values to things like input variables of flows." required="false"/> + + + + + diff --git a/force-di/main/aura/di_injectorAttribute/di_injectorAttributeController.js b/force-di/main/aura/di_injectorAttribute/di_injectorAttributeController.js new file mode 100644 index 0000000..69d2801 --- /dev/null +++ b/force-di/main/aura/di_injectorAttribute/di_injectorAttributeController.js @@ -0,0 +1,11 @@ +({ + // Leon Kempers - handle dynamic value change via event + handleValueChange : function(component, event, helper) { + let name = component.get('v.name'); + let newValue = event.getParam('value'); + + let changeEvent = component.getEvent('attributeChangeEvent'); + changeEvent.setParams({ 'name' : name, 'newValue' : newValue }); + changeEvent.fire(); + } +}) \ No newline at end of file diff --git a/force-di/main/aura/di_injectorAttributeChangeEvent/di_injectorAttributeChangeEvent.evt b/force-di/main/aura/di_injectorAttributeChangeEvent/di_injectorAttributeChangeEvent.evt new file mode 100644 index 0000000..2147c90 --- /dev/null +++ b/force-di/main/aura/di_injectorAttributeChangeEvent/di_injectorAttributeChangeEvent.evt @@ -0,0 +1,8 @@ + + + + + diff --git a/force-di/main/aura/di_injectorAttributeChangeEvent/di_injectorAttributeChangeEvent.evt-meta.xml b/force-di/main/aura/di_injectorAttributeChangeEvent/di_injectorAttributeChangeEvent.evt-meta.xml new file mode 100644 index 0000000..bc90b9b --- /dev/null +++ b/force-di/main/aura/di_injectorAttributeChangeEvent/di_injectorAttributeChangeEvent.evt-meta.xml @@ -0,0 +1,5 @@ + + + 48.0 + A Lightning Event Bundle + \ No newline at end of file From 7556999505945bbd5e6aa0292426be2c2ca37e84 Mon Sep 17 00:00:00 2001 From: bja Date: Mon, 27 Jul 2020 11:36:06 -0400 Subject: [PATCH 6/9] Update README.md deploy from this repo ... until changes (pull requests) are accepted. --- README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/README.md b/README.md index f21733d..a8b16d5 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,18 @@ Documentation - [Adopting Dependency Injection](https://douglascayers.com/2018/08/29/adopting-dependency-injection/) (webinar) - [Understanding the Value of Dependency Injection in the Lightning Platform](https://www.youtube.com/watch?v=oce2QO-E_3k) (DF18 session) +Deploy +------ +Deploying from this repo ... + +Using the SalesforceDX custom plugin ["shane-sfdx-plugins"](https://github.com/mshanemc/shane-sfdx-plugins) will be the simplest way to accomplish this. If you need to install this plugin, execute the following: + +- sfdx plugins:install shane-sfdx-plugins +- Setup the scratch org - note: if you already have a node available, no need to create a scratch org; just substitue the name for 'myForceDIScratch' +### Steps (Deploying from this repo **bjanderson70**) +- sfdx force:org:create -a myForceDIScratch -f config/project-scratch-def.json +- sfdx shane:github:src:install -c -g **bjanderson70** -r force-di -p force-di -u myForceDIScratch + Project Folders --------------- The "core" framework is found in this project. This includes the following: From 269c35abf84f01a00d5d49cd9e8bb6134b3d479e Mon Sep 17 00:00:00 2001 From: bjanderson70 Date: Fri, 31 Jul 2020 14:42:56 -0400 Subject: [PATCH 7/9] fixed test in di_ModuleTest --- force-di/test/classes/di_ModuleTest.cls | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/force-di/test/classes/di_ModuleTest.cls b/force-di/test/classes/di_ModuleTest.cls index dad7309..0ee322a 100644 --- a/force-di/test/classes/di_ModuleTest.cls +++ b/force-di/test/classes/di_ModuleTest.cls @@ -77,10 +77,13 @@ private class di_ModuleTest { .data('test') .sequence(1) .bind(di_BindingTest.Bob.class); + di_Module mod= module.to(di_BindingTest.Bob.class); + List bindings = module.getBindings(); + // Then system.assertEquals('test',(String)bindings[0].Data); system.assertEquals('apex',(String)bindings[0].BindingTypeAsString.toLowerCase()); - system.assertEquals('1',(String)bindings[0].BindingTypeAsString); + system.assertEquals(1,bindings[0].bindingSequence); } } From af5181b62395346b15154a3cb5c95801810162dd Mon Sep 17 00:00:00 2001 From: bjanderson70 Date: Sat, 1 Aug 2020 16:23:50 -0400 Subject: [PATCH 8/9] uncommented most of the "log" methods; left a large chunk in "getCacheKeyIndexMap" as I was not certain if originator had a purpose with that code --- force-di/main/classes/di_PlatformCache.cls | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/force-di/main/classes/di_PlatformCache.cls b/force-di/main/classes/di_PlatformCache.cls index 926de87..044934d 100644 --- a/force-di/main/classes/di_PlatformCache.cls +++ b/force-di/main/classes/di_PlatformCache.cls @@ -100,7 +100,7 @@ public with sharing class di_PlatformCache orgPartition.put(theKeyName, binding, getPartitionTTL(), Cache.Visibility.ALL, false); // add the binding's cache key name to the bindingKeyIndex addBindingToKeyIndex(binding); - //log('Adding binding for hash => ' + theKeyName + ' && developerName => ' + binding.developerName + ' && object => ' + binding.bindingObject); + log('Adding binding for hash => ' + theKeyName + ' && developerName => ' + binding.developerName + ' && object => ' + binding.bindingObject); result = true; } } @@ -115,7 +115,7 @@ public with sharing class di_PlatformCache && string.isNotBlank(developerName) && bindingSObjectType != null) { - //log('Retrieving from Cache Key => ' + developerName + ' && Cache Key Index => ' + bindingSObjectType); + log('Retrieving from Cache Key => ' + developerName + ' && Cache Key Index => ' + bindingSObjectType); // if there IS NO Partition created; let's not FAIL Cache.OrgPartition orgPartition = getPartition(); Map > keyIndexBySObjectTypeMap = getCacheKeyIndexMap().get(developerName.toLowerCase().trim()); @@ -188,7 +188,7 @@ public with sharing class di_PlatformCache if (di_Configurations__c.SObjectType.getDescribe().isCreateable() ) { insert config; - } + } } return config; @@ -258,7 +258,7 @@ public with sharing class di_PlatformCache if (generatedKeyNames.containsKey(key)) { return generatedKeyNames.get(key); } String hash = String.valueOf( Math.abs( ( key ).hashcode() ) ); - //log('Creating Hash For => ' + developerName + ' && ' + bindingSObjectType + ' := ' + hash); + log('Creating Hash For => ' + developerName + ' && ' + bindingSObjectType + ' := ' + hash); generatedKeyNames.put(key, hash); return hash; } From 676573efb7ec97ccf333c287ac71c87d2e3f2b84 Mon Sep 17 00:00:00 2001 From: "John M. Daniel" Date: Sun, 31 Jan 2021 22:58:58 -0500 Subject: [PATCH 9/9] minor updates --- README.md | 12 ---- force-di/main/classes/di_Binding.cls | 1 - force-di/main/classes/di_BindingParam.cls | 68 +++++++++++------------ force-di/main/classes/di_Injector.cls | 18 +++--- 4 files changed, 43 insertions(+), 56 deletions(-) diff --git a/README.md b/README.md index a8b16d5..f21733d 100644 --- a/README.md +++ b/README.md @@ -10,18 +10,6 @@ Documentation - [Adopting Dependency Injection](https://douglascayers.com/2018/08/29/adopting-dependency-injection/) (webinar) - [Understanding the Value of Dependency Injection in the Lightning Platform](https://www.youtube.com/watch?v=oce2QO-E_3k) (DF18 session) -Deploy ------- -Deploying from this repo ... - -Using the SalesforceDX custom plugin ["shane-sfdx-plugins"](https://github.com/mshanemc/shane-sfdx-plugins) will be the simplest way to accomplish this. If you need to install this plugin, execute the following: - -- sfdx plugins:install shane-sfdx-plugins -- Setup the scratch org - note: if you already have a node available, no need to create a scratch org; just substitue the name for 'myForceDIScratch' -### Steps (Deploying from this repo **bjanderson70**) -- sfdx force:org:create -a myForceDIScratch -f config/project-scratch-def.json -- sfdx shane:github:src:install -c -g **bjanderson70** -r force-di -p force-di -u myForceDIScratch - Project Folders --------------- The "core" framework is found in this project. This includes the following: diff --git a/force-di/main/classes/di_Binding.cls b/force-di/main/classes/di_Binding.cls index 538a939..6a659f7 100644 --- a/force-di/main/classes/di_Binding.cls +++ b/force-di/main/classes/di_Binding.cls @@ -275,7 +275,6 @@ public abstract class di_Binding implements Comparable { { if ( this.bindings == null ) { - //System.debug('// di_Binding.Resolver :: Loading Bindings //'); // Ask each module to configure and aggregate the resulting bindings this.bindings = new List(); for (di_Module module : modules) diff --git a/force-di/main/classes/di_BindingParam.cls b/force-di/main/classes/di_BindingParam.cls index fe8571a..fb224b9 100644 --- a/force-di/main/classes/di_BindingParam.cls +++ b/force-di/main/classes/di_BindingParam.cls @@ -22,7 +22,7 @@ * 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 with sharing class di_BindingParam { @@ -32,7 +32,7 @@ public with sharing class di_BindingParam { @InvocableMethod( label = 'Get Value' - ) + ) public static List invoke( List requests ) { List responses = new List(); @@ -177,18 +177,18 @@ public with sharing class di_BindingParam { } else { - // System.debug( LoggingLevel.WARN, 'BindingParam.parameters.get("' + req + '") is null' ); + System.debug( LoggingLevel.WARN, 'BindingParam.parameters.get("' + req + '") is null' ); } } else { - // System.debug( LoggingLevel.WARN, 'BindingParam.parameters is null' ); + System.debug( LoggingLevel.WARN, 'BindingParam.parameters is null' ); } - // System.debug( 'paramName=' + req ); - // System.debug( res ); + System.debug( 'paramName=' + req ); + System.debug( res ); responses.add( res ); @@ -214,8 +214,8 @@ public with sharing class di_BindingParam { private static Long toLongValue( Date value ) { return ( value == null ? null : toLongValue( - DateTime.newInstance( value.year(), value.month(), value.day(), 0, 0, 0 ) - )); + DateTime.newInstance( value.year(), value.month(), value.day(), 0, 0, 0 ) + )); } private static Long toLongValue( DateTime value ) { @@ -235,8 +235,8 @@ public with sharing class di_BindingParam { private static Decimal toDecimalValue( Date value ) { return ( value == null ? null : toDecimalValue( - DateTime.newInstance( value.year(), value.month(), value.day(), 0, 0, 0 ) - )); + DateTime.newInstance( value.year(), value.month(), value.day(), 0, 0, 0 ) + )); } private static Decimal toDecimalValue( DateTime value ) { @@ -333,8 +333,8 @@ public with sharing class di_BindingParam { @InvocableVariable( label = 'Parameter Name' - required = true - ) + required = true + ) public String paramName; } @@ -343,72 +343,72 @@ public with sharing class di_BindingParam { @InvocableVariable( label = 'Number' - description = 'Whole number (no decimals)' - ) + description = 'Whole number (no decimals)' + ) public Long longValue; @InvocableVariable( label = 'Decimal' - description = 'Number that may include decimal places' - ) + description = 'Number that may include decimal places' + ) public Decimal decimalValue; @InvocableVariable( label = 'Text' - description = 'Text value' - ) + description = 'Text value' + ) public String stringValue; @InvocableVariable( label = 'Boolean' - description = 'true/false' - ) + description = 'true/false' + ) public Boolean booleanValue; @InvocableVariable( label = 'Date' - ) + ) public Date dateValue; @InvocableVariable( label = 'Date/Time' - ) + ) public DateTime dateTimeValue; @InvocableVariable( label = 'Number Collection' - description = 'Collection of whole numbers' - ) + description = 'Collection of whole numbers' + ) public Long[] longValues = new Long[] {}; @InvocableVariable( label = 'Decimal Collection' - description = 'Collection of numbers that may include decimal places' - ) + description = 'Collection of numbers that may include decimal places' + ) public Decimal[] decimalValues = new Decimal[] {}; @InvocableVariable( label = 'Text Collection' - description = 'Collection of text values' - ) + description = 'Collection of text values' + ) public String[] stringValues = new String[] {}; @InvocableVariable( label = 'Boolean Collection' - description = 'Collection of true/false values' - ) + description = 'Collection of true/false values' + ) public Boolean[] booleanValues = new Boolean[] {}; @InvocableVariable( label = 'Date Collection' - description = 'Collection of date values' - ) + description = 'Collection of date values' + ) public Date[] dateValues = new Date[] {}; @InvocableVariable( label = 'Date/Time Collection' - description = 'Collection of date/time values' - ) + description = 'Collection of date/time values' + ) public DateTime[] dateTimeValues = new DateTime[] {}; } diff --git a/force-di/main/classes/di_Injector.cls b/force-di/main/classes/di_Injector.cls index eea27bf..b9f3d25 100644 --- a/force-di/main/classes/di_Injector.cls +++ b/force-di/main/classes/di_Injector.cls @@ -145,15 +145,15 @@ public class di_Injector { private List getDIBinding(){ List recordList = new List(); List bindingMDTRec = [SELECT QualifiedAPIName - , DeveloperName - , NamespacePrefix - , Type__c - , To__c - , BindingObject__c - , BindingObject__r.QualifiedApiName - , BindingObjectAlternate__c - , BindingSequence__c - FROM di_Binding__mdt]; + , DeveloperName + , NamespacePrefix + , Type__c + , To__c + , BindingObject__c + , BindingObject__r.QualifiedApiName + , BindingObjectAlternate__c + , BindingSequence__c + FROM di_Binding__mdt]; for(di_Binding__mdt records :bindingMDTRec) { recordList.add(new di_BindingConfigWrapper(records)); }