<?xml version="1.0" encoding="UTF-8"?>
<test-data
        xmlns="http://pmd.sourceforge.net/rule-tests"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://pmd.sourceforge.net/rule-tests http://pmd.sourceforge.net/rule-tests_1_0_0.xsd">

    <test-code>
        <description>SonarSource example 1</description>
        <rule-property name="classReportLevel">1</rule-property>
        <rule-property name="methodReportLevel">1</rule-property>
        <expected-problems>2</expected-problems>
        <expected-linenumbers>1,3</expected-linenumbers>
        <expected-messages>
            <message>The class 'Foo' has a total cognitive complexity of 19 (highest 19), current threshold is 1</message>
            <message>The method 'overriddenSymbolFrom(ClassJavaType)' has a cognitive complexity of 19, current threshold is 1</message>
        </expected-messages>
        <code>
            <![CDATA[
            public class Foo {
              @Nullable
              private MethodJavaSymbol overriddenSymbolFrom(ClassJavaType classType) {
                if (classType.isUnknown()) { // +1
                  return Symbols.unknownMethodSymbol;
                }
                boolean unknownFound = false;
                List<JavaSymbol> symbols = classType.getSymbol().members().lookup(name);
                for (JavaSymbol overrideSymbol : symbols) { // +1
                  if (overrideSymbol.isKind(JavaSymbol.MTH) // +2 (nesting = 1)
                      && !overrideSymbol.isStatic()) { // +1
                    MethodJavaSymbol methodJavaSymbol = (MethodJavaSymbol)overrideSymbol;
                    if (canOverride(methodJavaSymbol)) { // +3 (nesting = 2)
                      Boolean overriding = checkOverridingParameters(methodJavaSymbol,
                          classType);
                      if (overriding == null) { // +4 (nesting = 3)
                        if (!unknownFound) { // +5 (nesting = 4)
                          unknownFound = true;
                        }
                      } else if (overriding) { // +1
                        return methodJavaSymbol;
                      }
                    }
                  }
                }
                if (unknownFound) { // +1
                  return Symbols.unknownMethodSymbol;
                }
                return null;
              } // total complexity = 19
            }
            ]]>
        </code>
    </test-code>

    <test-code>
        <description>SonarSource example 2</description>
        <rule-property name="classReportLevel">1</rule-property>
        <rule-property name="methodReportLevel">1</rule-property>
        <expected-problems>2</expected-problems>
        <expected-linenumbers>1,2</expected-linenumbers>
        <expected-messages>
            <message>The class 'Foo' has a total cognitive complexity of 35 (highest 35), current threshold is 1</message>
            <message>The method 'addVersion(Entry, Transaction)' has a cognitive complexity of 35, current threshold is 1</message>
        </expected-messages>
        <code>
            <![CDATA[
            public class Foo {
              private void addVersion(final Entry entry, final Transaction txn)
                  /*throws PersistitInterruptedException, RollbackException*/ {
                final TransactionIndex ti = _persistit.getTransactionIndex();
                while (true) { // +1
                  try {
                    //synchronized (this) {
                      if (frst != null) { // +2 (nesting = 1)
                        if (frst.getVersion() > entry.getVersion()) { // +3 (nesting = 2)
                          throw new RollbackException();
                        }
                        if (txn.isActive()) { // +3 (nesting = 2)
                          for // +4 (nesting = 3)
                          (Entry e = frst; e != null; e = e.getPrevious()) {
                            final long version = e.getVersion();
                            final long depends = ti.wwDependency(version,
                                txn.getTransactionStatus(), 0);
                            if (depends == TIMED_OUT) { // +5 (nesting = 4)
                              throw new WWRetryException(version);
                            }
                            if (depends != 0 // +5 (nesting = 4)
                                && depends != ABORTED) { // +1
                              throw new RollbackException();
                            }
                          }
                        }
                      }
                      entry.setPrevious(frst);
                      frst = entry;
                      break;
                    //}
                  } catch (final WWRetryException re) { // +2 (nesting = 1)
                    try {
                      final long depends = _persistit.getTransactionIndex()
                          .wwDependency(re.getVersionHandle(),txn.getTransactionStatus(),
                              SharedResource.DEFAULT_MAX_WAIT_TIME);
                      if (depends != 0 // +3 (nesting = 2)
                          && depends != ABORTED) { // +1
                        throw new RollbackException();
                      }
                    } catch (final InterruptedException ie) { // +3 (nesting = 2)
                      throw new PersistitInterruptedException(ie);
                    }
                  } catch (final InterruptedException ie) { // +2 (nesting = 1)
                    throw new PersistitInterruptedException(ie);
                  }
                }
              } // total complexity = 35
            }
            ]]>
        </code>
    </test-code>

    <test-code>
        <description>SonarSource example 3</description>
        <rule-property name="classReportLevel">1</rule-property>
        <rule-property name="methodReportLevel">1</rule-property>
        <expected-problems>2</expected-problems>
        <expected-linenumbers>1,2</expected-linenumbers>
        <expected-messages>
            <message>The class 'Foo' has a total cognitive complexity of 20 (highest 20), current threshold is 1</message>
            <message>The method 'toRegexp(String, String)' has a cognitive complexity of 20, current threshold is 1</message>
        </expected-messages>
        <code>
            <![CDATA[
            public class Foo {
              private static String toRegexp(String antPattern,
                  String directorySeparator) {
                final String escapedDirectorySeparator = '\\' + directorySeparator;
                final StringBuilder sb = new StringBuilder(antPattern.length());
                sb.append('^');
                int i = antPattern.startsWith('/') || // +1
                    antPattern.startsWith('\\') ? 1 : 0; // +1
                while (i < antPattern.length()) { // +1
                  final char ch = antPattern.charAt(i);
                  if (SPECIAL_CHARS.indexOf(ch) != -1) { // +2 (nesting = 1)
                    sb.append('\\').append(ch);
                  } else if (ch == '*') { // +1
                    if (i + 1 < antPattern.length() // +3 (nesting = 2)
                        && antPattern.charAt(i + 1) == '*') { // +1
                      if (i + 2 < antPattern.length() // +4 (nesting = 3)
                          && isSlash(antPattern.charAt(i + 2))) { // +1
                        sb.append('(?:.*')
                            .append(escapedDirectorySeparator).append('|)');
                        i += 2;
                      } else { // +1
                        sb.append('.*');
                        i += 1;
                      }
                    } else { // +1
                      sb.append('[^').append(escapedDirectorySeparator).append(']*?');
                    }
                  } else if (ch == '?') { // +1
                    sb.append('[^').append(escapedDirectorySeparator).append(']');
                  } else if (isSlash(ch)) { // +1
                    sb.append(escapedDirectorySeparator);
                  } else { // +1
                    sb.append(ch);
                  }
                  i++;
                }
                sb.append('$');
                return sb.toString();
              } // total complexity = 20
            }
            ]]>
        </code>
    </test-code>

    <test-code>
        <description>Rule Doc Example</description>
        <rule-property name="classReportLevel">1</rule-property>
        <rule-property name="methodReportLevel">1</rule-property>
        <expected-problems>3</expected-problems>
        <expected-linenumbers>1,9,20</expected-linenumbers>
        <expected-messages>
            <message>The class 'Foo' has a total cognitive complexity of 5 (highest 4), current threshold is 1</message>
            <message>The method 'setPhoneNumberIfNotExisting(Account, String)' has a cognitive complexity of 1, current threshold is 1</message>
            <message>The method 'updateContacts(List&lt;Contact&gt;)' has a cognitive complexity of 4, current threshold is 1</message>
        </expected-messages>
        <code>
            <![CDATA[
public class Foo {
    // Has a cognitive complexity of 0
    public void createAccount() {
        Account account = new Account(Name = 'PMD');
        insert account;
    }

    // Has a cognitive complexity of 1
    public Boolean setPhoneNumberIfNotExisting(Account a, String phone) {
        if (a.Phone == null) {                          // +1
            a.Phone = phone;
            update a;
            return true;
        }

        return false;
    }

    // Has a cognitive complexity of 4
    public void updateContacts(List<Contact> contacts) {
        List<Contact> contactsToUpdate = new List<Contact>();

        for (Contact contact : contacts) {                           // +1
            if (contact.Department == 'Finance') {                   // +2 (nesting = 1)
                contact.Title = 'Finance Specialist';
                contactsToUpdate.add(contact);
            } else if (contact.Department == 'Sales') {              // +1
                contact.Title = 'Sales Specialist';
                contactsToUpdate.add(contact);
            }
        }

        update contactsToUpdate;
    }
}            ]]>
        </code>
    </test-code>

    <test-code>
        <description>Cognitive Complexity within triggers (#5138)</description>
        <rule-property name="methodReportLevel">15</rule-property>
        <expected-problems>1</expected-problems>
        <expected-linenumbers>2</expected-linenumbers>
        <expected-messages>
            <message>The trigger 'AccountTrigger' has a cognitive complexity of 18, current threshold is 15</message>
        </expected-messages>
        <code><![CDATA[
// https://github.com/SalesforceLabs/Partner-Onboarding/blob/main/Partner%20Onboarding/triggers/AccountTrigger.trigger
trigger AccountTrigger on Account (after insert, after update) {

    public List<Account> updatedAccounts = Trigger.new;
    if(trigger.isAfter){
        Map<Id,Account> mapOfOldValues = trigger.oldMap;
        Map<Id,Id> accountWithOnboardingTemplateIDs = new Map<Id,Id>();
        for(Account updated_Account : updatedAccounts) {
            if(updated_Account.Onboarding_Plan__c != null)
            {
                if(mapOfOldValues == null){
                    accountWithOnboardingTemplateIDs.put(updated_Account.Id, updated_Account.Onboarding_Plan__c);
                } else {
                    if(updated_Account.Onboarding_Plan__c != mapOfOldValues.get(updated_Account.Id).Onboarding_Plan__c)
                        accountWithOnboardingTemplateIDs.put(updated_Account.Id, updated_Account.Onboarding_Plan__c);
                }
            }
        } //End For

        if(accountWithOnboardingTemplateIDs.size() > 0){
            OnboardingPlanService.updateContactsWithOndbPlan(accountWithOnboardingTemplateIDs);
        }
    }
}
]]></code>
    </test-code>
</test-data>
