<?php
/**
 * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
 *
 * You are hereby granted a non-exclusive, worldwide, royalty-free license to
 * use, copy, modify, and distribute this software in source code or binary
 * form for use in connection with the web services and APIs provided by
 * Facebook.
 *
 * As with any software that integrates with the Facebook platform, your use
 * of this software is subject to the Facebook Developer Principles and
 * Policies [http://developers.facebook.com/policy/]. This copyright notice
 * shall be included in all copies or substantial portions of the software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

namespace FacebookAdsTest\Object;

use FacebookAds\Object\Campaign;
use FacebookAds\Object\AdCreative;
use FacebookAds\Object\Ad;
use FacebookAds\Object\AdImage;
use FacebookAds\Object\AdSet;
use FacebookAds\Object\Fields\CampaignFields;
use FacebookAds\Object\Fields\AdCreativeFields;
use FacebookAds\Object\Fields\AdFields;
use FacebookAds\Object\Fields\AdImageFields;
use FacebookAds\Object\Fields\AdSetFields;
use FacebookAds\Object\Fields\ObjectStory\LinkDataFields;
use FacebookAds\Object\Fields\ObjectStorySpecFields;
use FacebookAds\Object\ObjectStory\LinkData;
use FacebookAds\Object\ObjectStorySpec;
use FacebookAds\Object\TargetingSpecs;
use FacebookAds\Object\Fields\TargetingSpecsFields;
use FacebookAds\Object\Values\BillingEvents;
use FacebookAds\Object\Values\OptimizationGoals;
use FacebookAdsTest\Config\SkippableFeatureTestInterface;

class AdTest extends AbstractCrudObjectTestCase
  implements SkippableFeatureTestInterface {

  /**
   * @var Campaign
   */
  protected $campaign;

  /**
   * @var AdSet
   */
  protected $adSet;

  /**
   * @var AdCreative
   */
  protected $adCreative;

  /**
   * @var AdImage
   */
  protected $adImage;

  /**
   * @return array
   */
  public function skipIfAny() {
    return array('no_payment_method');
  }

  public function setup() {
    parent::setup();

    $targeting = new TargetingSpecs();
    $targeting->{TargetingSpecsFields::GEO_LOCATIONS} = array(
      'countries' => array('US'),
    );

    $this->campaign = new Campaign(null, $this->getConfig()->accountId);
    $this->campaign->{CampaignFields::NAME} = $this->getConfig()->testRunId;
    $this->campaign->create();

    $this->adSet = new AdSet(null, $this->getConfig()->accountId);
    $this->adSet->{AdSetFields::CAMPAIGN_ID}
      = (int) $this->campaign->{AdSetFields::ID};
    $this->adSet->{AdSetFields::NAME} = $this->getConfig()->testRunId;
    $this->adSet->{AdSetFields::DAILY_BUDGET} = '150';
    $this->adSet->{AdSetFields::START_TIME}
      = (new \DateTime("+1 week"))->format(\DateTime::ISO8601);
    $this->adSet->{AdSetFields::END_TIME}
      = (new \DateTime("+2 week"))->format(\DateTime::ISO8601);
    $this->adSet->{AdSetFields::TARGETING} = $targeting;
    $this->adSet->{AdSetFields::OPTIMIZATION_GOAL} = OptimizationGoals::REACH;
    $this->adSet->{AdSetFields::BILLING_EVENT} = BillingEvents::IMPRESSIONS;
    $this->adSet->{AdSetFields::BID_AMOUNT} = 2;
    $this->adSet->save(array(
      AdSet::STATUS_PARAM_NAME => AdSet::STATUS_PAUSED,
    ));

    $this->adImage = new AdImage(null, $this->getConfig()->accountId);
    $this->adImage->{AdImageFields::FILENAME}
      = $this->getConfig()->testImagePath;
    $this->adImage->save();

    $link = new LinkData();
    $link->{LinkDataFields::MESSAGE} = 'Message';
    $link->{LinkDataFields::IMAGE_HASH} = $this->adImage->{AdImageFields::HASH};
    $link->{LinkDataFields::LINK} = $this->getConfig()->appUrl;

    $story = new ObjectStorySpec();
    $story->{ObjectStorySpecFields::PAGE_ID} = $this->getConfig()->pageId;
    $story->{ObjectStorySpecFields::LINK_DATA} = $link;

    $this->adCreative = new AdCreative(null, $this->getConfig()->accountId);
    $this->adCreative->{AdCreativeFields::OBJECT_STORY_SPEC} = $story;
    $this->adCreative->create();
  }

  public function tearDown() {
    if ($this->adSet) {
      $this->adSet->deleteSelf();
      $this->adSet = null;
    }

    if ($this->campaign) {
      $this->campaign->deleteSelf();
      $this->campaign = null;
    }

    if ($this->adCreative) {
      $this->adCreative->deleteSelf();
      $this->adCreative = null;
    }

    if ($this->adImage) {
      $this->adImage->deleteSelf();
      $this->adImage = null;
    }

    parent::tearDown();
  }

  public function testCrudAccess() {

    $group = new Ad(null, $this->getConfig()->accountId);
    $group->{AdFields::NAME} = $this->getConfig()->testRunId;
    $group->{AdFields::ADSET_ID}
      = (int) $this->adSet->{AdSetFields::ID};
    $group->{AdFields::CREATIVE}
      = array('creative_id' => $this->adCreative->{AdCreativeFields::ID});

    $this->assertCanCreate($group, array(
      Ad::STATUS_PARAM_NAME => Ad::STATUS_PAUSED,
    ));
    $this->assertCanRead($group);
    $this->assertCanUpdate($group, array(
      AdFields::NAME => $this->getConfig()->testRunId.' updated',
    ));

    $this->assertCanFetchConnection($group, 'getAdCreatives');
    $this->assertCanFetchConnection($group, 'getLeads');
    $this->assertCanFetchConnection($group, 'getTargetingDescription');
    $this->assertCanFetchConnection($group, 'getAdPreviews',
      array(),
      array('ad_format' => 'RIGHT_COLUMN_STANDARD'));

    if (!$this->shouldSkipTest('no_reach_and_frequency')) {
      $this->assertCanFetchConnection($group, 'getReachEstimate');
    }
    $this->assertCanFetchConnection($group, 'getClickTrackingTag');
    $this->assertCanFetchConnection($group, 'getInsights');
    $this->assertCanFetchConnection($group, 'getInsightsAsync');

    $this->assertCanBeLabeled($group);
    $this->assertCanArchive($group);

    $this->assertCanDelete($group);
  }
}


<?php
/**
 * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
 *
 * You are hereby granted a non-exclusive, worldwide, royalty-free license to
 * use, copy, modify, and distribute this software in source code or binary
 * form for use in connection with the web services and APIs provided by
 * Facebook.
 *
 * As with any software that integrates with the Facebook platform, your use
 * of this software is subject to the Facebook Developer Principles and
 * Policies [http://developers.facebook.com/policy/]. This copyright notice
 * shall be included in all copies or substantial portions of the software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

namespace FacebookAdsTest\Object;

use FacebookAds\Object\AdAccount;
use FacebookAds\Object\AdUser;
use FacebookAds\Object\Fields\AdUserFields;

class AdUserTest extends AbstractCrudObjectTestCase {

  public function testCrudAccess() {
    $ad_account = new AdAccount($this->getConfig()->accountId);
    $ad_users = $ad_account->getAdUsers();

    $this->assertGreaterThan(0, $ad_users->count());

    $uid = (new AdUser('me'))->read()->{AdUserFields::ID};
    $found = false;
    foreach ($ad_users as $ad_user) {
      if ($ad_user->id === $uid) {
        $this->assertCanFetchConnection($ad_user, 'getAdAccounts');
        $this->assertCanFetchConnection($ad_user, 'getAdAccountGroups');
        $found = true;
        break;
      }
    }

    $this->assertTrue($found);
  }
}


<?php
/**
 * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
 *
 * You are hereby granted a non-exclusive, worldwide, royalty-free license to
 * use, copy, modify, and distribute this software in source code or binary
 * form for use in connection with the web services and APIs provided by
 * Facebook.
 *
 * As with any software that integrates with the Facebook platform, your use
 * of this software is subject to the Facebook Developer Principles and
 * Policies [http://developers.facebook.com/policy/]. This copyright notice
 * shall be included in all copies or substantial portions of the software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

namespace FacebookAdsTest\Object;

use FacebookAds\Object\AdVideo;
use FacebookAds\Object\Fields\AdVideoFields;
use FacebookAdsTest\Config\SkippableFeatureTestInterface;

class AdVideoTest extends AbstractCrudObjectTestCase
  implements SkippableFeatureTestInterface {

  /**
   * @return array
   */
  public function skipIfAny() {
    return array('no_video_upload');
  }

  public function testCrud() {
    $video = new AdVideo(null, $this->getConfig()->accountId);
    $video->{AdVideoFields::NAME} = $this->getConfig()->testRunId;
    $video->{AdVideoFields::SOURCE} = $this->getConfig()->testVideoPath;
    $this->assertCanCreate($video);
    $this->assertCanRead($video);
    $this->assertCanUpdate($video, array(
      AdVideoFields::NAME => $this->getConfig()->testRunId.' updated',
    ));
    $this->assertCanDelete($video);
  }
}


<?php
/**
 * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
 *
 * You are hereby granted a non-exclusive, worldwide, royalty-free license to
 * use, copy, modify, and distribute this software in source code or binary
 * form for use in connection with the web services and APIs provided by
 * Facebook.
 *
 * As with any software that integrates with the Facebook platform, your use
 * of this software is subject to the Facebook Developer Principles and
 * Policies [http://developers.facebook.com/policy/]. This copyright notice
 * shall be included in all copies or substantial portions of the software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

 namespace FacebookAdsTest\Object;

 use FacebookAds\Object\AdAccount;
 use FacebookAds\Object\Fields\AdAccountFields;
 use FacebookAds\Object\AdReportRun;
 use FacebookAds\Object\Fields\AdsInsightsFields;
 use FacebookAds\Api;

 class AsyncJobInsightsTest extends AbstractAsyncJobTestCase {

   public function testCrud() {
     $account = new AdAccount($this->getConfig()->accountId);
     $job = $account->getInsightsAsync();
     $this->assertTrue($job instanceof AdReportRun);
     $this->waitTillJobComplete($job);
     $job->getInsights();
   }

   public function testFields() {
     $account = new AdAccount($this->getConfig()->accountId);
     $fields = array(AdAccountFields::ACCOUNT_ID);
     $account->{AdAccountFields::ACCOUNT_ID} = $account->getSelf($fields)->{AdAccountFields::ACCOUNT_ID};
     $fields = array(AdsInsightsFields::ACCOUNT_ID);
     $job = $account->getInsightsAsync($fields);
     $this->assertTrue($job instanceof AdReportRun);
     $this->waitTillJobComplete($job);
     $result = $job->getInsights();
     $this->assertEquals(
       $result[0]->{AdsInsightsFields::ACCOUNT_ID},
       $account->{AdAccountFields::ACCOUNT_ID});
   }
 }


<?php
/**
 * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
 *
 * You are hereby granted a non-exclusive, worldwide, royalty-free license to
 * use, copy, modify, and distribute this software in source code or binary
 * form for use in connection with the web services and APIs provided by
 * Facebook.
 *
 * As with any software that integrates with the Facebook platform, your use
 * of this software is subject to the Facebook Developer Principles and
 * Policies [http://developers.facebook.com/policy/]. This copyright notice
 * shall be included in all copies or substantial portions of the software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

namespace FacebookAdsTest\Object;

use FacebookAds\Object\AdUser;
use FacebookAds\Object\Business;
use FacebookAds\Object\Fields\AdUserFields;
use FacebookAds\Object\Fields\BusinessFields;
use FacebookAds\Object\Values\AdAccountRoles;
use FacebookAdsTest\Config\SkippableFeatureTestInterface;
use FacebookAds\Object\Values\BusinessRoles;

class BusinessTest extends AbstractCrudObjectTestCase
  implements SkippableFeatureTestInterface {

  /**
   * @return array
   */
  public function skipIfAny() {
    return array('no_business_manager');
  }

  public function testCrud() {
    $business = new Business($this->getConfig()->businessId);
    $this->assertCanRead($business);
    $this->assertCannotDelete($business);

    $name = $business->read(array(BusinessFields::NAME))
      ->{BusinessFields::NAME};

    $this->assertCanUpdate($business, array(
      BusinessFields::NAME => "My Awesome Business"
    ));

    $business->{BusinessFields::NAME} = $name;
    $business->save();

    if ($this->getConfig()->secondaryPageId) {
      $business->claimPage(
        $this->getConfig()->secondaryPageId,
        BusinessRoles::OWNER);
      $business->deletePage($this->getConfig()->secondaryPageId);
    }

    $business->inviteUserByEmail('test@example.com', BusinessRoles::EMPLOYEE);
    $business->deleteUserByEmail('test@example.com');

    $user = (new AdUser('me'))->read(array('id'));
    $business->addUserPermissionById(
      $user->{AdUserFields::ID},
      BusinessRoles::ADMIN);

    if ($this->getConfig()->secondaryAccountId) {
      $business->claimAdAccount(
        $this->getConfig()->secondaryAccountId,
        BusinessRoles::AGENCY,
        array(AdAccountRoles::ADMIN));
      $business->deleteAdAccount(
        $this->getConfig()->secondaryAccountId);
    }

    if ($this->getConfig()->secondaryAppId) {
      $business->claimApp(
        $this->getConfig()->secondaryAppId,
        BusinessRoles::OWNER);
      $business->deleteApp($this->getConfig()->secondaryAppId);
    }
  }

  public function testConnections() {
    $business = new Business($this->getConfig()->businessId);
    $this->assertCanFetchConnection($business, 'getAdAccounts');
    $this->assertCanFetchConnection($business, 'getUserPermissions');
    $this->assertCanFetchConnection($business, 'getProjects');
    $this->assertCanFetchConnection($business, 'getPages');
    $this->assertCanFetchConnection($business, 'getApps');
    $this->assertCanFetchConnection($business, 'getClients');
    $this->assertCanFetchConnection($business, 'getAgencies');
    $this->assertCanFetchConnection($business, 'getCreditCards');
    $this->assertCanFetchConnection($business, 'getExtendedCredits');
    $this->assertCanFetchConnection($business, 'getProductCatalogues');
    $this->assertCanFetchConnection($business, 'getSystemUsers');
    $this->assertCanFetchConnection($business, 'getAdsPixels');
  }
}


<?php
/**
 * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
 *
 * You are hereby granted a non-exclusive, worldwide, royalty-free license to
 * use, copy, modify, and distribute this software in source code or binary
 * form for use in connection with the web services and APIs provided by
 * Facebook.
 *
 * As with any software that integrates with the Facebook platform, your use
 * of this software is subject to the Facebook Developer Principles and
 * Policies [http://developers.facebook.com/policy/]. This copyright notice
 * shall be included in all copies or substantial portions of the software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

namespace FacebookAdsTest\Object;

use FacebookAds\Object\Campaign;
use FacebookAds\Object\Fields\CampaignFields;

class CampaignTest extends AbstractCrudObjectTestCase {

  public function testCrud() {
    $campaign = new Campaign(null, $this->getConfig()->accountId);
    $campaign->{CampaignFields::NAME} = $this->getConfig()->testRunId;

    $this->assertCanCreate($campaign);
    $this->assertCanRead($campaign);
    $this->assertCanUpdate(
      $campaign,
      array(
        CampaignFields::NAME => $this->getConfig()->testRunId.' updated',
      ));
    $this->assertCanFetchConnection($campaign, 'getAdSets');
    $this->assertCanFetchConnection($campaign, 'getAds');
    $this->assertCanFetchConnection($campaign, 'getInsights');
    $this->assertCanFetchConnection($campaign, 'getInsightsAsync');

    $this->assertCanBeLabeled($campaign);
    $this->assertCanArchive($campaign);

    $this->assertCanDelete($campaign);
  }
}


<?php
/**
 * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
 *
 * You are hereby granted a non-exclusive, worldwide, royalty-free license to
 * use, copy, modify, and distribute this software in source code or binary
 * form for use in connection with the web services and APIs provided by
 * Facebook.
 *
 * As with any software that integrates with the Facebook platform, your use
 * of this software is subject to the Facebook Developer Principles and
 * Policies [http://developers.facebook.com/policy/]. This copyright notice
 * shall be included in all copies or substantial portions of the software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

namespace FacebookAdsTest\Object;

use FacebookAds\Object\CustomAudience;
use FacebookAds\Object\Fields\CustomAudienceFields;
use FacebookAds\Object\Fields\CustomAudienceMultikeySchemaFields;
use FacebookAds\Object\Values\CustomAudienceSubtypes;
use FacebookAds\Object\Values\CustomAudienceTypes;

class CustomAudienceMultikeyTest extends AbstractCrudObjectTestCase {

  /**
  * @var CustomAudience
  */
  protected $customaudience;

  public function setup() {
    parent::setup();
    $adaccount = new AdAccount($this->getConfig()->accountId);
    $params = array(
      CustomAudienceFields::NAME => $this->getConfig()->testRunId,
      CustomAudienceFields::SUBTYPE => CustomAudienceSubtypes::CUSTOM,
    );
    $this->customaudience = $adaccount->createCustomAudience(
      array(),
      $params
    );
  }

  public function tearDown() {
    if ($this->customaudience) {
      $this->customaudience->deleteSelf();
    }
  }

  private function checkServerResponse(
    CustomAudience $ca,
    array $users,
    array $schema,
    $is_hashed,
    $is_normalized) {
    $add = $ca->addUsersMultiKey($users, $schema, $is_hashed, $is_normalized);
    $this->assertClusterChangesResponse($ca, $users, $add);
    $remove = $ca->removeUsersMultiKey($users, $schema, $is_hashed, $is_normalized);
    $this->assertClusterChangesResponse($ca, $users, $remove);
  }

  protected function assertClusterChangesResponse(
    CustomAudience $ca, array $users, $response) {

    $this->assertTrue(is_array($response));

    $this->assertArrayHasKey('audience_id', $response);
    $this->assertEquals(
      $response['audience_id'], $ca->{CustomAudienceFields::ID});
    $this->assertArrayHasKey('num_received', $response);
    $this->assertEquals($response['num_received'], count($users));
    $this->assertArrayHasKey('num_invalid_entries', $response);
    $this->assertEquals($response['num_invalid_entries'], 0);
  }

  public function testMultikeyCustomAudiences() {
    $users = array(
      array('abc123def', 'fname', 'lname', 'someone@example.com'),
      array('abc234def', 'fname_new', 'lname_new', 'someone_new@example.com'),
    );
    $schema = array(
      CustomAudienceMultikeySchemaFields::EXTERN_ID,
      CustomAudienceMultikeySchemaFields::FIRST_NAME,
      CustomAudienceMultikeySchemaFields::LAST_NAME,
      CustomAudienceMultikeySchemaFields::EMAIL,
    );
    $is_hashed = false;
    $is_normalized = false;
    $this->checkServerResponse(
      $this->customaudience,
      $users,
      $schema,
      $is_hashed,
      $is_normalized);
  }

  public function testSinglekeyExternIDCustomAudiences() {
    $users = array(
      array('abc123def'),
      array('abc234def'),
      array('abc345def'),
      array('abc456def'),
    );
    $schema = array(
      CustomAudienceMultikeySchemaFields::EXTERN_ID,
    );
    $is_hashed = false;
    $is_normalized = false;
    $this->checkServerResponse(
      $this->customaudience,
      $users,
      $schema,
      $is_hashed,
      $is_normalized);
  }

}


<?php
/**
 * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
 *
 * You are hereby granted a non-exclusive, worldwide, royalty-free license to
 * use, copy, modify, and distribute this software in source code or binary
 * form for use in connection with the web services and APIs provided by
 * Facebook.
 *
 * As with any software that integrates with the Facebook platform, your use
 * of this software is subject to the Facebook Developer Principles and
 * Policies [http://developers.facebook.com/policy/]. This copyright notice
 * shall be included in all copies or substantial portions of the software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

namespace FacebookAdsTest\Object;

use FacebookAds\Object\CustomAudience;
use FacebookAds\Object\Fields\CustomAudienceFields;
use FacebookAds\Object\Values\CustomAudienceSubtypes;
use FacebookAds\Object\Values\CustomAudienceTypes;

class CustomAudienceTest extends AbstractCrudObjectTestCase {

  protected function assertClusterChangesResponse(
    CustomAudience $ca, array $users, $response) {

    $this->assertTrue(is_array($response));

    $this->assertArrayHasKey('audience_id', $response);
    $this->assertEquals(
      $response['audience_id'], $ca->{CustomAudienceFields::ID});
    $this->assertArrayHasKey('num_received', $response);
    $this->assertEquals($response['num_received'], count($users));
    $this->assertArrayHasKey('num_invalid_entries', $response);
    $this->assertEquals($response['num_invalid_entries'], 0);
  }

  public function testCustomAudiences() {
    $ca = new CustomAudience(null, $this->getConfig()->accountId);
    $ca->{CustomAudienceFields::NAME} = $this->getConfig()->testRunId;
    $ca->{CustomAudienceFields::SUBTYPE} = CustomAudienceSubtypes::CUSTOM;

    $this->assertCanCreate($ca);

    $this->assertCanRead($ca);
    $this->assertCanUpdate(
      $ca,
      array(
        CustomAudienceFields::NAME => $this->getConfig()->testRunId.' updated',
      ));

    $users = array('someone@example.com');

    $add = $ca->addUsers($users, CustomAudienceTypes::EMAIL);
    $this->assertClusterChangesResponse($ca, $users, $add);

    $remove = $ca->removeUsers($users, CustomAudienceTypes::EMAIL);
    $this->assertClusterChangesResponse($ca, $users, $remove);

    $optout = $ca->optOutUsers($users, CustomAudienceTypes::EMAIL);
    $this->assertSuccessResponse($optout);

    $this->assertCanDelete($ca);
  }

  /**
   * @depends testCustomAudiences
   */
  public function testAppIdsPayload() {
    $ca = new CustomAudience(null, $this->getConfig()->accountId);
    $ca->{CustomAudienceFields::NAME} = $this->getConfig()->testRunId;
    $ca->{CustomAudienceFields::SUBTYPE} = CustomAudienceSubtypes::CUSTOM;
    $ca->create();

    $users = array($this->getApi()->call('/me')->getContent()['id']);

    $add = $ca->addUsers(
      $users, CustomAudienceTypes::ID, array($this->getConfig()->appId));
    $this->assertClusterChangesResponse($ca, $users, $add);

    $remove = $ca->removeUsers(
      $users, CustomAudienceTypes::ID, array($this->getConfig()->appId));
    $this->assertClusterChangesResponse($ca, $users, $remove);

    $optout = $ca->optOutUsers(
      $users, CustomAudienceTypes::ID, array($this->getConfig()->appId));
    $this->assertSuccessResponse($optout);

    $ca->deleteSelf();
  }
}


<?php
/**
 * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
 *
 * You are hereby granted a non-exclusive, worldwide, royalty-free license to
 * use, copy, modify, and distribute this software in source code or binary
 * form for use in connection with the web services and APIs provided by
 * Facebook.
 *
 * As with any software that integrates with the Facebook platform, your use
 * of this software is subject to the Facebook Developer Principles and
 * Policies [http://developers.facebook.com/policy/]. This copyright notice
 * shall be included in all copies or substantial portions of the software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

namespace FacebookAdsTest\Object;

use FacebookAds\Object\AdAccount;
use FacebookAds\Object\Campaign;
use FacebookAds\Object\AdCreative;
use FacebookAds\Object\Ad;
use FacebookAds\Object\AdSet;
use FacebookAds\Object\AdsPixel;
use FacebookAds\Object\ObjectStorySpec;
use FacebookAds\Object\ProductAudience;
use FacebookAds\Object\ProductCatalog;
use FacebookAds\Object\ProductSet;
use FacebookAds\Object\TargetingSpecs;
use FacebookAds\Object\ObjectStory\TemplateData;
use FacebookAds\Object\Fields\CampaignFields;
use FacebookAds\Object\Fields\AdCreativeFields;
use FacebookAds\Object\Fields\AdFields;
use FacebookAds\Object\Fields\AdSetFields;
use FacebookAds\Object\Fields\AdsPixelsFields;
use FacebookAds\Object\Fields\ObjectStory\TemplateDataFields;
use FacebookAds\Object\Fields\ObjectStorySpecFields;
use FacebookAds\Object\Fields\ProductAudienceFields;
use FacebookAds\Object\Fields\ProductCatalogFields;
use FacebookAds\Object\Fields\ProductSetFields;
use FacebookAds\Object\Fields\TargetingSpecsFields;
use FacebookAds\Object\Values\AdObjectives;
use FacebookAds\Object\Values\BillingEvents;
use FacebookAds\Object\Values\CallToActionTypes;
use FacebookAds\Object\Values\OptimizationGoals;

class DynamicProductAdsAdvertTest extends AbstractCrudObjectTestCase {

  /**
   * @var ProductSet
   */
  protected $productSet;

  /**
   * @var ProductCatalog
   */
  protected $productCatalog;

  /**
   * @var AdsPixel
   */
  protected $adsPixel;

  /**
   * @var ProductAudience
   */
  protected $productAudience;

  /**
   * @var Campaign
   */
  protected $campaign;

  /**
   * @var AdSet
   */
  protected $adSet;

  /**
   * @var Ad
   */
  protected $ad;

  /**
   * @var AdCreative
   */
  protected $creative;

  public function setup() {
    parent::setup();

    $account = new AdAccount($this->getConfig()->accountId);
    $this->adsPixel = $account->getAdsPixels()->current();
    if ($this->adsPixel === null) {
      throw new \Exception('Ads Pixel is null');
    }

    $this->productCatalog =
      new ProductCatalog(null, $this->getConfig()->businessId);
    $this->productCatalog->setData(array(
      ProductCatalogFields::NAME => $this->getConfig()->testRunId,
    ));
    $this->productCatalog->create();

    $this->productSet =
      new ProductSet(null, $this->productCatalog->{ProductCatalogFields::ID});
    $this->productSet->setData(array(
      ProductSetFields::NAME => $this->getConfig()->testRunId,
      ProductSetFields::FILTER => array(
        'retailer_id' => array(
          'is_any' => array('pid1', 'pid2')
        )
      )
    ));
    $this->productSet->create();

    $this->productAudience
      = new ProductAudience(null, $this->getConfig()->accountId);
    $this->productAudience->setData(array(
      ProductAudienceFields::NAME => $this->getConfig()->testRunId,
      ProductAudienceFields::PRODUCT_SET_ID =>
        $this->productSet->{ProductSetFields::ID},
      ProductAudienceFields::PIXEL_ID =>
        $this->adsPixel->{AdsPixelsFields::ID},
      ProductAudienceFields::INCLUSIONS => array(array(
        'retention_seconds' => 86400,
        'rule' => array(
          'and' => array(
            array('event' => array('eq'=>'ViewContent')),
            array('userAgent' => array('i_contains'=>'iPhone'))
          )
        )
      )),
    ));

    $this->productAudience->create();
  }

  public function tearDown() {
    if ($this->productSet) {
      $this->productSet->deleteSelf();
      $this->productSet = null;
    }

    if ($this->productCatalog) {
      $this->productCatalog->deleteSelf();
      $this->productCatalog = null;
    }

    if ($this->productAudience) {
      $this->productAudience->deleteSelf();
      $this->productAudience = null;
    }

    if ($this->campaign) {
      $this->campaign->deleteSelf();
      $this->campaign = null;
    }

    if ($this->adSet) {
      $this->adSet->deleteSelf();
      $this->adSet = null;
    }

    if ($this->ad) {
      $this->ad->deleteSelf();
      $this->ad = null;
    }

    if ($this->creative) {
      $this->creative->deleteSelf();
      $this->creative = null;
    }

    parent::tearDown();
  }

  public function testDynamicProductAdsCreation() {
    $this->campaign = new Campaign(null, $this->getConfig()->accountId);
    $this->campaign->setData(array(
      CampaignFields::NAME => $this->getConfig()->testRunId,
      CampaignFields::OBJECTIVE => AdObjectives::PRODUCT_CATALOG_SALES,
      CampaignFields::PROMOTED_OBJECT =>
        array('product_catalog_id' =>
          $this->productCatalog->{ProductCatalogFields::ID})
     ));
    $this->assertCanCreate($this->campaign);

    $targeting = new TargetingSpecs();
    $targeting->{TargetingSpecsFields::GEO_LOCATIONS} =
      array('countries' => array('US'));
    $targeting->{TargetingSpecsFields::DYNAMIC_AUDIENCE_IDS} =
      array($this->productAudience->{ProductAudienceFields::ID});

    $this->adSet = new AdSet(null, $this->getConfig()->accountId);
    $this->adSet->setData(array(
      AdSetFields::NAME => $this->getConfig()->testRunId,
      AdSetFields::OPTIMIZATION_GOAL => OptimizationGoals::LINK_CLICKS,
      AdSetFields::BILLING_EVENT => BillingEvents::IMPRESSIONS,
      AdSetFields::BID_AMOUNT => 2,
      AdSetFields::DAILY_BUDGET => 2000,
      AdSetFields::CAMPAIGN_ID =>
        $this->campaign->{CampaignFields::ID},
      AdSetFields::TARGETING => $targeting,
      AdsetFields::PROMOTED_OBJECT =>
        array(
          'product_set_id' => $this->productSet->{ProductSetFields::ID},
        ),
    ));
    $this->assertCanCreate($this->adSet);

    $template = new TemplateData();
    $template->setData(array(
      TemplateDataFields::DESCRIPTION => '{{product.description}}',
      TemplateDataFields::LINK => 'http://www.example.com/',
      TemplateDataFields::MESSAGE => 'Test DPA Ad Message',
      TemplateDataFields::NAME => '{{product.name | titleize}}',
      TemplateDataFields::CALL_TO_ACTION => array(
        'type' => CallToActionTypes::SHOP_NOW
      ),
    ));

    $story = new ObjectStorySpec();
    $story->setData(array(
      ObjectStorySpecFields::PAGE_ID => $this->getConfig()->pageId,
      ObjectStorySpecFields::TEMPLATE_DATA => $template,
    ));

    $this->creative = new AdCreative(null, $this->getConfig()->accountId);
    $this->creative->setData(array(
      AdCreativeFields::NAME => $this->getConfig()->testRunId,
      AdCreativeFields::OBJECT_STORY_SPEC => $story,
      AdCreativeFields::PRODUCT_SET_ID =>
        $this->productSet->{ProductSetFields::ID},
    ));
    $this->assertCanCreate($this->creative);

    $this->ad = new Ad(null, $this->getConfig()->accountId);
    $this->ad->setData(array(
      AdFields::NAME => 'DPA Test Ad 1 '.$this->getConfig()->testRunId,
      AdFields::ADSET_ID => $this->adSet->{AdSetFields::ID},
      AdFields::CREATIVE =>
        array('creative_id' => $this->creative->{AdCreativeFields::ID}),
    ));
    $this->assertCanCreate($this->ad);
  }
}


<?php
/**
 * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
 *
 * You are hereby granted a non-exclusive, worldwide, royalty-free license to
 * use, copy, modify, and distribute this software in source code or binary
 * form for use in connection with the web services and APIs provided by
 * Facebook.
 *
 * As with any software that integrates with the Facebook platform, your use
 * of this software is subject to the Facebook Developer Principles and
 * Policies [http://developers.facebook.com/policy/]. This copyright notice
 * shall be included in all copies or substantial portions of the software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

namespace FacebookAdsTest\Object;

use FacebookAds\Object\AbstractCrudObject;

class EmptyCrudObject extends AbstractCrudObject {
}


<?php
/**
 * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
 *
 * You are hereby granted a non-exclusive, worldwide, royalty-free license to
 * use, copy, modify, and distribute this software in source code or binary
 * form for use in connection with the web services and APIs provided by
 * Facebook.
 *
 * As with any software that integrates with the Facebook platform, your use
 * of this software is subject to the Facebook Developer Principles and
 * Policies [http://developers.facebook.com/policy/]. This copyright notice
 * shall be included in all copies or substantial portions of the software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

namespace FacebookAdsTest\Object;

use FacebookAds\Object\AbstractCrudObject;
use FacebookAds\Object\AbstractObject;

class EmptyObject extends AbstractObject {

  /**
   * @var array
   */
  protected static $fields = array(
    AbstractCrudObject::FIELD_ID,
  );
}


<?php
/**
 * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
 *
 * You are hereby granted a non-exclusive, worldwide, royalty-free license to
 * use, copy, modify, and distribute this software in source code or binary
 * form for use in connection with the web services and APIs provided by
 * Facebook.
 *
 * As with any software that integrates with the Facebook platform, your use
 * of this software is subject to the Facebook Developer Principles and
 * Policies [http://developers.facebook.com/policy/]. This copyright notice
 * shall be included in all copies or substantial portions of the software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

namespace FacebookAdsTest\Object;

use FacebookAds\Object\Fields\LeadgenFormFields;
use FacebookAds\Object\LeadgenForm;
use FacebookAds\Object\Page;

class LeadgenFormTest extends AbstractCrudObjectTestCase {

  /**
   * @var int
   */
  protected $leadgenFormId;

  public function setup() {
    parent::setup();

    $page = new Page($this->getConfig()->pageId);
    $forms = $page->getLeadgenForms();

    if ($forms->count() === 0) {
      $this->markTestSkipped(sprintf(
        'LeadgenForms can\'t be created through the API.'
          .' Page %s has no leadgen forms',
        (string)$this->getConfig()->pageId));
    }

    $this->leadgenFormId = $forms->current()->{LeadgenFormFields::ID};
  }

  public function tearDown() {
    $this->leadgenFormId = null;

    parent::tearDown();
  }

  public function testCrud() {
    $form = new LeadgenForm($this->leadgenFormId);

    $this->assertCannotCreate($form);
    $this->assertCanRead($form);
    $this->assertCannotUpdate($form);
    $this->assertCanFetchConnection($form, 'getLeads');
    $this->assertCannotDelete($form);
  }
}


<?php
/**
 * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
 *
 * You are hereby granted a non-exclusive, worldwide, royalty-free license to
 * use, copy, modify, and distribute this software in source code or binary
 * form for use in connection with the web services and APIs provided by
 * Facebook.
 *
 * As with any software that integrates with the Facebook platform, your use
 * of this software is subject to the Facebook Developer Principles and
 * Policies [http://developers.facebook.com/policy/]. This copyright notice
 * shall be included in all copies or substantial portions of the software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

namespace FacebookAdsTest\Object;

use FacebookAds\Object\Fields\LeadFields;
use FacebookAds\Object\Fields\LeadgenFormFields;
use FacebookAds\Object\Lead;
use FacebookAds\Object\LeadgenForm;
use FacebookAds\Object\Page;

class LeadTest extends AbstractCrudObjectTestCase {

  /**
   * @var int
   */
  protected $leadId;

  public function setup() {
    parent::setup();

    $limit = 25;
    $page = new Page($this->getConfig()->pageId);
    $forms = $page->getLeadgenForms(
      array(LeadgenFormFields::ID),
      array('limit' => $limit));

    $forms->setUseImplicitFetch(false); // Force-disable pagination

    /** @var LeadgenForm $form */
    foreach ($forms as $form) {
      $leads = $form->getLeads();
      if ($leads->count() > 0) {
        $this->leadId = $leads->current()->{LeadFields::ID};
        break;
      }
    }

    if ($this->leadId === null) {
      $this->markTestSkipped(sprintf(
        'Leads can\'t be created through the API.'
          .' The first %d leadgen forms of Page %s have no leads',
        $limit,
        (string)$this->getConfig()->pageId));
    }
  }

  public function tearDown() {
    $this->leadId = null;

    parent::tearDown();
  }

  public function testCrud() {
    $lead = new Lead($this->leadId);

    $this->assertCannotCreate($lead);
    $this->assertCanRead($lead);
    $this->assertCannotUpdate($lead);
    $this->assertCannotDelete($lead);
  }
}


<?php
/**
 * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
 *
 * You are hereby granted a non-exclusive, worldwide, royalty-free license to
 * use, copy, modify, and distribute this software in source code or binary
 * form for use in connection with the web services and APIs provided by
 * Facebook.
 *
 * As with any software that integrates with the Facebook platform, your use
 * of this software is subject to the Facebook Developer Principles and
 * Policies [http://developers.facebook.com/policy/]. This copyright notice
 * shall be included in all copies or substantial portions of the software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

namespace FacebookAdsTest\Object;

use FacebookAds\Object\Page;

class PageTest extends AbstractCrudObjectTestCase {

  public function testConnections() {
    $page = new Page($this->getConfig()->pageId);

    $this->assertCannotCreate($page);
    $this->assertCanRead($page);
    $this->assertCanFetchConnection($page, 'getLeadgenForms');

    // Page editing is currently not supported in the SDK
  }
}


<?php
/**
 * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
 *
 * You are hereby granted a non-exclusive, worldwide, royalty-free license to
 * use, copy, modify, and distribute this software in source code or binary
 * form for use in connection with the web services and APIs provided by
 * Facebook.
 *
 * As with any software that integrates with the Facebook platform, your use
 * of this software is subject to the Facebook Developer Principles and
 * Policies [http://developers.facebook.com/policy/]. This copyright notice
 * shall be included in all copies or substantial portions of the software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

namespace FacebookAdsTest\Object;

use FacebookAds\Object\AbstractCrudObject;
use FacebookAds\Object\AdAccount;
use FacebookAds\Object\PartnerCategory;
use FacebookAdsTest\Config\SkippableFeatureTestInterface;

class PartnerCategoryTest extends AbstractCrudObjectTestCase
  implements SkippableFeatureTestInterface {

  /**
   * @return array
   */
  public function skipIfAny() {
    return array('no_partner_categories');
  }

  public function testCrudAccess() {
    $account = new AdAccount($this->getConfig()->accountId);
    $cursor = $account->getPartnerCategories();
    if (!$cursor->count()) {
      $this->markTestSkipped();
    }

    /* @var $category AbstractCrudObject */
    $category = $cursor->current();

    $this->assertTrue($category instanceof PartnerCategory);
    $this->assertCanRead($category);
    $this->assertCannotUpdate($category);
    $this->assertCannotDelete($category);
    $this->assertCannotCreate(
      new PartnerCategory(null, $this->getConfig()->accountId));
  }
}


<?php
/**
 * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
 *
 * You are hereby granted a non-exclusive, worldwide, royalty-free license to
 * use, copy, modify, and distribute this software in source code or binary
 * form for use in connection with the web services and APIs provided by
 * Facebook.
 *
 * As with any software that integrates with the Facebook platform, your use
 * of this software is subject to the Facebook Developer Principles and
 * Policies [http://developers.facebook.com/policy/]. This copyright notice
 * shall be included in all copies or substantial portions of the software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

namespace FacebookAdsTest\Object;

use FacebookAds\Object\AdAccount;
use FacebookAds\Object\AdsPixel;
use FacebookAds\Object\ProductAudience;
use FacebookAds\Object\ProductCatalog;
use FacebookAds\Object\ProductSet;
use FacebookAds\Object\Fields\AdsPixelsFields;
use FacebookAds\Object\Fields\ProductAudienceFields;
use FacebookAds\Object\Fields\ProductCatalogFields;
use FacebookAds\Object\Fields\ProductSetFields;

class ProductAudienceTest extends AbstractCrudObjectTestCase {

  /**
   * @var ProductSet
   */
  protected $productSet;

  /**
   * @var ProductCatalog
   */
  protected $productCatalog;

  /**
   * @var AdAccount
   */
  protected $account;

  /**
   * @var AdsPixel
   */
  protected $adsPixel;

  public function setup() {
    parent::setup();

    $this->account = new AdAccount($this->getConfig()->accountId);

    $cursor = $this->account->getAdsPixels();
    $this->adsPixel = $cursor->current();

    $this->productCatalog =
      new ProductCatalog(null, $this->getConfig()->businessId);
    $this->productCatalog->setData(array(
      ProductCatalogFields::NAME => $this->getConfig()->testRunId,
    ));
    $this->productCatalog->create();

    $this->productSet =
      new ProductSet(null, $this->productCatalog->{ProductCatalogFields::ID});
    $this->productSet->setData(array(
      ProductSetFields::NAME => $this->getConfig()->testRunId,
      ProductSetFields::FILTER => array(
        'retailer_id' => array(
          'is_any' => array('pid1', 'pid2')
        )
      )
    ));
    $this->productSet->create();
  }

  public function tearDown() {
    if ($this->productSet) {
      $this->productSet->deleteSelf();
      $this->productSet = null;
    }

    if ($this->productCatalog) {
      $this->productCatalog->deleteSelf();
      $this->productCatalog = null;
    }

    parent::tearDown();
  }

  public function testCrudAccess() {
    $audience_name = $this->getConfig()->testRunId;
    $this->adsPixel->{AdsPixelsFields::ID};

    $audience = new ProductAudience(null, $this->getConfig()->accountId);
    $audience->setData(array(
      ProductAudienceFields::NAME => $audience_name,
      ProductAudienceFields::PRODUCT_SET_ID =>
        $this->productSet->{ProductSetFields::ID},
      ProductAudienceFields::PIXEL_ID =>
        $this->adsPixel->{AdsPixelsFields::ID},
      ProductAudienceFields::INCLUSIONS => array(array(
        'retention_seconds' => 86400,
        'rule' => array(
          'and' => array(
            array('event' => array('eq'=>'ViewContent')),
            array('userAgent' => array('i_contains'=>'iPhone'))
          )
        )
      )),
    ));

    $this->assertCanCreate($audience);
    $this->assertCanRead($audience);
    $this->assertCanUpdate($audience, array(
      ProductAudienceFields::NAME => $audience_name.' updated',
    ));
    $this->assertCanDelete($audience);
  }
}


<?php
/**
 * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
 *
 * You are hereby granted a non-exclusive, worldwide, royalty-free license to
 * use, copy, modify, and distribute this software in source code or binary
 * form for use in connection with the web services and APIs provided by
 * Facebook.
 *
 * As with any software that integrates with the Facebook platform, your use
 * of this software is subject to the Facebook Developer Principles and
 * Policies [http://developers.facebook.com/policy/]. This copyright notice
 * shall be included in all copies or substantial portions of the software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

namespace FacebookAdsTest\Object;

use FacebookAds\Object\ProductCatalog;
use FacebookAds\Object\Fields\ProductCatalogFields;

class ProductCatalogTest extends AbstractCrudObjectTestCase {

  public function testCrud() {
    $catalog_name = $this->getConfig()->testRunId;
    $catalog = new ProductCatalog(null, $this->getConfig()->businessId);
    $catalog->setData(array(
      ProductCatalogFields::NAME => $catalog_name,
    ));

    $this->assertCanCreate($catalog);
    $this->assertCanRead($catalog);
    $this->assertCanUpdate($catalog, array(
      ProductCatalogFields::NAME => $catalog_name.' updated',
    ));
    $this->assertCanFetchConnectionAsArray($catalog, 'getExternalEventSources');
    $this->assertCanFetchConnection($catalog, 'getProductSets');
    $this->assertCanFetchConnection($catalog, 'getProductFeeds');
    $this->assertCanDelete($catalog);
  }
}


<?php
/**
 * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
 *
 * You are hereby granted a non-exclusive, worldwide, royalty-free license to
 * use, copy, modify, and distribute this software in source code or binary
 * form for use in connection with the web services and APIs provided by
 * Facebook.
 *
 * As with any software that integrates with the Facebook platform, your use
 * of this software is subject to the Facebook Developer Principles and
 * Policies [http://developers.facebook.com/policy/]. This copyright notice
 * shall be included in all copies or substantial portions of the software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

namespace FacebookAdsTest\Object;

use FacebookAds\Object\ProductCatalog;
use FacebookAds\Object\ProductFeed;
use FacebookAds\Object\Fields\ProductCatalogFields;
use FacebookAds\Object\Fields\ProductFeedFields;

class ProductFeedTest extends AbstractCrudObjectTestCase {

  /**
   * @var ProductCatalog
   */
  protected $productCatalog;

  public function setup() {
    parent::setup();

    $this->productCatalog
      = new ProductCatalog(null, $this->getConfig()->businessId);
    $this->productCatalog->setData(array(
      ProductCatalogFields::NAME => $this->getConfig()->testRunId,
    ));
    $this->productCatalog->create();
  }

  public function tearDown() {
    if ($this->productCatalog) {
      $this->productCatalog->deleteSelf();
      $this->productCatalog = null;
    }

    parent::tearDown();
  }

  public function testCrudAccess() {
    $feed_name = $this->getConfig()->testRunId;
    $feed = new ProductFeed(null, $this->productCatalog->id);
    $feed->setData(array(
      ProductFeedFields::FILE_NAME => 'my_product_feed.tsv',
      ProductFeedFields::NAME => $feed_name,
    ));

    $this->assertCanCreate($feed);
    $this->assertCanRead($feed);
    $this->assertCanUpdate($feed, array(
      ProductFeedFields::NAME => $feed_name.' updated',
    ));
    $this->assertCanFetchConnection($feed, 'getProducts');
    $this->assertCanFetchConnection($feed, 'getUploads');
    $this->assertCanDelete($feed);
  }
}


<?php
/**
 * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
 *
 * You are hereby granted a non-exclusive, worldwide, royalty-free license to
 * use, copy, modify, and distribute this software in source code or binary
 * form for use in connection with the web services and APIs provided by
 * Facebook.
 *
 * As with any software that integrates with the Facebook platform, your use
 * of this software is subject to the Facebook Developer Principles and
 * Policies [http://developers.facebook.com/policy/]. This copyright notice
 * shall be included in all copies or substantial portions of the software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

namespace FacebookAdsTest\Object;

use FacebookAds\Object\ProductCatalog;
use FacebookAds\Object\ProductSet;
use FacebookAds\Object\Fields\ProductCatalogFields;
use FacebookAds\Object\Fields\ProductSetFields;

class ProductSetTest extends AbstractCrudObjectTestCase {

  /**
   * @var ProductCatalog
   */
  protected $productCatalog;

  public function setup() {
    parent::setup();

    $this->productCatalog
      = new ProductCatalog(null, $this->getConfig()->businessId);
    $this->productCatalog->setData(array(
      ProductCatalogFields::NAME => $this->getConfig()->testRunId,
    ));
    $this->productCatalog->create();
  }

  public function tearDown() {
    if ($this->productCatalog) {
      $this->productCatalog->deleteSelf();
      $this->productCatalog = null;
    }

    parent::tearDown();
  }

  public function testCrudAccess() {
    $feed_name = $this->getConfig()->testRunId;
    $product_set = new ProductSet(null, $this->productCatalog->id);
    $product_set->setData(array(
      ProductSetFields::NAME => $feed_name,
      ProductSetFields::FILTER => array(
        'retailer_id' => array(
          'is_any' => array('pid1', 'pid2')
        )
      )
    ));

    $this->assertCanCreate($product_set);
    $this->assertCanRead($product_set);
    $this->assertCanUpdate($product_set, array(
      ProductSetFields::NAME => $feed_name.' updated',
    ));
    $this->assertCanFetchConnection($product_set, 'getProductGroups');
    $this->assertCanDelete($product_set);
  }
}


<?php
/**
 * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
 *
 * You are hereby granted a non-exclusive, worldwide, royalty-free license to
 * use, copy, modify, and distribute this software in source code or binary
 * form for use in connection with the web services and APIs provided by
 * Facebook.
 *
 * As with any software that integrates with the Facebook platform, your use
 * of this software is subject to the Facebook Developer Principles and
 * Policies [http://developers.facebook.com/policy/]. This copyright notice
 * shall be included in all copies or substantial portions of the software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

namespace FacebookAdsTest\Object;

use FacebookAds\Object\Project;
use FacebookAds\Object\Fields\ProjectFields;
use FacebookAdsTest\Config\SkippableFeatureTestInterface;

class ProjectTest extends AbstractCrudObjectTestCase
  implements SkippableFeatureTestInterface {

  /**
   * @return array
   */
  public function skipIfAny() {
    return array('no_business_manager');
  }

  public function testCrud() {
    $project = new Project(null, $this->getConfig()->businessId);
    $project->{ProjectFields::NAME} = 'Test Project';

    $this->assertCanCreate($project);
    $this->assertCanRead($project);
    $this->assertCanUpdate($project, array(
      ProjectFields::NAME => 'Updated Test Project Name'
    ));

    $this->assertCanFetchConnection($project, 'getPages');
    $this->assertCanFetchConnection($project, 'getAdAccounts');
    $this->assertCanFetchConnection($project, 'getApps');

    $project->addPage($this->getConfig()->pageId);
    $project->deletePage($this->getConfig()->pageId);

    $project->adAdAccount($this->getConfig()->accountId);
    $project->deleteAdAccount($this->getConfig()->accountId);

    $project->addApp($this->getConfig()->appId);
    $project->deleteApp($this->getConfig()->appId);

    $this->assertCanDelete($project);
  }
}


<?php
/**
 * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
 *
 * You are hereby granted a non-exclusive, worldwide, royalty-free license to
 * use, copy, modify, and distribute this software in source code or binary
 * form for use in connection with the web services and APIs provided by
 * Facebook.
 *
 * As with any software that integrates with the Facebook platform, your use
 * of this software is subject to the Facebook Developer Principles and
 * Policies [http://developers.facebook.com/policy/]. This copyright notice
 * shall be included in all copies or substantial portions of the software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

namespace FacebookAdsTest\Object;

use FacebookAdsTest\AbstractTestCase;
use FacebookAds\Object\ReachEstimate;
use FacebookAds\Object\Fields\ReachEstimateFields;

class ReachEstimateTest extends AbstractTestCase {

  public function testOnlyInnerData() {
    $reach_estimate = new ReachEstimate();
    $reach_estimate->setData(array(
      'data' => array(
        ReachEstimateFields::ESTIMATE_READY => true,
      ),
    ));
    $this->assertTrue($reach_estimate->{ReachEstimateFields::ESTIMATE_READY});
  }

  public function testOnlyOuterData() {
    $reach_estimate = new ReachEstimate();
    $reach_estimate->setData(array(
      ReachEstimateFields::ESTIMATE_READY => true,
    ));
    $this->assertTrue($reach_estimate->{ReachEstimateFields::ESTIMATE_READY});
  }

  public function testInnerDataTakesPrecedenceOverOuterData() {
    $reach_estimate = new ReachEstimate();
    $reach_estimate->setData(array(
      ReachEstimateFields::ESTIMATE_READY => false,
      'data' => array(
        ReachEstimateFields::ESTIMATE_READY => true,
      ),
     ));
    $this->assertTrue($reach_estimate->{ReachEstimateFields::ESTIMATE_READY});
  }
}


<?php
/**
 * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
 *
 * You are hereby granted a non-exclusive, worldwide, royalty-free license to
 * use, copy, modify, and distribute this software in source code or binary
 * form for use in connection with the web services and APIs provided by
 * Facebook.
 *
 * As with any software that integrates with the Facebook platform, your use
 * of this software is subject to the Facebook Developer Principles and
 * Policies [http://developers.facebook.com/policy/]. This copyright notice
 * shall be included in all copies or substantial portions of the software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

namespace FacebookAdsTest\Object;

use FacebookAds\Object\Fields\TargetingFields;
use FacebookAds\Object\ReachFrequencyPrediction;
use FacebookAds\Object\Fields\ReachFrequencyPredictionFields as RF;
use FacebookAds\Object\TargetingSpecs;
use FacebookAds\Object\Values\AdObjectives;
use FacebookAdsTest\Config\SkippableFeatureTestInterface;

class ReachFrequencyPredictionTest extends AbstractCrudObjectTestCase
  implements SkippableFeatureTestInterface {

  /**
   * @return array
   */
  public function skipIfAny() {
    return array('no_reach_and_frequency');
  }

  public function testCrudAccess() {

    $prediction
      = new ReachFrequencyPrediction(null, $this->getConfig()->accountId);

    $targeting = new TargetingSpecs();
    $targeting->{TargetingSpecsFields::GEO_LOCATIONS}
      = array('countries' => array('US'));
    $targeting->{TargetingFields::AGE_MAX} = 35;
    $targeting->{TargetingFields::AGE_MIN} = 20;
    $targeting->{TargetingFields::GENDERS} = array(2);
    $targeting->{TargetingFields::PUBLISHER_PLATFORMS} = array('facebook');
    $targeting->{TargetingFields::DEVICE_PLATFORMS} = array('desktop');
    $targeting->{TargetingFields::FACEBOOK_POSITIONS} = array('feed');

    $prediction->setData(array(
      RF::BUDGET => 3000000,
      RF::TARGET_SPEC => $targeting,
      RF::START_TIME => strtotime('midnight + 2 weeks'),
      RF::END_TIME => strtotime('midnight + 3 weeks'),
      RF::FREQUENCY_CAP => 4,
      RF::DESTINATION_ID => $this->getConfig()->pageId,
      RF::PREDICTION_MODE => ReachFrequencyPrediction::PREDICTION_MODE_REACH,
      RF::OBJECTIVE => AdObjectives::POST_ENGAGEMENT,
      RF::STORY_EVENT_TYPE => 128,
    ));

    $this->assertCanCreate($prediction);
    $this->assertCanDelete($prediction);
  }

}


<?php
/**
 * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
 *
 * You are hereby granted a non-exclusive, worldwide, royalty-free license to
 * use, copy, modify, and distribute this software in source code or binary
 * form for use in connection with the web services and APIs provided by
 * Facebook.
 *
 * As with any software that integrates with the Facebook platform, your use
 * of this software is subject to the Facebook Developer Principles and
 * Policies [http://developers.facebook.com/policy/]. This copyright notice
 * shall be included in all copies or substantial portions of the software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

namespace FacebookAdsTest\Object;

use FacebookAds\Object\AbstractCrudObject;
use FacebookAds\Object\TargetingSearch;
use FacebookAds\Object\Search\TargetingSearchTypes;

class TargetingSearchTest extends AbstractCrudObjectTestCase {

  public function testCrudAccess() {
    $cursor = TargetingSearch::search(
      TargetingSearchTypes::GEOLOCATION, null, 'Lon');

    /* @var $category AbstractCrudObject */
    $result = $cursor->current();
    $this->assertTrue($result instanceof TargetingSearch);
    $this->assertNotEmpty($result->key);
  }
}


<?php
/**
 * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
 *
 * You are hereby granted a non-exclusive, worldwide, royalty-free license to
 * use, copy, modify, and distribute this software in source code or binary
 * form for use in connection with the web services and APIs provided by
 * Facebook.
 *
 * As with any software that integrates with the Facebook platform, your use
 * of this software is subject to the Facebook Developer Principles and
 * Policies [http://developers.facebook.com/policy/]. This copyright notice
 * shall be included in all copies or substantial portions of the software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

namespace FacebookAdsTest\Object\CustomAudienceNormalizers;

use FacebookAdsTest\AbstractUnitTestCase;
use FacebookAds\Object\CustomAudienceNormalizers\EmailNormalizer;

class EmailNormalizerTest extends AbstractUnitTestCase {

    /**
     * @var EmailNormalizer
     */
    protected $emailNormalizer;

    public function setUp() {
        $this->emailNormalizer = new EmailNormalizer();
    }

    public function testNormalizeData() {
        return array(
            array(
                "foo@fb.com\t\r\n\0\x0B.",
                'foo@fb.com',
            ),
        );
    }

    /**
     * @dataProvider testNormalizeData
     */
    public function testNormalize($input, $expected) {
        $this->assertEquals(
            $expected,
            $this->emailNormalizer->normalize('email', $input));
    }
}


<?php
/**
 * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
 *
 * You are hereby granted a non-exclusive, worldwide, royalty-free license to
 * use, copy, modify, and distribute this software in source code or binary
 * form for use in connection with the web services and APIs provided by
 * Facebook.
 *
 * As with any software that integrates with the Facebook platform, your use
 * of this software is subject to the Facebook Developer Principles and
 * Policies [http://developers.facebook.com/policy/]. This copyright notice
 * shall be included in all copies or substantial portions of the software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

namespace FacebookAdsTest\Object\ServerSide;

use FacebookAdsTest\AbstractUnitTestCase;
use FacebookAds\Object\ServerSide\AsyncClient;
use FacebookAds\Api;

use GuzzleHttp\HandlerStack;
use GuzzleHttp\Handler\CurlHandler;

Api::init(null, null, 'access-token', false);

class AsyncClientTest extends AbstractUnitTestCase {
  public function testSingleton() {
    $client1 = AsyncClient::getInstance()->getClient();
    $client2 = AsyncClient::getInstance()->getClient();

    $this->assertEquals($client1, $client2);
  }

  public function testCurlOptions() {
    $async_client = AsyncClient::getInstance()->getClient();
    $expected_handler = HandlerStack::create(new CurlHandler([
      'options' => [
        CURLOPT_CONNECTTIMEOUT => 10,
        CURLOPT_TIMEOUT => 60,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HEADER => true,
        CURLOPT_CAINFO => Api::instance()->getHttpClient()->getCaBundlePath(),
      ]
    ]));

    $this->assertEquals($expected_handler, $async_client->getConfig()['handler']);
  }
}


<?php
/**
 * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
 *
 * You are hereby granted a non-exclusive, worldwide, royalty-free license to
 * use, copy, modify, and distribute this software in source code or binary
 * form for use in connection with the web services and APIs provided by
 * Facebook.
 *
 * As with any software that integrates with the Facebook platform, your use
 * of this software is subject to the Facebook Developer Principles and
 * Policies [http://developers.facebook.com/policy/]. This copyright notice
 * shall be included in all copies or substantial portions of the software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

namespace FacebookAdsTest\Object\ServerSide;

use FacebookAdsTest\AbstractUnitTestCase;
use FacebookAds\Object\ServerSide\Event;
use FacebookAds\Object\ServerSide\UserData;
use FacebookAds\Object\ServerSide\BatchProcessor;
use FacebookAds\Api;
use GuzzleHttp\Promise;
use Mockery as m;

class BatchProcessorTest extends AbstractUnitTestCase {
  protected function setUp(): void {
    $this->user_data = (new UserData())->setEmail('joe@eg.com');
    $this->event = (new Event())
      ->setEventName('Purchase')
      ->setEventTime(time())
      ->setUserData($this->user_data);
    $this->pixel_id = 'pixel-id-0';
    $this->test_event_code = 'test-code-1';
    $batch_size = 5;
    $concurrent_requests = 2;
    $this->batch_processor = new BatchProcessor($this->pixel_id, $batch_size, $concurrent_requests);
  }

  protected function tearDown(): void {
    m::close();
  }

  public function testProcessEvents() {
    $expected_event_request_params = array(
      'events' => array_fill(0, 5, $this->event),
      'test_event_code' => $this->test_event_code,
    );

    $mock_event_request_async = m::mock('overload:FacebookAds\Object\ServerSide\EventRequestAsync');
    $mock_guzzle_promise = m::mock();

    $mock_event_request_async
      ->shouldReceive('__construct')
      ->atLeast()
      ->once()
      ->with($this->pixel_id, $expected_event_request_params);
    $mock_event_request_async
      ->shouldReceive('execute')
      ->atLeast()
      ->once()
      ->andReturn($mock_guzzle_promise);
    $mock_guzzle_promise
      ->shouldReceive('wait')
      ->times(3);
    $this->addToAssertionCount(
      m::getContainer()->mockery_getExpectationCount()
    );

    $events = array_fill(0, 15, $this->event);
    $this->batch_processor->processEvents(
      array('test_event_code' => $this->test_event_code),
      $events
    );
  }

  public function testProcessEventsGenerator() {
    $expected_event_request_params = array(
      'events' => array_fill(0, 5, $this->event),
      'test_event_code' => $this->test_event_code,
    );

    $mock_event_request_async = m::mock('overload:FacebookAds\Object\ServerSide\EventRequestAsync');
    $mock_guzzle_promise = m::mock();

    $mock_event_request_async
      ->shouldReceive('__construct')
      ->atLeast()
      ->once()
      ->with($this->pixel_id, $expected_event_request_params);
    $mock_event_request_async
      ->shouldReceive('execute')
      ->atLeast()
      ->once()
      ->andReturn($mock_guzzle_promise);
    $mock_guzzle_promise
      ->shouldReceive('wait')
      ->times(3);

    $events = array_fill(0, 15, $this->event);
    $generator = $this->batch_processor->processEventsGenerator(
      array('test_event_code' => $this->test_event_code),
      $events
    );
    $iterations = 0;
    foreach ($generator as $promises) {
      $iterations += 1;
      Promise\unwrap($promises);
    }

    $this->assertEquals($iterations, 2);
  }

  public function testProcessEventRequests() {
    $mock_event_request_async = m::mock();
    $mock_guzzle_promise = m::mock();
    $expected_event_request_params = array_fill(0, 5, $mock_event_request_async);

    $mock_event_request_async
      ->shouldReceive('execute')
      ->times(5)
      ->andReturn($mock_guzzle_promise);
    $mock_guzzle_promise
      ->shouldReceive('wait')
      ->times(5);
    $this->addToAssertionCount(
      m::getContainer()->mockery_getExpectationCount()
    );

    $event_requests = array_fill(0, 5, $mock_event_request_async);
    $this->batch_processor->processEventRequests($event_requests);
  }

  public function testProcessEventRequestsGenerator() {
    $mock_event_request_async = m::mock();
    $mock_guzzle_promise = m::mock();
    $expected_event_request_params = array_fill(0, 5, $mock_event_request_async);

    $mock_event_request_async
      ->shouldReceive('execute')
      ->times(5)
      ->andReturn($mock_guzzle_promise);
    $mock_guzzle_promise
      ->shouldReceive('wait')
      ->times(5);

    $event_requests = array_fill(0, 5, $mock_event_request_async);
    $generator = $this->batch_processor->processEventRequestsGenerator($event_requests);
    $iterations = 0;
    foreach ($generator as $promises) {
      $iterations += 1;
      Promise\unwrap($promises);
    }

    $this->assertEquals(3, $iterations);
  }
}


<?php
/**
 * Copyright (c) 2015-present, Facebook, Inc. All rights reserved.
 *
 * You are hereby granted a non-exclusive, worldwide, royalty-free license to
 * use, copy, modify, and distribute this software in source code or binary
 * form for use in connection with the web services and APIs provided by
 * Facebook.
 *
 * As with any software that integrates with the Facebook platform, your use
 * of this software is subject to the Facebook Developer Principles and
 * Policies [http://developers.facebook.com/policy/]. This copyright notice
 * shall be included in all copies or substantial portions of the software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

namespace FacebookAdsTest\Object\ServerSide;

use FacebookAds\Object\ServerSide\CAPIGatewayEndpoint;
use FacebookAds\Object\ServerSide\Event;
use FacebookAds\Object\ServerSide\Filter;
use FacebookAdsTest\AbstractUnitTestCase;

class filterAllEvents implements Filter {
    public function shouldSendEvent(Event $event): bool
    {
        return false;
    }
}
class CAPIGatewayEndpointTest extends AbstractUnitTestCase {

    public function testBuildersAndGetters(){
        $capiIngressRequest = new CAPIGatewayEndpoint("https://example.com", "ACCESS_KEY");
        $this->assertEquals($capiIngressRequest->getEndpoint(), "https://example.com");
        $this->assertFalse($capiIngressRequest->isSendToEndpointOnly());
        $capiIngressRequest->setSendToEndpointOnly(true);
        $this->assertTrue($capiIngressRequest->isSendToEndpointOnly());
    }

    public function testInvalidUrl() {
        $has_throw_exception = false;
        try {
            new CAPIGatewayEndpoint("badDomain", "ACCESS_KEY");
        }
        catch (\Exception $exception) {
            $has_throw_exception = true;
            $expected_string = "URL is in invalid format";
            $this->assertStringContainsString($expected_string, $exception->getMessage());
        }
        $this->assertTrue($has_throw_exception);
    }

    public function testFilterAllEvents() {
        $capiIngressRequest = new CAPIGatewayEndpoint("https://example.com", "ACCESS_KEY");
        $capiIngressRequest->setFilter(new filterAllEvents());
        $event1 = new Event();
        $event1->setEventId('1');
        $event2 = new Event();
        $event2->setEventId('2');
        $events = array($event1, $event2);
        $response = $capiIngressRequest->sendEvent('pixelId', $events);
        $this->assertEquals($response->getMessage(), 'No events to send');
        $this->assertEquals($response->getResponseCode(), null);
    }
}


<?php
/**
 * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
 *
 * You are hereby granted a non-exclusive, worldwide, royalty-free license to
 * use, copy, modify, and distribute this software in source code or binary
 * form for use in connection with the web services and APIs provided by
 * Facebook.
 *
 * As with any software that integrates with the Facebook platform, your use
 * of this software is subject to the Facebook Developer Principles and
 * Policies [http://developers.facebook.com/policy/]. This copyright notice
 * shall be included in all copies or substantial portions of the software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

namespace FacebookAdsTest\Object;

use FacebookAdsTest\AbstractUnitTestCase;
use FacebookAds\Object\ServerSide\Content;
use FacebookAds\Object\ServerSide\DeliveryCategory;

class ContentTest extends AbstractUnitTestCase {
  public function testContentBuilder() {
    $expected = array(
      'id' => 'product-test',
      'quantity' => 10,
      'item_price' => 4.99,
      'title' => 'title-test',
      'description' => 'description-test',
      'brand' => 'brand-test',
      'category' => 'category-test',
      'delivery_category' => DeliveryCategory::CURBSIDE,
    );

    $content = (new Content())
      ->setProductId($expected['id'])
      ->setQuantity($expected['quantity'])
      ->setItemPrice($expected['item_price'])
      ->setTitle($expected['title'])
      ->setDescription($expected['description'])
      ->setBrand($expected['brand'])
      ->setCategory($expected['category'])
      ->setDeliveryCategory($expected['delivery_category']);

    $this->assertEquals($content->normalize(), $expected);
  }

  public function testContentConstructor() {
    $initial = array(
      'product_id' => 'product-test',
      'quantity' => 10,
      'item_price' => 4.99,
      'title' => 'title-test',
      'description' => 'description-test',
      'brand' => 'brand-test',
      'category' => 'category-test',
      'delivery_category' => DeliveryCategory::CURBSIDE,
    );
    $expected = array(
      'id' => $initial['product_id'],
      'quantity' => $initial['quantity'],
      'item_price' => $initial['item_price'],
      'title' => $initial['title'],
      'description' => $initial['description'],
      'brand' => $initial['brand'],
      'category' => $initial['category'],
      'delivery_category' => DeliveryCategory::CURBSIDE,
    );
    $content = new Content($initial);

    $this->assertEquals($content->normalize(), $expected);
  }

  public function testInvalidDeliveryCategory() {
    $test_delivery_category = 'invalid_delivery_category';
    $content = (new Content())->setDeliveryCategory($test_delivery_category);
    try {
     $normalized_payload = $content->normalize();
    } catch (\Exception $exception) {
      $threw_exception = true;
      $expected_string = sprintf("Invalid delivery_category passed: %s", $test_delivery_category);
      $this->assertStringContainsString($expected_string, $exception->getMessage());
    }

    $this->assertTrue($threw_exception);
  }
}


<?php
/**
 * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
 *
 * You are hereby granted a non-exclusive, worldwide, royalty-free license to
 * use, copy, modify, and distribute this software in source code or binary
 * form for use in connection with the web services and APIs provided by
 * Facebook.
 *
 * As with any software that integrates with the Facebook platform, your use
 * of this software is subject to the Facebook Developer Principles and
 * Policies [http://developers.facebook.com/policy/]. This copyright notice
 * shall be included in all copies or substantial portions of the software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

namespace FacebookAdsTest\Object;

use FacebookAdsTest\AbstractUnitTestCase;
use FacebookAds\Object\ServerSide\CustomData;
use FacebookAds\Object\ServerSide\Content;
use FacebookAds\Object\ServerSide\DeliveryCategory;

class CustomDataTest extends AbstractUnitTestCase {
  public function testBuilderAndConstructor() {
    $custom_properties = array(
      'custom1' => 'property1',
      'custom2' => 'property2'
    );
    $content_state = array('title' => 'content-1');
    $content = new Content($content_state);
    $state = array(
      'value' => 0.1,
      'currency' => 'usd',
      'content_name' => 'content-name-2',
      'content_category' => 'content-category-3',
      'content_ids' => array('id-1', 'id2'),
      'content_type' => 'content-type-4',
      'order_id' => 'order-id-5',
      'predicted_ltv' => 6.10,
      'num_items' => 7,
      'status' => 'status-8',
      'search_string' => 'search-string-9',
      'item_number' => 'item-number-10',
      'delivery_category' => DeliveryCategory::CURBSIDE,
    );
    $expected = array_merge(
      $state,
      array('contents' => array($content_state)),
      $custom_properties
    );
    $builder = (new CustomData())
      ->setValue($state['value'])
      ->setCurrency($state['currency'])
      ->setContentName($state['content_name'])
      ->setContentCategory($state['content_category'])
      ->setContentIds($state['content_ids'])
      ->setContents(array($content))
      ->setContentType($state['content_type'])
      ->setOrderId($state['order_id'])
      ->setPredictedLtv($state['predicted_ltv'])
      ->setNumItems($state['num_items'])
      ->setStatus($state['status'])
      ->setSearchString($state['search_string'])
      ->setItemNumber($state['item_number'])
      ->setDeliveryCategory($state['delivery_category'])
      ->setCustomProperties($custom_properties);
    $this->assertEquals($expected, $builder->normalize());

    $constructor = new CustomData(array(
      'value' => $state['value'],
      'currency' => $state['currency'],
      'content_name' => $state['content_name'],
      'content_category' => $state['content_category'],
      'content_ids' => $state['content_ids'],
      'contents' => array($content),
      'content_type' => $state['content_type'],
      'order_id' => $state['order_id'],
      'predicted_ltv' => $state['predicted_ltv'],
      'num_items' => $state['num_items'],
      'status' => $state['status'],
      'search_string' => $state['search_string'],
      'item_number' => $state['item_number'],
      'delivery_category' => $state['delivery_category'],
      'custom_properties' => $custom_properties
    ));
    $this->assertEquals($expected, $constructor->normalize());
  }

  public function testInvalidDeliveryCategory() {
    $test_delivery_category = 'invalid_delivery_category';

    $custom_data = (new CustomData())->setDeliveryCategory($test_delivery_category);

    try {
     $normalized_payload = $custom_data->normalize();
    } catch (\Exception $exception) {
      $has_throw_exception = true;
      $expected_string = sprintf("Invalid delivery_category passed: %s",$test_delivery_category);
      $this->assertStringContainsString($expected_string, $exception->getMessage());
    }

    $this->assertTrue($has_throw_exception);
  }

  public function testZeroCustomDataValue() {
    $custom_data = (new CustomData())->setValue(0.0);

    $normalized_payload = $custom_data->normalize();
    $this->assertEquals($normalized_payload['value'], 0);
  }
}


<?php
/**
 * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
 *
 * You are hereby granted a non-exclusive, worldwide, royalty-free license to
 * use, copy, modify, and distribute this software in source code or binary
 * form for use in connection with the web services and APIs provided by
 * Facebook.
 *
 * As with any software that integrates with the Facebook platform, your use
 * of this software is subject to the Facebook Developer Principles and
 * Policies [http://developers.facebook.com/policy/]. This copyright notice
 * shall be included in all copies or substantial portions of the software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

namespace FacebookAdsTest\Object\ServerSide;

use FacebookAdsTest\AbstractUnitTestCase;
use FacebookAds\Object\ServerSide\CustomData;
use FacebookAds\Object\ServerSide\Event;
use FacebookAds\Object\ServerSide\UserData;

class EventAMAPITest extends AbstractUnitTestCase {
    public function testBuilder() {
      $user_data = new UserData(array('email' => 'eg@test.com'));
      $custom_data = new CustomData(array('col_1' => 'foo2'));
      $expected = array(
        'event_name' => 'custom',
        'event_time' => 1234,
        'user_data' => $user_data->normalize(),
        'custom_data' => $custom_data->normalize(),
        'data_processing_options' => array('AMO'),
        'advanced_measurement_table' => 'test_am_table',
      );

      $event = (new Event())
        ->setEventName($expected['event_name'])
        ->setEventTime($expected['event_time'])
        ->setUserData($user_data)
        ->setCustomData($custom_data)
        ->setDataProcessingOptions($expected['data_processing_options'])
        ->setAdvancedMeasurementTable($expected['advanced_measurement_table']);

      $this->assertEquals($expected, $event->normalize());
    }
  }


<?php
/**
 * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
 *
 * You are hereby granted a non-exclusive, worldwide, royalty-free license to
 * use, copy, modify, and distribute this software in source code or binary
 * form for use in connection with the web services and APIs provided by
 * Facebook.
 *
 * As with any software that integrates with the Facebook platform, your use
 * of this software is subject to the Facebook Developer Principles and
 * Policies [http://developers.facebook.com/policy/]. This copyright notice
 * shall be included in all copies or substantial portions of the software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

namespace FacebookAdsTest\Object\ServerSide;

use FacebookAdsTest\AbstractUnitTestCase;
use FacebookAds\Object\ServerSide\Event;
use FacebookAds\Object\ServerSide\EventRequestAsync;
use FacebookAds\Api;

class EventRequestAsyncTest extends AbstractUnitTestCase {
  public function testBuilder() {
    $event = new Event(array('event_name' => 'my-event'));
    $expected = array(
      'data' => array(array('event_name' => $event['event_name'])),
      'test_event_code' => 'test-event-code-0',
      'partner_agent' => 'partner-agent-1',
      'namespace_id' => 'namespace-id-2',
      'upload_id' => 'upload-id-3',
      'upload_tag' => 'upload-tag-4',
      'upload_source' => 'upload-source-5',
    );
    $event_request_async = (new EventRequestAsync('pixel-id'))
      ->setEvents(array($event))
      ->setTestEventCode($expected['test_event_code'])
      ->setPartnerAgent($expected['partner_agent'])
      ->setNamespaceId($expected['namespace_id'])
      ->setUploadId($expected['upload_id'])
      ->setUploadTag($expected['upload_tag'])
      ->setUploadSource($expected['upload_source']);

    $this->assertEquals($expected, $event_request_async->normalize());
  }

  public function testConstructor() {
    $event = new Event(array('event_name' => 'my-event'));
    $expected_event = array('data' => [array('event_name' => $event['event_name'])]);
    $state = array(
      'test_event_code' => 'test-event-code-0',
      'partner_agent' => 'partner-agent-1',
      'namespace_id' => 'namespace-id-2',
      'upload_id' => 'upload-id-3',
      'upload_tag' => 'upload-tag-4',
      'upload_source' => 'upload-source-5',
    );
    $data = array_merge(array('events' => array($event)), $state);
    $expected = array_merge($state, $expected_event);
    $event_request_async = new EventRequestAsync('pixel-id', $data);

    $this->assertEquals($expected, $event_request_async->normalize());
  }

  public function testPromiseCancel() {
    Api::init(null, null, 'access-token-123');
    $event_request_async = new EventRequestAsync('pixel-id-456', array(
      'test_event_code' => 'test-event-code-0',
      'events' => array(new Event(array('event_name' => 'my-event')))
    ));
    $promise = $event_request_async->execute();
    $promise->cancel();

    $this->assertEquals('rejected', $promise->getState());
  }

  public function testPromiseReject() {
    Api::init(null, null, 'access-token-123');
    $event_request_async = new EventRequestAsync('pixel-id-456', array(
      'test_event_code' => 'test-event-code-0',
      'events' => array(new Event(array('event_name' => 'my-event')))
    ));
    $promise = $event_request_async->execute();
    $promise->reject('some error');

    $this->assertEquals('rejected', $promise->getState());
  }
}