Merge pull request #14812 from eileenmcnaughton/ee
[civicrm-core.git] / tests / phpunit / CRM / Export / BAO / ExportTest.php
index ad9eb22559ffe8083b84540ed9635f6623b459c7..29756b17c51c9e144300acc32b6ec25eaf07eecc 100644 (file)
@@ -28,7 +28,6 @@ class CRM_Export_BAO_ExportTest extends CiviUnitTestCase {
    */
   protected $activityIDs = [];
 
-
   /**
    * Contribution IDs created for testing.
    *
@@ -45,10 +44,33 @@ class CRM_Export_BAO_ExportTest extends CiviUnitTestCase {
 
   protected $locationTypes = [];
 
+  /**
+   * Processor generated in test.
+   *
+   * @var \CRM_Export_BAO_ExportProcessor
+   */
+  protected $processor;
+
+  /**
+   * Csv output from export.
+   *
+   * @var \League\Csv\Reader
+   */
+  protected $csv;
+
+  /**
+   * Cleanup data.
+   *
+   * @throws \Exception
+   */
   public function tearDown() {
+    $this->quickCleanUpFinancialEntities();
     $this->quickCleanup([
       'civicrm_contact',
       'civicrm_email',
+      'civicrm_phone',
+      'civicrm_im',
+      'civicrm_website',
       'civicrm_address',
       'civicrm_relationship',
       'civicrm_membership',
@@ -56,11 +78,15 @@ class CRM_Export_BAO_ExportTest extends CiviUnitTestCase {
       'civicrm_case_contact',
       'civicrm_case_activity',
     ]);
-    $this->quickCleanUpFinancialEntities();
+
     if (!empty($this->locationTypes)) {
       $this->callAPISuccess('LocationType', 'delete', ['id' => $this->locationTypes['Whare Kai']['id']]);
       $this->callAPISuccess('LocationType', 'create', ['id' => $this->locationTypes['Main']['id'], 'name' => 'Main']);
     }
+    if ($this->processor && $this->processor->getTemporaryTable()) {
+      // delete the export temp table
+      CRM_Core_DAO::executeQuery("DROP TABLE IF EXISTS " . $this->processor->getTemporaryTable());
+    }
     parent::tearDown();
   }
 
@@ -68,104 +94,204 @@ class CRM_Export_BAO_ExportTest extends CiviUnitTestCase {
    * Basic test to ensure the exportComponents function completes without error.
    *
    * @throws \CRM_Core_Exception
+   * @throws \League\Csv\Exception
    */
   public function testExportComponentsNull() {
-    list($tableName) = CRM_Export_BAO_Export::exportComponents(
-      TRUE,
-      [],
-      [],
-      NULL,
-      NULL,
-      NULL,
-      CRM_Export_Form_Select::CONTACT_EXPORT,
-      NULL,
-      NULL,
-      FALSE,
-      FALSE,
-      [
-        'exportOption' => 1,
-        'suppress_csv_for_testing' => TRUE,
-      ]
-    );
-
-    // delete the export temp table and component table
-    $sql = "DROP TABLE IF EXISTS {$tableName}";
-    CRM_Core_DAO::executeQuery($sql);
+    $this->doExportTest([]);
   }
 
   /**
    * Basic test to ensure the exportComponents function can export selected fields for contribution.
+   *
+   * @throws \CRM_Core_Exception
+   * @throws \League\Csv\Exception
    */
   public function testExportComponentsContribution() {
     $this->setUpContributionExportData();
     $selectedFields = [
-      ['Individual', 'first_name'],
-      ['Individual', 'last_name'],
-      ['Contribution', 'receive_date'],
-      ['Contribution', 'contribution_source'],
-      ['Individual', 'street_address', 1],
-      ['Individual', 'city', 1],
-      ['Individual', 'country', 1],
-      ['Individual', 'email', 1],
-      ['Contribution', 'trxn_id'],
+      ['contact_type' => 'Individual', 'name' => 'first_name'],
+      ['contact_type' => 'Individual', 'name' => 'last_name'],
+      ['name' => 'receive_date'],
+      ['name' => 'contribution_source'],
+      ['contact_type' => 'Individual', 'name' => 'street_address', 1],
+      ['contact_type' => 'Individual', 'name' => 'city', 1],
+      ['contact_type' => 'Individual', 'name' => 'country', 1],
+      ['contact_type' => 'Individual', 'name' => 'email', 1],
+      ['name' => 'trxn_id'],
     ];
 
-    list($tableName) = CRM_Export_BAO_Export::exportComponents(
-      TRUE,
-      $this->contributionIDs,
-      [],
-      'receive_date desc',
-      $selectedFields,
-      NULL,
-      CRM_Export_Form_Select::CONTRIBUTE_EXPORT,
-      'civicrm_contribution.id IN ( ' . implode(',', $this->contributionIDs) . ')',
-      NULL,
-      FALSE,
-      FALSE,
-      [
-        'exportOption' => CRM_Export_Form_Select::CONTRIBUTE_EXPORT,
-        'suppress_csv_for_testing' => TRUE,
-      ]
-    );
+    $this->doExportTest([
+      'ids' => $this->contributionIDs,
+      'order' => 'receive_date desc',
+      'fields' => $selectedFields,
+      'exportMode' => CRM_Export_Form_Select::CONTRIBUTE_EXPORT,
+      'componentClause' => 'civicrm_contribution.id IN ( ' . implode(',', $this->contributionIDs) . ')',
+    ]);
+  }
+
+  /**
+   * Basic test to ensure the exportComponents function can export with soft credits enabled.
+   *
+   * @throws \CRM_Core_Exception
+   * @throws \League\Csv\Exception
+   */
+  public function testExportComponentsContributionSoftCredits() {
+    $this->setUpContributionExportData();
+    $this->callAPISuccess('ContributionSoft', 'create', ['contact_id' => $this->contactIDs[1], 'contribution_id' => $this->contributionIDs[0], 'amount' => 5]);
+    $params = [
+      ['receive_date_low', '=', '20160101000000', 0, 0],
+      ['receive_date_high', '=', '20191231235959', 0, 0],
+      ['contribution_amount_low', '=', '1', 0, 0],
+      ['contribution_amount_high', '=', '10000000', 0, 0],
+      ['contribution_test', '=', '0', 0, 0],
+      ['contribution_or_softcredits', '=', 'both', 0, 0],
+    ];
+
+    $this->doExportTest([
+      'selectAll' => FALSE,
+      'ids' => $this->contributionIDs,
+      'params' => $params,
+      'order' => 'receive_date desc',
+      'exportMode' => CRM_Export_Form_Select::CONTRIBUTE_EXPORT,
+      'componentClause' => 'civicrm_contribution.id IN ( ' . implode(',', $this->contributionIDs) . ')',
+    ]);
+
+    $this->assertEquals(array_merge($this->getBasicHeaderDefinition(FALSE), $this->getContributeHeaderDefinition()), $this->csv->getHeader());
+    $this->assertCount(3, $this->csv);
+    $row = $this->csv->fetchOne(0);
+    $this->assertEquals(95, $row['Net Amount']);
+    $this->assertEquals('', $row['Soft Credit Amount']);
+    $row = $this->csv->fetchOne(1);
+    $this->assertEquals(95, $row['Net Amount']);
+    $this->assertEquals(5, $row['Soft Credit Amount']);
+    $this->assertEquals('Anderson, Anthony', $row['Soft Credit For']);
+    $this->assertEquals($this->contributionIDs[0], $row['Soft Credit For Contribution ID']);
+
+    // Ideally we would use a randomised temp table name & use generic temp cleanup for cleanup - but
+    // for now just make sure we don't leave a mess.
+    CRM_Core_DAO::executeQuery('DROP TABLE IF EXISTS contribution_search_scredit_combined');
 
-    // delete the export temp table and component table
-    $sql = "DROP TABLE IF EXISTS {$tableName}";
-    CRM_Core_DAO::executeQuery($sql);
   }
 
   /**
    * Basic test to ensure the exportComponents function can export selected fields for contribution.
+   *
+   * @throws \CRM_Core_Exception
+   * @throws \League\Csv\Exception
    */
   public function testExportComponentsMembership() {
     $this->setUpMembershipExportData();
-    list($tableName) = CRM_Export_BAO_Export::exportComponents(
-      TRUE,
-      $this->membershipIDs,
-      [],
-      NULL,
-      NULL,
-      NULL,
-      CRM_Export_Form_Select::MEMBER_EXPORT,
-      'civicrm_membership.id IN ( ' . implode(',', $this->membershipIDs) . ')',
-      NULL,
-      FALSE,
-      FALSE,
-      [
-        'exportOption' => CRM_Export_Form_Select::MEMBER_EXPORT,
-        'suppress_csv_for_testing' => TRUE,
-      ]
-    );
-
-    $dao = CRM_Core_DAO::executeQuery('SELECT * from ' . $tableName);
-    $dao->fetch();
-    $this->assertEquals('100.00', $dao->componentpaymentfield_total_amount);
-    $this->assertEquals('Completed', $dao->componentpaymentfield_contribution_status);
-    $this->assertEquals('Credit Card', $dao->componentpaymentfield_payment_instrument);
-    $this->assertEquals(1, $dao->N);
+    $this->doExportTest([
+      'selectAll' => TRUE,
+      'ids'  => $this->membershipIDs,
+      'exportMode' => CRM_Export_Form_Select::MEMBER_EXPORT,
+      'componentClause' => 'civicrm_membership.id IN ( ' . implode(',', $this->membershipIDs) . ')',
+    ]);
 
-    // delete the export temp table and component table
-    $sql = "DROP TABLE IF EXISTS {$tableName}";
-    CRM_Core_DAO::executeQuery($sql);
+    $row = $this->csv->fetchOne();
+    $expected = [
+      'Contact ID' => $this->contactIDs[0],
+      'Contact Type' => 'Individual',
+      'Contact Subtype' => '',
+      'Do Not Email' => '',
+      'Do Not Phone' => '',
+      'Do Not Mail' => '',
+      'Do Not Sms' => '',
+      'Do Not Trade' => '',
+      'No Bulk Emails (User Opt Out)' => '',
+      'Legal Identifier' => '',
+      'External Identifier' => '',
+      'Sort Name' => 'Anderson, Anthony',
+      'Display Name' => 'Mr. Anthony Anderson II',
+      'Nickname' => '',
+      'Legal Name' => '',
+      'Image Url' => '',
+      'Preferred Communication Method' => '',
+      'Preferred Language' => 'en_US',
+      'Preferred Mail Format' => 'Both',
+      'Contact Hash' => '059023a02d27d4e7f285a40ee0e30be8',
+      'Contact Source' => '',
+      'First Name' => 'Anthony',
+      'Middle Name' => 'J.',
+      'Last Name' => 'Anderson',
+      'Individual Prefix' => 'Mr.',
+      'Individual Suffix' => 'II',
+      'Formal Title' => '',
+      'Communication Style' => 'Formal',
+      'Email Greeting ID' => '1',
+      'Postal Greeting ID' => '1',
+      'Addressee ID' => '1',
+      'Job Title' => '',
+      'Gender' => 'Female',
+      'Birth Date' => '',
+      'Deceased' => '',
+      'Deceased Date' => '',
+      'Household Name' => '',
+      'Organization Name' => '',
+      'Sic Code' => '',
+      'Unique ID (OpenID)' => '',
+      'Current Employer ID' => '',
+      'Contact is in Trash' => '',
+      'Created Date' => '2019-07-11 09:56:18',
+      'Modified Date' => '2019-07-11 09:56:19',
+      'Addressee' => 'Mr. Anthony J. Anderson II',
+      'Email Greeting' => 'Dear Anthony',
+      'Postal Greeting' => 'Dear Anthony',
+      'Current Employer' => '',
+      'Location Type' => 'Home',
+      'Street Address' => 'Ambachtstraat 23',
+      'Street Number' => '',
+      'Street Number Suffix' => '',
+      'Street Name' => '',
+      'Street Unit' => '',
+      'Supplemental Address 1' => '',
+      'Supplemental Address 2' => '',
+      'Supplemental Address 3' => '',
+      'City' => 'Brummen',
+      'Postal Code Suffix' => '',
+      'Postal Code' => '6971 BN',
+      'Latitude' => '',
+      'Longitude' => '',
+      'Address Name' => '',
+      'Master Address Belongs To' => '',
+      'County' => '',
+      'State' => '',
+      'Country' => 'Netherlands',
+      'Phone' => '',
+      'Phone Extension' => '',
+      'Phone Type' => '',
+      'Email' => 'home@example.com',
+      'On Hold' => '',
+      'Use for Bulk Mail' => '',
+      'Signature Text' => '',
+      'Signature Html' => '',
+      'IM Provider' => '',
+      'IM Screen Name' => '',
+      'OpenID' => '',
+      'World Region' => 'Europe and Central Asia',
+      'Website' => '',
+      'Membership Type' => 'General',
+      'Test' => '',
+      'Is Pay Later' => '',
+      'Member Since' => '2007-01-21',
+      'Membership Start Date' => '2007-01-21',
+      'Membership Expiration Date' => '2007-12-21',
+      'Source' => 'Payment',
+      'Membership Status' => 'Expired',
+      'Membership ID' => '2',
+      'Primary Member ID' => '',
+      'max_related' => '',
+      'membership_recur_id' => '',
+      'Campaign ID' => '',
+      'member_is_override' => '',
+      'member_auto_renew' => '',
+      'Total Amount' => '100.00',
+      'Contribution Status' => 'Completed',
+      'Date Received' => '2019-07-25 07:34:23',
+      'Payment Method' => 'Credit Card',
+      'Transaction ID' => '',
+    ];
+    $this->assertExpectedOutput($expected, $row);
   }
 
   /**
@@ -174,8 +300,8 @@ class CRM_Export_BAO_ExportTest extends CiviUnitTestCase {
   public function testExportComponentsActivity() {
     $this->setUpActivityExportData();
     $selectedFields = [
-      ['Individual', 'display_name'],
-      ['Individual', '5_a_b', 'display_name'],
+      ['contact_type' => 'Individual', 'name' => 'display_name'],
+      ['contact_type' => 'Individual', 'relationship_type_id' => '5', 'relationship_direction' => 'a_b', 'name' => 'display_name'],
     ];
 
     list($tableName) = CRM_Export_BAO_Export::exportComponents(
@@ -234,16 +360,6 @@ class CRM_Export_BAO_ExportTest extends CiviUnitTestCase {
       'contribution_id' => 1,
     ];
 
-    $contactRelationshipTypes = CRM_Contact_BAO_Relationship::getContactRelationshipType(
-      NULL,
-      NULL,
-      NULL,
-      NULL,
-      TRUE,
-      'name',
-      FALSE
-    );
-
     $query = new CRM_Contact_BAO_Query([], $returnProperties, NULL,
       FALSE, FALSE, CRM_Contact_BAO_Query::MODE_CONTRIBUTE,
       FALSE, TRUE, TRUE, NULL, 'AND'
@@ -255,10 +371,11 @@ class CRM_Export_BAO_ExportTest extends CiviUnitTestCase {
     preg_match_all($pattern, $select, $queryFieldAliases, PREG_PATTERN_ORDER);
     $processor = new CRM_Export_BAO_ExportProcessor(CRM_Contact_BAO_Query::MODE_CONTRIBUTE, NULL, 'AND');
     $processor->setQueryFields($query->_fields);
+    $processor->setReturnProperties($returnProperties);
 
-    list($outputFields) = CRM_Export_BAO_Export::getExportStructureArrays($returnProperties, $processor, $contactRelationshipTypes, '');
+    list($outputFields) = $processor->getExportStructureArrays();
     foreach (array_keys($outputFields) as $fieldAlias) {
-      if ($fieldAlias == 'Home-country') {
+      if ($fieldAlias === 'Home-country') {
         $this->assertTrue(in_array($fieldAlias . '_id', $queryFieldAliases[1]), 'Country is subject to some funky translate so we make sure country id is present');
       }
       else {
@@ -270,15 +387,19 @@ class CRM_Export_BAO_ExportTest extends CiviUnitTestCase {
 
   /**
    * Set up some data for us to do testing on.
+   *
+   * @throws \CRM_Core_Exception
    */
   public function setUpContributionExportData() {
     $this->setUpContactExportData();
-    $this->contributionIDs[] = $this->contributionCreate(['contact_id' => $this->contactIDs[0], 'trxn_id' => 'null', 'invoice_id' => 'null']);
-    $this->contributionIDs[] = $this->contributionCreate(['contact_id' => $this->contactIDs[1], 'trxn_id' => 'null', 'invoice_id' => 'null']);
+    $this->contributionIDs[] = $this->contributionCreate(['contact_id' => $this->contactIDs[0], 'trxn_id' => 'null', 'invoice_id' => 'null', 'receive_date' => '2019-07-25 07:34:23']);
+    $this->contributionIDs[] = $this->contributionCreate(['contact_id' => $this->contactIDs[1], 'trxn_id' => 'null', 'invoice_id' => 'null', 'receive_date' => '2018-12-01 00:00:00']);
   }
 
   /**
    * Set up some data for us to do testing on.
+   *
+   * @throws \CRM_Core_Exception
    */
   public function setUpMembershipExportData() {
     $this->setUpContactExportData();
@@ -325,6 +446,8 @@ class CRM_Export_BAO_ExportTest extends CiviUnitTestCase {
 
   /**
    * Set up some data for us to do testing on.
+   *
+   * @throws \CRM_Core_Exception
    */
   public function setUpContactExportData() {
     $this->contactIDs[] = $contactA = $this->individualCreate(['gender_id' => 'Female']);
@@ -370,36 +493,32 @@ class CRM_Export_BAO_ExportTest extends CiviUnitTestCase {
    *
    * @dataProvider getBooleanDataProvider
    * @throws \CRM_Core_Exception
+   * @throws \League\Csv\Exception
    */
   public function testExportPrimaryAddress($isPrimaryOnly) {
     \Civi::settings()->set('searchPrimaryDetailsOnly', $isPrimaryOnly);
     $this->setUpContactExportData();
 
-    $selectedFields = [['Individual', 'email', ' '], ['Individual', 'email', '1'], ['Individual', 'email', '2']];
-    list($tableName) = CRM_Export_BAO_Export::exportComponents(
-      TRUE,
-      [],
-      [['email', 'LIKE', 'c', 0, 1]],
-      NULL,
-      $selectedFields,
-      NULL,
-      CRM_Export_Form_Select::CONTACT_EXPORT,
-      "contact_a.id IN ({$this->contactIDs[0]}, {$this->contactIDs[1]})",
-      NULL,
-      FALSE,
-      FALSE,
-      [
-        'exportOption' => CRM_Export_Form_Select::CONTACT_EXPORT,
-        'suppress_csv_for_testing' => TRUE,
-      ]
-    );
+    $selectedFields = [
+      ['contact_type' => 'Individual', 'name' => 'email'],
+      ['contact_type' => 'Individual', 'name' => 'email', 'location_type_id' => '1'],
+      ['contact_type' => 'Individual', 'name' => 'email', 'location_type_id' => '2'],
+    ];
+    $this->doExportTest([
+      'ids' => [],
+      'params' => [['email', 'LIKE', 'c', 0, 1]],
+      'fields' => $selectedFields,
+      'componentClause' => "contact_a.id IN ({$this->contactIDs[0]}, {$this->contactIDs[1]})",
+      'selectAll' => TRUE,
+    ]);
 
-    $dao = CRM_Core_DAO::executeQuery('SELECT * from ' . $tableName);
-    $dao->fetch();
-    $this->assertEquals('home@example.com', $dao->email);
-    $this->assertEquals('work@example.com', $dao->work_email);
-    $this->assertEquals('home@example.com', $dao->home_email);
-    $this->assertEquals(2, $dao->N);
+    $row = $this->csv->fetchOne();
+    $this->assertEquals([
+      'Email' => 'home@example.com',
+      'Home-Email' => 'home@example.com',
+      'Work-Email' => 'work@example.com',
+    ], $row);
+    $this->assertEquals(2, count($this->csv));
     \Civi::settings()->set('searchPrimaryDetailsOnly', FALSE);
   }
 
@@ -427,7 +546,10 @@ class CRM_Export_BAO_ExportTest extends CiviUnitTestCase {
     $this->setUpContributionExportData();
     $campaign = $this->callAPISuccess('Campaign', 'create', ['title' => 'Big campaign']);
     $this->callAPISuccess('Contribution', 'create', ['campaign_id' => 'Big_campaign', 'id' => $this->contributionIDs[0]]);
-    $selectedFields = [['Individual', 'gender_id'], ['Contribution', 'contribution_campaign_title']];
+    $selectedFields = [
+      ['contact_type' => 'Individual', 'name' => 'gender_id'],
+      ['contact_type' => 'Contribution', 'name' => 'contribution_campaign_title'],
+    ];
     list($tableName, $sqlColumns) = CRM_Export_BAO_Export::exportComponents(
       TRUE,
       $this->contactIDs[1],
@@ -441,7 +563,6 @@ class CRM_Export_BAO_ExportTest extends CiviUnitTestCase {
       FALSE,
       FALSE,
       [
-        'exportOption' => CRM_Export_Form_Select::CONTACT_EXPORT,
         'suppress_csv_for_testing' => TRUE,
       ]
     );
@@ -450,6 +571,9 @@ class CRM_Export_BAO_ExportTest extends CiviUnitTestCase {
 
   /**
    * Test exporting relationships.
+   *
+   * @throws \CRM_Core_Exception
+   * @throws \League\Csv\Exception
    */
   public function testExportRelationships() {
     $organization1 = $this->organizationCreate(['organization_name' => 'Org 1', 'legal_name' => 'pretty legal', 'contact_source' => 'friend who took a law paper once']);
@@ -458,46 +582,26 @@ class CRM_Export_BAO_ExportTest extends CiviUnitTestCase {
     $contact2 = $this->individualCreate(['employer_id' => $organization2, 'first_name' => 'one']);
     $employerRelationshipTypeID = $this->callAPISuccessGetValue('RelationshipType', ['return' => 'id', 'label_a_b' => 'Employee of']);
     $selectedFields = [
-      ['Individual', 'first_name', ''],
-      ['Individual', $employerRelationshipTypeID . '_a_b', 'organization_name', ''],
-      ['Individual', $employerRelationshipTypeID . '_a_b', 'legal_name', ''],
-      ['Individual', $employerRelationshipTypeID . '_a_b', 'contact_source', ''],
+      ['contact_type' => 'Individual', 'name' => 'first_name'],
+      ['contact_type' => 'Individual', 'relationship_type_id' => $employerRelationshipTypeID, 'relationship_direction' => 'a_b', 'name' => 'organization_name'],
+      ['contact_type' => 'Individual', 'relationship_type_id' => $employerRelationshipTypeID, 'relationship_direction' => 'a_b', 'name' => 'legal_name'],
+      ['contact_type' => 'Individual', 'relationship_type_id' => $employerRelationshipTypeID, 'relationship_direction' => 'a_b', 'name' => 'contact_source'],
     ];
-    list($tableName, $sqlColumns, $headerRows) = CRM_Export_BAO_Export::exportComponents(
-      FALSE,
-      [$contact1, $contact2],
-      [],
-      NULL,
-      $selectedFields,
-      NULL,
-      CRM_Export_Form_Select::CONTACT_EXPORT,
-      "contact_a.id IN ( $contact1, $contact2 )",
-      NULL,
-      FALSE,
-      FALSE,
-      [
-        'exportOption' => CRM_Export_Form_Select::CONTACT_EXPORT,
-        'suppress_csv_for_testing' => TRUE,
-      ]
-    );
-
-    $dao = CRM_Core_DAO::executeQuery("SELECT * FROM {$tableName}");
-    $dao->fetch();
-    $this->assertEquals('one', $dao->first_name);
-    $this->assertEquals('Org 1', $dao->{$employerRelationshipTypeID . '_a_b_organization_name'});
-    $this->assertEquals('pretty legal', $dao->{$employerRelationshipTypeID . '_a_b_legal_name'});
-    $this->assertEquals('friend who took a law paper once', $dao->{$employerRelationshipTypeID . '_a_b_contact_source'});
+    $this->doExportTest([
+      'ids' => [$contact1, $contact2],
+      'componentClause' => "contact_a.id IN ( $contact1, $contact2 )",
+      'fields' => $selectedFields,
+    ]);
 
-    $dao->fetch();
-    $this->assertEquals('Org 2', $dao->{$employerRelationshipTypeID . '_a_b_organization_name'});
-    $this->assertEquals('well dodgey', $dao->{$employerRelationshipTypeID . '_a_b_legal_name'});
+    $row = $this->csv->fetchOne();
+    $this->assertEquals('one', $row['First Name']);
+    $this->assertEquals('Org 1', $row['Employee of-Organization Name']);
+    $this->assertEquals('pretty legal', $row['Employee of-Legal Name']);
+    $this->assertEquals('friend who took a law paper once', $row['Employee of-Contact Source']);
 
-    $this->assertEquals([
-      0 => 'First Name',
-      1 => 'Employee of-Organization Name',
-      2 => 'Employee of-Legal Name',
-      3 => 'Employee of-Contact Source',
-    ], $headerRows);
+    $row = $this->csv->fetchOne(1);
+    $this->assertEquals('Org 2', $row['Employee of-Organization Name']);
+    $this->assertEquals('well dodgey', $row['Employee of-Legal Name']);
   }
 
   /**
@@ -518,11 +622,11 @@ class CRM_Export_BAO_ExportTest extends CiviUnitTestCase {
       $this->contactIDs[] = $householdID;
     }
     $selectedFields = [
-      ['Individual', $houseHoldTypeID . '_a_b', 'state_province', ''],
-      ['Individual', $houseHoldTypeID . '_a_b', 'city', ''],
-      ['Individual', 'city', ''],
-      ['Individual', 'state_province', ''],
-      ['Individual', 'contact_source', ''],
+      ['contact_type' => 'Individual', 'relationship_type_id' => $houseHoldTypeID, 'relationship_direction' => 'a_b', 'name' => 'state_province', 'location_type_id' => ''],
+      ['contact_type' => 'Individual', 'relationship_type_id' => $houseHoldTypeID, 'relationship_direction' => 'a_b', 'name' => 'city', 'location_type_id' => ''],
+      ['contact_type' => 'Individual', 'name' => 'city', 'location_type_id' => ''],
+      ['contact_type' => 'Individual', 'name' => 'state_province', 'location_type_id' => ''],
+      ['contact_type' => 'Individual', 'name' => 'contact_source', 'location_type_id' => ''],
     ];
     list($tableName, $sqlColumns, $headerRows) = CRM_Export_BAO_Export::exportComponents(
       FALSE,
@@ -537,7 +641,6 @@ class CRM_Export_BAO_ExportTest extends CiviUnitTestCase {
       FALSE,
       TRUE,
       [
-        'exportOption' => CRM_Export_Form_Select::CONTACT_EXPORT,
         'suppress_csv_for_testing' => TRUE,
       ]
     );
@@ -584,7 +687,6 @@ class CRM_Export_BAO_ExportTest extends CiviUnitTestCase {
       FALSE,
       TRUE,
       [
-        'exportOption' => CRM_Export_Form_Select::CONTACT_EXPORT,
         'suppress_csv_for_testing' => TRUE,
       ]
     );
@@ -633,6 +735,9 @@ class CRM_Export_BAO_ExportTest extends CiviUnitTestCase {
 
   /**
    * Attempt to do a fairly full export of location data.
+   *
+   * @throws \CRM_Core_Exception
+   * @throws \League\Csv\Exception
    */
   public function testExportIMData() {
     // Use default providers.
@@ -710,125 +815,35 @@ class CRM_Export_BAO_ExportTest extends CiviUnitTestCase {
         }
       }
     }
-    list($tableName, $sqlColumns) = $this->doExport($fields, $this->contactIDs[0]);
 
-    $dao = CRM_Core_DAO::executeQuery('SELECT * FROM ' . $tableName);
-    while ($dao->fetch()) {
-      $id = $dao->contact_id;
-      $this->assertEquals('AIM', $dao->billing_im_provider);
-      $this->assertEquals('BillingJabber' . $id, $dao->billing_im_screen_name_jabber);
-      $this->assertEquals('BillingSkype' . $id, $dao->billing_im_screen_name_skype);
+    // @todo switch to just declaring the new format....
+    $mappedFields = [];
+    foreach ($fields as $field) {
+      $mappedFields[] = CRM_Core_BAO_Mapping::getMappingParams([], $field);
+    }
+    $this->doExportTest(['fields' => $mappedFields, 'ids' => [$this->contactIDs[0]]]);
+
+    foreach ($this->csv->getRecords() as $row) {
+      $id = $row['contact_id'];
+      $this->assertEquals('AIM', $row['Billing-IM Provider']);
+      $this->assertEquals('AIM', $row['Whare Kai-IM Provider']);
+      $this->assertEquals('BillingJabber' . $id, $row['Billing-IM Screen Name-Jabber']);
+      $this->assertEquals('Whare KaiJabber' . $id, $row['Whare Kai-IM Screen Name-Jabber']);
+      $this->assertEquals('BillingSkype' . $id, $row['Billing-IM Screen Name-Skype']);
       foreach ($relationships as $relatedContactID => $relationship) {
-        $relationshipString = $field = $relationship['relationship_type_id'] . '_a_b';
-        $field = $relationshipString . '_billing_im_screen_name_yahoo';
-        $this->assertEquals('BillingYahoo' . $relatedContactID, $dao->$field);
-        // @todo efforts to output 'im_provider' for related contacts seem to be giving a blank field.
+        $this->assertEquals('BillingYahoo' . $relatedContactID, $row[$relationship['label'] . '-Billing-IM Screen Name-Yahoo']);
+        $this->assertEquals('Whare KaiJabber' . $relatedContactID, $row[$relationship['label'] . '-Whare Kai-IM Screen Name-Jabber']);
       }
     }
-
-    $this->assertEquals([
-      'billing_im_provider' => 'billing_im_provider text',
-      'billing_im_screen_name' => 'billing_im_screen_name varchar(64)',
-      'billing_im_screen_name_jabber' => 'billing_im_screen_name_jabber varchar(64)',
-      'billing_im_screen_name_skype' => 'billing_im_screen_name_skype varchar(64)',
-      'billing_im_screen_name_yahoo' => 'billing_im_screen_name_yahoo varchar(64)',
-      'home_im_provider' => 'home_im_provider text',
-      'home_im_screen_name' => 'home_im_screen_name varchar(64)',
-      'home_im_screen_name_jabber' => 'home_im_screen_name_jabber varchar(64)',
-      'home_im_screen_name_skype' => 'home_im_screen_name_skype varchar(64)',
-      'home_im_screen_name_yahoo' => 'home_im_screen_name_yahoo varchar(64)',
-      'main_im_provider' => 'main_im_provider text',
-      'main_im_screen_name' => 'main_im_screen_name varchar(64)',
-      'main_im_screen_name_jabber' => 'main_im_screen_name_jabber varchar(64)',
-      'main_im_screen_name_skype' => 'main_im_screen_name_skype varchar(64)',
-      'main_im_screen_name_yahoo' => 'main_im_screen_name_yahoo varchar(64)',
-      'other_im_provider' => 'other_im_provider text',
-      'other_im_screen_name' => 'other_im_screen_name varchar(64)',
-      'other_im_screen_name_jabber' => 'other_im_screen_name_jabber varchar(64)',
-      'other_im_screen_name_skype' => 'other_im_screen_name_skype varchar(64)',
-      'other_im_screen_name_yahoo' => 'other_im_screen_name_yahoo varchar(64)',
-      'im_provider' => 'im_provider text',
-      'im_screen_name' => 'im_screen_name varchar(64)',
-      'contact_id' => 'contact_id varchar(255)',
-      '2_a_b_im_provider' => '2_a_b_im_provider text',
-      '2_a_b_billing_im_screen_name' => '2_a_b_billing_im_screen_name varchar(64)',
-      '2_a_b_billing_im_screen_name_jabber' => '2_a_b_billing_im_screen_name_jabber varchar(64)',
-      '2_a_b_billing_im_screen_name_skype' => '2_a_b_billing_im_screen_name_skype varchar(64)',
-      '2_a_b_billing_im_screen_name_yahoo' => '2_a_b_billing_im_screen_name_yahoo varchar(64)',
-      '2_a_b_home_im_screen_name' => '2_a_b_home_im_screen_name varchar(64)',
-      '2_a_b_home_im_screen_name_jabber' => '2_a_b_home_im_screen_name_jabber varchar(64)',
-      '2_a_b_home_im_screen_name_skype' => '2_a_b_home_im_screen_name_skype varchar(64)',
-      '2_a_b_home_im_screen_name_yahoo' => '2_a_b_home_im_screen_name_yahoo varchar(64)',
-      '2_a_b_main_im_screen_name' => '2_a_b_main_im_screen_name varchar(64)',
-      '2_a_b_main_im_screen_name_jabber' => '2_a_b_main_im_screen_name_jabber varchar(64)',
-      '2_a_b_main_im_screen_name_skype' => '2_a_b_main_im_screen_name_skype varchar(64)',
-      '2_a_b_main_im_screen_name_yahoo' => '2_a_b_main_im_screen_name_yahoo varchar(64)',
-      '2_a_b_other_im_screen_name' => '2_a_b_other_im_screen_name varchar(64)',
-      '2_a_b_other_im_screen_name_jabber' => '2_a_b_other_im_screen_name_jabber varchar(64)',
-      '2_a_b_other_im_screen_name_skype' => '2_a_b_other_im_screen_name_skype varchar(64)',
-      '2_a_b_other_im_screen_name_yahoo' => '2_a_b_other_im_screen_name_yahoo varchar(64)',
-      '2_a_b_im_screen_name' => '2_a_b_im_screen_name varchar(64)',
-      '8_a_b_im_provider' => '8_a_b_im_provider text',
-      '8_a_b_billing_im_screen_name' => '8_a_b_billing_im_screen_name varchar(64)',
-      '8_a_b_billing_im_screen_name_jabber' => '8_a_b_billing_im_screen_name_jabber varchar(64)',
-      '8_a_b_billing_im_screen_name_skype' => '8_a_b_billing_im_screen_name_skype varchar(64)',
-      '8_a_b_billing_im_screen_name_yahoo' => '8_a_b_billing_im_screen_name_yahoo varchar(64)',
-      '8_a_b_home_im_screen_name' => '8_a_b_home_im_screen_name varchar(64)',
-      '8_a_b_home_im_screen_name_jabber' => '8_a_b_home_im_screen_name_jabber varchar(64)',
-      '8_a_b_home_im_screen_name_skype' => '8_a_b_home_im_screen_name_skype varchar(64)',
-      '8_a_b_home_im_screen_name_yahoo' => '8_a_b_home_im_screen_name_yahoo varchar(64)',
-      '8_a_b_main_im_screen_name' => '8_a_b_main_im_screen_name varchar(64)',
-      '8_a_b_main_im_screen_name_jabber' => '8_a_b_main_im_screen_name_jabber varchar(64)',
-      '8_a_b_main_im_screen_name_skype' => '8_a_b_main_im_screen_name_skype varchar(64)',
-      '8_a_b_main_im_screen_name_yahoo' => '8_a_b_main_im_screen_name_yahoo varchar(64)',
-      '8_a_b_other_im_screen_name' => '8_a_b_other_im_screen_name varchar(64)',
-      '8_a_b_other_im_screen_name_jabber' => '8_a_b_other_im_screen_name_jabber varchar(64)',
-      '8_a_b_other_im_screen_name_skype' => '8_a_b_other_im_screen_name_skype varchar(64)',
-      '8_a_b_other_im_screen_name_yahoo' => '8_a_b_other_im_screen_name_yahoo varchar(64)',
-      '8_a_b_im_screen_name' => '8_a_b_im_screen_name varchar(64)',
-      '5_a_b_im_provider' => '5_a_b_im_provider text',
-      '5_a_b_billing_im_screen_name' => '5_a_b_billing_im_screen_name varchar(64)',
-      '5_a_b_billing_im_screen_name_jabber' => '5_a_b_billing_im_screen_name_jabber varchar(64)',
-      '5_a_b_billing_im_screen_name_skype' => '5_a_b_billing_im_screen_name_skype varchar(64)',
-      '5_a_b_billing_im_screen_name_yahoo' => '5_a_b_billing_im_screen_name_yahoo varchar(64)',
-      '5_a_b_home_im_screen_name' => '5_a_b_home_im_screen_name varchar(64)',
-      '5_a_b_home_im_screen_name_jabber' => '5_a_b_home_im_screen_name_jabber varchar(64)',
-      '5_a_b_home_im_screen_name_skype' => '5_a_b_home_im_screen_name_skype varchar(64)',
-      '5_a_b_home_im_screen_name_yahoo' => '5_a_b_home_im_screen_name_yahoo varchar(64)',
-      '5_a_b_main_im_screen_name' => '5_a_b_main_im_screen_name varchar(64)',
-      '5_a_b_main_im_screen_name_jabber' => '5_a_b_main_im_screen_name_jabber varchar(64)',
-      '5_a_b_main_im_screen_name_skype' => '5_a_b_main_im_screen_name_skype varchar(64)',
-      '5_a_b_main_im_screen_name_yahoo' => '5_a_b_main_im_screen_name_yahoo varchar(64)',
-      '5_a_b_other_im_screen_name' => '5_a_b_other_im_screen_name varchar(64)',
-      '5_a_b_other_im_screen_name_jabber' => '5_a_b_other_im_screen_name_jabber varchar(64)',
-      '5_a_b_other_im_screen_name_skype' => '5_a_b_other_im_screen_name_skype varchar(64)',
-      '5_a_b_other_im_screen_name_yahoo' => '5_a_b_other_im_screen_name_yahoo varchar(64)',
-      '5_a_b_im_screen_name' => '5_a_b_im_screen_name varchar(64)',
-      'whare_kai_im_provider' => 'whare_kai_im_provider text',
-      'whare_kai_im_screen_name' => 'whare_kai_im_screen_name varchar(64)',
-      'whare_kai_im_screen_name_jabber' => 'whare_kai_im_screen_name_jabber varchar(64)',
-      'whare_kai_im_screen_name_skype' => 'whare_kai_im_screen_name_skype varchar(64)',
-      'whare_kai_im_screen_name_yahoo' => 'whare_kai_im_screen_name_yahoo varchar(64)',
-      '2_a_b_whare_kai_im_screen_name' => '2_a_b_whare_kai_im_screen_name varchar(64)',
-      '2_a_b_whare_kai_im_screen_name_jabber' => '2_a_b_whare_kai_im_screen_name_jabber varchar(64)',
-      '2_a_b_whare_kai_im_screen_name_skype' => '2_a_b_whare_kai_im_screen_name_skype varchar(64)',
-      '2_a_b_whare_kai_im_screen_name_yahoo' => '2_a_b_whare_kai_im_screen_name_yahoo varchar(64)',
-      '8_a_b_whare_kai_im_screen_name' => '8_a_b_whare_kai_im_screen_name varchar(64)',
-      '8_a_b_whare_kai_im_screen_name_jabber' => '8_a_b_whare_kai_im_screen_name_jabber varchar(64)',
-      '8_a_b_whare_kai_im_screen_name_skype' => '8_a_b_whare_kai_im_screen_name_skype varchar(64)',
-      '8_a_b_whare_kai_im_screen_name_yahoo' => '8_a_b_whare_kai_im_screen_name_yahoo varchar(64)',
-      '5_a_b_whare_kai_im_screen_name' => '5_a_b_whare_kai_im_screen_name varchar(64)',
-      '5_a_b_whare_kai_im_screen_name_jabber' => '5_a_b_whare_kai_im_screen_name_jabber varchar(64)',
-      '5_a_b_whare_kai_im_screen_name_skype' => '5_a_b_whare_kai_im_screen_name_skype varchar(64)',
-      '5_a_b_whare_kai_im_screen_name_yahoo' => '5_a_b_whare_kai_im_screen_name_yahoo varchar(64)',
-    ], $sqlColumns);
-
   }
 
   /**
    * Test phone data export.
    *
    * Less over the top complete than the im test.
+   *
+   * @throws \CRM_Core_Exception
+   * @throws \League\Csv\Exception
    */
   public function testExportPhoneData() {
     $this->contactIDs[] = $this->individualCreate();
@@ -905,17 +920,18 @@ class CRM_Export_BAO_ExportTest extends CiviUnitTestCase {
         }
       }
     }
-    list($tableName) = $this->doExport($fields, $this->contactIDs[0]);
-
-    $dao = CRM_Core_DAO::executeQuery('SELECT * FROM ' . $tableName);
-    while ($dao->fetch()) {
-      // note there is some chance these might be random on some mysql co
-      $this->assertEquals('BillingMobile3', $dao->billing_phone_mobile);
-      $this->assertEquals('', $dao->billing_phone_phone);
-      $relField = '2_a_b_phone_type_id';
-      $this->assertEquals('Phone', $dao->$relField);
-      $this->assertEquals('Mobile', $dao->phone_type_id);
-      $this->assertEquals('Mobile', $dao->billing_phone_type_id);
+    // @todo switch to just declaring the new format....
+    $mappedFields = [];
+    foreach ($fields as $field) {
+      $mappedFields[] = CRM_Core_BAO_Mapping::getMappingParams([], $field);
+    }
+    $this->doExportTest(['fields' => $mappedFields, 'ids' => [$this->contactIDs[0]]]);
+    foreach ($this->csv->getRecords() as $row) {
+      $this->assertEquals('BillingMobile3', $row['Billing-Phone-Mobile']);
+      $this->assertEquals('', $row['Billing-Phone-Phone']);
+      $this->assertEquals('Phone', $row['Spouse of-Phone Type']);
+      $this->assertEquals('Mobile', $row['Phone Type']);
+      $this->assertEquals('Mobile', $row['Billing-Phone Type']);
     }
   }
 
@@ -1036,7 +1052,7 @@ class CRM_Export_BAO_ExportTest extends CiviUnitTestCase {
 
     //export the master address for contact B
     $selectedFields = [
-      ['Individual', 'master_id', 1],
+      ['contact_type' => 'Individual', 'name' => 'master_id', 'location_type_id' => 1],
     ];
     list($tableName, $sqlColumns) = CRM_Export_BAO_Export::exportComponents(
       TRUE,
@@ -1051,7 +1067,6 @@ class CRM_Export_BAO_ExportTest extends CiviUnitTestCase {
       FALSE,
       FALSE,
       [
-        'exportOption' => CRM_Export_Form_Select::CONTACT_EXPORT,
         'suppress_csv_for_testing' => TRUE,
       ]
     );
@@ -1067,6 +1082,117 @@ class CRM_Export_BAO_ExportTest extends CiviUnitTestCase {
     CRM_Core_DAO::executeQuery($sql);
   }
 
+  /**
+   * Test the merge same address option.
+   *
+   * @throws \CRM_Core_Exception
+   * @throws \League\Csv\Exception
+   */
+  public function testMergeSameAddress() {
+    $this->setUpContactExportData();
+    $this->contactIDs[] = $contact3 = $this->individualCreate(['first_name' => 'Sarah', 'last_name' => 'Smith', 'prefix_id' => 'Dr.']);
+    // Create address for contact A.
+    $params = [
+      'contact_id' => $contact3,
+      'location_type_id' => 'Home',
+      'street_address' => 'Ambachtstraat 23',
+      'postal_code' => '6971 BN',
+      'country_id' => '1152',
+      'city' => 'Brummen',
+      'is_primary' => 1,
+    ];
+    $this->callAPISuccess('address', 'create', $params);
+    $this->doExportTest(['mergeSameAddress' => TRUE, 'ids' => $this->contactIDs]);
+    // ie 2 merged, one extra.
+    $this->assertCount(2, $this->csv);
+    $expected = [
+      'Contact ID' => $this->contactIDs[0],
+      'Contact Type' => 'Individual',
+      'Contact Subtype' => '',
+      'Do Not Email' => '',
+      'Do Not Phone' => '',
+      'Do Not Mail' => '',
+      'Do Not Sms' => '',
+      'Do Not Trade' => '',
+      'No Bulk Emails (User Opt Out)' => '',
+      'Legal Identifier' => '',
+      'External Identifier' => '',
+      'Sort Name' => 'Anderson, Anthony',
+      'Display Name' => 'Mr. Anthony Anderson II',
+      'Nickname' => '',
+      'Legal Name' => '',
+      'Image Url' => '',
+      'Preferred Communication Method' => '',
+      'Preferred Language' => 'en_US',
+      'Preferred Mail Format' => 'Both',
+      'Contact Hash' => 'e9bd0913cc05cc5aeae69ba04ee3be84',
+      'Contact Source' => '',
+      'First Name' => 'Anthony',
+      'Middle Name' => 'J.',
+      'Last Name' => 'Anderson',
+      'Individual Prefix' => 'Mr.',
+      'Individual Suffix' => 'II',
+      'Formal Title' => '',
+      'Communication Style' => 'Formal',
+      'Email Greeting ID' => '1',
+      'Postal Greeting ID' => '1',
+      'Addressee ID' => '1',
+      'Job Title' => '',
+      'Gender' => 'Female',
+      'Birth Date' => '',
+      'Deceased' => '',
+      'Deceased Date' => '',
+      'Household Name' => '',
+      'Organization Name' => '',
+      'Sic Code' => '',
+      'Unique ID (OpenID)' => '',
+      'Current Employer ID' => '',
+      'Contact is in Trash' => '',
+      'Created Date' => '2019-07-11 10:28:15',
+      'Modified Date' => '2019-07-11 10:28:15',
+      'Addressee' => 'Mr. Anthony J. Anderson II, Dr. Sarah J. Smith II',
+      'Email Greeting' => 'Dear Anthony, Sarah',
+      'Postal Greeting' => 'Dear Anthony, Sarah',
+      'Current Employer' => '',
+      'Location Type' => 'Home',
+      'Street Address' => 'Ambachtstraat 23',
+      'Street Number' => '',
+      'Street Number Suffix' => '',
+      'Street Name' => '',
+      'Street Unit' => '',
+      'Supplemental Address 1' => '',
+      'Supplemental Address 2' => '',
+      'Supplemental Address 3' => '',
+      'City' => 'Brummen',
+      'Postal Code Suffix' => '',
+      'Postal Code' => '6971 BN',
+      'Latitude' => '',
+      'Longitude' => '',
+      'Address Name' => '',
+      'Master Address Belongs To' => '',
+      'County' => '',
+      'State' => '',
+      'Country' => 'Netherlands',
+      'Phone' => '',
+      'Phone Extension' => '',
+      'Phone Type' => '',
+      'Email' => 'home@example.com',
+      'On Hold' => '',
+      'Use for Bulk Mail' => '',
+      'Signature Text' => '',
+      'Signature Html' => '',
+      'IM Provider' => '',
+      'IM Screen Name' => '',
+      'OpenID' => '',
+      'World Region' => 'Europe and Central Asia',
+      'Website' => '',
+      'Group(s)' => '',
+      'Tag(s)' => '',
+      'Note(s)' => '',
+    ];
+    $this->assertExpectedOutput($expected, $this->csv->fetchOne());
+  }
+
   /**
    * Test that deceased and do not mail contacts are removed from contacts before
    *
@@ -1126,7 +1252,6 @@ class CRM_Export_BAO_ExportTest extends CiviUnitTestCase {
       TRUE,
       FALSE,
       [
-        'exportOption' => CRM_Export_Form_Select::CONTACT_EXPORT,
         'mergeOption' => TRUE,
         'suppress_csv_for_testing' => TRUE,
         'postal_mailing_export' => [
@@ -1209,12 +1334,16 @@ class CRM_Export_BAO_ExportTest extends CiviUnitTestCase {
    */
   protected function doExport($selectedFields, $id, $exportMode = CRM_Export_Form_Select::CONTACT_EXPORT) {
     $ids = (array) $id;
+    $mappedFields = [];
+    foreach ((array) $selectedFields as $field) {
+      $mappedFields[] = CRM_Core_BAO_Mapping::getMappingParams([], $field);
+    }
     list($tableName, $sqlColumns) = CRM_Export_BAO_Export::exportComponents(
       TRUE,
       $ids,
       [],
       NULL,
-      $selectedFields,
+      $mappedFields,
       NULL,
       $exportMode,
       "contact_a.id IN (" . implode(',', $ids) . ")",
@@ -1222,7 +1351,6 @@ class CRM_Export_BAO_ExportTest extends CiviUnitTestCase {
       FALSE,
       FALSE,
       [
-        'exportOption' => CRM_Export_Form_Select::CONTACT_EXPORT,
         'suppress_csv_for_testing' => TRUE,
       ]
     );
@@ -1699,7 +1827,6 @@ class CRM_Export_BAO_ExportTest extends CiviUnitTestCase {
       FALSE,
       FALSE,
       [
-        'exportOption' => CRM_Export_Form_Select::CONTRIBUTE_EXPORT,
         'suppress_csv_for_testing' => TRUE,
       ]
     );
@@ -2725,4 +2852,64 @@ class CRM_Export_BAO_ExportTest extends CiviUnitTestCase {
     ]);
   }
 
+  /**
+   * Test export components.
+   *
+   * Tests the exportComponents function with the provided parameters.
+   *
+   * This exportComponents will export a csv but it will also throw a prematureExitException
+   * which we catch & grab the processor from.
+   *
+   * $this->processor is set to the export processor.
+   *
+   * @param $params
+   *
+   * @throws \CRM_Core_Exception
+   * @throws \League\Csv\Exception
+   */
+  protected function doExportTest($params) {
+    $this->startCapturingOutput();
+    try {
+      $defaultClause = (empty($params['ids']) ? NULL : "contact_a.id IN (" . implode(',', $params['ids']) . ")");
+
+      CRM_Export_BAO_Export::exportComponents(
+        CRM_Utils_Array::value('selectAll', $params, (empty($params['fields']))),
+        CRM_Utils_Array::value('ids', $params, []),
+        CRM_Utils_Array::value('params', $params, []),
+        CRM_Utils_Array::value('order', $params),
+        CRM_Utils_Array::value('fields', $params, []),
+        CRM_Utils_Array::value('moreReturnProperties', $params),
+        CRM_Utils_Array::value('exportMode', $params, CRM_Export_Form_Select::CONTACT_EXPORT),
+        CRM_Utils_Array::value('componentClause', $params, $defaultClause),
+        CRM_Utils_Array::value('componentTable', $params),
+        CRM_Utils_Array::value('mergeSameAddress', $params, FALSE),
+        CRM_Utils_Array::value('mergeSameHousehold', $params, FALSE)
+      );
+    }
+    catch (CRM_Core_Exception_PrematureExitException $e) {
+      $this->processor = $e->errorData['processor'];
+      $this->csv = $this->captureOutputToCSV();
+      return;
+    }
+    $this->fail('We expected a premature exit exception');
+  }
+
+  /**
+   * Assert that the received array matches the expected, ignoring time sensitive fields.
+   *
+   * @param array $expected
+   * @param array $row
+   */
+  protected function assertExpectedOutput(array $expected, array $row) {
+    $variableFields = ['Created Date', 'Modified Date', 'Contact Hash'];
+    foreach ($expected as $key => $value) {
+      if (in_array($key, $variableFields)) {
+        $this->assertTrue(!empty($row[$key]));
+      }
+      else {
+        $this->assertEquals($value, $row[$key]);
+      }
+    }
+  }
+
 }