From baaf94d6d47835697f6dd485774c74f8b3d30abe Mon Sep 17 00:00:00 2001 From: Robert Baillie Date: Thu, 21 Apr 2022 15:30:55 +0100 Subject: [PATCH] Block duplicate config records --- .../default/classes/Application.cls | 34 ++- .../default/classes/FrameworkErrorCodes.cls | 1 + .../default/classes/tests/ApplicationTest.cls | 240 +++++++++++++++++- 3 files changed, 272 insertions(+), 3 deletions(-) diff --git a/framework/default/ortoo-core/default/classes/Application.cls b/framework/default/ortoo-core/default/classes/Application.cls index 43a36a0ac0b..9595ea23a77 100644 --- a/framework/default/ortoo-core/default/classes/Application.cls +++ b/framework/default/ortoo-core/default/classes/Application.cls @@ -123,7 +123,18 @@ public inherited sharing class Application { public void put( Application_Configuration__mdt thisConfiguration ) { - configuration.put( classTypeBuilder.build( thisConfiguration.Object_Type__c ), classTypeBuilder.build( thisConfiguration.Implementation__c ) ); + Type objectType = classTypeBuilder.build( thisConfiguration.Object_Type__c ); + Type implementation = classTypeBuilder.build( thisConfiguration.Implementation__c ); + + if ( configuration.containsKey( objectType ) ) + { + throw new InvalidApplicationConfigurationException( 'Duplicate configuration exists for ' + thisConfiguration.Type__c + ' - ' + thisConfiguration.Object_Type__c ) + .setErrorCode( FrameworkErrorCodes.CONFIGURATION_WITH_DUPLICATE_TYPE ) + .addContext( 'typeName', thisConfiguration.Type__c ) + .addContext( 'objectType', thisConfiguration.Object_Type__c ); + } + + configuration.put( objectType, implementation ); } public Map getConfiguration() @@ -143,6 +154,14 @@ public inherited sharing class Application { public void put( Application_Configuration__mdt thisConfiguration ) { + if ( configuration.containsKey( thisConfiguration.Object_Type__c ) ) + { + throw new InvalidApplicationConfigurationException( 'Duplicate configuration exists for ' + thisConfiguration.Type__c + ' - ' + thisConfiguration.Object_Type__c ) + .setErrorCode( FrameworkErrorCodes.CONFIGURATION_WITH_DUPLICATE_TYPE ) + .addContext( 'typeName', thisConfiguration.Type__c ) + .addContext( 'objectType', thisConfiguration.Object_Type__c ); + } + configuration.put( thisConfiguration.Object_Type__c, thisConfiguration.Implementation__c ); } @@ -163,7 +182,18 @@ public inherited sharing class Application { public void put( Application_Configuration__mdt thisConfiguration ) { - configuration.put( sobjectTypeBuilder.build( thisConfiguration.Object_Type__c ), classTypeBuilder.build( thisConfiguration.Implementation__c ) ); + SobjectType objectType = sobjectTypeBuilder.build( thisConfiguration.Object_Type__c ); + Type implementation = classTypeBuilder.build( thisConfiguration.Implementation__c ); + + if ( configuration.containsKey( objectType ) ) + { + throw new InvalidApplicationConfigurationException( 'Duplicate configuration exists for ' + thisConfiguration.Type__c + ' - ' + thisConfiguration.Object_Type__c ) + .setErrorCode( FrameworkErrorCodes.CONFIGURATION_WITH_DUPLICATE_TYPE ) + .addContext( 'typeName', thisConfiguration.Type__c ) + .addContext( 'objectType', thisConfiguration.Object_Type__c ); + } + + configuration.put( objectType, implementation ); } public Map getConfiguration() diff --git a/framework/default/ortoo-core/default/classes/FrameworkErrorCodes.cls b/framework/default/ortoo-core/default/classes/FrameworkErrorCodes.cls index 41d88ad29b3..1e8de186547 100644 --- a/framework/default/ortoo-core/default/classes/FrameworkErrorCodes.cls +++ b/framework/default/ortoo-core/default/classes/FrameworkErrorCodes.cls @@ -22,6 +22,7 @@ public inherited sharing class FrameworkErrorCodes { public final static String CONFIGURATION_WITH_INVALID_TYPE = 'APP-00001'; public final static String CONFIGURATION_WITH_INVALID_CLASS = 'APP-00002'; public final static String CONFIGURATION_WITH_INVALID_SOBJECT_TYPE = 'APP-00003'; + public final static String CONFIGURATION_WITH_DUPLICATE_TYPE = 'APP-00004'; public final static String NON_EVALUATABLE_CRITERIA = 'CRI-00000'; diff --git a/framework/default/ortoo-core/default/classes/tests/ApplicationTest.cls b/framework/default/ortoo-core/default/classes/tests/ApplicationTest.cls index 5de24df91a7..c0e28636fd9 100644 --- a/framework/default/ortoo-core/default/classes/tests/ApplicationTest.cls +++ b/framework/default/ortoo-core/default/classes/tests/ApplicationTest.cls @@ -39,6 +39,40 @@ private without sharing class ApplicationTest System.assertEquals( fflib_ISObjectSelector.class, Application.SELECTOR.getSelectorType( Contact.sobjectType ), 'selector, when referenced, will be configured based on metadata' ); } + @isTest + private static void selector_whenConfiguredWithDuplicates_throwsAnException() // NOPMD: Test method name format + { + List configurations = new List + { + new Application_Configuration__mdt + ( + Type__c = 'Selector', + Object_Type__c = 'Contact', + Implementation__c = 'fflib_ISObjectSelector' + ), + new Application_Configuration__mdt + ( + Type__c = 'Selector', + Object_Type__c = 'Contact', + Implementation__c = 'fflib_ISObjectSelector' + ) + }; + + Test.startTest(); + String exceptionMessage; + try + { + Application.applyConfiguration( configurations ); + } + catch ( Application.InvalidApplicationConfigurationException e ) + { + exceptionMessage = e.getMessage(); + } + Test.stopTest(); + + ortoo_Asserts.assertContains( 'Duplicate configuration exists for Selector - Contact', exceptionMessage, 'selector, when configured with duplicates, will throw an exception' ); + } + @isTest private static void domain_whenReferenced_willBeConfiguredBasedOnMetadata() // NOPMD: Test method name format { @@ -65,6 +99,40 @@ private without sharing class ApplicationTest System.assert( true, 'domain, when referenced, will be configured based on metadata - unfortunately it is too much hassle to actually test it returns the right thing, so we do not' ); } + @isTest + private static void domain_whenConfiguredWithDuplicates_throwsAnException() // NOPMD: Test method name format + { + List configurations = new List + { + new Application_Configuration__mdt + ( + Type__c = 'Domain', + Object_Type__c = 'Contact', + Implementation__c = 'fflib_ISObjectSelector' + ), + new Application_Configuration__mdt + ( + Type__c = 'Domain', + Object_Type__c = 'Contact', + Implementation__c = 'fflib_ISObjectSelector' + ) + }; + + Test.startTest(); + String exceptionMessage; + try + { + Application.applyConfiguration( configurations ); + } + catch ( Application.InvalidApplicationConfigurationException e ) + { + exceptionMessage = e.getMessage(); + } + Test.stopTest(); + + ortoo_Asserts.assertContains( 'Duplicate configuration exists for Domain - Contact', exceptionMessage, 'domain, when configured with duplicates, will throw an exception' ); + } + @isTest private static void service_whenReferenced_willBeConfiguredBasedOnMetadata() // NOPMD: Test method name format { @@ -92,6 +160,40 @@ private without sharing class ApplicationTest System.assert( service instanceOf ServiceClass , 'Service, when referenced, will be configured based on metadata' ); } + @isTest + private static void service_whenConfiguredWithDuplicates_throwsAnException() // NOPMD: Test method name format + { + List configurations = new List + { + new Application_Configuration__mdt + ( + Type__c = 'Service', + Object_Type__c = 'ApplicationTest.IServiceInterface', + Implementation__c = 'ApplicationTest.ServiceClass' + ), + new Application_Configuration__mdt + ( + Type__c = 'Service', + Object_Type__c = 'ApplicationTest.IServiceInterface', + Implementation__c = 'ApplicationTest.ServiceClass' + ) + }; + + Test.startTest(); + String exceptionMessage; + try + { + Application.applyConfiguration( configurations ); + } + catch ( Application.InvalidApplicationConfigurationException e ) + { + exceptionMessage = e.getMessage(); + } + Test.stopTest(); + + ortoo_Asserts.assertContains( 'Duplicate configuration exists for Service - ApplicationTest.IServiceInterface', exceptionMessage, 'service, when configured with duplicates, will throw an exception' ); + } + @isTest private static void validator_whenReferenced_willBeConfiguredBasedOnMetadata() // NOPMD: Test method name format { @@ -105,7 +207,7 @@ private without sharing class ApplicationTest ), new Application_Configuration__mdt ( - Type__c = 'Service', + Type__c = 'Validator', Object_Type__c = 'Account', Implementation__c = 'ApplicationTest.AccountValidator' ) @@ -119,6 +221,40 @@ private without sharing class ApplicationTest System.assert( validator instanceOf ContactValidator , 'Validator, when referenced, will be configured based on metadata' ); } + @isTest + private static void validator_whenConfiguredWithDuplicates_throwsAnException() // NOPMD: Test method name format + { + List configurations = new List + { + new Application_Configuration__mdt + ( + Type__c = 'Validator', + Object_Type__c = 'Contact', + Implementation__c = 'ApplicationTest.ContactValidator' + ), + new Application_Configuration__mdt + ( + Type__c = 'Validator', + Object_Type__c = 'Contact', + Implementation__c = 'ApplicationTest.ContactValidator' + ) + }; + + Test.startTest(); + String exceptionMessage; + try + { + Application.applyConfiguration( configurations ); + } + catch ( Application.InvalidApplicationConfigurationException e ) + { + exceptionMessage = e.getMessage(); + } + Test.stopTest(); + + ortoo_Asserts.assertContains( 'Duplicate configuration exists for Validator - Contact', exceptionMessage, 'validator, when configured with duplicates, will throw an exception' ); + } + @isTest private static void appLogic_whenReferenced_willBeConfiguredBasedOnMetadata() // NOPMD: Test method name format { @@ -146,6 +282,40 @@ private without sharing class ApplicationTest System.assert( appLogic instanceOf AppLogicClass , 'AppLogic, when referenced, will be configured based on metadata' ); } + @isTest + private static void appLogic_whenConfiguredWithDuplicates_throwsAnException() // NOPMD: Test method name format + { + List configurations = new List + { + new Application_Configuration__mdt + ( + Type__c = 'App Logic', + Object_Type__c = 'ApplicationTest.IAppLogicInterface', + Implementation__c = 'ApplicationTest.AppLogicClass' + ), + new Application_Configuration__mdt + ( + Type__c = 'App Logic', + Object_Type__c = 'ApplicationTest.IAppLogicInterface', + Implementation__c = 'ApplicationTest.AppLogicClass' + ) + }; + + Test.startTest(); + String exceptionMessage; + try + { + Application.applyConfiguration( configurations ); + } + catch ( Application.InvalidApplicationConfigurationException e ) + { + exceptionMessage = e.getMessage(); + } + Test.stopTest(); + + ortoo_Asserts.assertContains( 'Duplicate configuration exists for App Logic - ApplicationTest.IAppLogicInterface', exceptionMessage, 'app logic, when configured with duplicates, will throw an exception' ); + } + @isTest private static void childRecordFinder_whenReferenced_willBeConfiguredBasedOnMetadata() // NOPMD: Test method name format { @@ -173,6 +343,40 @@ private without sharing class ApplicationTest System.assert( childRecordFinder instanceOf ChildRecordFinderClass , 'childRecordFinder, when referenced, will be configured based on metadata' ); } + @isTest + private static void childRecordFinder_whenConfiguredWithDuplicates_throwsAnException() // NOPMD: Test method name format + { + List configurations = new List + { + new Application_Configuration__mdt + ( + Type__c = 'Child Record Finder', + Object_Type__c = 'ApplicationTest.IChildRecordFinderInterface', + Implementation__c = 'ApplicationTest.ChildRecordFinderClass' + ), + new Application_Configuration__mdt + ( + Type__c = 'Child Record Finder', + Object_Type__c = 'ApplicationTest.IChildRecordFinderInterface', + Implementation__c = 'ApplicationTest.ChildRecordFinderClass' + ) + }; + + Test.startTest(); + String exceptionMessage; + try + { + Application.applyConfiguration( configurations ); + } + catch ( Application.InvalidApplicationConfigurationException e ) + { + exceptionMessage = e.getMessage(); + } + Test.stopTest(); + + ortoo_Asserts.assertContains( 'Duplicate configuration exists for Child Record Finder - ApplicationTest.IChildRecordFinderInterface', exceptionMessage, 'child record finder, when configured with duplicates, will throw an exception' ); + } + @isTest private static void messageRenderer_whenReferenced_willBeConfiguredBasedOnMetadata() // NOPMD: Test method name format { @@ -200,6 +404,40 @@ private without sharing class ApplicationTest System.assert( messageRenderer.getRenderer() instanceOf MessageRendererEngine.SobjectMessageAdder , 'messageRenderer, when referenced, will be configured based on metadata' ); } + @isTest + private static void messageRenderer_whenConfiguredWithDuplicates_throwsAnException() // NOPMD: Test method name format + { + List configurations = new List + { + new Application_Configuration__mdt + ( + Type__c = 'Message Renderer', + Object_Type__c = 'MessageRendererEngine.VisualforceMessageRenderer', + Implementation__c = 'MessageRendererEngine.SobjectMessageAdder' + ), + new Application_Configuration__mdt + ( + Type__c = 'Message Renderer', + Object_Type__c = 'MessageRendererEngine.VisualforceMessageRenderer', + Implementation__c = 'MessageRendererEngine.SobjectMessageAdder' + ) + }; + + Test.startTest(); + String exceptionMessage; + try + { + Application.applyConfiguration( configurations ); + } + catch ( Application.InvalidApplicationConfigurationException e ) + { + exceptionMessage = e.getMessage(); + } + Test.stopTest(); + + ortoo_Asserts.assertContains( 'Duplicate configuration exists for Message Renderer - MessageRendererEngine.VisualforceMessageRenderer', exceptionMessage, 'messageRenderer, when configured with duplicates, will throw an exception' ); + } + @isTest private static void applyConfiguration_whenARecordHasAnInvalidType_willThrowAnException() // NOPMD: Test method name format {