├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── workflows │ ├── deploy.and.test.yml │ └── manage.sf.api.versions.yml ├── .gitignore ├── LICENSE ├── README.md ├── config └── project-scratch-def.json ├── sfdx-project.json └── sfdx-source └── apex-mocks ├── main └── classes │ ├── fflib_Answer.cls │ ├── fflib_Answer.cls-meta.xml │ ├── fflib_AnyOrder.cls │ ├── fflib_AnyOrder.cls-meta.xml │ ├── fflib_ApexMocks.cls │ ├── fflib_ApexMocks.cls-meta.xml │ ├── fflib_ApexMocksConfig.cls │ ├── fflib_ApexMocksConfig.cls-meta.xml │ ├── fflib_ApexMocksUtils.cls │ ├── fflib_ApexMocksUtils.cls-meta.xml │ ├── fflib_ArgumentCaptor.cls │ ├── fflib_ArgumentCaptor.cls-meta.xml │ ├── fflib_IDGenerator.cls │ ├── fflib_IDGenerator.cls-meta.xml │ ├── fflib_IMatcher.cls │ ├── fflib_IMatcher.cls-meta.xml │ ├── fflib_InOrder.cls │ ├── fflib_InOrder.cls-meta.xml │ ├── fflib_Inheritor.cls │ ├── fflib_Inheritor.cls-meta.xml │ ├── fflib_InvocationOnMock.cls │ ├── fflib_InvocationOnMock.cls-meta.xml │ ├── fflib_Match.cls │ ├── fflib_Match.cls-meta.xml │ ├── fflib_MatcherDefinitions.cls │ ├── fflib_MatcherDefinitions.cls-meta.xml │ ├── fflib_MatchersReturnValue.cls │ ├── fflib_MatchersReturnValue.cls-meta.xml │ ├── fflib_MethodArgValues.cls │ ├── fflib_MethodArgValues.cls-meta.xml │ ├── fflib_MethodCountRecorder.cls │ ├── fflib_MethodCountRecorder.cls-meta.xml │ ├── fflib_MethodReturnValue.cls │ ├── fflib_MethodReturnValue.cls-meta.xml │ ├── fflib_MethodReturnValueRecorder.cls │ ├── fflib_MethodReturnValueRecorder.cls-meta.xml │ ├── fflib_MethodVerifier.cls │ ├── fflib_MethodVerifier.cls-meta.xml │ ├── fflib_QualifiedMethod.cls │ ├── fflib_QualifiedMethod.cls-meta.xml │ ├── fflib_QualifiedMethodAndArgValues.cls │ ├── fflib_QualifiedMethodAndArgValues.cls-meta.xml │ ├── fflib_System.cls │ ├── fflib_System.cls-meta.xml │ ├── fflib_VerificationMode.cls │ └── fflib_VerificationMode.cls-meta.xml └── test └── classes ├── fflib_AnswerTest.cls ├── fflib_AnswerTest.cls-meta.xml ├── fflib_AnyOrderTest.cls ├── fflib_AnyOrderTest.cls-meta.xml ├── fflib_ApexMocksTest.cls ├── fflib_ApexMocksTest.cls-meta.xml ├── fflib_ApexMocksUtilsTest.cls ├── fflib_ApexMocksUtilsTest.cls-meta.xml ├── fflib_ArgumentCaptorTest.cls ├── fflib_ArgumentCaptorTest.cls-meta.xml ├── fflib_IDGeneratorTest.cls ├── fflib_IDGeneratorTest.cls-meta.xml ├── fflib_InOrderTest.cls ├── fflib_InOrderTest.cls-meta.xml ├── fflib_InheritorTest.cls ├── fflib_InheritorTest.cls-meta.xml ├── fflib_MatchTest.cls ├── fflib_MatchTest.cls-meta.xml ├── fflib_MatcherDefinitionsTest.cls ├── fflib_MatcherDefinitionsTest.cls-meta.xml ├── fflib_MethodArgValuesTest.cls ├── fflib_MethodArgValuesTest.cls-meta.xml ├── fflib_MyList.cls ├── fflib_MyList.cls-meta.xml ├── fflib_QualifiedMethodAndArgValuesTest.cls ├── fflib_QualifiedMethodAndArgValuesTest.cls-meta.xml ├── fflib_QualifiedMethodTest.cls ├── fflib_QualifiedMethodTest.cls-meta.xml ├── fflib_SystemTest.cls └── fflib_SystemTest.cls-meta.xml /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | (A clear and concise description of what the bug is.) 12 | 13 | **To Reproduce** 14 | 15 | (Please provide a public github repo with a full SFDX project that demonstrates the problem. If the repro case can be followed with a single example Apex class against a scratch org with just the fflib-apex-mocks project deployed into it, you don't need to provide a github repo) 16 | 17 | Steps to reproduce the behavior: 18 | 1. Create a scratch org as follows.... 19 | 2. Run the following Anonymous Apex.... 20 | 3. See error 21 | 22 | **Expected behavior** 23 | A clear and concise description of what you expected to happen. 24 | 25 | **Screenshots and text of error observed** 26 | If applicable, add screenshots to help explain your problem. Also, paste the text of the raw error into the issue as well so that it can be found by others via search. 27 | 28 | **Version** 29 | Did you try to reproduce the problem against the latest fflib-apex-mocks code? 30 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/workflows/deploy.and.test.yml: -------------------------------------------------------------------------------- 1 | name: Create a Scratch Org, Push Source and Run Apex Tests 2 | 3 | on: 4 | push: 5 | pull_request_target: 6 | workflow_dispatch: 7 | 8 | jobs: 9 | build: 10 | 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - uses: actions/checkout@v2 #Check out this repo 15 | with: 16 | ref: ${{github.event.pull_request.head.ref}} 17 | repository: ${{github.event.pull_request.head.repo.full_name}} 18 | - name: Install SF CLI and authorize DevHub 19 | uses: apex-enterprise-patterns/setup-sfdx@v2 #We're using a fork of https://github.com/sfdx-actions/setup-sfdx for safety 20 | with: 21 | sfdx-auth-url: ${{ secrets.DEVHUB_SFDXURL }} 22 | - name: Setup the config parameters needed 23 | run: sf config set target-dev-hub SFDX-ENV --global #Even though the setup-sfdx action uses --setdefaultdevhubusername, it doesn't seem to stick since it uses --setdefaultusername so we brute force it here 24 | - name: Create the scratch org 25 | run: sf org create scratch --definition-file config/project-scratch-def.json --set-default --duration-days 1 --no-track-source 26 | - name: Deploy and compile the codebase 27 | run: sf project deploy start 28 | - name: Run the core framework tests 29 | run: sf apex run test --wait 5 30 | - name: Destroy scratch org 31 | run: sf org delete scratch --no-prompt 32 | if: always() 33 | -------------------------------------------------------------------------------- /.github/workflows/manage.sf.api.versions.yml: -------------------------------------------------------------------------------- 1 | name: Manage SF API Versions 2 | on: 3 | workflow_dispatch: 4 | inputs: 5 | api-version: 6 | description: 'api version in the format XX e.g 58' 7 | required: true 8 | type: string 9 | jobs: 10 | update: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v3 14 | - uses: apex-enterprise-patterns/manage-sf-api-version@v1.0.0 15 | with: 16 | api-version: ${{inputs.api-version}} 17 | - uses: peter-evans/create-pull-request@v5 18 | with: 19 | title: 'Bump API Versions to ${{inputs.api-version}}.0' 20 | body: 'Automatically bumped by GitHub Actions ' 21 | branch: 'devops/bump-api-versions-v${{inputs.api-version}}.0' 22 | commit-message: 'chore: bump api to v${{inputs.api-version}}.0' 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # General Project related 2 | .DS_Store 3 | target/ 4 | temp/ 5 | /deploy/* 6 | /debug/ 7 | **/dep-dir.txt 8 | *.prefs 9 | build.properties 10 | /sfdx-source/apex-mocks/main/default 11 | 12 | # MavensMate IDE related 13 | *mm.log 14 | *.sublime-build 15 | *.sublime-project 16 | *.sublime-settings 17 | *.sublime-workspace 18 | .sublime-project 19 | .tm_properties 20 | 21 | # Eclipse IDE Related 22 | .project 23 | .settings/ 24 | salesforce.schema 25 | Referenced Packages/ 26 | 27 | # VS Code IDE Related 28 | .vscode/ 29 | .history/ 30 | 31 | # Illuminated Cloud Related 32 | .idea/ 33 | IlluminatedCloud 34 | 35 | # SFDX Related 36 | .sfdx/ 37 | .sf/ 38 | sfdx-source/untracked/ 39 | .execanon 40 | 41 | # NPM Related 42 | package.json 43 | /node_modules 44 | package-lock.json 45 | 46 | 47 | sfdx-source/group* 48 | research/ 49 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c), FinancialForce.com, inc 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, 5 | are permitted provided that the following conditions are met: 6 | 7 | - Redistributions of source code must retain the above copyright notice, 8 | this list of conditions and the following disclaimer. 9 | - Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | - Neither the name of the FinancialForce.com, inc nor the names of its contributors 13 | may be used to endorse or promote products derived from this software without 14 | specific prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 19 | THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 20 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 | OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 22 | OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FFLib ApexMocks Framework 2 | 3 | ![Push Source and Run Apex Tests](https://github.com/apex-enterprise-patterns/fflib-apex-mocks/workflows/Create%20a%20Scratch%20Org,%20Push%20Source%20and%20Run%20Apex%20Tests/badge.svg) 4 | 5 | ApexMocks is a mocking framework for the Salesforce Lightning Apex language. 6 | 7 | It derives its inspiration from the well known Java mocking framework [Mockito](https://site.mockito.org/) 8 | 9 | 10 | Deploy to Salesforce 12 | 13 | 14 | ## Using ApexMocks on the Salesforce Lightning Platform 15 | 16 | ApexMocks allows you to write tests to both verify behavior and stub dependencies. 17 | 18 | An assumption is made that you are using some form of [Dependency Injection](http://en.wikipedia.org/wiki/Dependency_injection) - for example passing dependencies via a constructor: 19 | ```Java 20 | public MyClass(ClassA.IClassA dependencyA, ClassB.IClassB dependencyB) 21 | ``` 22 | This allows you to pass mock implementations of dependencies A and B when you want to unit test MyClass. 23 | 24 | Lets assume we've written our own list interface fflib_MyList.IList that we want to either verify or stub: 25 | ```Java 26 | public class fflib_MyList implements IList 27 | { 28 | public interface IList 29 | { 30 | void add(String value); 31 | String get(Integer index); 32 | void clear(); 33 | Boolean isEmpty(); 34 | } 35 | } 36 | ``` 37 | ### verify() behaviour verification 38 | ```Java 39 | // Given 40 | fflib_ApexMocks mocks = new fflib_ApexMocks(); 41 | fflib_MyList.IList mockList = (fflib_MyList.IList)mocks.mock(fflib_MyList.class); 42 | 43 | // When 44 | mockList.add('bob'); 45 | 46 | // Then 47 | ((fflib_MyList.IList) mocks.verify(mockList)).add('bob'); 48 | ((fflib_MyList.IList) mocks.verify(mockList, fflib_ApexMocks.NEVER)).clear(); 49 | ``` 50 | 51 | If the method wasn't called the expected number of times, or with the expected arguments, verify will throw an exception. 52 | The exception message contains details of the expected and actual invocations: 53 | 54 | ``` 55 | EXPECTED COUNT: 1 56 | ACTUAL COUNT: 0 57 | METHOD: EmailService__sfdc_ApexStub.sendTo(String) 58 | --- 59 | ACTUAL ARGS: ("user-two@example.com") 60 | --- 61 | EXPECTED ARGS: [[contains "user-one"]] 62 | 63 | ``` 64 | 65 | ### when() dependency stubbing 66 | ```Java 67 | fflib_ApexMocks mocks = new fflib_ApexMocks(); 68 | fflib_MyList.IList mockList = (fflib_MyList.IList)mocks.mock(fflib_MyList.class); 69 | 70 | mocks.startStubbing(); 71 | mocks.when(mockList.get(0)).thenReturn('bob'); 72 | mocks.when(mockList.get(1)).thenReturn('fred'); 73 | mocks.stopStubbing(); 74 | ``` 75 | 76 | ## Utilties 77 | 78 | ### Setting a read-only field, such as a formula 79 | 80 | ```Java 81 | Account acc = new Account(); 82 | Integer mockFormulaResult = 10; 83 | acc = (Account)fflib_ApexMocksUtils.setReadOnlyFields( 84 | acc, 85 | Account.class, 86 | new Map {Account.Your_Formula_Field__c => mockFormulaResult} 87 | ); 88 | System.assertEquals(mockFormulaResult, acc.Your_Formula_Field__c); 89 | ``` 90 | 91 | ## Stub API 92 | Using Salesforce's [Stub API](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_testing_stub_api.htm), stub objects are generated dynamically at run time. 93 | ```Java 94 | fflib_ApexMocks mocks = new fflib_ApexMocks(); 95 | fflib_MyList mockList = (fflib_MyList)mocks.mock(fflib_MyList.class); 96 | ``` 97 | 98 | ## Documentation 99 | 100 | * [ApexMocks Framework Tutorial](http://code4cloud.wordpress.com/2014/05/06/apexmocks-framework-tutorial/) 101 | * [Simple Dependency Injection](http://code4cloud.wordpress.com/2014/05/09/simple-dependency-injection/) 102 | * [ApexMocks Generator](http://code4cloud.wordpress.com/2014/05/15/using-apex-mocks-generator-to-create-mock-class-definitions/) 103 | * [Behaviour Verification](http://code4cloud.wordpress.com/2014/05/15/writing-behaviour-verification-unit-tests/) 104 | * [Stubbing Dependencies](http://code4cloud.wordpress.com/2014/05/15/stubbing-dependencies-in-a-unit-test/) 105 | * [Supported Features](http://code4cloud.wordpress.com/2014/05/15/apexmocks-supported-features/) 106 | * [New Improved apex-mocks-generator](http://code4cloud.wordpress.com/2014/06/27/new-improved-apex-mocks-generator/) 107 | * [ApexMocks Improvements - exception stubbing, base classes and more](http://code4cloud.wordpress.com/2014/11/05/apexmocks-improvements-exception-stubbing-inner-interfaces-and-mock-base-classes/) 108 | * [Matchers](http://superdupercode.blogspot.co.uk/2016/03/apex-mocks-matchers.html) 109 | * [ApexMock blogs from Jesse Altman](http://jessealtman.com/tag/apexmocks/) 110 | * [Order of calls verification](https://xonoxforce.wordpress.com/2017/03/26/inorder-verify/) 111 | * [Answering](https://xonoxforce.wordpress.com/2017/03/31/answering-with-apex-mocks/) 112 | * [Counters](https://xonoxforce.wordpress.com/2017/04/01/counters-in-apex-mocks-verifications/) 113 | * [Troubleshooting](https://salesforce.stackexchange.com/questions/252460/my-apexmocks-arent-working-what-could-be-wrong) 114 | -------------------------------------------------------------------------------- /config/project-scratch-def.json: -------------------------------------------------------------------------------- 1 | { 2 | "orgName": "apex-mocks", 3 | "edition": "Developer", 4 | "settings": { 5 | "lightningExperienceSettings": { 6 | "enableS1DesktopEnabled": true 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /sfdx-project.json: -------------------------------------------------------------------------------- 1 | { 2 | "packageDirectories": [ 3 | { 4 | "path": "sfdx-source/apex-mocks", 5 | "default": true 6 | } 7 | ], 8 | "namespace": "", 9 | "sfdcLoginUrl": "https://login.salesforce.com", 10 | "sourceApiVersion": "63.0" 11 | } -------------------------------------------------------------------------------- /sfdx-source/apex-mocks/main/classes/fflib_Answer.cls: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017 FinancialForce.com, inc. All rights reserved. 3 | */ 4 | 5 | /** 6 | * Interface for the answering framework. 7 | * This interface must be implemented inside the test class and implement the call back method answer. 8 | * @group Core 9 | */ 10 | public interface fflib_Answer 11 | { 12 | /** 13 | * Method to be implemented in the test class to implement the call back method. 14 | * @param invocation The invocation on the mock. 15 | * @throws The exception to be thrown. 16 | * @return The value to be returned. 17 | */ 18 | Object answer(fflib_InvocationOnMock invocation); 19 | } -------------------------------------------------------------------------------- /sfdx-source/apex-mocks/main/classes/fflib_Answer.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 63.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /sfdx-source/apex-mocks/main/classes/fflib_AnyOrder.cls: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017 FinancialForce.com, inc. All rights reserved. 3 | */ 4 | 5 | /** 6 | * 'Classic' invocation verifier - checks that a method was called with the given arguments the expected number of times. 7 | * The order of method calls is not important. 8 | * @group Core 9 | */ 10 | public class fflib_AnyOrder extends fflib_MethodVerifier 11 | { 12 | /* 13 | * Verifies a method was invoked the expected number of times, with the expected arguments. 14 | * @param qualifiedMethod The method to be verified. 15 | * @param methodArg The arguments of the method that needs to be verified. 16 | * @param verificationMode The verification mode that holds the setting about how the verification should be performed. 17 | */ 18 | protected override void verify( 19 | fflib_QualifiedMethod qm, 20 | fflib_MethodArgValues expectedArguments, 21 | fflib_VerificationMode verificationMode) 22 | { 23 | List expectedMatchers = fflib_Match.Matching ? fflib_Match.getAndClearMatchers(expectedArguments.argValues.size()) : null; 24 | List actualArguments = fflib_MethodCountRecorder.getMethodArgumentsByTypeName().get(qm); 25 | 26 | Integer methodCount = getMethodCount(expectedArguments, expectedMatchers, actualArguments); 27 | 28 | String qualifier = ''; 29 | Integer expectedCount = null; 30 | 31 | if((verificationMode.VerifyMin == verificationMode.VerifyMax) && methodCount != verificationMode.VerifyMin) 32 | { 33 | expectedCount = verificationMode.VerifyMin; 34 | } 35 | else if (verificationMode.VerifyMin != null && verificationMode.VerifyMin > methodCount) 36 | { 37 | expectedCount = verificationMode.VerifyMin; 38 | qualifier = ' or more times'; 39 | } 40 | else if (verificationMode.VerifyMax != null && verificationMode.VerifyMax < methodCount) 41 | { 42 | expectedCount = verificationMode.VerifyMax; 43 | qualifier = ' or fewer times'; 44 | } 45 | 46 | if (expectedCount != null) 47 | { 48 | throwException(qm, '', expectedCount, qualifier, methodCount, verificationMode.CustomAssertMessage, expectedArguments, expectedMatchers, actualArguments); 49 | } 50 | } 51 | 52 | private Integer getMethodCount(fflib_MethodArgValues methodArg, List matchers, List methodArgs) 53 | { 54 | Integer retval = 0; 55 | 56 | if (methodArgs != null) 57 | { 58 | if (matchers != null) 59 | { 60 | for (fflib_MethodArgValues args : methodArgs) 61 | { 62 | if (fflib_Match.matchesAllArgs(args, matchers)) 63 | { 64 | capture(matchers); 65 | retval ++; 66 | } 67 | } 68 | } 69 | else 70 | { 71 | return countCalls(methodArgs, methodArg); 72 | } 73 | } 74 | 75 | return retval; 76 | } 77 | 78 | private Integer countCalls(List methodArgs, fflib_MethodArgValues methodArg) 79 | { 80 | Integer count = 0; 81 | 82 | for(fflib_MethodArgValues arg: methodArgs) 83 | { 84 | if( arg == methodArg) count++; 85 | } 86 | 87 | return count; 88 | } 89 | 90 | /* 91 | * Method that validate the verification mode used in the verify. 92 | * Not all the methods from the fflib_VerificationMode are implemented for the different classes that extends the fflib_MethodVerifier. 93 | * The error is thrown at run time, so this method is called in the method that actually performs the verify. 94 | * @param verificationMode The verification mode that have to been verified. 95 | * @throws Exception with message for the fflib_VerificationMode not implemented. 96 | */ 97 | protected override void validateMode(fflib_VerificationMode verificationMode) 98 | { 99 | if(verificationMode.Method == fflib_VerificationMode.ModeName.CALLS) 100 | { 101 | throw new fflib_ApexMocks.ApexMocksException( 102 | 'The calls() method is available only in the InOrder Verification.'); 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /sfdx-source/apex-mocks/main/classes/fflib_AnyOrder.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 63.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /sfdx-source/apex-mocks/main/classes/fflib_ApexMocks.cls: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2014-2017 FinancialForce.com, inc. All rights reserved. 3 | */ 4 | 5 | /** 6 | * @group Core 7 | */ 8 | public with sharing class fflib_ApexMocks implements System.StubProvider 9 | { 10 | public static final Integer NEVER = 0; 11 | 12 | private final fflib_MethodCountRecorder methodCountRecorder; 13 | private final fflib_MethodReturnValueRecorder methodReturnValueRecorder; 14 | 15 | private fflib_MethodVerifier methodVerifier; 16 | private fflib_VerificationMode verificationMode; 17 | private fflib_Answer myAnswer; 18 | 19 | public Boolean verifying { get; set; } 20 | 21 | public Boolean Stubbing 22 | { 23 | get 24 | { 25 | return methodReturnValueRecorder.Stubbing; 26 | } 27 | 28 | private set; 29 | } 30 | 31 | public List DoThrowWhenExceptions 32 | { 33 | get 34 | { 35 | return methodReturnValueRecorder.DoThrowWhenExceptions; 36 | } 37 | 38 | set 39 | { 40 | methodReturnValueRecorder.DoThrowWhenExceptions = value; 41 | } 42 | } 43 | 44 | /** 45 | * Construct an ApexMocks instance. 46 | */ 47 | public fflib_ApexMocks() 48 | { 49 | this.verifying = false; 50 | 51 | this.methodCountRecorder = new fflib_MethodCountRecorder(); 52 | this.verificationMode = new fflib_VerificationMode(); 53 | this.methodVerifier = new fflib_AnyOrder(); 54 | 55 | this.methodReturnValueRecorder = new fflib_MethodReturnValueRecorder(); 56 | 57 | this.methodReturnValueRecorder.Stubbing = false; 58 | } 59 | 60 | /** 61 | * Creates mock object of given class or interface. 62 | * @param classToMock class or interface to mock. 63 | * @return mock object. 64 | */ 65 | public Object mock(Type classToMock) 66 | { 67 | return Test.createStub(classToMock, this); 68 | } 69 | 70 | /** 71 | * Inherited from StubProvider. 72 | * @param stubbedObject The stubbed object. 73 | * @param stubbedMethodName The name of the invoked method. 74 | * @param returnType The return type of the invoked method. 75 | * @param listOfParamTypes A list of the parameter types of the invoked method. 76 | * @param listOfParamNames A list of the parameter names of the invoked method. 77 | * @param listOfArgs The actual argument values passed into this method at runtime. 78 | * @return The stubbed return value. Null by default, unless you prepared one that matches this method and argument values in stubbing. 79 | */ 80 | public Object handleMethodCall(Object stubbedObject, String stubbedMethodName, Type returnType, 81 | List listOfParamTypes, List listOfParamNames, List listOfArgs) 82 | { 83 | return mockNonVoidMethod(stubbedObject, stubbedMethodName, listOfParamTypes, listOfArgs); 84 | } 85 | 86 | public static String extractTypeName(Object mockInstance) 87 | { 88 | return String.valueOf(mockInstance).split(':').get(0); 89 | } 90 | 91 | /** 92 | * Verify a method was called on a mock object. 93 | * @param mockInstance The mock object instance. 94 | * @return The mock object instance. 95 | */ 96 | public Object verify(Object mockInstance) 97 | { 98 | return verify(mockInstance, this.times(1)); 99 | } 100 | 101 | /** 102 | * Verify a method was called on a mock object. 103 | * @param mockInstance The mock object instance. 104 | * @param verificationMode Defines the constraints for performing the verification (e.g. the minimum and maximum expected invocation counts). 105 | * @return The mock object instance. 106 | */ 107 | public Object verify(Object mockInstance, fflib_VerificationMode verificationMode) 108 | { 109 | this.verifying = true; 110 | this.verificationMode = verificationMode; 111 | 112 | return mockInstance; 113 | } 114 | 115 | /** 116 | * Verify a method was called on a mock object. 117 | * @param mockInstance The mock object instance. 118 | * @param times The number of times you expect the method to have been called. 119 | * @return The mock object instance. 120 | */ 121 | public Object verify(Object mockInstance, Integer times) 122 | { 123 | return verify(mockInstance, this.times(times)); 124 | } 125 | 126 | /** 127 | * Verfiy a method was called on a mock object. 128 | * @param mockInvocation The invocation on the mock containing information about the method and the arguments. 129 | */ 130 | public void verifyMethodCall(fflib_InvocationOnMock mockInvocation) 131 | { 132 | this.methodVerifier.verifyMethodCall(mockInvocation, verificationMode); 133 | this.methodVerifier = new fflib_AnyOrder(); 134 | 135 | this.verifying = false; 136 | } 137 | 138 | /** 139 | * Tell ApexMocks framework you are about to start stubbing using when() calls. 140 | */ 141 | public void startStubbing() 142 | { 143 | methodReturnValueRecorder.Stubbing = true; 144 | } 145 | 146 | /** 147 | * Tell ApexMocks framework you are about to stop stubbing using when() calls. 148 | */ 149 | public void stopStubbing() 150 | { 151 | methodReturnValueRecorder.Stubbing = false; 152 | } 153 | 154 | /** 155 | * Setup when stubbing for a mock object instance. 156 | * @param ignoredRetVal This is the return value from the method called on the mockInstance, and is ignored here since we are about to setup 157 | * the stubbed return value using thenReturn() (see MethodReturnValue class below). 158 | */ 159 | public fflib_MethodReturnValue when(Object ignoredRetVal) 160 | { 161 | return methodReturnValueRecorder.MethodReturnValue; 162 | } 163 | 164 | /** 165 | * Record a method was called on a mock object. 166 | * @param mockInvocation The invocation on the mock containing information about the method and the arguments. 167 | */ 168 | public void recordMethod(fflib_InvocationOnMock mockInvocation) 169 | { 170 | methodCountRecorder.recordMethod(mockInvocation); 171 | } 172 | 173 | /** 174 | * Prepare a stubbed method return value. 175 | * @param mockInvocation The invocation on the mock containing information about the method and the arguments. 176 | * @return The MethodReturnValue instance. 177 | */ 178 | public fflib_MethodReturnValue prepareMethodReturnValue(fflib_InvocationOnMock mockInvocation) 179 | { 180 | return methodReturnValueRecorder.prepareMethodReturnValue(mockInvocation); 181 | } 182 | 183 | /** 184 | * Get the method return value for the given method call. 185 | * @param mockInvocation The invocation on the mock containing information about the method and the arguments. 186 | * @return The MethodReturnValue instance. 187 | */ 188 | public fflib_MethodReturnValue getMethodReturnValue(fflib_InvocationOnMock mockInvocation) 189 | { 190 | return methodReturnValueRecorder.getMethodReturnValue(mockInvocation); 191 | } 192 | 193 | /** 194 | * Setup exception stubbing for a void method. 195 | * @param e The exception to throw. 196 | * @param mockInstance The mock object instance. 197 | */ 198 | public Object doThrowWhen(Exception e, Object mockInstance) 199 | { 200 | methodReturnValueRecorder.prepareDoThrowWhenExceptions(new List{e}); 201 | return mockInstance; 202 | } 203 | 204 | /** 205 | * Setup exception stubbing for a void method. 206 | * @param exps The list of exceptions to throw. 207 | * @param mockInstance The mock object instance. 208 | */ 209 | public Object doThrowWhen(List exps, Object mockInstance) 210 | { 211 | methodReturnValueRecorder.prepareDoThrowWhenExceptions(exps); 212 | return mockInstance; 213 | } 214 | 215 | /** 216 | * Setup answer stubbing for a void method. 217 | * @param answer The answer to invoke. 218 | * @param mockInstance The mock object instance. 219 | */ 220 | public Object doAnswer(fflib_Answer answer, Object mockInstance) 221 | { 222 | this.myAnswer = answer; 223 | return mockInstance; 224 | } 225 | 226 | /** 227 | * Mock a void method. Called by generated mock instance classes, not directly by a developers 228 | * code. 229 | * @param mockInstance The mock object instance. 230 | * @param methodName The method for which to prepare a return value. 231 | * @param methodArgTypes The method argument types for which to prepare a return value. 232 | * @param methodArgValues The method argument values for which to prepare a return value. 233 | */ 234 | public void mockVoidMethod(Object mockInstance, String methodName, List methodArgTypes, List methodArgValues) 235 | { 236 | mockNonVoidMethod(mockInstance, methodName, methodArgTypes, methodArgValues); 237 | } 238 | 239 | /** 240 | * Mock a non-void method. Called by generated mock instance classes, not directly by a developers 241 | * code. 242 | * @param mockInstance The mock object instance. 243 | * @param methodName The method for which to prepare a return value. 244 | * @param methodArgTypes The method argument types for which to prepare a return value. 245 | * @param methodArgValues The method argument values for which to prepare a return value. 246 | */ 247 | public Object mockNonVoidMethod(Object mockInstance, String methodName, List methodArgTypes, List methodArgValues) 248 | { 249 | fflib_QualifiedMethod qm = new fflib_QualifiedMethod(extractTypeName(mockInstance), methodName, methodArgTypes, mockInstance); 250 | fflib_MethodArgValues argValues = new fflib_MethodArgValues(methodArgValues); 251 | 252 | fflib_InvocationOnMock invocation = new fflib_InvocationOnMock(qm, argValues, mockInstance); 253 | 254 | if (this.verifying) 255 | { 256 | verifyMethodCall(invocation); 257 | } 258 | else if (Stubbing) 259 | { 260 | fflib_MethodReturnValue methotReturnValue = prepareMethodReturnValue(invocation); 261 | 262 | if(DoThrowWhenExceptions != null) 263 | { 264 | methotReturnValue.thenThrowMulti(DoThrowWhenExceptions); 265 | DoThrowWhenExceptions = null; 266 | return null; 267 | } 268 | 269 | if(this.myAnswer != null) 270 | { 271 | methotReturnValue.thenAnswer(this.myAnswer); 272 | this.myAnswer = null; 273 | return null; 274 | } 275 | 276 | return null; 277 | } 278 | else 279 | { 280 | recordMethod(invocation); 281 | return returnValue(invocation); 282 | } 283 | 284 | return null; 285 | } 286 | 287 | public class ApexMocksException extends Exception 288 | { 289 | 290 | } 291 | 292 | private Object returnValue(fflib_InvocationOnMock invocation) 293 | { 294 | fflib_MethodReturnValue methodReturnValue = getMethodReturnValue(invocation); 295 | 296 | if (methodReturnValue != null) 297 | { 298 | if(methodReturnValue.Answer == null) 299 | { 300 | throw new fflib_ApexMocks.ApexMocksException( 301 | 'The stubbing is not correct, no return values have been set.'); 302 | } 303 | 304 | Object returnedValue = methodReturnValue.Answer.answer(invocation); 305 | 306 | if(returnedValue == null) 307 | { 308 | return null; 309 | } 310 | 311 | if (returnedValue instanceof Exception) 312 | { 313 | throw ((Exception) returnedValue); 314 | } 315 | 316 | return returnedValue; 317 | } 318 | 319 | return null; 320 | } 321 | 322 | /** 323 | * Sets how many times the method is expected to be called. 324 | * For InOrder verification we copy Mockito behavior which is as follows; 325 | *
    326 | *
  • Consume the specified number of matching invocations, ignoring non-matching invocations in between
  • 327 | *
  • Fail an assert if the very next invocation matches, but additional matches can still exist so long as at least one non-matching invocation exists before them
  • 328 | *
329 | * For example if you had a(); a(); b(); a(); 330 | * then inOrder.verify(myMock, 2)).a(); or inOrder.verify(myMock, 3)).a(); would pass but not inOrder.verify(myMock, 1)).a(); 331 | * @param times The number of times you expect the method to have been called. 332 | * @return The fflib_VerificationMode object instance with the proper settings. 333 | */ 334 | public fflib_VerificationMode times(Integer times) 335 | { 336 | return new fflib_VerificationMode().times(times); 337 | } 338 | 339 | /** 340 | * Sets how many times the method is expected to be called for an InOrder verifier. Available Only with the InOrder verification. 341 | * A verification mode using calls will not fail if the method is called more times than expected. 342 | * @param times The number of times you expect the method to have been called in the InOrder verifying ( no greedy verify). 343 | * @return The fflib_VerificationMode object instance with the proper settings. 344 | */ 345 | public fflib_VerificationMode calls(Integer times) 346 | { 347 | return new fflib_VerificationMode().calls(times); 348 | } 349 | 350 | /** 351 | * Sets a custom assert message for the verify. 352 | * @param customAssertMessage The custom message for the assert in case the assert is false. The custom message is queued to the default message. 353 | * @return The fflib_VerificationMode object instance with the proper settings. 354 | */ 355 | public fflib_VerificationMode description(String customAssertMessage) 356 | { 357 | return new fflib_VerificationMode().description(customAssertMessage); 358 | } 359 | 360 | /** 361 | * Sets the minimum number of times the method is expected to be called. 362 | * With the InOrder verification it performs a greedy verification, which means it would consume all the instances of the method verified. 363 | * @param atLeastTimes The minimum number of times you expect the method to have been called. 364 | * @return The fflib_VerificationMode object instance with the proper settings. 365 | */ 366 | public fflib_VerificationMode atLeast(Integer atLeastTimes) 367 | { 368 | return new fflib_VerificationMode().atLeast(atLeastTimes); 369 | } 370 | 371 | /** 372 | * Sets the maximum number of times the method is expected to be called. Not available in the InOrder verification. 373 | * @param atMostTimes The maximum number of times the method is expected to be called. 374 | * @return The fflib_VerificationMode object instance with the proper settings. 375 | */ 376 | public fflib_VerificationMode atMost(Integer atMostTimes) 377 | { 378 | return new fflib_VerificationMode().atMost(atMostTimes); 379 | } 380 | 381 | /** 382 | * Sets that the method is called at least once. 383 | * With the InOrder verification it performs a greedy verification, which means it would consume all the instances of the method verified. 384 | * @return The fflib_VerificationMode object instance with the proper settings. 385 | */ 386 | public fflib_VerificationMode atLeastOnce() 387 | { 388 | return new fflib_VerificationMode().atLeastOnce(); 389 | } 390 | 391 | /** 392 | * Sets the range of how many times the method is expected to be called. Not available in the InOrder verification. 393 | * @param atLeastTimes The minimum number of times you expect the method to have been called. 394 | * @param atMostTimes The maximum number of times the method is expected to be called. 395 | * @return The fflib_VerificationMode object instance with the proper settings. 396 | */ 397 | public fflib_VerificationMode between(Integer atLeastTimes, Integer atMostTimes) 398 | { 399 | return new fflib_VerificationMode().between(atLeastTimes, atMostTimes); 400 | } 401 | 402 | /** 403 | * Sets that the method is not expected to be called. 404 | * @return The fflib_VerificationMode object instance with the proper settings. 405 | */ 406 | public fflib_VerificationMode never() 407 | { 408 | return new fflib_VerificationMode().never(); 409 | } 410 | 411 | /** 412 | * Sets the fflib_VerificationMode object. 413 | * To internal use only. 414 | * Used to pass the verification mode that has been set in the verify of the fflib_InOrder class. 415 | * @return The fflib_VerificationMode object instance with the proper settings. 416 | */ 417 | public void setOrderedVerifier(fflib_InOrder verifyOrderingMode) 418 | { 419 | this.methodVerifier = verifyOrderingMode; 420 | } 421 | 422 | /** 423 | * A simple override to suppress the default toString logic, which is noisy and rarely useful. 424 | * In some cases, the Salesforce default implementation of toString here can cause internal Salesforce errors 425 | * if it has circular references. 426 | * @return "fflib_ApexMocks" String literal 427 | */ 428 | public override String toString() 429 | { 430 | return 'fflib_ApexMocks'; 431 | } 432 | } 433 | -------------------------------------------------------------------------------- /sfdx-source/apex-mocks/main/classes/fflib_ApexMocks.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 63.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /sfdx-source/apex-mocks/main/classes/fflib_ApexMocksConfig.cls: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 FinancialForce.com, inc. All rights reserved. 3 | */ 4 | @IsTest 5 | public class fflib_ApexMocksConfig 6 | { 7 | /** 8 | * When false, stubbed behaviour and invocation counts are shared among all test spies. 9 | * - See fflib_ApexMocksTest.thatMultipleInstancesCanBeMockedDependently 10 | * - This is the default for backwards compatibility. 11 | * When true, each test spy instance has its own stubbed behaviour and invocations. 12 | * - See fflib_ApexMocksTest.thatMultipleInstancesCanBeMockedIndependently 13 | */ 14 | public static Boolean HasIndependentMocks {get; set;} 15 | 16 | static 17 | { 18 | HasIndependentMocks = false; 19 | } 20 | } -------------------------------------------------------------------------------- /sfdx-source/apex-mocks/main/classes/fflib_ApexMocksConfig.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 63.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /sfdx-source/apex-mocks/main/classes/fflib_ApexMocksUtils.cls: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014-2016, FinancialForce.com, inc 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without modification, 6 | * are permitted provided that the following conditions are met: 7 | * 8 | * - Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * - Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * - Neither the name of the FinancialForce.com, inc nor the names of its contributors 14 | * may be used to endorse or promote products derived from this software without 15 | * specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 20 | * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 23 | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | public class fflib_ApexMocksUtils 27 | { 28 | /** 29 | * This is taken from https://gist.github.com/afawcett/8dbfc0e1d8c43c982881. 30 | * 31 | * This method works on the principle that serializing and deserialising child records is supported 32 | * 33 | * System.assertEquals(1, ((List) 34 | * JSON.deserialize( 35 | * JSON.serialize( 36 | * [select Id, Name, 37 | * (select Id, Name from Children__r) from Master__c]), List.class)) 38 | * [0].Children__r.size()); 39 | * 40 | * This method results internally in constructing this JSON, before deserialising it back into SObject's 41 | * 42 | * [ 43 | * { 44 | * "attributes": { 45 | * "type": "Master__c", 46 | * "url": "/services/data/v32.0/sobjects/Master__c/a0YG0000005Jn5uMAC" 47 | * }, 48 | * "Name": "Fred", 49 | * "Id": "a0YG0000005Jn5uMAC", 50 | * "Children__r": { 51 | * "totalSize": 1, 52 | * "done": true, 53 | * "records": [ 54 | * { 55 | * "attributes": { 56 | * "type": "Child__c", 57 | * "url": "/services/data/v32.0/sobjects/Child__c/a0ZG0000006JGPAMA4" 58 | * }, 59 | * "Name": "Bob", 60 | * "Id": "a0ZG0000006JGPAMA4", 61 | * "Master__c": "a0YG0000005Jn5uMAC" 62 | * } 63 | * ] 64 | * } 65 | * ] 66 | */ 67 | public static Object makeRelationship(Type parentsType, List parents, SObjectField relationshipField, List> children) { 68 | 69 | // Find out more about this relationship... 70 | String relationshipFieldName = relationshipField.getDescribe().getName(); 71 | DescribeSObjectResult parentDescribe = parents.getSObjectType().getDescribe(); 72 | return deserializeParentsAndChildren(parentsType, parentDescribe, relationshipField, parents, children); 73 | } 74 | 75 | /** 76 | * Generic overload to makeRelationship. Enables creation of 77 | * relationships in a loosely-coupled manner. 78 | */ 79 | public static Object makeRelationship( 80 | String parentTypeName, 81 | String childTypeName, 82 | List parents, 83 | String relationshipFieldName, 84 | List> children) { 85 | 86 | // Find out more about this relationship... 87 | SObjectType parentType = getType(parentTypeName); 88 | SObjectField relationshipField = getField(childTypeName, relationshipFieldName); 89 | DescribeSObjectResult parentDescribe = parentType.getDescribe(); 90 | Type parentsType = List.class; 91 | return deserializeParentsAndChildren(parentsType, parentDescribe, relationshipField, parents, children); 92 | } 93 | 94 | /** 95 | * Gives the ability to set test values on formula 96 | * and other read-only fields of mock SObjects 97 | */ 98 | public static Object setReadOnlyFields(SObject objInstance, Type deserializeType, Map properties) { 99 | 100 | Map fieldNameMap = new Map(); 101 | for (SObjectField field : properties.keySet()) { 102 | // Resolve the fieldNames from the FieldTokens 103 | fieldNameMap.put(field.getDescribe().getName(), properties.get(field)); 104 | } 105 | return (SObject) setReadOnlyFields(objInstance, deserializeType, fieldNameMap); 106 | } 107 | 108 | /** 109 | * Generic overload to setReadOnlyFields. Enables setting test 110 | * values on read-only fields by their name 111 | */ 112 | public static Object setReadOnlyFields(SObject objInstance, Type deserializeType, Map properties) { 113 | 114 | Map mergedMap = new Map(objInstance.getPopulatedFieldsAsMap()); 115 | // Merge the values from the properties map into the fields already set on the object 116 | mergedMap.putAll(properties); 117 | // Serialize the merged map, and then deserialize it as the desired object type. 118 | String jsonString = JSON.serializePretty(mergedMap); 119 | return (SObject) JSON.deserialize(jsonString, deserializeType); 120 | } 121 | 122 | /** 123 | * Helper Methods 124 | */ 125 | private static Object deserializeParentsAndChildren( 126 | Type parentsType, 127 | DescribeSObjectResult parentDescribe, 128 | SObjectField relationshipField, 129 | List parents, 130 | List> children 131 | ) { 132 | List childRelationships = parentDescribe.getChildRelationships(); 133 | 134 | String relationshipName = null; 135 | for(Schema.ChildRelationship childRelationship : childRelationships) { 136 | if(childRelationship.getField() == relationshipField) { 137 | relationshipName = childRelationship.getRelationshipName(); 138 | break; 139 | } 140 | } 141 | 142 | // Stream the parsed JSON representation of the parent objects back out, injecting children as it goes 143 | JSONParser parentsParser = JSON.createParser(JSON.serialize(parents)); 144 | JSONParser childrenParser = JSON.createParser(JSON.serialize(children)); 145 | JSONGenerator combinedOutput = JSON.createGenerator(false); 146 | streamTokens(parentsParser, combinedOutput, new InjectChildrenEventHandler(childrenParser, relationshipName, children) ); 147 | 148 | // Derserialise back into SObject list complete with children 149 | return JSON.deserialize(combinedOutput.getAsString(), parentsType); 150 | } 151 | 152 | /** 153 | * Monitors stream events for end of object for each SObject contained in the parent list 154 | * then injects the respective childs record list into the stream 155 | */ 156 | private class InjectChildrenEventHandler implements JSONParserEvents 157 | { 158 | private JSONParser childrenParser; 159 | private String relationshipName; 160 | private List> children; 161 | private Integer childListIdx = 0; 162 | 163 | public InjectChildrenEventHandler(JSONParser childrenParser, String relationshipName, List> children) { 164 | this.childrenParser = childrenParser; 165 | this.relationshipName = relationshipName; 166 | this.children = children; 167 | this.childrenParser.nextToken(); // Consume the outer array token 168 | } 169 | 170 | public void nextToken(JSONParser fromStream, Integer depth, JSONGenerator toStream) { 171 | // Inject children? 172 | JSONToken currentToken = fromStream.getCurrentToken(); 173 | if(depth == 2 && currentToken == JSONToken.END_OBJECT ) { 174 | toStream.writeFieldName(relationshipName); 175 | toStream.writeStartObject(); 176 | toStream.writeNumberField('totalSize', children[childListIdx].size()); 177 | toStream.writeBooleanField('done', true); 178 | toStream.writeFieldName('records'); 179 | streamTokens(childrenParser, toStream, null); 180 | toStream.writeEndObject(); 181 | childListIdx++; 182 | } 183 | } 184 | } 185 | 186 | /** 187 | * Utility function to stream tokens from a reader to a write, while providing a basic eventing model 188 | */ 189 | private static void streamTokens(JSONParser fromStream, JSONGenerator toStream, JSONParserEvents events) 190 | { 191 | Integer depth = 0; 192 | while (fromStream.nextToken() != null) 193 | { 194 | // Give event handler chance to inject 195 | if (events != null) { 196 | events.nextToken(fromStream, depth, toStream); 197 | } 198 | 199 | // Forward to output stream 200 | switch on fromStream.getCurrentToken() { 201 | when START_ARRAY { 202 | toStream.writeStartArray(); 203 | depth++; 204 | } 205 | when START_OBJECT { 206 | toStream.writeStartObject(); 207 | depth++; 208 | } 209 | when FIELD_NAME { 210 | toStream.writeFieldName(fromStream.getCurrentName()); 211 | } 212 | when VALUE_STRING, VALUE_FALSE, VALUE_TRUE, VALUE_NUMBER_FLOAT, VALUE_NUMBER_INT { 213 | toStream.writeString(fromStream.getText()); 214 | } 215 | when VALUE_NULL { 216 | toStream.writeNull(); 217 | } 218 | when END_OBJECT { 219 | toStream.writeEndObject(); 220 | depth--; 221 | } 222 | when END_ARRAY { 223 | toStream.writeEndArray(); 224 | depth--; 225 | } 226 | } 227 | // Don't continue to stream beyond the initial starting point 228 | if (depth == 0) 229 | break; 230 | } 231 | } 232 | 233 | /** 234 | * Basic event used during the above streaming 235 | */ 236 | private interface JSONParserEvents 237 | { 238 | void nextToken(JSONParser fromStream, Integer depth, JSONGenerator toStream); 239 | } 240 | 241 | /** 242 | * Gets the SObjectType by name 243 | */ 244 | private static Schema.SObjectType getType(String typeName) { 245 | Map gd = Schema.getGlobalDescribe(); 246 | SObjectType sobjType = gd.get(typeName); 247 | if (sobjType == null) { 248 | throw new fflib_ApexMocks.ApexMocksException('SObject type not found: ' + typeName); 249 | } 250 | return sobjType; 251 | } 252 | 253 | /** 254 | * Gets the SObjectField of an object by name 255 | */ 256 | private static Schema.SObjectField getField(String objectName, String fieldName) { 257 | 258 | SObjectType sobjType = getType(objectName); 259 | Map objectFields = sobjType.getDescribe().fields.getMap(); 260 | Schema.SObjectField sobjField = objectFields.get(fieldName); 261 | if (sobjField == null) { 262 | throw new fflib_ApexMocks.ApexMocksException('SObject field not found: ' + fieldName); 263 | } 264 | return sobjField; 265 | } 266 | } -------------------------------------------------------------------------------- /sfdx-source/apex-mocks/main/classes/fflib_ApexMocksUtils.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 63.0 4 | 5 | -------------------------------------------------------------------------------- /sfdx-source/apex-mocks/main/classes/fflib_ArgumentCaptor.cls: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016, FinancialForce.com, inc 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without modification, 6 | * are permitted provided that the following conditions are met: 7 | * 8 | * - Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * - Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * - Neither the name of the FinancialForce.com, inc nor the names of its contributors 14 | * may be used to endorse or promote products derived from this software without 15 | * specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 20 | * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 23 | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | /** 28 | * This class implements the capturing framework for ApexMocks 29 | * According to Mockito's syntax the type is passed in the capturer construction, 30 | * however Apex cannot perform the auto casting that Java can. 31 | * To be consistent with Mockito, the capturer does not perform any checks on the type of the argument. 32 | * @group Core 33 | */ 34 | public with sharing class fflib_ArgumentCaptor 35 | { 36 | protected List argumentsCaptured = new List(); 37 | 38 | /** 39 | * Factory method to create a new fflib_ArgumentCaptor. 40 | * Takes the captured argument's Type for consistency with Mockito syntax. 41 | * The Type is IGNORED because we can't determine an object instance's Type at runtime unlike in Java. 42 | * Rigorous type checking may be introduced in a future release, so you should specify the expected argument type correctly. 43 | * 44 | * @param ignoredCaptureType Type (class) of the captured argument 45 | * @return A new fflib_ArgumentCaptor. 46 | */ 47 | public static fflib_ArgumentCaptor forClass(Type ignoredCaptureType) 48 | { 49 | return new fflib_ArgumentCaptor(); 50 | } 51 | 52 | /** 53 | * Use it to capture the argument. This method must be used inside verification. 54 | * Internally, this method registers a special implementation of a Matcher. 55 | * This argument matcher stores the argument value so that you can use it later to perform assertions. 56 | * 57 | * @return a special matcher that matches any argument and remembers the value. 58 | */ 59 | public Object capture() 60 | { 61 | AnyObject myMatcher = new AnyObject(this); 62 | 63 | return fflib_Match.matches(myMatcher); 64 | } 65 | 66 | /** 67 | * Returns the captured value of the argument. When capturing all arguments use getAllValues(). 68 | * If verified method was called multiple times then this method returns the latest captured value. 69 | * 70 | * @return captured argument value. 71 | */ 72 | public Object getValue() 73 | { 74 | if( argumentsCaptured == null || 75 | argumentsCaptured.size() == 0) 76 | { 77 | return null; 78 | } 79 | 80 | //returns the last argument called 81 | return argumentsCaptured.get( argumentsCaptured.size() - 1 ); 82 | } 83 | 84 | /** 85 | * Returns all captured values. Use it when capturing multiple arguments or when the verified method was called multiple times. 86 | * When capturing multiple arguments is called multiple times, this method returns a merged list of all values from all invocations. 87 | * 88 | * @return Returns all captured values. Use it when capturing multiple arguments on the same call or when the verified method was called multiple times. 89 | */ 90 | public List getAllValues() 91 | { 92 | return argumentsCaptured; 93 | } 94 | 95 | public class AnyObject implements fflib_IMatcher 96 | { 97 | private fflib_ArgumentCaptor captor; 98 | private Object value; 99 | 100 | public AnyObject(fflib_ArgumentCaptor captor) 101 | { 102 | this.captor = captor; 103 | } 104 | 105 | //match with all the possible values and store the arg value 106 | public Boolean matches(Object arg) 107 | { 108 | value = arg; 109 | return true; 110 | } 111 | 112 | //store the argument in the list ( this would be called inside the method counter where is compared with the matchers of the method) 113 | public void storeArgument() 114 | { 115 | captor.argumentsCaptured.add(value); 116 | } 117 | } 118 | } -------------------------------------------------------------------------------- /sfdx-source/apex-mocks/main/classes/fflib_ArgumentCaptor.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 63.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /sfdx-source/apex-mocks/main/classes/fflib_IDGenerator.cls: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014, FinancialForce.com, inc 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without modification, 6 | * are permitted provided that the following conditions are met: 7 | * 8 | * - Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * - Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * - Neither the name of the FinancialForce.com, inc nor the names of its contributors 14 | * may be used to endorse or promote products derived from this software without 15 | * specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 20 | * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 23 | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | public with sharing class fflib_IDGenerator 27 | { 28 | private static Integer fakeIdCount = 0; 29 | private static final String ID_PATTERN = '000000000000'; 30 | 31 | /** 32 | * Generate a fake Salesforce Id for the given SObjectType 33 | */ 34 | public static Id generate(Schema.SObjectType sobjectType) 35 | { 36 | String keyPrefix = sobjectType.getDescribe().getKeyPrefix(); 37 | fakeIdCount++; 38 | 39 | String fakeIdPrefix = ID_PATTERN.substring(0, ID_PATTERN.length() - String.valueOf(fakeIdCount).length()); 40 | 41 | return Id.valueOf(keyPrefix + fakeIdPrefix + fakeIdCount); 42 | } 43 | } -------------------------------------------------------------------------------- /sfdx-source/apex-mocks/main/classes/fflib_IDGenerator.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 63.0 4 | 5 | -------------------------------------------------------------------------------- /sfdx-source/apex-mocks/main/classes/fflib_IMatcher.cls: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014-2016, FinancialForce.com, inc 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without modification, 6 | * are permitted provided that the following conditions are met: 7 | * 8 | * - Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * - Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * - Neither the name of the FinancialForce.com, inc nor the names of its contributors 14 | * may be used to endorse or promote products derived from this software without 15 | * specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 20 | * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 23 | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | public interface fflib_IMatcher 27 | { 28 | /** 29 | * Whether or not the supplied argument is a match. 30 | * Any supplementary information (e.g. boundary conditions, objects to match to etc) 31 | * should be cached by the matcher constructor. 32 | * @param arg The argument value supplied to the method 33 | * @return Boolean True if the argument value is a match, false otherwise. 34 | */ 35 | Boolean matches(Object arg); 36 | } -------------------------------------------------------------------------------- /sfdx-source/apex-mocks/main/classes/fflib_IMatcher.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 63.0 4 | 5 | -------------------------------------------------------------------------------- /sfdx-source/apex-mocks/main/classes/fflib_InOrder.cls: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017 FinancialForce.com, inc. All rights reserved. 3 | */ 4 | 5 | 6 | /** 7 | * @group Core 8 | */ 9 | public with sharing class fflib_InOrder extends fflib_MethodVerifier 10 | { 11 | private final List unorderedMockInstances; 12 | private Integer idxMethodCall = 0; 13 | 14 | private Set notImplementedMethods = 15 | new Set 16 | { 17 | fflib_VerificationMode.ModeName.atMost, 18 | fflib_VerificationMode.ModeName.between 19 | }; 20 | 21 | private final fflib_ApexMocks mocks; 22 | 23 | /** 24 | * Construct the InOrder instance. 25 | * @param mocks The apex mock object instance. 26 | * @param unorderedMockInstances One or more mock implementation classes (listed in any order), whose ordered method calls require verification. 27 | */ 28 | public fflib_InOrder(fflib_ApexMocks mocks, List unorderedMockInstances) 29 | { 30 | this.unorderedMockInstances = unorderedMockInstances; 31 | this.mocks = mocks; 32 | } 33 | 34 | /** 35 | * Verify a method was called on a mock object. 36 | * It performs a no strict ordered verification. 37 | * The verification could be either greedy or not depending of the verificationMode passed. 38 | * Check the fflib_VerificationMode methods for details. 39 | * @param mockInstance The mock object instance. 40 | * @param verificationMode Defines the constraints for performing the verification (e.g. the minimum and maximum expected invocation counts). 41 | * @return The mock object instance. 42 | */ 43 | public Object verify(Object mockInstance, fflib_VerificationMode verificationMode) 44 | { 45 | mocks.setOrderedVerifier(this); 46 | return mocks.verify(mockInstance, verificationMode); 47 | } 48 | 49 | /** 50 | * Verify a method was called on a mock object. 51 | * It performs the default times(1) verification for the InOrder. 52 | * @param mockInstance The mock object instance. 53 | * @return The mock object instance. 54 | */ 55 | public Object verify(Object mockInstance) 56 | { 57 | mocks.setOrderedVerifier(this); 58 | return mocks.verify(mockInstance); 59 | } 60 | 61 | /** 62 | * Verify a method was called on a mock object. 63 | * Wrapper for the new syntax call to be conformed to the old style notation 64 | * It performs the equivalent of times(times) verification for the InOrder. 65 | * @param mockInstance The mock object instance. 66 | * @param times The number of times you expect the method to have been called. 67 | * @return The mock object instance. 68 | */ 69 | public Object verify(Object mockInstance, Integer times) 70 | { 71 | mocks.setOrderedVerifier(this); 72 | return mocks.verify(mockInstance, times); 73 | } 74 | 75 | /** 76 | * Verify that after the last successful verified method no more interactions happened on the inOrderMock instance. 77 | * @throws Exception with message to help to identify the last method called. 78 | */ 79 | public void verifyNoMoreInteractions() 80 | { 81 | if(idxMethodCall == 0) 82 | { 83 | verifyNoInteractions(); 84 | } 85 | 86 | if(hasNextInteraction(unorderedMockInstances, idxMethodCall)) 87 | { 88 | fflib_InvocationOnMock invocation = 89 | fflib_MethodCountRecorder.getOrderedMethodCalls().get(idxMethodCall -1); 90 | 91 | throw new fflib_ApexMocks.ApexMocksException( 92 | 'No more Interactions were expected after the ' + invocation.getMethod() +' method.'); 93 | } 94 | } 95 | 96 | /** 97 | * Verify that no interactions at all happened on the inOrderMock instance. 98 | * @throws Exception with message. 99 | */ 100 | public void verifyNoInteractions() 101 | { 102 | if(hasNextInteraction(unorderedMockInstances, 0)) 103 | { 104 | throw new fflib_ApexMocks.ApexMocksException( 105 | 'No Interactions expected on this InOrder Mock instance!'); 106 | } 107 | } 108 | 109 | /* 110 | * Verifies a method was invoked the expected number of times, with the expected arguments. 111 | * The in-order verifier remembers the last method invocation it successfully verified, 112 | * and only considers subsequent method invocations for subsequent verifications. 113 | * @param qualifiedMethod The method to be verified. 114 | * @param expectedArguments The arguments of the method that needs to be verified. 115 | * @param verificationMode The verification mode that holds the setting about how the verification should be performed. 116 | */ 117 | protected override void verify( 118 | fflib_QualifiedMethod qm, 119 | fflib_MethodArgValues expectedArguments, 120 | fflib_VerificationMode verificationMode) 121 | { 122 | String inOrder = ' in order'; 123 | List matchers = fflib_Match.Matching ? fflib_Match.getAndClearMatchers(expectedArguments.argValues.size()) : null; 124 | List actualInvocations = fflib_MethodCountRecorder.getOrderedMethodCalls(); 125 | List actualArguments = new List(); 126 | for (fflib_InvocationOnMock invocation : actualInvocations) 127 | { 128 | actualArguments.add(invocation.getMethodArgValues()); 129 | } 130 | 131 | if( verificationMode.VerifyMin == 0 && verificationMode.VerifyMax == 0) 132 | { 133 | Integer methodCounts = countInteractions(matchers, qm, expectedArguments); 134 | if(methodCounts != 0 ) 135 | throwException(qm, inOrder, fflib_ApexMocks.NEVER, '', methodCounts, verificationMode.CustomAssertMessage, expectedArguments, matchers, actualArguments); 136 | } 137 | 138 | Integer i=0; 139 | for ( ; i matchers, 174 | fflib_QualifiedMethod qm, 175 | fflib_MethodArgValues methodArg) 176 | { 177 | fflib_InvocationOnMock calledMethod = getNextMethodCall(); 178 | while(calledMethod != null) 179 | { 180 | if(calledMethod.getMethod() == qm && 181 | argumentsMatch(calledMethod.getMethodArgValues(), matchers, methodArg)) 182 | { 183 | //it's our method 184 | if (matchers != null) 185 | { 186 | capture(matchers); 187 | } 188 | return true; 189 | } 190 | 191 | calledMethod = getNextMethodCall(); 192 | } 193 | 194 | return false; 195 | } 196 | 197 | private Integer countInteractions( 198 | List matchers, 199 | fflib_QualifiedMethod qualifiedMethod, 200 | fflib_MethodArgValues methodArg) 201 | { 202 | Integer interactionsCouter = 0; 203 | 204 | for (Integer i = idxMethodCall, len = fflib_MethodCountRecorder.getOrderedMethodCalls().size(); i matchers, 223 | fflib_QualifiedMethod qualifiedMethod, 224 | fflib_MethodArgValues methodArg) 225 | { 226 | Integer lastInteracionIndex = 0; 227 | 228 | //going all through the orderedMethodCalls to find all the interaction of the method 229 | for (Integer i = idxMethodCall, len = fflib_MethodCountRecorder.getOrderedMethodCalls().size(); i matchers, 255 | fflib_MethodArgValues methodArg) 256 | { 257 | //Check it was called with the right args. 258 | if (matchers != null) 259 | { 260 | if(fflib_Match.matchesAllArgs(calledMethodArg, matchers)) 261 | { 262 | //Return now we've matched the method call 263 | return true; 264 | } 265 | } 266 | else if(calledMethodArg == methodArg) 267 | { 268 | //Return now we've matched the method call 269 | return true; 270 | } 271 | 272 | return false; 273 | } 274 | 275 | private fflib_InvocationOnMock getNextMethodCall() 276 | { 277 | return getNextMethodCall(true); 278 | } 279 | 280 | private fflib_InvocationOnMock getNextMethodCall(Boolean updateIdxMethodCall) 281 | { 282 | Integer idx = 0; 283 | for (fflib_InvocationOnMock invocation : fflib_MethodCountRecorder.getOrderedMethodCalls()) 284 | { 285 | if (idx == idxMethodCall) 286 | { 287 | if(isForMockInstance(invocation)) 288 | { 289 | if(updateIdxMethodCall) 290 | idxMethodCall++; 291 | return invocation; 292 | } 293 | } 294 | else 295 | { 296 | idx++; 297 | } 298 | } 299 | 300 | return null; 301 | } 302 | 303 | private Boolean isForMockInstance(fflib_InvocationOnMock invocation) 304 | { 305 | for (Object mi : unorderedMockInstances) 306 | { 307 | if (mi === invocation.getMock()) 308 | { 309 | return true; 310 | } 311 | } 312 | 313 | return false; 314 | } 315 | 316 | /* 317 | * Used by the fflib_InOrder invocation verifier to find further interactions with a given mock instances. 318 | * @param mockInstances The tracked mock instances - only methods called on these objects are counted as an invocation. 319 | * @param idxLastMethodCalled The index of the last matched method, used to offset the search for invocations so we don't double count invocations. 320 | * @return Whether or not there were further interactions. 321 | */ 322 | private Boolean hasNextInteraction(List mockInstances, Integer idxLastMethodCalled) 323 | { 324 | Integer idx = 0; 325 | 326 | for (fflib_InvocationOnMock methodCall : fflib_MethodCountRecorder.getOrderedMethodCalls()) 327 | { 328 | if (isForMockInstance(methodCall)) 329 | { 330 | idx++; 331 | if (idx > idxLastMethodCalled) 332 | { 333 | return true; 334 | } 335 | } 336 | } 337 | 338 | return false; 339 | } 340 | 341 | /* 342 | * Method that validate the verification mode used in the verify. 343 | * Not all the methods from the fflib_VerificationMode are implemented for the different classes that extends the fflib_MethodVerifier. 344 | * The error is thrown at run time, so this method is called in the method that actually performs the verify. 345 | * @param verificationMode The verification mode that have to been verified. 346 | * @throws Exception with message for the fflib_VerificationMode not implemented. 347 | */ 348 | protected override void validateMode(fflib_VerificationMode verificationMode) 349 | { 350 | if(notImplementedMethods.contains(verificationMode.Method)) 351 | { 352 | throw new fflib_ApexMocks.ApexMocksException( 353 | 'The ' + verificationMode.Method.name() + ' method is not implemented for the fflib_InOrder class'); 354 | } 355 | } 356 | } -------------------------------------------------------------------------------- /sfdx-source/apex-mocks/main/classes/fflib_InOrder.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 63.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /sfdx-source/apex-mocks/main/classes/fflib_Inheritor.cls: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2017 FinancialForce.com, inc. All rights reserved. 3 | */ 4 | @isTest 5 | public class fflib_Inheritor implements IA, IB, IC 6 | { 7 | public interface IA {String doA();} 8 | public interface IB {String doB();} 9 | public interface IC {String doC();} 10 | 11 | public String doA(){return 'Did A';} 12 | public String doB(){return 'Did B';} 13 | public String doC(){return 'Did C';} 14 | } -------------------------------------------------------------------------------- /sfdx-source/apex-mocks/main/classes/fflib_Inheritor.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 63.0 4 | 5 | -------------------------------------------------------------------------------- /sfdx-source/apex-mocks/main/classes/fflib_InvocationOnMock.cls: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017 FinancialForce.com, inc. All rights reserved. 3 | */ 4 | 5 | /** 6 | * An invocation on a mock. 7 | * A place holder for mock, the method that was called and the arguments that were passed. 8 | * @group Core 9 | */ 10 | public with sharing class fflib_InvocationOnMock 11 | { 12 | private fflib_QualifiedMethod qm; 13 | private fflib_MethodArgValues methodArg; 14 | private Object mockInstance; 15 | 16 | /** 17 | * Constructor for the class. 18 | * @param qm The fflib_QualifiedMethod instance to be stored. 19 | * @param args The fflib_MethodArgValues instance to be stored. 20 | * @param mockInstance The mock instance to be stored. 21 | */ 22 | public fflib_InvocationOnMock(fflib_QualifiedMethod qm, fflib_MethodArgValues args, Object mockInstance) 23 | { 24 | this.qm = qm; 25 | this.methodArg = args; 26 | this.mockInstance = mockInstance; 27 | } 28 | 29 | /** 30 | * Returns the argument at the given index. 31 | * @param index The index of the wanted argument. 32 | * @throws ApexMocksException in case the index is out of range. 33 | * @return The argument at the given index. 34 | */ 35 | public Object getArgument(Integer index) 36 | { 37 | validateIndex(index); 38 | return methodArg.argValues[index]; 39 | } 40 | 41 | /** 42 | * Returns the list of arguments passed to the method. 43 | * @return The list of arguments. 44 | */ 45 | public List getArguments() 46 | { 47 | return methodArg.argValues; 48 | } 49 | 50 | /** 51 | * Returns fflib_MethodArgValues instance that represents the arguments passed to the method. 52 | * @return The fflib_MethodArgValues instance that represents the arguments passed to the method. 53 | */ 54 | public fflib_MethodArgValues getMethodArgValues() 55 | { 56 | return methodArg; 57 | } 58 | 59 | /** 60 | * Returns the fflib_QualifiedMethod instance that represent the fully qualified method called within the invocation. 61 | * @return The method stored in the invocation. 62 | */ 63 | public fflib_QualifiedMethod getMethod() 64 | { 65 | return qm; 66 | } 67 | 68 | /** 69 | * Returns the mock object on which the invocation occurs. 70 | * @return The mock object on which the invocation occurs. 71 | */ 72 | public Object getMock() 73 | { 74 | return mockInstance; 75 | } 76 | 77 | private void validateIndex(Integer index) 78 | { 79 | if(index < 0 || index >= methodArg.argValues.size()) 80 | { 81 | throw new fflib_ApexMocks.ApexMocksException('Invalid index, must be greater or equal to zero and less of ' + methodArg.argValues.size()+'.'); 82 | } 83 | } 84 | } -------------------------------------------------------------------------------- /sfdx-source/apex-mocks/main/classes/fflib_InvocationOnMock.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 63.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /sfdx-source/apex-mocks/main/classes/fflib_Match.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 63.0 4 | 5 | -------------------------------------------------------------------------------- /sfdx-source/apex-mocks/main/classes/fflib_MatcherDefinitions.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 63.0 4 | 5 | -------------------------------------------------------------------------------- /sfdx-source/apex-mocks/main/classes/fflib_MatchersReturnValue.cls: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014-2016, FinancialForce.com, inc 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without modification, 6 | * are permitted provided that the following conditions are met: 7 | * 8 | * - Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * - Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * - Neither the name of the FinancialForce.com, inc nor the names of its contributors 14 | * may be used to endorse or promote products derived from this software without 15 | * specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 20 | * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 23 | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | public with sharing class fflib_MatchersReturnValue 27 | { 28 | public List matchers; 29 | public fflib_MethodReturnValue returnValue; 30 | 31 | public fflib_MatchersReturnValue(List matchers, fflib_MethodReturnValue returnValue) 32 | { 33 | this.matchers = matchers; 34 | this.returnValue = returnValue; 35 | } 36 | } -------------------------------------------------------------------------------- /sfdx-source/apex-mocks/main/classes/fflib_MatchersReturnValue.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 63.0 4 | 5 | -------------------------------------------------------------------------------- /sfdx-source/apex-mocks/main/classes/fflib_MethodArgValues.cls: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014-2016, FinancialForce.com, inc 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without modification, 6 | * are permitted provided that the following conditions are met: 7 | * 8 | * - Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * - Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * - Neither the name of the FinancialForce.com, inc nor the names of its contributors 14 | * may be used to endorse or promote products derived from this software without 15 | * specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 20 | * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 23 | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | public with sharing class fflib_MethodArgValues 27 | { 28 | public List argValues; 29 | 30 | /** 31 | * Wrapper object which encapsulates the argument values 32 | * supplied during a given method call. 33 | * @param argValues The 34 | * @return fflib_MethodArgValues The method argument wrapper object 35 | */ 36 | public fflib_MethodArgValues(List argValues) 37 | { 38 | this.argValues = argValues; 39 | } 40 | 41 | /** 42 | * Standard equals override. 43 | * @param other The object whose equality we are verifying 44 | * @return Boolean True if meaningfully equivalent, false otherwise. 45 | */ 46 | public Boolean equals(Object other) 47 | { 48 | if (this === other) 49 | { 50 | return true; 51 | } 52 | 53 | fflib_MethodArgValues that = other instanceof fflib_MethodArgValues ? (fflib_MethodArgValues)other : null; 54 | return that != null && this.argValues == that.argValues; 55 | } 56 | 57 | /** 58 | * Standard hashCode override. 59 | * @return Integer The generated hashCode 60 | */ 61 | public Integer hashCode() 62 | { 63 | Integer prime = 31; 64 | Integer result = 1; 65 | 66 | result = prime * result + ((argValues == null) ? 0 : argValues.hashCode()); 67 | 68 | return result; 69 | } 70 | } -------------------------------------------------------------------------------- /sfdx-source/apex-mocks/main/classes/fflib_MethodArgValues.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 63.0 4 | 5 | -------------------------------------------------------------------------------- /sfdx-source/apex-mocks/main/classes/fflib_MethodCountRecorder.cls: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2014-2017 FinancialForce.com, inc. All rights reserved. 3 | */ 4 | 5 | /** 6 | * @group Core 7 | */ 8 | public with sharing class fflib_MethodCountRecorder 9 | { 10 | /* 11 | * Map of method arguments by type name. 12 | * 13 | * Key: qualifiedMethod 14 | * Object: list of method arguments. 15 | * 16 | * Object: map of count by method call argument. 17 | */ 18 | private static Map> methodArgumentsByTypeName = 19 | new Map>(); 20 | 21 | private static List orderedMethodCalls = 22 | new List(); 23 | 24 | /** 25 | * Getter for the list of the methods ordered calls. 26 | * @return The list of methods called in order. 27 | */ 28 | public static List getOrderedMethodCalls() 29 | { 30 | return orderedMethodCalls; 31 | } 32 | 33 | /** 34 | * Getter for the map of the method's calls with the related arguments. 35 | * @return The map of methods called with the arguments. 36 | */ 37 | public static Map> getMethodArgumentsByTypeName() 38 | { 39 | return methodArgumentsByTypeName; 40 | } 41 | 42 | /** 43 | * Record a method was called on a mock object. 44 | * @param invocation The object holding all the data of the invocation, like the method and arguments and the mock instance. 45 | */ 46 | public void recordMethod(fflib_InvocationOnMock invocation) 47 | { 48 | List methodArgs = 49 | methodArgumentsByTypeName.get(invocation.getMethod()); 50 | 51 | if (methodArgs == null) 52 | { 53 | methodArgs = new List(); 54 | methodArgumentsByTypeName.put(invocation.getMethod(), methodArgs); 55 | } 56 | 57 | methodArgs.add(invocation.getMethodArgValues()); 58 | 59 | orderedMethodCalls.add(invocation); 60 | } 61 | } -------------------------------------------------------------------------------- /sfdx-source/apex-mocks/main/classes/fflib_MethodCountRecorder.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 63.0 4 | 5 | -------------------------------------------------------------------------------- /sfdx-source/apex-mocks/main/classes/fflib_MethodReturnValue.cls: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014-2017, FinancialForce.com, inc 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without modification, 6 | * are permitted provided that the following conditions are met: 7 | * 8 | * - Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * - Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * - Neither the name of the FinancialForce.com, inc nor the names of its contributors 14 | * may be used to endorse or promote products derived from this software without 15 | * specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 20 | * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 23 | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | /** 28 | * @group Core 29 | * Class defining a method return value. 30 | */ 31 | @isTest 32 | public with sharing class fflib_MethodReturnValue 33 | { 34 | private StandardAnswer basicAnswer = new StandardAnswer(); 35 | 36 | /** 37 | * Instance of the implementation of the Answer interface that implements the answer, 38 | * if an answer isn't explicitly set the standard answer will be used, which just returns the stubbed return value. 39 | */ 40 | public fflib_Answer Answer { get; set; } 41 | 42 | /** 43 | * Setup a stubbed return value. 44 | * @param value The value to return from the stubbed method call. 45 | * @return The fflib_MethodReturnValue instance to allow you to chain the methods. 46 | */ 47 | public fflib_MethodReturnValue thenReturn(Object value) 48 | { 49 | thenAnswer(this.basicAnswer.setValue(value)); 50 | return this; 51 | } 52 | 53 | /** 54 | * Setup a stubbed exception. 55 | * @param e The exception to throw from the stubbed method call. 56 | * @return The fflib_MethodReturnValue instance to allow you to chain the methods. 57 | */ 58 | public fflib_MethodReturnValue thenThrow(Exception e) 59 | { 60 | thenAnswer(this.basicAnswer.setValue(e)); 61 | return this; 62 | } 63 | 64 | /** 65 | * Setup a stubbed answer. 66 | * @param answer The answer to run from the stubbed method call. 67 | */ 68 | public void thenAnswer(fflib_Answer answer) 69 | { 70 | this.Answer = answer; 71 | } 72 | 73 | /** 74 | * Setup a list of stubbed return values. 75 | * @param values The values to return from the stubbed method call in consecutive calls. 76 | * @return The fflib_MethodReturnValue instance to allow you to chain the methods. 77 | */ 78 | public fflib_MethodReturnValue thenReturnMulti(List values) 79 | { 80 | thenAnswer(this.basicAnswer.setValues(values)); 81 | return this; 82 | } 83 | 84 | /** 85 | * Setup a list stubbed exceptions. 86 | * @param es The exceptions to throw from the stubbed method call in consecutive calls. 87 | * @return The fflib_MethodReturnValue instance to allow you to chain the methods. 88 | */ 89 | public fflib_MethodReturnValue thenThrowMulti(List es) 90 | { 91 | thenAnswer(this.basicAnswer.setValues(es)); 92 | return this; 93 | } 94 | 95 | /** 96 | * @group Core 97 | * Inner class to handle all the stubs that do not use the thenAnswer method directly. 98 | * For internal use only. 99 | */ 100 | public class StandardAnswer implements fflib_Answer 101 | { 102 | private Integer whichStubReturnIndex = 0; 103 | /* 104 | * It stores the return values for the method stubbed. 105 | * The values would be stored and then returned as part of the standard answer invocation. 106 | */ 107 | private List ReturnValues = new List(); 108 | 109 | /** 110 | * Setter of a single return value. 111 | * @param value The value to be set as return value for the StandardAnswer object. 112 | * @return The StandardAnswer instance. 113 | */ 114 | public StandardAnswer setValue(Object value) 115 | { 116 | ReturnValues.add(value); 117 | return this; 118 | } 119 | 120 | /** 121 | * Setter of the list of return values. 122 | * @param value The value to be set as return value for the StandardAnswer object. 123 | * @return the StandardAnswer instance. 124 | */ 125 | public StandardAnswer setValues(List values) 126 | { 127 | if(values == null || values.size() == 0) 128 | { 129 | throw new fflib_ApexMocks.ApexMocksException( 130 | 'The stubbing is not correct, no return values have been set.'); 131 | } 132 | 133 | ReturnValues.addAll(values); 134 | return this; 135 | } 136 | 137 | /** 138 | * Standard basic implementation for the fflib_Answer answer method, to be used as default answering. 139 | * @param invocation The invocation to answer for. 140 | * @return The ReturnValue for the method stubbed. 141 | */ 142 | public Object answer(fflib_InvocationOnMock invocation) 143 | { 144 | if(ReturnValues == null || ReturnValues.size() == 0) 145 | { 146 | throw new fflib_ApexMocks.ApexMocksException( 147 | 'The stubbing is not correct, no return values have been set.'); 148 | } 149 | 150 | Integer returnValuesSize = ReturnValues.size()-1; 151 | 152 | if(whichStubReturnIndex < returnValuesSize) 153 | { 154 | return ReturnValues[whichStubReturnIndex++]; 155 | } 156 | else 157 | { 158 | return ReturnValues[returnValuesSize]; 159 | } 160 | } 161 | } 162 | } -------------------------------------------------------------------------------- /sfdx-source/apex-mocks/main/classes/fflib_MethodReturnValue.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 63.0 4 | 5 | -------------------------------------------------------------------------------- /sfdx-source/apex-mocks/main/classes/fflib_MethodReturnValueRecorder.cls: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, FinancialForce.com, inc 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without modification, 6 | * are permitted provided that the following conditions are met: 7 | * 8 | * - Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * - Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * - Neither the name of the FinancialForce.com, inc nor the names of its contributors 14 | * may be used to endorse or promote products derived from this software without 15 | * specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 20 | * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 23 | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | /** 28 | * @group Core 29 | */ 30 | public with sharing class fflib_MethodReturnValueRecorder 31 | { 32 | public Boolean Stubbing { get; set; } 33 | 34 | public List DoThrowWhenExceptions { get; set; } 35 | 36 | /** 37 | * Map of matchers by method. 38 | * 39 | * Key: qualifiedMethod 40 | * Object: map of method return values by method. 41 | */ 42 | 43 | private Map> matcherReturnValuesByMethod; 44 | 45 | public fflib_MethodReturnValue MethodReturnValue { get; private set; } 46 | 47 | public fflib_MethodReturnValueRecorder() 48 | { 49 | matcherReturnValuesByMethod = new Map>(); 50 | 51 | MethodReturnValue = null; 52 | } 53 | 54 | /** 55 | * Prepare a stubbed method return value. 56 | * @param invocation The object holding all the data of the invocation, like the method and arguments and the mock instance. 57 | * @return The MethodReturnValue instance. 58 | */ 59 | public fflib_MethodReturnValue prepareMethodReturnValue(fflib_InvocationOnMock invocation) 60 | { 61 | MethodReturnValue = new fflib_MethodReturnValue(); 62 | 63 | List matcherReturnValues = matcherReturnValuesByMethod.get(invocation.getMethod()); 64 | if (matcherReturnValues == null) 65 | { 66 | matcherReturnValues = new List(); 67 | matcherReturnValuesByMethod.put(invocation.getMethod(), matcherReturnValues); 68 | } 69 | 70 | List argValues = invocation.getMethodArgValues().argValues; 71 | 72 | //Register explicit arg values as 'equals' matchers, to preserve old behaviour 73 | if (!fflib_Match.Matching) 74 | { 75 | for (Object arg : argValues) 76 | { 77 | if (arg == null) 78 | fflib_Match.isNull(); 79 | else 80 | fflib_Match.eq(arg); 81 | } 82 | } 83 | 84 | List matchers = fflib_Match.getAndClearMatchers(argValues.size()); 85 | matcherReturnValues.add(new fflib_MatchersReturnValue(matchers, MethodReturnValue)); 86 | 87 | return MethodReturnValue; 88 | } 89 | 90 | /** 91 | * Get the method return value for the given method call. 92 | * @param invocation The object holding all the data of the invocation, like the method and arguments and the mock instance. 93 | * @return The MethodReturnValue instance. 94 | */ 95 | public fflib_MethodReturnValue getMethodReturnValue(fflib_InvocationOnMock invocation) 96 | { 97 | List matchersForMethods = matcherReturnValuesByMethod.get(invocation.getMethod()); 98 | if (matchersForMethods != null) 99 | { 100 | for (Integer i = matchersForMethods.size() - 1; i >= 0; i--) 101 | { 102 | fflib_MatchersReturnValue matchersReturnValue = (fflib_MatchersReturnValue)matchersForMethods.get(i); 103 | if (fflib_Match.matchesAllArgs(invocation.getMethodArgValues(), matchersReturnValue.matchers)) 104 | { 105 | return matchersReturnValue.ReturnValue; 106 | } 107 | } 108 | } 109 | 110 | return null; 111 | } 112 | 113 | /** 114 | * Prepare a stubbed exceptions for a void method. 115 | * @param exps The list of exception to throw. 116 | */ 117 | public void prepareDoThrowWhenExceptions(List exps) 118 | { 119 | DoThrowWhenExceptions = exps; 120 | } 121 | } -------------------------------------------------------------------------------- /sfdx-source/apex-mocks/main/classes/fflib_MethodReturnValueRecorder.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 63.0 4 | 5 | -------------------------------------------------------------------------------- /sfdx-source/apex-mocks/main/classes/fflib_MethodVerifier.cls: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017 FinancialForce.com, inc. All rights reserved. 3 | */ 4 | 5 | /** 6 | * This class implements the actual verification. 7 | * @group Core 8 | */ 9 | public abstract class fflib_MethodVerifier 10 | { 11 | /** 12 | * Verify a method was called on a mock object. 13 | * @param mockInvocation The object holding all the data of the invocation, like the method and arguments and the mock instance. 14 | * @param verificationMode The verification mode that holds the setting about how the verification should be performed. 15 | */ 16 | public void verifyMethodCall(fflib_InvocationOnMock mockInvocation, fflib_VerificationMode verificationMode) 17 | { 18 | validateMode(verificationMode); 19 | 20 | verify(mockinvocation.getMethod(), mockinvocation.getMethodArgValues(), verificationMode); 21 | } 22 | 23 | /* 24 | * Method that actually performs the verify 25 | * @param qm The method to be verified. 26 | * @param methodArg The arguments of the method that needs to be verified. 27 | * @param verificationMode The verification mode that holds the setting about how the verification should be performed. 28 | */ 29 | protected abstract void verify( 30 | fflib_QualifiedMethod qm, 31 | fflib_MethodArgValues methodArg, 32 | fflib_VerificationMode verificationMode); 33 | 34 | /* 35 | * Method that validates the verification mode used in the verify. 36 | * Not all the methods from the fflib_VerificationMode are implemented for the different classes that extends the fflib_MethodVerifier. 37 | * The error is thrown at run time, so this method is called in the method that actually performs the verify. 38 | * @param verificationMode The verification mode that has to have been verified. 39 | * @throws Exception with message for the fflib_VerificationMode not implemented. 40 | */ 41 | protected abstract void validateMode(fflib_VerificationMode verificationMode); 42 | 43 | /* 44 | * Method that performs the argument capturing. 45 | * Captures argument values during verification. 46 | * @param matchers The list of matcher with which a method is verified. 47 | */ 48 | protected void capture(List matchers) 49 | { 50 | for(fflib_IMatcher matcher : matchers) 51 | { 52 | if( matcher instanceof fflib_ArgumentCaptor.AnyObject ) 53 | { 54 | ((fflib_ArgumentCaptor.AnyObject)matcher).storeArgument(); 55 | } 56 | } 57 | } 58 | 59 | protected void throwException( 60 | fflib_QualifiedMethod qm, 61 | String inOrder, 62 | Integer expectedCount, 63 | String qualifier, 64 | Integer methodCount, 65 | String customAssertMessage, 66 | fflib_MethodArgValues expectedArguments, 67 | List expectedMatchers, 68 | List actualArguments) 69 | { 70 | String template = 'EXPECTED COUNT: {0}{1}{2}' // qualified expected count (e.g. "3 or fewer times in order") 71 | + '\nACTUAL COUNT: {3}' // actual count 72 | + '\nMETHOD: {4}' // method signature 73 | + '{5}'; // custom assert message 74 | 75 | String expectedDescription = ''; 76 | String actualDescription = ''; 77 | 78 | if (qm.hasArguments()) 79 | { 80 | template += '\n---' // separator 81 | + '\nACTUAL ARGS: {6}' // actual args 82 | + '\n---' // separator 83 | + '\nEXPECTED ARGS: {7}'; // matcher descriptions 84 | 85 | if (expectedMatchers == null) 86 | { 87 | expectedDescription = describe(expectedArguments); 88 | } 89 | else 90 | { 91 | expectedDescription = describe(expectedMatchers); 92 | } 93 | actualDescription = describe(actualArguments); 94 | } 95 | 96 | String message = String.format(template, new List{ 97 | '' + expectedCount, 98 | String.isBlank(qualifier) ? '' : ('' + qualifier), 99 | inOrder, 100 | '' + methodCount, 101 | '' + qm, 102 | String.isBlank(customAssertMessage) ? '' : ('\n' + customAssertMessage), 103 | actualDescription, 104 | expectedDescription 105 | }); 106 | 107 | throw new fflib_ApexMocks.ApexMocksException(message); 108 | } 109 | 110 | private static String describe(List matchers) 111 | { 112 | List descriptions = new List(); 113 | for (fflib_IMatcher matcher : matchers) 114 | { 115 | descriptions.add('' + matcher); 116 | } 117 | 118 | return String.join(descriptions, ', '); 119 | } 120 | 121 | private static String describe(List valuesFromAllInvocations) 122 | { 123 | List descriptions = new List(); 124 | if (valuesFromAllInvocations != null) 125 | { 126 | for (fflib_MethodArgValues valuesFromOneInvocation : valuesFromAllInvocations) 127 | { 128 | descriptions.add(describe(valuesFromOneInvocation)); 129 | } 130 | } 131 | 132 | return '(' + String.join(descriptions, '), (') + ')'; 133 | } 134 | 135 | private static String describe(fflib_MethodArgValues values) 136 | { 137 | List descriptions = new List(); 138 | for (Object value : values.argValues) 139 | { 140 | try 141 | { 142 | // Attempt to JSON serialize - that way it doesn't truncate SObject fields etc. 143 | // Bear in mind that something are not JSON serializable, e.g. things with circular references. 144 | descriptions.add(JSON.serialize(value)); 145 | } 146 | catch (Exception error) 147 | { 148 | descriptions.add('' + value); 149 | } 150 | } 151 | 152 | return String.join(descriptions, ', '); 153 | } 154 | } -------------------------------------------------------------------------------- /sfdx-source/apex-mocks/main/classes/fflib_MethodVerifier.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 63.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /sfdx-source/apex-mocks/main/classes/fflib_QualifiedMethod.cls: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2017 FinancialForce.com, inc. All rights reserved. 3 | */ 4 | public with sharing class fflib_QualifiedMethod 5 | { 6 | public final Object mockInstance; 7 | public final String typeName; 8 | public final String methodName; 9 | public final List methodArgTypes; 10 | 11 | public fflib_QualifiedMethod(String typeName, String methodName, List methodArgTypes) 12 | { 13 | this(typeName, methodName, methodArgTypes, null); 14 | } 15 | 16 | public fflib_QualifiedMethod(String typeName, String methodName, List methodArgTypes, Object mockInstance) 17 | { 18 | this.mockInstance = mockInstance; 19 | this.typeName = typeName; 20 | this.methodName = methodName; 21 | this.methodArgTypes = methodArgTypes; 22 | } 23 | 24 | /** 25 | * Standard equals override. 26 | * @param other The object whose equality we are verifying 27 | * @return Boolean True if meaningfully equivalent, false otherwise. 28 | */ 29 | public Boolean equals(Object other) 30 | { 31 | if (this === other) 32 | { 33 | return true; 34 | } 35 | 36 | fflib_QualifiedMethod that = other instanceof fflib_QualifiedMethod ? (fflib_QualifiedMethod)other : null; 37 | 38 | return that != null 39 | && (this.mockInstance === that.mockInstance || !fflib_ApexMocksConfig.HasIndependentMocks) 40 | && this.typeName == that.typeName 41 | && this.methodName == that.methodName 42 | && this.methodArgTypes == that.methodArgTypes; 43 | } 44 | 45 | /** 46 | * Standard hashCode override. 47 | * @return Integer The generated hashCode 48 | */ 49 | public Integer hashCode() 50 | { 51 | Integer prime = 31; 52 | Integer result = 1; 53 | 54 | if (fflib_ApexMocksConfig.HasIndependentMocks) 55 | { 56 | result = prime * result + ((mockInstance == null) ? 0 : mockInstance.hashCode()); 57 | } 58 | result = prime * result + ((methodArgTypes == null) ? 0 : methodArgTypes.hashCode()); 59 | result = prime * result + ((methodName == null) ? 0 : methodName.hashCode()); 60 | result = prime * result + ((typeName == null) ? 0 : typeName.hashCode()); 61 | 62 | return result; 63 | } 64 | 65 | /** 66 | * Standard toString override. 67 | * @return String The human friendly description of the method. 68 | */ 69 | public override String toString() 70 | { 71 | return typeName + '.' + methodName + methodArgTypes; 72 | } 73 | 74 | /** 75 | * Predicate describing whether the qualified method accepts arguments or not. 76 | * @return True if the method accepts arguments. 77 | */ 78 | public Boolean hasArguments() 79 | { 80 | return this.methodArgTypes != null && !this.methodArgTypes.isEmpty(); 81 | } 82 | } -------------------------------------------------------------------------------- /sfdx-source/apex-mocks/main/classes/fflib_QualifiedMethod.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 63.0 4 | 5 | -------------------------------------------------------------------------------- /sfdx-source/apex-mocks/main/classes/fflib_QualifiedMethodAndArgValues.cls: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2016-2017 FinancialForce.com, inc. All rights reserved. 3 | */ 4 | 5 | /** 6 | * @group Core 7 | */ 8 | public with sharing class fflib_QualifiedMethodAndArgValues 9 | { 10 | private final fflib_QualifiedMethod qm; 11 | private final fflib_MethodArgValues args; 12 | private final Object mockInstance; 13 | 14 | public fflib_QualifiedMethodAndArgValues(fflib_QualifiedMethod qm, fflib_MethodArgValues args, Object mockInstance) 15 | { 16 | this.qm = qm; 17 | this.args = args; 18 | this.mockInstance = mockInstance; 19 | } 20 | 21 | public fflib_QualifiedMethod getQualifiedMethod() 22 | { 23 | return qm; 24 | } 25 | 26 | public fflib_MethodArgValues getMethodArgValues() 27 | { 28 | return args; 29 | } 30 | 31 | public Object getMockInstance() 32 | { 33 | return mockInstance; 34 | } 35 | 36 | public override String toString() 37 | { 38 | return qm + ' with args: [' + String.join(args.argValues, '],[') + ']'; 39 | } 40 | } -------------------------------------------------------------------------------- /sfdx-source/apex-mocks/main/classes/fflib_QualifiedMethodAndArgValues.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 63.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /sfdx-source/apex-mocks/main/classes/fflib_System.cls: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 FinancialForce.com, inc. All rights reserved. 3 | */ 4 | 5 | /** 6 | * @group Core 7 | * Contains counterparts for helper methods in the native System class. 8 | */ 9 | 10 | public class fflib_System 11 | { 12 | /** 13 | * Verifies that the supplied argument is meaningfully equivalent to the expected argument, as defined by its matcher. 14 | * See fflib_SystemTest for examples of usage. 15 | * @param ignoredRetval Dummy value, returned on registering an fflib_IMatcher. 16 | * @param value The object instance upon which we are checking equality. 17 | */ 18 | public static void assertEquals(Object ignoredRetval, Object value) 19 | { 20 | assertEquals(ignoredRetval, value, null); 21 | } 22 | 23 | /** 24 | * Verifies that the supplied argument is meaningfully equivalent to the expected argument, as defined by its matcher. 25 | * See fflib_SystemTest for examples of usage. 26 | * @param ignoredRetval Dummy value, returned on registering an fflib_IMatcher. 27 | * @param value The object instance upon which we are checking equality. 28 | * @param customAssertMessage Provides context or additional information for the assertion. 29 | */ 30 | public static void assertEquals(Object ignoredRetval, Object value, String customAssertMessage) 31 | { 32 | fflib_IMatcher matcher = null; 33 | try 34 | { 35 | List matchers = fflib_Match.getAndClearMatchers(1); 36 | matcher = matchers[0]; 37 | } 38 | catch (fflib_ApexMocks.ApexMocksException e) 39 | { 40 | throw new fflib_ApexMocks.ApexMocksException('fflib_System.assertEquals expects you to register exactly 1 fflib_IMatcher (typically through the helpers in fflib_Match).'); 41 | } 42 | 43 | if (!matcher.matches(value)) 44 | { 45 | throw new fflib_ApexMocks.ApexMocksException(String.format('Expected : {0}, Actual: {1}{2}', new String[]{ 46 | String.valueOf(matcher), 47 | String.valueOf(value), 48 | String.isBlank(customAssertMessage) ? '' : (' -- ' + customAssertMessage) 49 | })); 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /sfdx-source/apex-mocks/main/classes/fflib_System.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 63.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /sfdx-source/apex-mocks/main/classes/fflib_VerificationMode.cls: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017 FinancialForce.com, inc. All rights reserved. 3 | */ 4 | 5 | /** 6 | * This class implements the verification modes with Mockito syntax style. 7 | * It can be used in the classic verify and in the ordered verify. 8 | * @group Core 9 | */ 10 | public with sharing class fflib_VerificationMode 11 | { 12 | public Integer VerifyMin {get; set;} 13 | public Integer VerifyMax {get; set;} 14 | public String CustomAssertMessage { get; set; } 15 | 16 | public enum ModeName {times, atLeast, atMost, between, atLeastOnce, calls} 17 | 18 | public ModeName Method; 19 | 20 | public fflib_VerificationMode() 21 | { 22 | VerifyMin = 1; 23 | VerifyMax = null; 24 | CustomAssertMessage = null; 25 | Method = null; 26 | } 27 | 28 | /** 29 | * Sets how many times the method is expected to be called. 30 | * For InOrder verification we copy Mockito behavior which is as follows; 31 | *
    32 | *
  • Consume the specified number of matching invocations, ignoring non-matching invocations in between
  • 33 | *
  • Fail an assert if the very next invocation matches, but additional matches can still exist so long as at least one non-matching invocation exists before them
  • 34 | *
35 | * For example if you had a(); a(); b(); a(); 36 | * then inOrder.verify(myMock, 2)).a(); or inOrder.verify(myMock, 3)).a(); would pass but not inOrder.verify(myMock, 1)).a(); 37 | * @param times The number of times you expect the method to have been called. 38 | * @return The fflib_VerificationMode object instance with the proper settings. 39 | */ 40 | public fflib_VerificationMode times(Integer times) 41 | { 42 | this.Method = ModeName.times; 43 | this.VerifyMin = this.VerifyMax = times; 44 | return this; 45 | } 46 | 47 | /** 48 | * Sets a custom assert message for the verify. 49 | * @param customAssertMessage The custom message for the assert in case the assert is false. The custom message is queued to the default message. 50 | * @return The fflib_VerificationMode object instance with the proper settings. 51 | */ 52 | public fflib_VerificationMode description(String customAssertMessage) 53 | { 54 | this.CustomAssertMessage = customAssertMessage; 55 | return this; 56 | } 57 | 58 | /** 59 | * Sets the minimum number of times the method is expected to be called. 60 | * With the InOrder verification it performs a greedy verification, which means it would consume all the instances of the method verified. 61 | * @param atLeastTimes The minimum number of times you expect the method to have been called. 62 | * @return The fflib_VerificationMode object instance with the proper settings. 63 | */ 64 | public fflib_VerificationMode atLeast(Integer atLeastTimes) 65 | { 66 | this.Method = ModeName.atLeast; 67 | this.VerifyMin = atLeastTimes; 68 | 69 | return this; 70 | } 71 | 72 | /** 73 | * Sets the maximum number of times the method is expected to be called. Not available in the InOrder verification. 74 | * @param atMostTimes The maximum number of times the method is expected to be called. 75 | * @return The fflib_VerificationMode object instance with the proper settings. 76 | */ 77 | public fflib_VerificationMode atMost(Integer atMostTimes) 78 | { 79 | this.Method = ModeName.atMost; 80 | this.VerifyMax = atMostTimes; 81 | 82 | return this; 83 | } 84 | 85 | /** 86 | * Sets that the method is called at least once. 87 | * With the InOrder verification it performs a greedy verification, which means it would consume all the instances of the method verified. 88 | * @return The fflib_VerificationMode object instance with the proper settings. 89 | */ 90 | public fflib_VerificationMode atLeastOnce() 91 | { 92 | this.Method = ModeName.atLeastOnce; 93 | this.VerifyMin = 1; 94 | 95 | return this; 96 | } 97 | 98 | /** 99 | * Sets the range of how many times the method is expected to be called. Not available in the InOrder verification. 100 | * @param atLeastTimes The minimum number of times you expect the method to have been called. 101 | * @param atMostTimes The maximum number of times the method is expected to be called. 102 | * @return The fflib_VerificationMode object instance with the proper settings. 103 | */ 104 | public fflib_VerificationMode between(Integer atLeastTimes, Integer atMostTimes) 105 | { 106 | this.Method = ModeName.between; 107 | this.VerifyMin = atLeastTimes; 108 | this.VerifyMax = atMostTimes; 109 | 110 | return this; 111 | } 112 | 113 | /** 114 | * Sets that the method is not expected to be called. 115 | * @return The fflib_VerificationMode object instance with the proper settings. 116 | */ 117 | public fflib_VerificationMode never() 118 | { 119 | this.VerifyMin = fflib_ApexMocks.NEVER; 120 | this.VerifyMax = fflib_ApexMocks.NEVER; 121 | 122 | return this; 123 | } 124 | 125 | /** 126 | * Sets how many times the method is expected to be called for an InOrder verifier. Available Only with the InOrder verification. 127 | * A verification mode using calls will not fail if the method is called more times than expected. 128 | * @param callingTimes The number of times you expect the method to have been called in the InOrder verifying (no greedy verify). 129 | * @return The fflib_VerificationMode object instance with the proper settings. 130 | */ 131 | public fflib_VerificationMode calls(Integer callingTimes) 132 | { 133 | this.Method = ModeName.calls; 134 | this.VerifyMin = callingTimes; 135 | this.VerifyMax = null; 136 | 137 | return this; 138 | } 139 | } -------------------------------------------------------------------------------- /sfdx-source/apex-mocks/main/classes/fflib_VerificationMode.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 63.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /sfdx-source/apex-mocks/test/classes/fflib_AnswerTest.cls: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017 FinancialForce.com, inc. All rights reserved. 3 | */ 4 | 5 | /** 6 | * @nodoc 7 | */ 8 | @isTest 9 | private class fflib_AnswerTest 10 | { 11 | 12 | private static fflib_InvocationOnMock actualInvocation = null; 13 | 14 | @isTest 15 | static void thatAnswersWithException() 16 | { 17 | // Given 18 | fflib_ApexMocks mocks = new fflib_ApexMocks(); 19 | fflib_MyList mockList = (fflib_MyList)mocks.mock(fflib_MyList.class); 20 | 21 | mocks.startStubbing(); 22 | mocks.when(mockList.get2(0, 'Hi hi Hello Hi hi')).thenAnswer(new fflib_AnswerTest.ExceptionForAnswer()); 23 | mocks.stopStubbing(); 24 | 25 | // When 26 | try 27 | { 28 | mockList.get2(0, 'Hi hi Hello Hi hi'); 29 | System.Assert.fail('an exception is expected to be thrown on the answer execution'); 30 | } 31 | catch(fflib_ApexMocks.ApexMocksException ansExpt) 32 | { 33 | String expectedMessage = 'an error occurs on the execution of the answer'; 34 | // Then 35 | System.Assert.areEqual(expectedMessage, ansExpt.getMessage(), 'the message from the answer is not as expected'); 36 | } 37 | } 38 | 39 | @isTest 40 | static void thatStoresMethodIntoInvocationOnMock() 41 | { 42 | // Given 43 | fflib_ApexMocks mocks = new fflib_ApexMocks(); 44 | fflib_MyList mockList = (fflib_MyList)mocks.mock(fflib_MyList.class); 45 | 46 | mocks.startStubbing(); 47 | mocks.when(mockList.get2(0, 'Hi hi Hello Hi hi')).thenAnswer(new fflib_AnswerTest.BasicAnswer()); 48 | mocks.stopStubbing(); 49 | 50 | // When 51 | mockList.get2(0, 'Hi hi Hello Hi hi'); 52 | 53 | // Then 54 | 55 | Object methodCalled = actualInvocation.getMethod(); 56 | System.Assert.isInstanceOfType(methodCalled, fflib_QualifiedMethod.class, 'the object returned is not a method as expected'); 57 | 58 | String expectedMethodSignature = fflib_MyList.getStubClassName() + '.get2(Integer, String)'; 59 | System.Assert.areEqual(expectedMethodSignature, ((fflib_QualifiedMethod)methodCalled).toString(), ' the method is no the one expected'); 60 | } 61 | 62 | @isTest 63 | static void thatAnswerOnlyForTheMethodStubbedWithAnswer() 64 | { 65 | // Given 66 | fflib_ApexMocks mocks = new fflib_ApexMocks(); 67 | fflib_MyList mockList = (fflib_MyList)mocks.mock(fflib_MyList.class); 68 | 69 | mocks.startStubbing(); 70 | mocks.when(mockList.get(3)).thenReturn('ted'); 71 | mocks.when(mockList.get2(0, 'Hi hi Hello Hi hi')).thenAnswer(new fflib_AnswerTest.BasicAnswer()); 72 | mocks.stopStubbing(); 73 | 74 | // When 75 | mockList.add('one'); 76 | String noAnswered = mockList.get(3); 77 | mockList.get2(0, 'Hi hi Hello Hi hi'); 78 | 79 | // Then 80 | Object methodCalled = actualInvocation.getMethod(); 81 | System.Assert.isInstanceOfType(methodCalled, fflib_QualifiedMethod.class, 'the object returned is not a method as expected'); 82 | 83 | String expectedMethodSignature = fflib_MyList.getStubClassName() + '.get2(Integer, String)'; 84 | System.Assert.areEqual(expectedMethodSignature, ((fflib_QualifiedMethod)methodCalled).toString(), ' the method is no the one expected'); 85 | 86 | System.Assert.areEqual('ted', noAnswered, 'the get method should have returned the stubbed string'); 87 | } 88 | 89 | @isTest 90 | static void thatMultipleAnswersAreHandled() 91 | { 92 | // Given 93 | fflib_ApexMocks mocks = new fflib_ApexMocks(); 94 | fflib_MyList mockList = (fflib_MyList)mocks.mock(fflib_MyList.class); 95 | 96 | mocks.startStubbing(); 97 | mocks.when(mockList.get(3)).thenAnswer(new fflib_AnswerTest.FirstAnswer()); 98 | mocks.when(mockList.get2(0, 'Hi hi Hello Hi hi')).thenAnswer(new fflib_AnswerTest.SecondAnswer()); 99 | mocks.stopStubbing(); 100 | 101 | // When 102 | mockList.add('one'); 103 | String answer1 = mockList.get(3); 104 | String answer2 = mockList.get2(0, 'Hi hi Hello Hi hi'); 105 | 106 | System.Assert.areEqual('this is the first answer', answer1, 'the answer wasnt the one expected'); 107 | System.Assert.areEqual('and this is the second one', answer2, 'the answer wasnt the one expected'); 108 | } 109 | 110 | @isTest 111 | static void thatStoresMockInstanceIntoInvocationOnMock() 112 | { 113 | // Given 114 | fflib_ApexMocks mocks = new fflib_ApexMocks(); 115 | fflib_MyList mockList = (fflib_MyList)mocks.mock(fflib_MyList.class); 116 | 117 | mocks.startStubbing(); 118 | mocks.when(mockList.get2(0, 'Hi hi Hello Hi hi')).thenAnswer(new fflib_AnswerTest.BasicAnswer()); 119 | mocks.stopStubbing(); 120 | 121 | // When 122 | String mockCalled = mockList.get2(0, 'Hi hi Hello Hi hi'); 123 | 124 | // Then 125 | System.Assert.isInstanceOfType(actualInvocation.getMock(), fflib_MyList.IList.class, 'the object returned is not a mock instance as expected'); 126 | System.Assert.areEqual(mockList, actualInvocation.getMock(), 'the mock returned should be the mockList used in the stubbing'); 127 | } 128 | 129 | @isTest 130 | static void thatMethodsParametersAreAccessible() 131 | { 132 | // Given 133 | fflib_ApexMocks mocks = new fflib_ApexMocks(); 134 | fflib_MyList mockList = (fflib_MyList)mocks.mock(fflib_MyList.class); 135 | 136 | mocks.startStubbing(); 137 | mocks.when(mockList.get2(0, 'Hi hi Hello Hi hi')).thenAnswer(new fflib_AnswerTest.ProcessArgumentAnswer()); 138 | mocks.stopStubbing(); 139 | 140 | // When 141 | String actualValue = mockList.get2(0, 'Hi hi Hello Hi hi'); 142 | 143 | // Then 144 | System.Assert.areEqual('Bye hi Hello Bye hi', actualValue, 'the answer is not correct'); 145 | } 146 | 147 | @isTest 148 | static void thatAnswerOnlyForTheStubbedParameter() 149 | { 150 | // Given 151 | fflib_ApexMocks mocks = new fflib_ApexMocks(); 152 | fflib_MyList mockList = (fflib_MyList)mocks.mock(fflib_MyList.class); 153 | 154 | mocks.startStubbing(); 155 | mocks.when(mockList.get2(0, 'Hi hi Hello Hi hi')).thenAnswer(new fflib_AnswerTest.ProcessArgumentAnswer()); 156 | mocks.stopStubbing(); 157 | 158 | // When 159 | String actualValue1 = mockList.get2(0, 'some string for my method'); 160 | String actualValue2 = mockList.get2(0, 'Hi hi Hello Hi hi'); 161 | String actualValue3 = mockList.get2(0, 'another string for the same method'); 162 | 163 | // Then 164 | System.Assert.areEqual('Bye hi Hello Bye hi', actualValue2, 'the answer is not correct'); 165 | System.Assert.areEqual(null, actualValue1, 'the answer is not correct'); 166 | System.Assert.areEqual(null, actualValue3, 'the answer is not correct'); 167 | } 168 | 169 | @isTest 170 | static void thatMethodsParametersAreAccessibleWhenCalledWithMatchers() 171 | { 172 | // Given 173 | fflib_ApexMocks mocks = new fflib_ApexMocks(); 174 | fflib_MyList mockList = (fflib_MyList)mocks.mock(fflib_MyList.class); 175 | 176 | mocks.startStubbing(); 177 | mocks.when(mockList.get2(fflib_Match.anyInteger(), fflib_Match.anyString())).thenAnswer(new fflib_AnswerTest.ProcessArgumentAnswer()); 178 | mocks.stopStubbing(); 179 | 180 | // When 181 | String actualValue = mockList.get2(0, 'Hi hi Hello Hi hi'); 182 | 183 | // Then 184 | System.Assert.areEqual('Bye hi Hello Bye hi', actualValue, 'the answer is not correct'); 185 | } 186 | 187 | @isTest 188 | static void thatExceptionIsThrownWhenAccessOutOfIndexArgument() 189 | { 190 | // Given 191 | fflib_ApexMocks mocks = new fflib_ApexMocks(); 192 | fflib_MyList mockList = (fflib_MyList)mocks.mock(fflib_MyList.class); 193 | 194 | mocks.startStubbing(); 195 | mocks.when(mockList.get2(0, 'Hi hi Hello Hi hi')).thenAnswer(new fflib_AnswerTest.ExceptionForArgumentsOutOfBound()); 196 | mocks.stopStubbing(); 197 | 198 | // When 199 | String actualValue = mockList.get2(0, 'Hi hi Hello Hi hi'); 200 | } 201 | 202 | @isTest 203 | static void thatExceptionIsThrownWhenAccessNegativeIndexArgument() 204 | { 205 | // Given 206 | fflib_ApexMocks mocks = new fflib_ApexMocks(); 207 | fflib_MyList mockList = (fflib_MyList)mocks.mock(fflib_MyList.class); 208 | 209 | mocks.startStubbing(); 210 | mocks.when(mockList.get2(0, 'Hi hi Hello Hi hi')).thenAnswer(new fflib_AnswerTest.ExceptionForNegativeArgumentIndex()); 211 | mocks.stopStubbing(); 212 | 213 | // When 214 | String actualValue = mockList.get2(0, 'Hi hi Hello Hi hi'); 215 | } 216 | 217 | @isTest 218 | static void thatArgumentListEmptyForMethodWithNoArgument() 219 | { 220 | // Given 221 | fflib_ApexMocks mocks = new fflib_ApexMocks(); 222 | fflib_MyList mockList = (fflib_MyList)mocks.mock(fflib_MyList.class); 223 | 224 | mocks.startStubbing(); 225 | mocks.when(mockList.isEmpty()).thenAnswer(new fflib_AnswerTest.ArgumentListEmptyForMethodWithNoArgument()); 226 | mocks.stopStubbing(); 227 | 228 | // When 229 | Boolean actualValue = mockList.isEmpty(); 230 | } 231 | 232 | @isTest 233 | static void thatAnswerToVoidMethod() 234 | { 235 | // Given 236 | fflib_ApexMocks mocks = new fflib_ApexMocks(); 237 | fflib_MyList mockList = (fflib_MyList)mocks.mock(fflib_MyList.class); 238 | 239 | mocks.startStubbing(); 240 | ((fflib_MyList) mocks.doAnswer(new fflib_AnswerTest.BasicAnswer(), mockList)).addMore('Hi hi Hello Hi hi'); 241 | mocks.stopStubbing(); 242 | 243 | // When 244 | mockList.addMore('Hi hi Hello Hi hi'); 245 | 246 | // Then 247 | Object methodCalled = actualInvocation.getMethod(); 248 | System.Assert.isInstanceOfType(methodCalled, fflib_QualifiedMethod.class, 'the object returned is not a method as expected'); 249 | 250 | String expectedMethodSignature = fflib_MyList.getStubClassName() + '.addMore(String)'; 251 | System.Assert.areEqual(expectedMethodSignature, ((fflib_QualifiedMethod)methodCalled).toString(), 'Unexpected method name: ' + methodCalled); 252 | } 253 | 254 | @isTest 255 | static void thatAnswerToVoidAndNotVoidMethods() 256 | { 257 | // Given 258 | fflib_ApexMocks mocks = new fflib_ApexMocks(); 259 | fflib_MyList mockList = (fflib_MyList)mocks.mock(fflib_MyList.class); 260 | 261 | mocks.startStubbing(); 262 | ((fflib_MyList) mocks.doAnswer(new fflib_AnswerTest.FirstAnswer(), mockList)).get(3); 263 | ((fflib_MyList) mocks.doAnswer(new fflib_AnswerTest.BasicAnswer(), mockList)).addMore('Hi hi Hello Hi hi'); 264 | ((fflib_MyList) mocks.doAnswer(new fflib_AnswerTest.SecondAnswer(), mockList)).get2(4, 'Hi hi Hello Hi hi'); 265 | mocks.stopStubbing(); 266 | 267 | // When 268 | String answer1 = mockList.get(3); 269 | String answer2 = mockList.get2(4, 'Hi hi Hello Hi hi'); 270 | mockList.addMore('Hi hi Hello Hi hi'); 271 | 272 | // Then 273 | Object methodCalled = actualInvocation.getMethod(); 274 | System.Assert.isInstanceOfType(methodCalled, fflib_QualifiedMethod.class, 'the object returned is not a method as expected'); 275 | 276 | String expectedMethodSignature = fflib_MyList.getStubClassName() + '.addMore(String)'; 277 | System.Assert.areEqual(expectedMethodSignature, ((fflib_QualifiedMethod)methodCalled).toString(), 278 | 'the last method called should be the addMore, so should be the last to set the actualInvocation variable.'); 279 | 280 | System.Assert.areEqual('this is the first answer', answer1, 'the answer was not the one expected'); 281 | System.Assert.areEqual('and this is the second one', answer2, 'the answer was not the one expected'); 282 | } 283 | 284 | @isTest 285 | static void thatAnswerToDifferentVoidMethods() 286 | { 287 | // Given 288 | fflib_ApexMocks mocks = new fflib_ApexMocks(); 289 | fflib_MyList mockList = (fflib_MyList)mocks.mock(fflib_MyList.class); 290 | 291 | fflib_AnswerTest.FirstAnswer answer1 = new fflib_AnswerTest.FirstAnswer(); 292 | fflib_AnswerTest.SecondAnswer answer2 = new fflib_AnswerTest.SecondAnswer(); 293 | 294 | System.Assert.areEqual(null, answer1.getMessage(), 'the answer message should be null at this stage'); 295 | System.Assert.areEqual(null, answer2.getMessage(), 'the answer message should be null at this stage'); 296 | 297 | mocks.startStubbing(); 298 | ((fflib_MyList) mocks.doAnswer(answer1, mockList)).addMore('Hi hi Hello Hi hi'); 299 | ((fflib_MyList) mocks.doAnswer(answer2, mockList)).add('Hello'); 300 | mocks.stopStubbing(); 301 | 302 | // When 303 | mockList.addMore('Hi hi Hello Hi hi'); 304 | mockList.add('Hello'); 305 | 306 | // Then 307 | System.Assert.areEqual('this is the first answer', answer1.getMessage(), 'the answer was not the one expected'); 308 | System.Assert.areEqual('and this is the second one', answer2.getMessage(), 'the answer was not the one expected'); 309 | } 310 | 311 | //Answers 312 | 313 | public class BasicAnswer implements fflib_Answer 314 | { 315 | public Object answer(fflib_InvocationOnMock invocation) 316 | { 317 | actualInvocation = invocation; 318 | return null; 319 | } 320 | } 321 | 322 | public class ExceptionForAnswer implements fflib_Answer 323 | { 324 | public Object answer(fflib_InvocationOnMock invocation) 325 | { 326 | actualInvocation = invocation; 327 | 328 | throw new fflib_ApexMocks.ApexMocksException('an error occurs on the execution of the answer'); 329 | } 330 | } 331 | 332 | public class ExceptionForArgumentsOutOfBound implements fflib_Answer 333 | { 334 | public Object answer(fflib_InvocationOnMock invocation) 335 | { 336 | actualInvocation = invocation; 337 | 338 | try 339 | { 340 | Object noExistingObj = invocation.getArgument(2); 341 | System.Assert.fail('an exception was expected because the argument in the method are only 2'); 342 | } 343 | catch(fflib_ApexMocks.ApexMocksException exp) 344 | { 345 | String expectedMessage = 'Invalid index, must be greater or equal to zero and less of 2.'; 346 | String actualMessage = exp.getMessage(); 347 | System.Assert.areEqual(expectedMessage, actualMessage, 'the message return by the exception is not as expected'); 348 | } 349 | return null; 350 | } 351 | } 352 | 353 | public class ExceptionForNegativeArgumentIndex implements fflib_Answer 354 | { 355 | public Object answer(fflib_InvocationOnMock invocation) 356 | { 357 | actualInvocation = invocation; 358 | 359 | try 360 | { 361 | Object noExistingObj = invocation.getArgument(-1); 362 | System.Assert.fail('an exception was expected because the argument index cannot be negative'); 363 | } 364 | catch(fflib_ApexMocks.ApexMocksException exp) 365 | { 366 | String expectedMessage = 'Invalid index, must be greater or equal to zero and less of 2.'; 367 | String actualMessage = exp.getMessage(); 368 | System.Assert.areEqual(expectedMessage, actualMessage, 'the message return by the exception is not as expected'); 369 | } 370 | return null; 371 | } 372 | } 373 | 374 | public class ArgumentListEmptyForMethodWithNoArgument implements fflib_Answer 375 | { 376 | public Object answer(fflib_InvocationOnMock invocation) 377 | { 378 | actualInvocation = invocation; 379 | 380 | List emptyList = invocation.getArguments(); 381 | 382 | System.Assert.areEqual(0, emptyList.size(), 'the argument list from a method without arguments should be empty'); 383 | 384 | return null; 385 | } 386 | } 387 | 388 | public class FirstAnswer implements fflib_Answer 389 | { 390 | private String answerMessage; 391 | 392 | public String getMessage() 393 | { 394 | return this.answerMessage; 395 | } 396 | 397 | public Object answer(fflib_InvocationOnMock invocation) 398 | { 399 | actualInvocation = invocation; 400 | 401 | this.answerMessage = 'this is the first answer'; 402 | 403 | return answerMessage; 404 | } 405 | } 406 | 407 | public class SecondAnswer implements fflib_Answer 408 | { 409 | private String answerMessage; 410 | 411 | public String getMessage() 412 | { 413 | return this.answerMessage; 414 | } 415 | 416 | public Object answer(fflib_InvocationOnMock invocation) 417 | { 418 | actualInvocation = invocation; 419 | 420 | this.answerMessage = 'and this is the second one'; 421 | 422 | return answerMessage; 423 | } 424 | } 425 | 426 | public class ProcessArgumentAnswer implements fflib_Answer 427 | { 428 | public Object answer(fflib_InvocationOnMock invocation) 429 | { 430 | actualInvocation = invocation; 431 | 432 | String argument = (String) invocation.getArgument(1); 433 | System.Assert.areNotEqual(null, argument, ' the argument should have some value'); 434 | argument = argument.replace('Hi', 'Bye'); 435 | return argument; 436 | } 437 | } 438 | } -------------------------------------------------------------------------------- /sfdx-source/apex-mocks/test/classes/fflib_AnswerTest.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 63.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /sfdx-source/apex-mocks/test/classes/fflib_AnyOrderTest.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 63.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /sfdx-source/apex-mocks/test/classes/fflib_ApexMocksTest.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 63.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /sfdx-source/apex-mocks/test/classes/fflib_ApexMocksUtilsTest.cls: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014-2016, FinancialForce.com, inc 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without modification, 6 | * are permitted provided that the following conditions are met: 7 | * 8 | * - Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * - Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * - Neither the name of the FinancialForce.com, inc nor the names of its contributors 14 | * may be used to endorse or promote products derived from this software without 15 | * specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 20 | * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 23 | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | @isTest 27 | public class fflib_ApexMocksUtilsTest 28 | { 29 | public static Schema.FieldSet findAnyFieldSet() 30 | { 31 | for (Schema.SObjectType objectType : Schema.getGlobalDescribe().values()) 32 | { 33 | for (Schema.FieldSet fs : objectType.getDescribe().FieldSets.getMap().values()) 34 | { 35 | return fs; 36 | } 37 | } 38 | 39 | return null; 40 | } 41 | 42 | @isTest 43 | private static void makeRelationship_returnsObjectsWithRelationFieldSet() 44 | { 45 | //Given 46 | Account acc = new Account( 47 | Id = fflib_IDGenerator.generate(Account.SObjectType), 48 | Name = 'AccName', 49 | NumberOfEmployees = 7 50 | ); 51 | 52 | Contact contact1 = new Contact( 53 | Id = fflib_IDGenerator.generate(Contact.SObjectType), 54 | DoNotCall = true 55 | ); 56 | 57 | Contact contact2 = new Contact( 58 | Id = fflib_IDGenerator.generate(Contact.SObjectType), 59 | DoNotCall = false 60 | ); 61 | 62 | //When 63 | Account accWithRelationships = ((List)fflib_ApexMocksUtils.makeRelationship( 64 | List.class, 65 | new List { acc }, 66 | Contact.AccountId, 67 | new List> { new List { contact1, contact2 }} 68 | ))[0]; 69 | 70 | //Then 71 | System.Assert.areEqual(acc.Id, accWithRelationships.Id); 72 | System.Assert.areEqual(acc.Name, accWithRelationships.Name); 73 | System.Assert.areEqual(acc.NumberOfEmployees, accWithRelationships.NumberOfEmployees); 74 | 75 | //Assert relationship fields 76 | List contacts = accWithRelationships.Contacts; 77 | System.Assert.areNotEqual(null, contacts); 78 | System.Assert.areEqual(2, contacts.size()); 79 | 80 | System.Assert.areEqual(contact1.Id, contacts[0].Id); 81 | System.Assert.areEqual(contact1.DoNotCall, contacts[0].DoNotCall); 82 | 83 | System.Assert.areEqual(contact2.Id, contacts[1].Id); 84 | System.Assert.areEqual(contact2.DoNotCall, contacts[1].DoNotCall); 85 | } 86 | 87 | @isTest 88 | private static void makeRelationship_GenericOverload_ReturnsObjectsWithRelationFieldSet() 89 | { 90 | //Given 91 | SObject acc = Schema.getGlobalDescribe().get('Account').newSObject(); 92 | acc.put('Id', fflib_IDGenerator.generate(acc.getSObjectType())); 93 | acc.put('Name', 'AccName'); 94 | acc.put('NumberOfEmployees', 7); 95 | 96 | SObject contact1 = Schema.getGlobalDescribe().get('Contact').newSObject(); 97 | contact1.put('Id', fflib_IDGenerator.generate(contact1.getSObjectType())); 98 | contact1.put('DoNotCall', true); 99 | 100 | SObject contact2 = Schema.getGlobalDescribe().get('Contact').newSObject(); 101 | contact2.put('Id', fflib_IDGenerator.generate(contact2.getSObjectType())); 102 | contact2.put('DoNotCall', false); 103 | 104 | //When 105 | SObject accWithRelationships = ((List)fflib_ApexMocksUtils.makeRelationship( 106 | 'Account', 107 | 'Contact', 108 | new List { acc }, 109 | 'AccountId', 110 | new List> { new List { contact1, contact2 }} 111 | 112 | ))[0]; 113 | 114 | //Then 115 | System.Assert.areEqual(acc.Id, accWithRelationships.Id); 116 | System.Assert.areEqual(acc.get('Name'), accWithRelationships.get('Name')); 117 | System.Assert.areEqual(acc.get('NumberOfEmployees'), accWithRelationships.get('NumberOfEmployees')); 118 | 119 | //Assert relationship fields 120 | List contacts = accWithRelationships.getSObjects('Contacts'); 121 | System.Assert.areNotEqual(null, contacts); 122 | System.Assert.areEqual(2, contacts.size()); 123 | 124 | System.Assert.areEqual(contact1.Id, contacts[0].Id); 125 | System.Assert.areEqual((Boolean)contact1.get('DoNotCall'), (Boolean)contacts[0].get('DoNotCall')); 126 | 127 | System.Assert.areEqual(contact2.Id, contacts[1].Id); 128 | System.Assert.areEqual((Boolean)contact2.get('DoNotCall'), (Boolean)contacts[1].get('DoNotCall')); 129 | } 130 | 131 | @isTest 132 | private static void makeRelationship_GenericOverload_ThrowsErrorOnInvalidParentType() 133 | { 134 | // Setup parent object 135 | SObject acc = Schema.getGlobalDescribe().get('Account').newSObject(); 136 | acc.put('Id', fflib_IDGenerator.generate(acc.getSObjectType())); 137 | 138 | // Setup child object 139 | SObject cont = Schema.getGlobalDescribe().get('Contact').newSObject(); 140 | cont.put('Id', fflib_IDGenerator.generate(cont.getSObjectType())); 141 | 142 | String errorMessage = ''; 143 | try { 144 | // Call method under test 145 | SObject accWithRelationships = ((List)fflib_ApexMocksUtils.makeRelationship( 146 | 'MyInvalidParentType', 147 | 'Contact', 148 | new List { acc }, 149 | 'AccountId', 150 | new List> { new List { cont }} 151 | ))[0]; 152 | } catch (Exception exc) { 153 | errorMessage = exc.getMessage(); 154 | } 155 | System.Assert.areEqual('SObject type not found: MyInvalidParentType', errorMessage); 156 | } 157 | 158 | @isTest 159 | private static void makeRelationship_GenericOverload_ThrowsErrorOnInvalidChildType() 160 | { 161 | // Setup parent object 162 | SObject acc = Schema.getGlobalDescribe().get('Account').newSObject(); 163 | acc.put('Id', fflib_IDGenerator.generate(acc.getSObjectType())); 164 | 165 | // Setup child object 166 | SObject cont = Schema.getGlobalDescribe().get('Contact').newSObject(); 167 | cont.put('Id', fflib_IDGenerator.generate(cont.getSObjectType())); 168 | 169 | String errorMessage = ''; 170 | try { 171 | // Call method under test 172 | SObject accWithRelationships = ((List)fflib_ApexMocksUtils.makeRelationship( 173 | 'Account', 174 | 'MyInvalidChildType', 175 | new List { acc }, 176 | 'AccountId', 177 | new List> { new List { cont }} 178 | ))[0]; 179 | } catch (Exception exc) { 180 | errorMessage = exc.getMessage(); 181 | } 182 | System.Assert.areEqual('SObject type not found: MyInvalidChildType', errorMessage); 183 | } 184 | 185 | @isTest 186 | private static void makeRelationship_GenericOverload_ThrowsErrorOnInvalidFieldName() 187 | { 188 | // Setup parent object 189 | SObject acc = Schema.getGlobalDescribe().get('Account').newSObject(); 190 | acc.put('Id', fflib_IDGenerator.generate(acc.getSObjectType())); 191 | 192 | // Setup child object 193 | SObject cont = Schema.getGlobalDescribe().get('Contact').newSObject(); 194 | cont.put('Id', fflib_IDGenerator.generate(cont.getSObjectType())); 195 | 196 | String errorMessage = ''; 197 | try { 198 | // Call method under test 199 | SObject accWithRelationships = ((List)fflib_ApexMocksUtils.makeRelationship( 200 | 'Account', 201 | 'Contact', 202 | new List { acc }, 203 | 'MyInvalidField', 204 | new List> { new List { cont }} 205 | ))[0]; 206 | } catch (Exception exc) { 207 | errorMessage = exc.getMessage(); 208 | } 209 | System.Assert.areEqual('SObject field not found: MyInvalidField', errorMessage); 210 | } 211 | 212 | @IsTest 213 | private static void makeRelationship_ObjectWithNull_DoesNotThrowErrorOnJSONExceptionCanNotWriteAFieldNameExpectingAValue() 214 | { 215 | // Given 216 | Product2 prod1 = new Product2( 217 | Id = fflib_IDGenerator.generate(Product2.SObjectType), 218 | Name = 'Product1', 219 | ProductCode = 'P1', 220 | Description = null, 221 | StockKeepingUnit = 'P1' 222 | ); 223 | 224 | Product2 prod2 = new Product2( 225 | Id = fflib_IDGenerator.generate(Product2.SObjectType), 226 | Name = 'Product2', 227 | ProductCode = 'P2', 228 | Description = 'this is another product', 229 | StockKeepingUnit = 'P2' 230 | ); 231 | 232 | OpportunityLineItem oli1 = new OpportunityLineItem( 233 | Id = fflib_IDGenerator.generate(OpportunityLineItem.SObjectType), 234 | Product2Id = prod1.Id, 235 | Product2 = prod1, 236 | UnitPrice = 10, 237 | Quantity = 1 238 | ); 239 | 240 | OpportunityLineItem oli2 = new OpportunityLineItem( 241 | Id = fflib_IDGenerator.generate(OpportunityLineItem.SObjectType), 242 | Product2Id = prod2.Id, 243 | Product2 = prod2, 244 | UnitPrice = 10, 245 | Quantity = 1 246 | ); 247 | 248 | Opportunity opportunity = new Opportunity(); 249 | 250 | Exception exceptionThatWasCalled = null; 251 | 252 | // When 253 | Test.startTest(); 254 | 255 | try { 256 | fflib_ApexMocksUtils.makeRelationship( 257 | List.class, 258 | new List{ opportunity }, 259 | OpportunityLineItem.OpportunityId, 260 | new List>{ new List{oli1, oli2} } 261 | ); 262 | } catch (JSONException e) { 263 | exceptionThatWasCalled = e; 264 | } 265 | 266 | Test.stopTest(); 267 | 268 | // Then 269 | System.debug(exceptionThatWasCalled); 270 | Assert.isNull(exceptionThatWasCalled, 'Exception should not have been called'); 271 | } 272 | 273 | @isTest 274 | static void setReadOnlyFields_CreatedByIdSetToCurrentUserId_IdFieldSetSuccessfully() { 275 | 276 | Account acc = new Account(); 277 | Id userId = fflib_IDGenerator.generate((new User()).getSObjectType()); 278 | 279 | Test.startTest(); 280 | acc = (Account)fflib_ApexMocksUtils.setReadOnlyFields( 281 | acc, 282 | Account.class, 283 | new Map{Account.CreatedById => userId} 284 | ); 285 | Test.stopTest(); 286 | 287 | System.Assert.areEqual(userId, acc.CreatedById); 288 | } 289 | 290 | @isTest 291 | static void setReadOnlyFields_LastReferencedDateSetOnAccount_DateTimeFieldSetSuccessfully() { 292 | 293 | Account acc = new Account(); 294 | DateTime lastRefDate = DateTime.newInstanceGmt(2020, 1, 7, 23, 30, 0); 295 | 296 | Test.startTest(); 297 | acc = (Account)fflib_ApexMocksUtils.setReadOnlyFields( 298 | acc, 299 | Account.class, 300 | new Map {Account.LastReferencedDate => lastRefDate} 301 | ); 302 | Test.stopTest(); 303 | 304 | System.Assert.areEqual(lastRefDate, acc.LastReferencedDate); 305 | } 306 | 307 | @isTest 308 | static void setReadOnlyFields_IsDeletedSetOnAccount_BooleanFieldSetSuccessfully() { 309 | 310 | Account acc = new Account(); 311 | Boolean isDeleted = true; 312 | 313 | Test.startTest(); 314 | acc = (Account)fflib_ApexMocksUtils.setReadOnlyFields( 315 | acc, 316 | Account.class, 317 | new Map {Account.IsDeleted => isDeleted} 318 | ); 319 | Test.stopTest(); 320 | 321 | System.Assert.areEqual(isDeleted, acc.IsDeleted); 322 | } 323 | 324 | @isTest 325 | static void setReadOnlyFields_PolymorphicRelationJoin_FieldSetSuccessfully() { 326 | 327 | Account acc = new Account(Name='TestAccount'); 328 | Task t = new Task(); 329 | 330 | Test.startTest(); 331 | t = (Task)fflib_ApexMocksUtils.setReadOnlyFields( 332 | t, 333 | Task.class, 334 | new Map {'What' => acc} 335 | ); 336 | Test.stopTest(); 337 | 338 | System.Assert.areEqual(acc.Name, t.What.Name); 339 | } 340 | } 341 | -------------------------------------------------------------------------------- /sfdx-source/apex-mocks/test/classes/fflib_ApexMocksUtilsTest.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 63.0 4 | 5 | -------------------------------------------------------------------------------- /sfdx-source/apex-mocks/test/classes/fflib_ArgumentCaptorTest.cls: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2017 FinancialForce.com, inc. All rights reserved. 3 | */ 4 | /** 5 | * @nodoc 6 | */ 7 | @isTest 8 | private class fflib_ArgumentCaptorTest 9 | { 10 | @isTest 11 | static void thatArgumentValueIsCaptured() 12 | { 13 | // Given 14 | fflib_ApexMocks mocks = new fflib_ApexMocks(); 15 | fflib_MyList mockList = (fflib_MyList)mocks.mock(fflib_MyList.class); 16 | 17 | // When 18 | mockList.add('Fred'); 19 | 20 | // Then 21 | fflib_ArgumentCaptor argument = fflib_ArgumentCaptor.forClass(String.class); 22 | ((fflib_MyList.IList) mocks.verify(mockList)).add((String) argument.capture()); 23 | 24 | System.Assert.areEqual('Fred', (String)argument.getValue(), 'the argument captured is not as expected'); 25 | } 26 | 27 | @isTest 28 | static void thatCanPerformFurtherAssertionsOnCapturedArgumentValue() 29 | { 30 | // Given 31 | fflib_ApexMocks mocks = new fflib_ApexMocks(); 32 | fflib_MyList mockList = (fflib_MyList)mocks.mock(fflib_MyList.class); 33 | 34 | //When 35 | TestInnerClass testValue = new TestInnerClass(); 36 | testValue.i = 4; 37 | testValue.s = '5'; 38 | 39 | mockList.set(1, testValue); 40 | 41 | //Then 42 | fflib_ArgumentCaptor argument = fflib_ArgumentCaptor.forClass(TestInnerClass.class); 43 | 44 | ((fflib_MyList.IList) mocks.verify(mockList)).set(fflib_Match.anyInteger(), argument.capture()); 45 | 46 | Object capturedArg = argument.getValue(); 47 | System.Assert.areNotEqual(null, capturedArg, 'CapturedArg should not be null'); 48 | 49 | System.Assert.isInstanceOfType(capturedArg, TestInnerClass.class, 'CapturedArg should be SObject, instead was ' + capturedArg); 50 | 51 | TestInnerClass testValueCaptured = (TestInnerClass)capturedArg; 52 | 53 | System.Assert.areEqual(4, testValueCaptured.i, 'the values inside the argument captured should be the same of the original one'); 54 | System.Assert.areEqual('5', testValueCaptured.s, 'the values inside the argument captured should be the same of the original one'); 55 | } 56 | 57 | @isTest 58 | static void thatCaptureArgumentOnlyFromVerifiedMethod() 59 | { 60 | // Given 61 | fflib_ApexMocks mocks = new fflib_ApexMocks(); 62 | fflib_MyList mockList = (fflib_MyList)mocks.mock(fflib_MyList.class); 63 | 64 | // When 65 | mockList.add('Fred'); 66 | //the next call should be ignored because is not the method that has under verify, 67 | //even if have the same type specified in the capturer. 68 | mockList.addMore('Barney'); 69 | 70 | // Then 71 | 72 | fflib_ArgumentCaptor argument = fflib_ArgumentCaptor.forClass(String.class); 73 | ((fflib_MyList.IList) mocks.verify(mockList)).add((String) argument.capture()); 74 | 75 | System.Assert.areEqual('Fred', (String)argument.getValue(), 'the argument captured is not as expected'); 76 | System.Assert.areEqual(1, argument.getAllValues().size(), 'the argument captured should be only one'); 77 | } 78 | 79 | @isTest 80 | static void thatCaptureAllArgumentsForTheVerifiedMethods() 81 | { 82 | // Given 83 | fflib_ApexMocks mocks = new fflib_ApexMocks(); 84 | fflib_MyList mockList = (fflib_MyList)mocks.mock(fflib_MyList.class); 85 | 86 | List stringList = new List {'3'}; 87 | // When 88 | mockList.add('Fred'); 89 | mockList.add(stringList); 90 | 91 | mockList.clear(); 92 | 93 | // Then 94 | fflib_ArgumentCaptor argument = fflib_ArgumentCaptor.forClass(String.class); 95 | 96 | ((fflib_MyList.IList) mocks.verify(mockList)).add((String) argument.capture()); 97 | ((fflib_MyList.IList) mocks.verify(mockList)).add((List) argument.capture()); 98 | 99 | System.Assert.areEqual(stringList, (List)argument.getValue(), 'the argument captured is not as expected'); 100 | 101 | List argsCaptured = argument.getAllValues(); 102 | 103 | System.Assert.areEqual(2, argsCaptured.size(), 'expected 2 argument to be captured'); 104 | 105 | System.Assert.areEqual('Fred', (String) argsCaptured[0], 'the first value is not as expected'); 106 | } 107 | 108 | @isTest 109 | static void thatCaptureArgumentFromRequestedParameter() 110 | { 111 | // Given 112 | fflib_ApexMocks mocks = new fflib_ApexMocks(); 113 | fflib_MyList mockList = (fflib_MyList)mocks.mock(fflib_MyList.class); 114 | 115 | // When 116 | mockList.add('Fred', 'Barney', 'Wilma', 'Betty'); 117 | 118 | // Then 119 | fflib_ArgumentCaptor argument = fflib_ArgumentCaptor.forClass(String.class); 120 | 121 | ((fflib_MyList.IList) mocks.verify(mockList)) 122 | .add( 123 | (String) fflib_Match.eq('Fred'), 124 | (String) fflib_Match.eq('Barney'), 125 | (String) argument.capture(), 126 | (String) fflib_Match.eq('Betty')); 127 | 128 | System.Assert.areEqual('Wilma', (String)argument.getValue(), 129 | 'the argument captured is not as expected, should be Wilma because is the 3rd parameter in the call'); 130 | } 131 | 132 | @isTest 133 | static void thatCaptureLastArgument() 134 | { 135 | // Given 136 | fflib_ApexMocks mocks = new fflib_ApexMocks(); 137 | fflib_MyList mockList = (fflib_MyList)mocks.mock(fflib_MyList.class); 138 | 139 | // When 140 | mockList.add('Barney'); 141 | mockList.add('Fred'); 142 | 143 | // Then 144 | fflib_ArgumentCaptor argument = fflib_ArgumentCaptor.forClass(String.class); 145 | 146 | ((fflib_MyList.IList) mocks.verify(mockList, 2)).add((String) argument.capture()); 147 | 148 | System.Assert.areEqual('Fred', (String)argument.getValue(), 'the argument captured is not as expected'); 149 | } 150 | 151 | @isTest 152 | static void thatCaptureAllArguments() 153 | { 154 | // Given 155 | fflib_ApexMocks mocks = new fflib_ApexMocks(); 156 | fflib_MyList mockList = (fflib_MyList)mocks.mock(fflib_MyList.class); 157 | 158 | // When 159 | mockList.add('Fred'); 160 | mockList.add('Barney'); 161 | mockList.add('Wilma'); 162 | mockList.add('Betty'); 163 | 164 | // Then 165 | fflib_ArgumentCaptor argument = fflib_ArgumentCaptor.forClass(String.class); 166 | 167 | ((fflib_MyList.IList) mocks.verify(mockList, 4)).add((String) argument.capture()); 168 | 169 | List argsCaptured = argument.getAllValues(); 170 | 171 | System.Assert.areEqual(4, argsCaptured.size(), 'expected 4 argument to be captured'); 172 | 173 | System.Assert.areEqual('Fred', (String) argsCaptured[0], 'the first value is not as expected'); 174 | System.Assert.areEqual('Barney', (String) argsCaptured[1], 'the second value is not as expected'); 175 | System.Assert.areEqual('Wilma', (String) argsCaptured[2], 'the third value is not as expected'); 176 | System.Assert.areEqual('Betty', (String) argsCaptured[3], 'the forth value is not as expected'); 177 | } 178 | 179 | @isTest 180 | static void thatCaptureAllArgumentsFromMultipleMethods() 181 | { 182 | // Given 183 | fflib_ApexMocks mocks = new fflib_ApexMocks(); 184 | fflib_MyList mockList = (fflib_MyList)mocks.mock(fflib_MyList.class); 185 | 186 | // When 187 | mockList.add('Fred'); 188 | mockList.add('Barney'); 189 | mockList.get2(3, 'pebble'); 190 | 191 | // Then 192 | fflib_ArgumentCaptor argument = fflib_ArgumentCaptor.forClass(String.class); 193 | 194 | ((fflib_MyList.IList) mocks.verify(mockList, 2)).add((String) argument.capture()); 195 | 196 | ((fflib_MyList.IList) mocks.verify(mockList)) 197 | .get2( 198 | (Integer) fflib_Match.eq(3), 199 | (String) argument.capture()); 200 | 201 | List argsCaptured = argument.getAllValues(); 202 | 203 | System.Assert.areEqual(3, argsCaptured.size(), 'expected 3 argument to be captured'); 204 | 205 | System.Assert.areEqual('Fred', (String) argsCaptured[0], 'the first value is not as expected'); 206 | System.Assert.areEqual('Barney', (String) argsCaptured[1], 'the second value is not as expected'); 207 | 208 | System.Assert.areEqual('pebble', (String) argsCaptured[2], 'the third value is not as expected'); 209 | } 210 | 211 | @isTest 212 | static void thatCanHandleMultipleCapturesInOneMethodCall() 213 | { 214 | // Given 215 | fflib_ApexMocks mocks = new fflib_ApexMocks(); 216 | fflib_MyList mockList = (fflib_MyList)mocks.mock(fflib_MyList.class); 217 | 218 | // When 219 | mockList.add('Fred', 'Barney', 'Wilma', 'Betty'); 220 | 221 | // Then 222 | fflib_ArgumentCaptor argument = fflib_ArgumentCaptor.forClass(String.class); 223 | 224 | ((fflib_MyList.IList) mocks.verify(mockList)) 225 | .add( 226 | (String) fflib_Match.eq('Fred'), 227 | (String) argument.capture(), 228 | (String) argument.capture(), 229 | (String) fflib_Match.eq('Betty')); 230 | 231 | List argsCaptured = argument.getAllValues(); 232 | 233 | System.Assert.areEqual(2, argsCaptured.size(), 'expected 2 argument to be captured'); 234 | 235 | System.Assert.areEqual('Barney', (String) argsCaptured[0], 'the first value is not as expected'); 236 | 237 | System.Assert.areEqual('Wilma', (String) argsCaptured[1], 'the second value is not as expected'); 238 | } 239 | 240 | @isTest 241 | static void thatDoesNotCaptureIfNotVerified() 242 | { 243 | // Given 244 | fflib_ApexMocks mocks = new fflib_ApexMocks(); 245 | fflib_MyList mockList = (fflib_MyList)mocks.mock(fflib_MyList.class); 246 | 247 | // When 248 | mockList.add('3'); 249 | 250 | // Then 251 | fflib_ArgumentCaptor argument = fflib_ArgumentCaptor.forClass(List.class); 252 | 253 | ((fflib_MyList.IList) mocks.verify(mockList, fflib_ApexMocks.NEVER)) 254 | .add((List) argument.capture()); 255 | 256 | List argsCaptured = argument.getAllValues(); 257 | 258 | System.Assert.areEqual(0, argsCaptured.size(), 'expected 0 argument to be captured'); 259 | 260 | System.Assert.areEqual(null, argument.getValue(), 'no value should be captured, so must return null'); 261 | } 262 | 263 | @isTest 264 | static void thatCaptureOnlyMethodsThatMatchesWithOtherMatcherAsWell() 265 | { 266 | // Given 267 | fflib_ApexMocks mocks = new fflib_ApexMocks(); 268 | fflib_MyList mockList = (fflib_MyList)mocks.mock(fflib_MyList.class); 269 | 270 | // When 271 | mockList.add('Same', 'Same', 'First call', 'First call'); 272 | mockList.add('Same', 'Same', 'Second call', 'Second call'); 273 | 274 | // Then 275 | fflib_ArgumentCaptor argument = fflib_ArgumentCaptor.forClass(String.class); 276 | 277 | ((fflib_MyList.IList) mocks.verify(mockList)).add( 278 | fflib_Match.eqString('Same'), 279 | fflib_Match.eqString('Same'), 280 | (String)argument.capture(), 281 | fflib_Match.eqString('First call')); 282 | 283 | System.Assert.areEqual('First call', (String)argument.getValue()); 284 | } 285 | 286 | @isTest 287 | static void thatDoesNotCaptureAnythingWhenCaptorIsWrappedInAMatcher() 288 | { 289 | // Given 290 | fflib_ApexMocks mocks = new fflib_ApexMocks(); 291 | fflib_MyList mockList = (fflib_MyList)mocks.mock(fflib_MyList.class); 292 | 293 | // When 294 | mockList.add('Same', 'Same', 'First call', 'First call'); 295 | mockList.add('Same', 'Same', 'Second call', 'Second call'); 296 | 297 | // Then 298 | fflib_ArgumentCaptor argument = fflib_ArgumentCaptor.forClass(String.class); 299 | 300 | ((fflib_MyList.IList) mocks.verify(mockList)).add( 301 | (String) fflib_Match.allOf( 302 | fflib_Match.eqString('Same'), 303 | fflib_Match.eqString('Same'), 304 | argument.capture()), 305 | (String) fflib_Match.allOf( 306 | fflib_Match.eqString('Same'), 307 | fflib_Match.eqString('Same'), 308 | argument.capture()), 309 | (String) fflib_Match.allOf( 310 | argument.capture(), 311 | fflib_Match.eqString('First call')), 312 | (String) fflib_Match.allOf( 313 | argument.capture(), 314 | fflib_Match.eqString('First call')) 315 | ); 316 | 317 | List capturedValues = argument.getAllValues(); 318 | 319 | System.Assert.areEqual(0, capturedValues.size(), 320 | 'nothing should have been capture because the matcher it not really a capture type, but a allOf()'); 321 | System.Assert.isNull((String)argument.getValue(), 322 | 'nothing should have been capture because the matcher it not really a capture type, but a allOf()'); 323 | } 324 | 325 | @isTest 326 | static void thatArgumentValueIsCapturedWithInOrderVerification() 327 | { 328 | // Given 329 | fflib_ApexMocks mocks = new fflib_ApexMocks(); 330 | fflib_MyList mockList = (fflib_MyList)mocks.mock(fflib_MyList.class); 331 | fflib_InOrder inOrder1 = new fflib_InOrder(mocks, new List{ mockList }); 332 | 333 | // When 334 | mockList.add('Fred'); 335 | 336 | // Then 337 | fflib_ArgumentCaptor argument = fflib_ArgumentCaptor.forClass(String.class); 338 | 339 | ((fflib_MyList.IList)inOrder1.verify(mockList, mocks.calls(1))).add((String) argument.capture()); 340 | 341 | System.Assert.areEqual('Fred', (String)argument.getValue(), 'the argument captured is not as expected'); 342 | } 343 | 344 | @isTest 345 | static void thatCanPerformFurtherAssertionsOnCapturedArgumentValueWithInOrderVerification() 346 | { 347 | // Given 348 | fflib_ApexMocks mocks = new fflib_ApexMocks(); 349 | fflib_MyList mockList = (fflib_MyList)mocks.mock(fflib_MyList.class); 350 | fflib_InOrder inOrder1 = new fflib_InOrder(mocks, new List{ mockList }); 351 | 352 | 353 | //When 354 | TestInnerClass testValue = new TestInnerClass(); 355 | testValue.i = 4; 356 | testValue.s = '5'; 357 | 358 | mockList.set(1, testValue); 359 | 360 | //Then 361 | fflib_ArgumentCaptor argument = fflib_ArgumentCaptor.forClass(TestInnerClass.class); 362 | 363 | ((fflib_MyList.IList) inOrder1.verify(mockList, mocks.calls(1))).set(fflib_Match.anyInteger(), argument.capture()); 364 | 365 | Object capturedArg = argument.getValue(); 366 | System.Assert.areNotEqual(null, capturedArg, 'CapturedArg should not be null'); 367 | 368 | System.Assert.isInstanceOfType(capturedArg, TestInnerClass.class, 'CapturedArg should be SObject, instead was ' + capturedArg); 369 | 370 | TestInnerClass testValueCaptured = (TestInnerClass)capturedArg; 371 | 372 | System.Assert.areEqual(4, testValueCaptured.i, 'the values inside the argument captured should be the same of the original one'); 373 | System.Assert.areEqual('5', testValueCaptured.s, 'the values inside the argument captured should be the same of the original one'); 374 | } 375 | 376 | @isTest 377 | static void thatCaptureArgumentOnlyFromVerifiedMethodWithInOrderVerification() 378 | { 379 | // Given 380 | fflib_ApexMocks mocks = new fflib_ApexMocks(); 381 | fflib_MyList mockList = (fflib_MyList)mocks.mock(fflib_MyList.class); 382 | fflib_InOrder inOrder1 = new fflib_InOrder(mocks, new List{ mockList }); 383 | 384 | 385 | // When 386 | mockList.add('Fred'); 387 | //the next call should be ignored because is not the method that has under verify, 388 | //even if have the same type specified in the capturer. 389 | mockList.addMore('Barney'); 390 | 391 | // Then 392 | 393 | fflib_ArgumentCaptor argument = fflib_ArgumentCaptor.forClass(String.class); 394 | ((fflib_MyList.IList) inOrder1.verify(mockList, mocks.calls(1))).add((String) argument.capture()); 395 | 396 | System.Assert.areEqual('Fred', (String)argument.getValue(), 'the argument captured is not as expected'); 397 | System.Assert.areEqual(1, argument.getAllValues().size(), 'the argument captured should be only one'); 398 | } 399 | 400 | @isTest 401 | static void thatCaptureAllArgumentsForTheVerifiedMethodsWithInOrderVerification() 402 | { 403 | // Given 404 | fflib_ApexMocks mocks = new fflib_ApexMocks(); 405 | fflib_MyList mockList = (fflib_MyList)mocks.mock(fflib_MyList.class); 406 | fflib_InOrder inOrder1 = new fflib_InOrder(mocks, new List{ mockList }); 407 | 408 | 409 | List stringList = new List {'3'}; 410 | // When 411 | mockList.add('Fred'); 412 | mockList.add(stringList); 413 | 414 | mockList.clear(); 415 | 416 | // Then 417 | fflib_ArgumentCaptor argument = fflib_ArgumentCaptor.forClass(String.class); 418 | 419 | ((fflib_MyList.IList) inOrder1.verify(mockList, mocks.calls(1))).add((String) argument.capture()); 420 | ((fflib_MyList.IList) inOrder1.verify(mockList, mocks.calls(1))).add((List) argument.capture()); 421 | 422 | System.Assert.areEqual(stringList, (List)argument.getValue(), 'the argument captured is not as expected'); 423 | 424 | List argsCaptured = argument.getAllValues(); 425 | 426 | System.Assert.areEqual(2, argsCaptured.size(), 'expected 2 argument to be captured'); 427 | 428 | System.Assert.areEqual('Fred', (String) argsCaptured[0], 'the first value is not as expected'); 429 | } 430 | 431 | @isTest 432 | static void thatCaptureArgumentFromRequestedParameterWithInOrderVerification() 433 | { 434 | // Given 435 | fflib_ApexMocks mocks = new fflib_ApexMocks(); 436 | fflib_MyList mockList = (fflib_MyList)mocks.mock(fflib_MyList.class); 437 | fflib_InOrder inOrder1 = new fflib_InOrder(mocks, new List{ mockList }); 438 | 439 | 440 | // When 441 | mockList.add('Fred', 'Barney', 'Wilma', 'Betty'); 442 | 443 | // Then 444 | fflib_ArgumentCaptor argument = fflib_ArgumentCaptor.forClass(String.class); 445 | 446 | ((fflib_MyList.IList) inOrder1.verify(mockList, mocks.calls(1))) 447 | .add( 448 | (String) fflib_Match.eq('Fred'), 449 | (String) fflib_Match.eq('Barney'), 450 | (String) argument.capture(), 451 | (String) fflib_Match.eq('Betty')); 452 | 453 | System.Assert.areEqual('Wilma', (String)argument.getValue(), 454 | 'the argument captured is not as expected, should be Wilma because is the 3rd parameter in the call'); 455 | } 456 | 457 | @isTest 458 | static void thatCaptureLastArgumentWithInOrderVerification() 459 | { 460 | // Given 461 | fflib_ApexMocks mocks = new fflib_ApexMocks(); 462 | fflib_MyList mockList = (fflib_MyList)mocks.mock(fflib_MyList.class); 463 | fflib_InOrder inOrder1 = new fflib_InOrder(mocks, new List{ mockList }); 464 | 465 | 466 | // When 467 | mockList.add('Barney'); 468 | mockList.add('Fred'); 469 | 470 | // Then 471 | fflib_ArgumentCaptor argument = fflib_ArgumentCaptor.forClass(String.class); 472 | 473 | ((fflib_MyList.IList) inOrder1.verify(mockList, mocks.calls(2))).add((String) argument.capture()); 474 | 475 | System.Assert.areEqual('Fred', (String)argument.getValue(), 'the argument captured is not as expected'); 476 | } 477 | 478 | @isTest 479 | static void thatCaptureAllArgumentsWithInOrderVerification() 480 | { 481 | // Given 482 | fflib_ApexMocks mocks = new fflib_ApexMocks(); 483 | fflib_MyList mockList = (fflib_MyList)mocks.mock(fflib_MyList.class); 484 | fflib_InOrder inOrder1 = new fflib_InOrder(mocks, new List{ mockList }); 485 | 486 | 487 | // When 488 | mockList.add('Fred'); 489 | mockList.add('Barney'); 490 | mockList.add('Wilma'); 491 | mockList.add('Betty'); 492 | 493 | // Then 494 | fflib_ArgumentCaptor argument = fflib_ArgumentCaptor.forClass(String.class); 495 | 496 | ((fflib_MyList.IList) inOrder1.verify(mockList, mocks.calls(4))).add((String) argument.capture()); 497 | 498 | List argsCaptured = argument.getAllValues(); 499 | 500 | System.Assert.areEqual(4, argsCaptured.size(), 'expected 4 argument to be captured'); 501 | 502 | System.Assert.areEqual('Fred', (String) argsCaptured[0], 'the first value is not as expected'); 503 | System.Assert.areEqual('Barney', (String) argsCaptured[1], 'the second value is not as expected'); 504 | System.Assert.areEqual('Wilma', (String) argsCaptured[2], 'the third value is not as expected'); 505 | System.Assert.areEqual('Betty', (String) argsCaptured[3], 'the forth value is not as expected'); 506 | } 507 | 508 | @isTest 509 | static void thatCaptureAllArgumentsFromMultipleMethodsWithInOrderVerification() 510 | { 511 | // Given 512 | fflib_ApexMocks mocks = new fflib_ApexMocks(); 513 | fflib_MyList mockList = (fflib_MyList)mocks.mock(fflib_MyList.class); 514 | fflib_InOrder inOrder1 = new fflib_InOrder(mocks, new List{ mockList }); 515 | 516 | 517 | // When 518 | mockList.add('Fred'); 519 | mockList.add('Barney'); 520 | mockList.get2(3, 'pebble'); 521 | 522 | // Then 523 | fflib_ArgumentCaptor argument = fflib_ArgumentCaptor.forClass(String.class); 524 | 525 | ((fflib_MyList.IList) inOrder1.verify(mockList, mocks.calls(2))).add((String) argument.capture()); 526 | 527 | ((fflib_MyList.IList) inOrder1.verify(mockList, mocks.calls(1))) 528 | .get2( 529 | (Integer) fflib_Match.eq(3), 530 | (String) argument.capture()); 531 | 532 | List argsCaptured = argument.getAllValues(); 533 | 534 | System.Assert.areEqual(3, argsCaptured.size(), 'expected 3 argument to be captured'); 535 | 536 | System.Assert.areEqual('Fred', (String) argsCaptured[0], 'the first value is not as expected'); 537 | System.Assert.areEqual('Barney', (String) argsCaptured[1], 'the second value is not as expected'); 538 | 539 | System.Assert.areEqual('pebble', (String) argsCaptured[2], 'the third value is not as expected'); 540 | } 541 | 542 | @isTest 543 | static void thatCanHandleMultipleCapturesInOneMethodCallWithInOrderVerification() 544 | { 545 | // Given 546 | fflib_ApexMocks mocks = new fflib_ApexMocks(); 547 | fflib_MyList mockList = (fflib_MyList)mocks.mock(fflib_MyList.class); 548 | fflib_InOrder inOrder1 = new fflib_InOrder(mocks, new List{ mockList }); 549 | 550 | 551 | // When 552 | mockList.add('Fred', 'Barney', 'Wilma', 'Betty'); 553 | 554 | // Then 555 | fflib_ArgumentCaptor argument = fflib_ArgumentCaptor.forClass(String.class); 556 | 557 | ((fflib_MyList.IList) inOrder1.verify(mockList, mocks.calls(1))) 558 | .add( 559 | (String) fflib_Match.eq('Fred'), 560 | (String) argument.capture(), 561 | (String) argument.capture(), 562 | (String) fflib_Match.eq('Betty')); 563 | 564 | List argsCaptured = argument.getAllValues(); 565 | 566 | System.Assert.areEqual(2, argsCaptured.size(), 'expected 2 argument to be captured'); 567 | 568 | System.Assert.areEqual('Barney', (String) argsCaptured[0], 'the first value is not as expected'); 569 | 570 | System.Assert.areEqual('Wilma', (String) argsCaptured[1], 'the second value is not as expected'); 571 | } 572 | 573 | @isTest 574 | static void thatDoesNotCaptureIfNotVerifiedWithInOrderVerification() 575 | { 576 | // Given 577 | fflib_ApexMocks mocks = new fflib_ApexMocks(); 578 | fflib_MyList mockList = (fflib_MyList)mocks.mock(fflib_MyList.class); 579 | fflib_InOrder inOrder1 = new fflib_InOrder(mocks, new List{ mockList }); 580 | 581 | 582 | // When 583 | mockList.add('3'); 584 | 585 | // Then 586 | fflib_ArgumentCaptor argument = fflib_ArgumentCaptor.forClass(List.class); 587 | 588 | ((fflib_MyList.IList) inOrder1.verify(mockList, mocks.never())) 589 | .add((List) argument.capture()); 590 | 591 | List argsCaptured = argument.getAllValues(); 592 | 593 | System.Assert.areEqual(0, argsCaptured.size(), 'expected 0 argument to be captured'); 594 | 595 | System.Assert.areEqual(null, argument.getValue(), 'no value should be captured, so must return null'); 596 | } 597 | 598 | @isTest 599 | static void thatCaptureOnlyMethodsThatMatchesWithOtherMatcherAsWellWithInOrderVerification() 600 | { 601 | // Given 602 | fflib_ApexMocks mocks = new fflib_ApexMocks(); 603 | fflib_MyList mockList = (fflib_MyList)mocks.mock(fflib_MyList.class); 604 | fflib_InOrder inOrder1 = new fflib_InOrder(mocks, new List{ mockList }); 605 | 606 | 607 | // When 608 | mockList.add('Same', 'Same', 'First call', 'First call'); 609 | mockList.add('Same', 'Same', 'Second call', 'Second call'); 610 | 611 | // Then 612 | fflib_ArgumentCaptor argument = fflib_ArgumentCaptor.forClass(String.class); 613 | 614 | ((fflib_MyList.IList) inOrder1.verify(mockList, mocks.calls(1))).add( 615 | fflib_Match.eqString('Same'), 616 | fflib_Match.eqString('Same'), 617 | (String)argument.capture(), 618 | fflib_Match.eqString('First call')); 619 | 620 | System.Assert.areEqual('First call', (String)argument.getValue()); 621 | } 622 | 623 | @isTest 624 | static void thatDoesNotCaptureAnythingWhenCaptorIsWrappedInAMatcherWithInOrderVerification() 625 | { 626 | // Given 627 | fflib_ApexMocks mocks = new fflib_ApexMocks(); 628 | fflib_MyList mockList = (fflib_MyList)mocks.mock(fflib_MyList.class); 629 | fflib_InOrder inOrder1 = new fflib_InOrder(mocks, new List{ mockList }); 630 | 631 | 632 | // When 633 | mockList.add('Same', 'Same', 'First call', 'First call'); 634 | mockList.add('Same', 'Same', 'Second call', 'Second call'); 635 | 636 | // Then 637 | fflib_ArgumentCaptor argument = fflib_ArgumentCaptor.forClass(String.class); 638 | 639 | ((fflib_MyList.IList) inOrder1.verify(mockList, mocks.calls(1))).add( 640 | (String) fflib_Match.allOf( 641 | fflib_Match.eqString('Same'), 642 | fflib_Match.eqString('Same'), 643 | argument.capture()), 644 | (String) fflib_Match.allOf( 645 | fflib_Match.eqString('Same'), 646 | fflib_Match.eqString('Same'), 647 | argument.capture()), 648 | (String) fflib_Match.allOf( 649 | argument.capture(), 650 | fflib_Match.eqString('First call')), 651 | (String) fflib_Match.allOf( 652 | argument.capture(), 653 | fflib_Match.eqString('First call')) 654 | ); 655 | 656 | List capturedValues = argument.getAllValues(); 657 | 658 | System.Assert.areEqual(0, capturedValues.size(), 659 | 'nothing should have been capture because the matcher it not really a capture type, but a allOf()'); 660 | System.Assert.isNull((String)argument.getValue(), 661 | 'nothing should have been capture because the matcher it not really a capture type, but a allOf()'); 662 | } 663 | 664 | @isTest 665 | static void thatCaptureAllArgumentswhenMethodIsCalledWithTheSameArgument() 666 | { 667 | // Given 668 | fflib_ApexMocks mocks = new fflib_ApexMocks(); 669 | fflib_MyList mockList = (fflib_MyList)mocks.mock(fflib_MyList.class); 670 | 671 | // When 672 | mockList.add('Fred'); 673 | mockList.add('Barney'); 674 | mockList.add('Wilma'); 675 | mockList.add('Barney'); 676 | mockList.add('Barney'); 677 | mockList.add('Betty'); 678 | 679 | // Then 680 | fflib_ArgumentCaptor argument = fflib_ArgumentCaptor.forClass(String.class); 681 | 682 | ((fflib_MyList.IList) mocks.verify(mockList, 6)).add((String) argument.capture()); 683 | 684 | List argsCaptured = argument.getAllValues(); 685 | 686 | System.Assert.areEqual(6, argsCaptured.size(), 'expected 6 arguments to be captured'); 687 | 688 | System.Assert.areEqual('Fred', (String) argsCaptured[0], 'the first value is not as expected'); 689 | System.Assert.areEqual('Barney', (String) argsCaptured[1], 'the second value is not as expected'); 690 | System.Assert.areEqual('Wilma', (String) argsCaptured[2], 'the third value is not as expected'); 691 | System.Assert.areEqual('Barney', (String) argsCaptured[3], 'the fourth value is not as expected'); 692 | System.Assert.areEqual('Barney', (String) argsCaptured[4], 'the fifth value is not as expected'); 693 | System.Assert.areEqual('Betty', (String) argsCaptured[5], 'the sixth value is not as expected'); 694 | } 695 | 696 | 697 | private class TestInnerClass 698 | { 699 | public Integer i; 700 | public String s; 701 | } 702 | } -------------------------------------------------------------------------------- /sfdx-source/apex-mocks/test/classes/fflib_ArgumentCaptorTest.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 63.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /sfdx-source/apex-mocks/test/classes/fflib_IDGeneratorTest.cls: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014, FinancialForce.com, inc 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without modification, 6 | * are permitted provided that the following conditions are met: 7 | * 8 | * - Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * - Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * - Neither the name of the FinancialForce.com, inc nor the names of its contributors 14 | * may be used to endorse or promote products derived from this software without 15 | * specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 20 | * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 23 | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | @isTest 27 | private class fflib_IDGeneratorTest 28 | { 29 | @isTest 30 | static void itShouldGenerateValidIDs() 31 | { 32 | String id1 = fflib_IDGenerator.generate(Account.SObjectType); 33 | String id2 = fflib_IDGenerator.generate(Account.SObjectType); 34 | String id3 = fflib_IDGenerator.generate(Account.SObjectType); 35 | String id4 = fflib_IDGenerator.generate(Account.SObjectType); 36 | String id5 = fflib_IDGenerator.generate(Account.SObjectType); 37 | String id6 = fflib_IDGenerator.generate(Account.SObjectType); 38 | String id7 = fflib_IDGenerator.generate(Account.SObjectType); 39 | String id8 = fflib_IDGenerator.generate(Account.SObjectType); 40 | String id9 = fflib_IDGenerator.generate(Account.SObjectType); 41 | String id10 = fflib_IDGenerator.generate(Account.SObjectType); 42 | String id11 = fflib_IDGenerator.generate(Account.SObjectType); 43 | 44 | System.Assert.areEqual('001000000000001AAA', id1); 45 | System.Assert.areEqual('001000000000002AAA', id2); 46 | System.Assert.areEqual('001000000000003AAA', id3); 47 | System.Assert.areEqual('001000000000004AAA', id4); 48 | System.Assert.areEqual('001000000000005AAA', id5); 49 | System.Assert.areEqual('001000000000006AAA', id6); 50 | System.Assert.areEqual('001000000000007AAA', id7); 51 | System.Assert.areEqual('001000000000008AAA', id8); 52 | System.Assert.areEqual('001000000000009AAA', id9); 53 | System.Assert.areEqual('001000000000010AAA', id10); 54 | System.Assert.areEqual('001000000000011AAA', id11); 55 | } 56 | } -------------------------------------------------------------------------------- /sfdx-source/apex-mocks/test/classes/fflib_IDGeneratorTest.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 63.0 4 | 5 | -------------------------------------------------------------------------------- /sfdx-source/apex-mocks/test/classes/fflib_InOrderTest.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 63.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /sfdx-source/apex-mocks/test/classes/fflib_InheritorTest.cls: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2017 FinancialForce.com, inc. All rights reserved. 3 | */ 4 | @isTest 5 | public class fflib_InheritorTest 6 | { 7 | @isTest 8 | public static void canInstantiateMultipleInterfaceInheritor() 9 | { 10 | fflib_ApexMocks mocks = new fflib_ApexMocks(); 11 | Object inheritor = mocks.mock(fflib_Inheritor.class); 12 | System.Assert.isInstanceOfType(inheritor, fflib_Inheritor.IA.class); 13 | System.Assert.isInstanceOfType(inheritor, fflib_Inheritor.IB.class); 14 | System.Assert.isInstanceOfType(inheritor, fflib_Inheritor.IC.class); 15 | } 16 | 17 | @isTest 18 | public static void canStubMultipleInterfaceInheritor() 19 | { 20 | fflib_ApexMocks mocks = new fflib_ApexMocks(); 21 | fflib_Inheritor inheritor = (fflib_Inheritor)mocks.mock(fflib_Inheritor.class); 22 | 23 | mocks.startStubbing(); 24 | mocks.when(inheritor.doA()).thenReturn('Did not do A'); 25 | mocks.when(inheritor.doB()).thenReturn('Did not do B'); 26 | mocks.when(inheritor.doC()).thenReturn('Did not do C'); 27 | mocks.stopStubbing(); 28 | 29 | System.Assert.areEqual('Did not do A', inheritor.doA()); 30 | System.Assert.areEqual('Did not do B', inheritor.doB()); 31 | System.Assert.areEqual('Did not do C', inheritor.doC()); 32 | } 33 | } -------------------------------------------------------------------------------- /sfdx-source/apex-mocks/test/classes/fflib_InheritorTest.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 63.0 4 | 5 | -------------------------------------------------------------------------------- /sfdx-source/apex-mocks/test/classes/fflib_MatchTest.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 63.0 4 | 5 | -------------------------------------------------------------------------------- /sfdx-source/apex-mocks/test/classes/fflib_MatcherDefinitionsTest.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 63.0 4 | 5 | -------------------------------------------------------------------------------- /sfdx-source/apex-mocks/test/classes/fflib_MethodArgValuesTest.cls: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014-2016, FinancialForce.com, inc 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without modification, 6 | * are permitted provided that the following conditions are met: 7 | * 8 | * - Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * - Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * - Neither the name of the FinancialForce.com, inc nor the names of its contributors 14 | * may be used to endorse or promote products derived from this software without 15 | * specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 20 | * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 23 | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | @isTest 27 | public with sharing class fflib_MethodArgValuesTest 28 | { 29 | @isTest 30 | private static void equalsReturnsExpectedResults() 31 | { 32 | //Given 33 | fflib_MethodArgValues qm1 = new fflib_MethodArgValues(new List{ 'hello' }); 34 | fflib_MethodArgValues qm2 = new fflib_MethodArgValues(new List{ 'hello' }); 35 | fflib_MethodArgValues qm3 = new fflib_MethodArgValues(new List{ 'hi' }); 36 | fflib_MethodArgValues qm4 = new fflib_MethodArgValues(new List{ 'hello', 'hello', 'hello' }); 37 | fflib_MethodArgValues qm5 = new fflib_MethodArgValues(new List()); 38 | fflib_MethodArgValues qm6 = new fflib_MethodArgValues(null); 39 | 40 | //When/thens 41 | System.Assert.areEqual(qm1, qm1); 42 | System.Assert.areEqual(qm1, qm2); 43 | System.Assert.areNotEqual(qm1, qm3); 44 | System.Assert.areNotEqual(qm1, qm4); 45 | System.Assert.areNotEqual(qm1, qm5); 46 | System.Assert.areNotEqual(qm1, qm6); 47 | 48 | System.Assert.areEqual(qm2, qm2); 49 | System.Assert.areNotEqual(qm2, qm3); 50 | System.Assert.areNotEqual(qm2, qm4); 51 | System.Assert.areNotEqual(qm2, qm5); 52 | System.Assert.areNotEqual(qm2, qm6); 53 | 54 | System.Assert.areEqual(qm3, qm3); 55 | System.Assert.areNotEqual(qm3, qm4); 56 | System.Assert.areNotEqual(qm3, qm5); 57 | System.Assert.areNotEqual(qm3, qm6); 58 | 59 | System.Assert.areEqual(qm4, qm4); 60 | System.Assert.areNotEqual(qm4, qm5); 61 | System.Assert.areNotEqual(qm4, qm6); 62 | 63 | System.Assert.areEqual(qm5, qm5); 64 | System.Assert.areNotEqual(qm5, qm6); 65 | 66 | System.Assert.areEqual(qm6, qm6); 67 | } 68 | 69 | @isTest 70 | private static void hashCodeReturnsExpectedResults() 71 | { 72 | //Given 73 | fflib_MethodArgValues qm1 = new fflib_MethodArgValues(new List{ 'hello' }); 74 | fflib_MethodArgValues qm2 = new fflib_MethodArgValues(new List{ 'hello' }); 75 | fflib_MethodArgValues qm3 = new fflib_MethodArgValues(new List{ 'hi' }); 76 | fflib_MethodArgValues qm4 = new fflib_MethodArgValues(new List{ 'hello', 'hello', 'hello' }); 77 | fflib_MethodArgValues qm5 = new fflib_MethodArgValues(new List()); 78 | fflib_MethodArgValues qm6 = new fflib_MethodArgValues(null); 79 | 80 | //When/thens 81 | System.Assert.areEqual(qm1.hashCode(), qm1.hashCode()); 82 | System.Assert.areEqual(qm1.hashCode(), qm2.hashCode()); 83 | System.Assert.areNotEqual(qm1.hashCode(), qm3.hashCode()); 84 | System.Assert.areNotEqual(qm1.hashCode(), qm4.hashCode()); 85 | System.Assert.areNotEqual(qm1.hashCode(), qm5.hashCode()); 86 | System.Assert.areNotEqual(qm1.hashCode(), qm6.hashCode()); 87 | 88 | System.Assert.areEqual(qm2.hashCode(), qm2.hashCode()); 89 | System.Assert.areNotEqual(qm2.hashCode(), qm3.hashCode()); 90 | System.Assert.areNotEqual(qm2.hashCode(), qm4.hashCode()); 91 | System.Assert.areNotEqual(qm2.hashCode(), qm5.hashCode()); 92 | System.Assert.areNotEqual(qm2.hashCode(), qm6.hashCode()); 93 | 94 | System.Assert.areEqual(qm3.hashCode(), qm3.hashCode()); 95 | System.Assert.areNotEqual(qm3.hashCode(), qm4.hashCode()); 96 | System.Assert.areNotEqual(qm3.hashCode(), qm5.hashCode()); 97 | System.Assert.areNotEqual(qm3.hashCode(), qm6.hashCode()); 98 | 99 | System.Assert.areEqual(qm4.hashCode(), qm4.hashCode()); 100 | System.Assert.areNotEqual(qm4.hashCode(), qm5.hashCode()); 101 | System.Assert.areNotEqual(qm4.hashCode(), qm6.hashCode()); 102 | 103 | System.Assert.areEqual(qm5.hashCode(), qm5.hashCode()); 104 | System.Assert.areNotEqual(qm5.hashCode(), qm6.hashCode()); 105 | 106 | System.Assert.areEqual(qm6.hashCode(), qm6.hashCode()); 107 | } 108 | } -------------------------------------------------------------------------------- /sfdx-source/apex-mocks/test/classes/fflib_MethodArgValuesTest.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 63.0 4 | 5 | -------------------------------------------------------------------------------- /sfdx-source/apex-mocks/test/classes/fflib_MyList.cls: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2014-2017 FinancialForce.com, inc. All rights reserved. 3 | */ 4 | 5 | /** 6 | * @nodoc 7 | */ 8 | @isTest 9 | public with sharing class fflib_MyList implements IList 10 | { 11 | public interface IList 12 | { 13 | void add(String value); 14 | void add(String value1, String value2, String value3, String value4); 15 | void addMore(String value); 16 | void add(String[] value); // Test methods with the same name and number of params 17 | String get(Integer index); 18 | String get2(Integer index, String value); // This is just a method signature to allow me to test stubbing a method with multiple arguments 19 | void clear(); 20 | Boolean isEmpty(); 21 | void set(Integer index, Object value); 22 | } 23 | 24 | public void add(String[] value) 25 | { 26 | } 27 | 28 | public void add(String value) 29 | { 30 | } 31 | 32 | public void add(String value1, String value2, String value3, String value4) 33 | { 34 | } 35 | 36 | public void addMore(String value) 37 | { 38 | } 39 | 40 | public String get(Integer index) 41 | { 42 | return 'fred'; 43 | } 44 | 45 | public void clear() 46 | { 47 | } 48 | 49 | public Boolean isEmpty() 50 | { 51 | return true; 52 | } 53 | 54 | public void set(Integer index, Object value) 55 | { 56 | } 57 | 58 | public String get2(Integer index, String value) 59 | { 60 | return 'mary'; 61 | } 62 | 63 | public static String getStubClassName() 64 | { 65 | return fflib_ApexMocks.extractTypeName(new fflib_ApexMocks().mock(fflib_MyList.class)); 66 | } 67 | } -------------------------------------------------------------------------------- /sfdx-source/apex-mocks/test/classes/fflib_MyList.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 63.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /sfdx-source/apex-mocks/test/classes/fflib_QualifiedMethodAndArgValuesTest.cls: -------------------------------------------------------------------------------- 1 | @isTest 2 | public class fflib_QualifiedMethodAndArgValuesTest 3 | { 4 | @isTest 5 | private static void equalsReturnsExpectedResults() 6 | { 7 | fflib_QualifiedMethod qm1 = new fflib_QualifiedMethod('Type1', 'Method1', new List{ Integer.class } ); 8 | fflib_MethodArgValues mav1 = new fflib_MethodArgValues(new List{ 'hello' }); 9 | Object obj1 = 'hello'; 10 | 11 | fflib_QualifiedMethodAndArgValues qmaav = new fflib_QualifiedMethodAndArgValues(qm1, mav1, obj1); 12 | 13 | fflib_QualifiedMethod qm2 = qmaav.getQualifiedMethod(); 14 | fflib_MethodArgValues mav2 = qmaav.getMethodArgValues(); 15 | Object obj2 = qmaav.getMockInstance(); 16 | String string1 = qmaav.toString(); 17 | 18 | System.Assert.areEqual(qm1, qm2); 19 | System.Assert.areEqual(mav1, mav2); 20 | System.Assert.areEqual(obj1, obj2); 21 | System.Assert.areEqual('Type1.Method1(Integer) with args: [hello]', string1); 22 | 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /sfdx-source/apex-mocks/test/classes/fflib_QualifiedMethodAndArgValuesTest.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 63.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /sfdx-source/apex-mocks/test/classes/fflib_QualifiedMethodTest.cls: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2017 FinancialForce.com, inc. All rights reserved. 3 | */ 4 | @isTest 5 | public with sharing class fflib_QualifiedMethodTest 6 | { 7 | @isTest 8 | private static void equalsReturnsExpectedResults() 9 | { 10 | //Given 11 | fflib_QualifiedMethod qm1 = new fflib_QualifiedMethod('Type1', 'Method1', new List{ Integer.class } ); 12 | fflib_QualifiedMethod qm2 = new fflib_QualifiedMethod('Type1', 'Method1', new List{ Integer.class } ); 13 | fflib_QualifiedMethod qm3 = new fflib_QualifiedMethod('Type1', 'Method1', new List{ String.class } ); 14 | fflib_QualifiedMethod qm4 = new fflib_QualifiedMethod('Type2', 'Method2', new List{ Integer.class, String.class, fflib_QualifiedMethodTest.class } ); 15 | fflib_QualifiedMethod qm5 = new fflib_QualifiedMethod('', '', new List{} ); 16 | fflib_QualifiedMethod qm6 = new fflib_QualifiedMethod(null, null, null ); 17 | 18 | //When/thens 19 | System.Assert.areEqual(qm1, qm1); 20 | System.Assert.areEqual(qm1, qm2); 21 | System.Assert.areNotEqual(qm1, qm3); 22 | System.Assert.areNotEqual(qm1, qm4); 23 | System.Assert.areNotEqual(qm1, qm5); 24 | System.Assert.areNotEqual(qm1, qm6); 25 | 26 | System.Assert.areEqual(qm2, qm2); 27 | System.Assert.areNotEqual(qm2, qm3); 28 | System.Assert.areNotEqual(qm2, qm4); 29 | System.Assert.areNotEqual(qm2, qm5); 30 | System.Assert.areNotEqual(qm2, qm6); 31 | 32 | System.Assert.areEqual(qm3, qm3); 33 | System.Assert.areNotEqual(qm3, qm4); 34 | System.Assert.areNotEqual(qm3, qm5); 35 | System.Assert.areNotEqual(qm3, qm6); 36 | 37 | System.Assert.areEqual(qm4, qm4); 38 | System.Assert.areNotEqual(qm4, qm5); 39 | System.Assert.areNotEqual(qm4, qm6); 40 | 41 | System.Assert.areEqual(qm5, qm5); 42 | System.Assert.areNotEqual(qm5, qm6); 43 | 44 | System.Assert.areEqual(qm6, qm6); 45 | } 46 | 47 | @isTest 48 | private static void hashCodeReturnsExpectedResults() 49 | { 50 | //Given 51 | fflib_QualifiedMethod qm1 = new fflib_QualifiedMethod('Type1', 'Method1', new List{ Integer.class } ); 52 | fflib_QualifiedMethod qm2 = new fflib_QualifiedMethod('Type1', 'Method1', new List{ Integer.class } ); 53 | fflib_QualifiedMethod qm3 = new fflib_QualifiedMethod('Type1', 'Method1', new List{ String.class } ); 54 | fflib_QualifiedMethod qm4 = new fflib_QualifiedMethod('Type2', 'Method2', new List{ Integer.class, String.class, fflib_QualifiedMethodTest.class } ); 55 | fflib_QualifiedMethod qm5 = new fflib_QualifiedMethod('', '', new List{} ); 56 | fflib_QualifiedMethod qm6 = new fflib_QualifiedMethod(null, null, null ); 57 | 58 | //When/thens 59 | System.Assert.areEqual(qm1.hashCode(), qm1.hashCode()); 60 | System.Assert.areEqual(qm1.hashCode(), qm2.hashCode()); 61 | System.Assert.areNotEqual(qm1.hashCode(), qm3.hashCode()); 62 | System.Assert.areNotEqual(qm1.hashCode(), qm4.hashCode()); 63 | System.Assert.areNotEqual(qm1.hashCode(), qm5.hashCode()); 64 | System.Assert.areNotEqual(qm1.hashCode(), qm6.hashCode()); 65 | 66 | System.Assert.areEqual(qm2.hashCode(), qm2.hashCode()); 67 | System.Assert.areNotEqual(qm2.hashCode(), qm3.hashCode()); 68 | System.Assert.areNotEqual(qm2.hashCode(), qm4.hashCode()); 69 | System.Assert.areNotEqual(qm2.hashCode(), qm5.hashCode()); 70 | System.Assert.areNotEqual(qm2.hashCode(), qm6.hashCode()); 71 | 72 | System.Assert.areEqual(qm3.hashCode(), qm3.hashCode()); 73 | System.Assert.areNotEqual(qm3.hashCode(), qm4.hashCode()); 74 | System.Assert.areNotEqual(qm3.hashCode(), qm5.hashCode()); 75 | System.Assert.areNotEqual(qm3.hashCode(), qm6.hashCode()); 76 | 77 | System.Assert.areEqual(qm4.hashCode(), qm4.hashCode()); 78 | System.Assert.areNotEqual(qm4.hashCode(), qm5.hashCode()); 79 | System.Assert.areNotEqual(qm4.hashCode(), qm6.hashCode()); 80 | 81 | System.Assert.areEqual(qm5.hashCode(), qm5.hashCode()); 82 | System.Assert.areNotEqual(qm5.hashCode(), qm6.hashCode()); 83 | 84 | System.Assert.areEqual(qm6.hashCode(), qm6.hashCode()); 85 | } 86 | 87 | @isTest 88 | public static void toStringReturnsExpectedResult() 89 | { 90 | System.Assert.areEqual('MyClass.MyMethod(Integer)', new fflib_QualifiedMethod('MyClass', 'MyMethod', new List{ Integer.class }).toString()); 91 | } 92 | 93 | @isTest 94 | private static void equalsReturnsExpectedResultsForHasDependentMocks() 95 | { 96 | //Given 97 | String instance = 'My object instance'; 98 | String instance2 = 'My other object instance'; 99 | fflib_QualifiedMethod qm1 = new fflib_QualifiedMethod('Type1', 'Method1', new List{ Integer.class } ); 100 | fflib_QualifiedMethod qm2 = new fflib_QualifiedMethod('Type1', 'Method1', new List{ Integer.class }, instance); 101 | fflib_QualifiedMethod qm3 = new fflib_QualifiedMethod('Type1', 'Method1', new List{ Integer.class }, instance); 102 | fflib_QualifiedMethod qm4 = new fflib_QualifiedMethod('Type1', 'Method1', new List{ Integer.class }, instance2); 103 | 104 | //When/thens 105 | fflib_ApexMocksConfig.HasIndependentMocks = false; 106 | 107 | System.Assert.areEqual(qm1, qm2); 108 | System.Assert.areEqual(qm1, qm3); 109 | System.Assert.areEqual(qm1, qm4); 110 | 111 | fflib_ApexMocksConfig.HasIndependentMocks = true; 112 | 113 | System.Assert.areNotEqual(qm1, qm2); 114 | System.Assert.areNotEqual(qm1, qm3); 115 | System.Assert.areNotEqual(qm1, qm4); 116 | 117 | System.Assert.areEqual(qm2, qm3); 118 | System.Assert.areNotEqual(qm2, qm4); 119 | 120 | System.Assert.areNotEqual(qm3, qm4); 121 | } 122 | 123 | @isTest 124 | private static void hashCodeReturnsExpectedResultsForHasDependentMocks() 125 | { 126 | //Given 127 | String instance = 'My object instance'; 128 | String instance2 = 'My other object instance'; 129 | fflib_QualifiedMethod qm1 = new fflib_QualifiedMethod('Type1', 'Method1', new List{ Integer.class } ); 130 | fflib_QualifiedMethod qm2 = new fflib_QualifiedMethod('Type1', 'Method1', new List{ Integer.class }, instance); 131 | fflib_QualifiedMethod qm3 = new fflib_QualifiedMethod('Type1', 'Method1', new List{ Integer.class }, instance); 132 | fflib_QualifiedMethod qm4 = new fflib_QualifiedMethod('Type1', 'Method1', new List{ Integer.class }, instance2); 133 | 134 | //When/thens 135 | fflib_ApexMocksConfig.HasIndependentMocks = false; 136 | 137 | System.Assert.areEqual(qm1.hashCode(), qm2.hashCode()); 138 | System.Assert.areEqual(qm1.hashCode(), qm3.hashCode()); 139 | System.Assert.areEqual(qm1.hashCode(), qm4.hashCode()); 140 | 141 | fflib_ApexMocksConfig.HasIndependentMocks = true; 142 | 143 | System.Assert.areNotEqual(qm1.hashCode(), qm2.hashCode()); 144 | System.Assert.areNotEqual(qm1.hashCode(), qm3.hashCode()); 145 | System.Assert.areNotEqual(qm1.hashCode(), qm4.hashCode()); 146 | 147 | System.Assert.areEqual(qm2.hashCode(), qm3.hashCode()); 148 | System.Assert.areNotEqual(qm2.hashCode(), qm4.hashCode()); 149 | 150 | System.Assert.areNotEqual(qm3.hashCode(), qm4.hashCode()); 151 | } 152 | } -------------------------------------------------------------------------------- /sfdx-source/apex-mocks/test/classes/fflib_QualifiedMethodTest.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 63.0 4 | 5 | -------------------------------------------------------------------------------- /sfdx-source/apex-mocks/test/classes/fflib_SystemTest.cls: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 FinancialForce.com, inc. All rights reserved. 3 | */ 4 | @IsTest 5 | private class fflib_SystemTest 6 | { 7 | @IsTest 8 | private static void assertEquals_WithNoMatchers_ShouldThrowException() 9 | { 10 | try 11 | { 12 | fflib_System.assertEquals('Test String', 'Test String'); 13 | System.Assert.fail('Expected exception'); 14 | } 15 | catch (fflib_ApexMocks.ApexMocksException e) 16 | { 17 | System.Assert.areEqual('fflib_System.assertEquals expects you to register exactly 1 fflib_IMatcher (typically through the helpers in fflib_Match).', e.getMessage()); 18 | } 19 | } 20 | 21 | @IsTest 22 | private static void assertEquals_WithTooManyMatchers_ShouldThrowException() 23 | { 24 | //Register matchers prematurely 25 | fflib_Match.stringStartsWith('Test S'); 26 | fflib_Match.stringEndsWith('t String'); 27 | fflib_Match.stringIsNotBlank(); 28 | 29 | try 30 | { 31 | fflib_System.assertEquals(fflib_Match.stringStartsWith('Test S'), 'Test String'); 32 | System.Assert.fail('Expected exception'); 33 | } 34 | catch (fflib_ApexMocks.ApexMocksException e) 35 | { 36 | System.Assert.areEqual('fflib_System.assertEquals expects you to register exactly 1 fflib_IMatcher (typically through the helpers in fflib_Match).', e.getMessage()); 37 | } 38 | } 39 | 40 | @IsTest 41 | private static void assertEquals_WithMismatch_ShouldThrowException() 42 | { 43 | try 44 | { 45 | fflib_System.assertEquals(fflib_Match.stringStartsWith('Test X'), 'Test String'); 46 | System.Assert.fail('Expected exception'); 47 | } 48 | catch (fflib_ApexMocks.ApexMocksException e) 49 | { 50 | String expected = 'Actual: Test String'; 51 | String actual = e.getMessage(); 52 | System.Assert.isTrue(actual.contains(expected), 'Expected: ' + expected + ', Actual: ' + actual); 53 | } 54 | } 55 | 56 | @IsTest 57 | private static void assertEquals_WithMatch_ShouldPass() 58 | { 59 | fflib_System.assertEquals(fflib_Match.stringStartsWith('Test S'), 'Test String'); 60 | } 61 | 62 | @IsTest 63 | private static void assertEquals_WithCombinedMatcher_ShouldPass() 64 | { 65 | fflib_System.assertEquals(fflib_Match.allOf( 66 | fflib_Match.stringStartsWith('Test S'), 67 | fflib_Match.stringEndsWith('t String'), 68 | fflib_Match.stringIsNotBlank()) 69 | , 'Test String'); 70 | } 71 | 72 | @IsTest 73 | private static void assertEquals_WithCustomMessage_WithNoMatchers_ShouldThrowException() 74 | { 75 | try 76 | { 77 | fflib_System.assertEquals('Test String', 'Test String', 'My Custom Message'); 78 | System.Assert.fail('Expected exception'); 79 | } 80 | catch (fflib_ApexMocks.ApexMocksException e) 81 | { 82 | System.Assert.areEqual('fflib_System.assertEquals expects you to register exactly 1 fflib_IMatcher (typically through the helpers in fflib_Match).', e.getMessage()); 83 | } 84 | } 85 | 86 | @IsTest 87 | private static void assertEquals_WithCustomMessage_WithTooManyMatchers_ShouldThrowException() 88 | { 89 | //Register matchers prematurely 90 | fflib_Match.stringStartsWith('Test S'); 91 | fflib_Match.stringEndsWith('t String'); 92 | fflib_Match.stringIsNotBlank(); 93 | 94 | try 95 | { 96 | fflib_System.assertEquals(fflib_Match.stringStartsWith('Test S'), 'Test String', 'My Custom Message'); 97 | System.Assert.fail('Expected exception'); 98 | } 99 | catch (fflib_ApexMocks.ApexMocksException e) 100 | { 101 | System.Assert.areEqual('fflib_System.assertEquals expects you to register exactly 1 fflib_IMatcher (typically through the helpers in fflib_Match).', e.getMessage()); 102 | } 103 | } 104 | 105 | @IsTest 106 | private static void assertEquals_WithCustomMessage_WithMismatch_ShouldThrowException() 107 | { 108 | try 109 | { 110 | fflib_System.assertEquals(fflib_Match.stringStartsWith('Test X'), 'Test String', 'My Custom Message'); 111 | System.Assert.fail('Expected exception'); 112 | } 113 | catch (fflib_ApexMocks.ApexMocksException e) 114 | { 115 | String expected = 'Actual: Test String -- My Custom Message'; 116 | String actual = e.getMessage(); 117 | System.Assert.isTrue(actual.contains(expected), 'Expected: ' + expected + ', Actual: ' + actual); 118 | } 119 | } 120 | 121 | @IsTest 122 | private static void assertEquals_WithCustomMessage_WithMatch_ShouldPass() 123 | { 124 | fflib_System.assertEquals(fflib_Match.stringStartsWith('Test S'), 'Test String', 'My Custom Message'); 125 | } 126 | 127 | @IsTest 128 | private static void assertEquals_WithCustomMessage_WithCombinedMatcher_ShouldPass() 129 | { 130 | fflib_System.assertEquals(fflib_Match.allOf( 131 | fflib_Match.stringStartsWith('Test S'), 132 | fflib_Match.stringEndsWith('t String'), 133 | fflib_Match.stringIsNotBlank()) 134 | , 'Test String', 'My Custom Message'); 135 | } 136 | } -------------------------------------------------------------------------------- /sfdx-source/apex-mocks/test/classes/fflib_SystemTest.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 63.0 4 | Active 5 | 6 | --------------------------------------------------------------------------------