<?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 FacebookAds\Object\Values;

use FacebookAds\Enum\AbstractEnum;

/**
 * This class is auto-generated.
 *
 * For any issues or feature requests related to this class, please let us know
 * on github and we'll fix in our codegen framework. We'll not be able to accept
 * pull request for this class.
 *
 * @method static VehicleAvailabilityValues getInstance()
 */
class VehicleAvailabilityValues extends AbstractEnum {

  const AVAILABLE = 'AVAILABLE';
  const NOT_AVAILABLE = 'NOT_AVAILABLE';
  const PENDING = 'PENDING';
}


<?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 FacebookAds\Object\Values;

use FacebookAds\Enum\AbstractEnum;

/**
 * This class is auto-generated.
 *
 * For any issues or feature requests related to this class, please let us know
 * on github and we'll fix in our codegen framework. We'll not be able to accept
 * pull request for this class.
 *
 * @method static VehicleBodyStyleValues getInstance()
 */
class VehicleBodyStyleValues extends AbstractEnum {

  const CONVERTIBLE = 'CONVERTIBLE';
  const COUPE = 'COUPE';
  const CROSSOVER = 'CROSSOVER';
  const ESTATE = 'ESTATE';
  const GRANDTOURER = 'GRANDTOURER';
  const HATCHBACK = 'HATCHBACK';
  const MINIBUS = 'MINIBUS';
  const MINIVAN = 'MINIVAN';
  const MPV = 'MPV';
  const NONE = 'NONE';
  const OTHER = 'OTHER';
  const PICKUP = 'PICKUP';
  const ROADSTER = 'ROADSTER';
  const SALOON = 'SALOON';
  const SEDAN = 'SEDAN';
  const SMALL_CAR = 'SMALL_CAR';
  const SPORTSCAR = 'SPORTSCAR';
  const SUPERCAR = 'SUPERCAR';
  const SUPERMINI = 'SUPERMINI';
  const SUV = 'SUV';
  const TRUCK = 'TRUCK';
  const VAN = 'VAN';
  const WAGON = 'WAGON';
}


<?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 FacebookAds\Object\Values;

use FacebookAds\Enum\AbstractEnum;

/**
 * This class is auto-generated.
 *
 * For any issues or feature requests related to this class, please let us know
 * on github and we'll fix in our codegen framework. We'll not be able to accept
 * pull request for this class.
 *
 * @method static VehicleConditionValues getInstance()
 */
class VehicleConditionValues extends AbstractEnum {

  const EXCELLENT = 'EXCELLENT';
  const FAIR = 'FAIR';
  const GOOD = 'GOOD';
  const NONE = 'NONE';
  const OTHER = 'OTHER';
  const POOR = 'POOR';
  const VERY_GOOD = 'VERY_GOOD';
}


<?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 FacebookAds\Object\Values;

use FacebookAds\Enum\AbstractEnum;

/**
 * This class is auto-generated.
 *
 * For any issues or feature requests related to this class, please let us know
 * on github and we'll fix in our codegen framework. We'll not be able to accept
 * pull request for this class.
 *
 * @method static VehicleDrivetrainValues getInstance()
 */
class VehicleDrivetrainValues extends AbstractEnum {

  const AWD = 'AWD';
  const FOUR_WD = 'FOUR_WD';
  const FWD = 'FWD';
  const NONE = 'NONE';
  const OTHER = 'OTHER';
  const RWD = 'RWD';
  const TWO_WD = 'TWO_WD';
}


<?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 FacebookAds\Object\Values;

use FacebookAds\Enum\AbstractEnum;

/**
 * This class is auto-generated.
 *
 * For any issues or feature requests related to this class, please let us know
 * on github and we'll fix in our codegen framework. We'll not be able to accept
 * pull request for this class.
 *
 * @method static VehicleFuelTypeValues getInstance()
 */
class VehicleFuelTypeValues extends AbstractEnum {

  const DIESEL = 'DIESEL';
  const ELECTRIC = 'ELECTRIC';
  const FLEX = 'FLEX';
  const GASOLINE = 'GASOLINE';
  const HYBRID = 'HYBRID';
  const NONE = 'NONE';
  const OTHER = 'OTHER';
  const PETROL = 'PETROL';
  const PLUGIN_HYBRID = 'PLUGIN_HYBRID';
}


<?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 FacebookAds\Object\Values;

use FacebookAds\Enum\AbstractEnum;

/**
 * This class is auto-generated.
 *
 * For any issues or feature requests related to this class, please let us know
 * on github and we'll fix in our codegen framework. We'll not be able to accept
 * pull request for this class.
 *
 * @method static VehicleImageFetchStatusValues getInstance()
 */
class VehicleImageFetchStatusValues extends AbstractEnum {

  const DIRECT_UPLOAD = 'DIRECT_UPLOAD';
  const FETCHED = 'FETCHED';
  const FETCH_FAILED = 'FETCH_FAILED';
  const NO_STATUS = 'NO_STATUS';
  const OUTDATED = 'OUTDATED';
  const PARTIAL_FETCH = 'PARTIAL_FETCH';
}


<?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 FacebookAds\Object\Values;

use FacebookAds\Enum\AbstractEnum;

/**
 * This class is auto-generated.
 *
 * For any issues or feature requests related to this class, please let us know
 * on github and we'll fix in our codegen framework. We'll not be able to accept
 * pull request for this class.
 *
 * @method static VehicleOfferImageFetchStatusValues getInstance()
 */
class VehicleOfferImageFetchStatusValues extends AbstractEnum {

  const DIRECT_UPLOAD = 'DIRECT_UPLOAD';
  const FETCHED = 'FETCHED';
  const FETCH_FAILED = 'FETCH_FAILED';
  const NO_STATUS = 'NO_STATUS';
  const OUTDATED = 'OUTDATED';
  const PARTIAL_FETCH = 'PARTIAL_FETCH';
}


<?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 FacebookAds\Object\Values;

use FacebookAds\Enum\AbstractEnum;

/**
 * This class is auto-generated.
 *
 * For any issues or feature requests related to this class, please let us know
 * on github and we'll fix in our codegen framework. We'll not be able to accept
 * pull request for this class.
 *
 * @method static VehicleOfferVisibilityValues getInstance()
 */
class VehicleOfferVisibilityValues extends AbstractEnum {

  const PUBLISHED = 'PUBLISHED';
  const STAGING = 'STAGING';
}


<?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 FacebookAds\Object\Values;

use FacebookAds\Enum\AbstractEnum;

/**
 * This class is auto-generated.
 *
 * For any issues or feature requests related to this class, please let us know
 * on github and we'll fix in our codegen framework. We'll not be able to accept
 * pull request for this class.
 *
 * @method static VehicleStateOfVehicleValues getInstance()
 */
class VehicleStateOfVehicleValues extends AbstractEnum {

  const CPO = 'CPO';
  const VALUE_NEW = 'NEW';
  const USED = 'USED';
}


<?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 FacebookAds\Object\Values;

use FacebookAds\Enum\AbstractEnum;

/**
 * This class is auto-generated.
 *
 * For any issues or feature requests related to this class, please let us know
 * on github and we'll fix in our codegen framework. We'll not be able to accept
 * pull request for this class.
 *
 * @method static VehicleTransmissionValues getInstance()
 */
class VehicleTransmissionValues extends AbstractEnum {

  const AUTOMATIC = 'AUTOMATIC';
  const MANUAL = 'MANUAL';
  const NONE = 'NONE';
  const OTHER = 'OTHER';
}


<?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 FacebookAds\Object\Values;

use FacebookAds\Enum\AbstractEnum;

/**
 * This class is auto-generated.
 *
 * For any issues or feature requests related to this class, please let us know
 * on github and we'll fix in our codegen framework. We'll not be able to accept
 * pull request for this class.
 *
 * @method static VehicleVehicleTypeValues getInstance()
 */
class VehicleVehicleTypeValues extends AbstractEnum {

  const BOAT = 'BOAT';
  const CAR_TRUCK = 'CAR_TRUCK';
  const COMMERCIAL = 'COMMERCIAL';
  const MOTORCYCLE = 'MOTORCYCLE';
  const OTHER = 'OTHER';
  const POWERSPORT = 'POWERSPORT';
  const RV_CAMPER = 'RV_CAMPER';
  const TRAILER = 'TRAILER';
}


<?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 FacebookAds\Object\Values;

use FacebookAds\Enum\AbstractEnum;

/**
 * This class is auto-generated.
 *
 * For any issues or feature requests related to this class, please let us know
 * on github and we'll fix in our codegen framework. We'll not be able to accept
 * pull request for this class.
 *
 * @method static VehicleVisibilityValues getInstance()
 */
class VehicleVisibilityValues extends AbstractEnum {

  const PUBLISHED = 'PUBLISHED';
  const STAGING = 'STAGING';
}


<?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 FacebookAds\Object\Values;

use FacebookAds\Enum\AbstractEnum;

/**
 * This class is auto-generated.
 *
 * For any issues or feature requests related to this class, please let us know
 * on github and we'll fix in our codegen framework. We'll not be able to accept
 * pull request for this class.
 *
 * @method static VideoCopyrightContentCategoryValues getInstance()
 */
class VideoCopyrightContentCategoryValues extends AbstractEnum {

  const EPISODE = 'episode';
  const MOVIE = 'movie';
  const WEB = 'web';
}


<?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 FacebookAds\Object\Values;

use FacebookAds\Enum\AbstractEnum;

/**
 * This class is auto-generated.
 *
 * For any issues or feature requests related to this class, please let us know
 * on github and we'll fix in our codegen framework. We'll not be able to accept
 * pull request for this class.
 *
 * @method static VideoCopyrightMonitoringTypeValues getInstance()
 */
class VideoCopyrightMonitoringTypeValues extends AbstractEnum {

  const AUDIO_ONLY = 'AUDIO_ONLY';
  const VIDEO_AND_AUDIO = 'VIDEO_AND_AUDIO';
  const VIDEO_ONLY = 'VIDEO_ONLY';
}


<?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 FacebookAds\Object\Values;

use FacebookAds\Enum\AbstractEnum;

/**
 * This class is auto-generated.
 *
 * For any issues or feature requests related to this class, please let us know
 * on github and we'll fix in our codegen framework. We'll not be able to accept
 * pull request for this class.
 *
 * @method static VideoCopyrightRuleSourceValues getInstance()
 */
class VideoCopyrightRuleSourceValues extends AbstractEnum {

  const MATCH_SETTINGS_DIALOG = 'MATCH_SETTINGS_DIALOG';
  const RULES_SELECTOR = 'RULES_SELECTOR';
  const RULES_TAB = 'RULES_TAB';
}


<?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 FacebookAds\Object\Values;

use FacebookAds\Enum\AbstractEnum;

/**
 * This class is auto-generated.
 *
 * For any issues or feature requests related to this class, please let us know
 * on github and we'll fix in our codegen framework. We'll not be able to accept
 * pull request for this class.
 *
 * @method static VideoPollActionValues getInstance()
 */
class VideoPollActionValues extends AbstractEnum {

  const ATTACH_TO_VIDEO = 'ATTACH_TO_VIDEO';
  const CLOSE = 'CLOSE';
  const DELETE_POLL = 'DELETE_POLL';
  const SHOW_RESULTS = 'SHOW_RESULTS';
  const SHOW_VOTING = 'SHOW_VOTING';
}


<?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 FacebookAds\Object\Values;

use FacebookAds\Enum\AbstractEnum;

/**
 * This class is auto-generated.
 *
 * For any issues or feature requests related to this class, please let us know
 * on github and we'll fix in our codegen framework. We'll not be able to accept
 * pull request for this class.
 *
 * @method static VideoPollStatusValues getInstance()
 */
class VideoPollStatusValues extends AbstractEnum {

  const CLOSED = 'closed';
  const RESULTS_OPEN = 'results_open';
  const VOTING_OPEN = 'voting_open';
}


<?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 FacebookAds\Object\Values;

use FacebookAds\Enum\AbstractEnum;

/**
 * This class is auto-generated.
 *
 * For any issues or feature requests related to this class, please let us know
 * on github and we'll fix in our codegen framework. We'll not be able to accept
 * pull request for this class.
 *
 * @method static WhatsAppBusinessAccountCategoryValues getInstance()
 */
class WhatsAppBusinessAccountCategoryValues extends AbstractEnum {

  const AUTHENTICATION = 'AUTHENTICATION';
  const MARKETING = 'MARKETING';
  const UTILITY = 'UTILITY';
}


<?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 FacebookAds\Object\Values;

use FacebookAds\Enum\AbstractEnum;

/**
 * This class is auto-generated.
 *
 * For any issues or feature requests related to this class, please let us know
 * on github and we'll fix in our codegen framework. We'll not be able to accept
 * pull request for this class.
 *
 * @method static WhatsAppBusinessAccountTasksValues getInstance()
 */
class WhatsAppBusinessAccountTasksValues extends AbstractEnum {

  const DEVELOP = 'DEVELOP';
  const FULL_CONTROL = 'FULL_CONTROL';
  const MANAGE = 'MANAGE';
  const MANAGE_EXTENSIONS = 'MANAGE_EXTENSIONS';
  const MANAGE_PHONE = 'MANAGE_PHONE';
  const MANAGE_PHONE_ASSETS = 'MANAGE_PHONE_ASSETS';
  const MANAGE_TEMPLATES = 'MANAGE_TEMPLATES';
  const MESSAGING = 'MESSAGING';
  const VIEW_COST = 'VIEW_COST';
  const VIEW_PHONE_ASSETS = 'VIEW_PHONE_ASSETS';
  const VIEW_TEMPLATES = 'VIEW_TEMPLATES';
}


<?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 FacebookAds\Object\Values;

use FacebookAds\Enum\AbstractEnum;

/**
 * This class is auto-generated.
 *
 * For any issues or feature requests related to this class, please let us know
 * on github and we'll fix in our codegen framework. We'll not be able to accept
 * pull request for this class.
 *
 * @method static WhatsAppBusinessPreVerifiedPhoneNumberCodeVerificationStatusValues getInstance()
 */
class WhatsAppBusinessPreVerifiedPhoneNumberCodeVerificationStatusValues extends AbstractEnum {

  const EXPIRED = 'EXPIRED';
  const NOT_VERIFIED = 'NOT_VERIFIED';
  const VERIFIED = 'VERIFIED';
}


<?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.
 *
 */

return array(

  /**
   * @var string Numeric Facebook app id, espressed as string
   */
  'app_id' => '',

  /**
   * @var string App Secret
   * @see https://developers.facebook.com/apps/<APP_ID>/dashboard/
   */
  'app_secret' => '',

  /**
   * @var string User Access Token
   * @see https://developers.facebook.com/docs/facebook-login/access-tokens/
   */
  'access_token' => '',

  /**
   * @var string Numeric Facebook Business Manager id, espressed as string
   */
  'business_id' => '',

  /**
   * @var string Numeric Facebook id, preceded by 'act_', espressed as string
   * @see https://www.facebook.com/ads/manage/home/
   */
  'act_id' => '',

  /**
   * @var string PHP timezone compatible with the AdAccount timezone, override php.ini config
   * @see http://php.net/manual/en/timezones.php
   */
  'act_timezone' => '',

  /**
   * @var string Numeric Facebook id, espressed as string
   * @see https://www.facebook.com/ads/manage/home/
   */
  'page_id' => '',

  /**
   * @var string Url of your app [Stream post URL security]
   *             Example: 'http://my.domain.com/'
   * @see https://developers.facebook.com/docs/facebook-login/security/#surfacearea
   */
  'app_url' => '',

  /**
   * @var string Numeric Instagram actor id, espressed as string
   */
  'instagram_actor_id' => '',

  // OPTIONAL INTEGRATION TESTS

  'skip_if' => array(

    /**
     * @var bool Skip tests that require an business manager
     * @see https://developers.facebook.com/docs/marketing-api/businessmanager/
     */
    'no_business_manager' => true,

    /**
     * @var bool Skip tests that require an account with a valid payment method
     * @see https://secure.facebook.com/ads/manage/funding.php
     */
    'no_payment_method' => true,

    /**
     * @var bool Skip tests that require parnet categories whitelisting
     * @see https://developers.facebook.com/docs/reference/ads-api/partnercategories
     */
    'no_partner_categories' => true,

    /**
     * @var bool Skip tests that require video upload
     */
    'no_video_upload' => true,

    /**
     * @var bool Skip tests that require reach and frequency whitelisting
     */
    'no_reach_and_frequency_whitelist' => true,

    /**
     * @var bool Skip tests that require polling for async jobs execution
     */
    'no_async_jobs' => true,

    /**
     * @var bool Skip tests that require an instagram actor
     */
    'no_instagram' => true,
  ),

  // OPTIONAL CONFIGURATIONS

  /**
   * @var string Override Facebook graph domain
   *             Example: try hitting beta.facebook.com
   */
  'graph_base_domain' => '',

  /**
   * @var string Disable SSL verification between CA and host
   *             [Security] Do not change this unless you trust your network
   */
  'skip_ssl_verification' => false,

  /**
   * @var string Filepath to which cUrl shell equivalents will be dumped
   *             Tip: access std streams with 'php://stdout' or 'php://stderr'
   */
  'curl_logger' => '',

  // OPTIONAL SECONDARY ENTITIES
  // Do not set the same as primary. May incurr in lost permissions.

  /**
   * @var string Ausiliary Business ID for permissions and sharing testing
   */
  'secondary_business_id' => '',

  /**
   * @var string Ausiliary Account ID for permissions and sharing testing
   */
  'secondary_account_id' => '',

  /**
   * @var string Ausiliary Page ID for permissions and sharing testing
   */
  'secondary_page_id' => '',

  /**
   * @var string Ausiliary Page ID for permissions and sharing testing
   */
  'secondary_app_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\Bootstrap;

error_reporting(E_ALL | E_STRICT);
if (!ini_get('date.timezone')) {
  ini_set('date.timezone', 'UTC');
}

require_once __DIR__.'/FacebookAdsTest/Bootstrap/Bootstrap.php';
require_once __DIR__.'/FacebookAdsTest/Bootstrap/IntegrationBootstrap.php';

$bootstrap = new IntegrationBootstrap();
$bootstrap->init();

return $bootstrap;


<?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\Bootstrap;

error_reporting(E_ALL | E_STRICT);
if (!ini_get('date.timezone')) {
  ini_set('date.timezone', 'UTC');
}
require_once __DIR__.'/FacebookAdsTest/Bootstrap/Bootstrap.php';

$bootstrap = new Bootstrap();
$bootstrap->init();

return $bootstrap;


<?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;

use FacebookAds\Api;
use FacebookAds\Http\Adapter\CurlAdapter;
use FacebookAds\Http\Client;
use FacebookAds\Http\Exception\RequestException;
use FacebookAds\Logger\CurlLogger;
use FacebookAds\Logger\LoggerInterface;
use FacebookAds\Logger\NullLogger;
use FacebookAds\Session;
use FacebookAdsTest\Exception\PHPUnitRequestExceptionWrapper;

/**
 * Base class for the integration test cases.
 * Provide Network services.
 */
class AbstractIntegrationTestCase extends AbstractTestCase {

  /**
   * @var LoggerInterface
   */
  protected $logger;

  /**
   * @var Client
   */
  protected $httpClient;

  /**
   * @var Session
   */
  protected $session;

  /**
   * @var Api
   */
  protected $api;

  /**
   * @return LoggerInterface
   */
  public function getLogger() {
    return $this->logger;
  }

  /**
   * @return Session
   */
  public function getSession() {
    return $this->session;
  }

  /**
   * @return Client
   */
  public function getHttpClient() {
    return $this->httpClient;
  }

  /**
   * @return Api
   */
  public function getApi() {
    return $this->api;
  }

  protected function setupSession() {
    $this->session = new Session(
      $this->getConfig()->appId,
      $this->getConfig()->appSecret,
      $this->getConfig()->accessToken);
  }

  protected function setupHttpClient() {
    $this->httpClient = new Client();
    if ($this->getConfig()->graphBaseDomain) {
      $this->httpClient->setDefaultGraphBaseDomain(
        $this->getConfig()->graphBaseDomain);
    }
    if ($this->getConfig()->skipSslVerification) {
      /** @var CurlAdapter $adapter */
      $adapter = $this->httpClient->getAdapter();
      $adapter->getOpts()->offsetSet(CURLOPT_SSL_VERIFYHOST, false);
      $adapter->getOpts()->offsetSet(CURLOPT_SSL_VERIFYPEER, false);
    }
  }

  protected function setupLogger() {
    $this->logger = $this->getConfig()->curlLogger
      ? new CurlLogger(fopen($this->getConfig()->curlLogger, "a"))
      : new NullLogger();
  }

  protected function setupApi() {
    $this->api = new Api(
      $this->getHttpClient(),
      $this->getSession());

    $this->api->setLogger($this->getLogger());

    Api::setInstance($this->api);
  }

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

    $this->getSkippableFeaturesManager()->enforceSkipTest($this);

    $this->setupLogger();
    $this->setupSession();
    $this->setupHttpClient();
    $this->setupApi();
  }

  public function tearDown() : void {
    $this->api = null;
    $this->httpClient = null;
    $this->session = null;
    $this->logger = null;

    parent::tearDown();
  }

  /**
   * This method is called when a test method did not execute successfully.
   *
   * @param \Throwable $e
   * @throws \Throwable
   */
  protected function onNotSuccessfulTest(\Throwable $e) : void {
    if ($e instanceof RequestException) {
      throw new PHPUnitRequestExceptionWrapper($e);
    } else {
      throw $e;
    }
  }
}


<?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;

use FacebookAdsTest\Config\Config;
use FacebookAdsTest\Config\SkippableFeaturesManager;
use \PHPUnit_Framework_MockObject_Builder_InvocationMocker as Mock;
use PHPUnit\Framework\TestCase;

/**
 * Base class for the unit test cases, providing the functions for AdsAPI
 * initialization etc.
 */
class AbstractTestCase extends TestCase {

  /**
   * @return SkippableFeaturesManager
   */
  public function getSkippableFeaturesManager() {
    return SkippableFeaturesManager::instance();
  }

  /**
   * @param string $key
   * @return bool
   */
  public function shouldSkipTest($key) {
    return $this->getSkippableFeaturesManager()->isSkipKey($key);
  }

  public function skipIf($key) {
    if ($this->shouldSkipTest($key)) {
      $this->markTestSkipped();
    }
  }

  /**
   * @return Config
   */
  public function getConfig() {
    return Config::instance();
  }

  /**
   * @return string
   * @deprecated use getConfig()
   */
  public function getTestRunId() {
    return $this->getConfig()->testRunId;
  }

  /**
   * @return string
   * @deprecated use getConfig()
   */
  public function getTestImagePath() {
    return $this->getConfig()->testImagePath;
  }

  /**
   * @return string
   * @deprecated use getConfig()
   */
  public function getTestZippedImagesPath() {
    return $this->getConfig()->testZippedImagesPath;
  }

  /**
   * @return string
   * @deprecated use getConfig()
   */
  public function getTestVideoPath() {
    return $this->getConfig()->testVideoPath;
  }

  /**
   * @param mixed $mock
   * @param array $data
   */
  protected function makeMockIterable(
    $mock, array $data = array()) {

    /** @var Mock $mock */
    $mock->method('count')->willReturn(count($data));
    $mock->method('getIterator')->willReturn(new \ArrayIterator($data));
    $mock->method('getArrayCopy')->willReturn($data);
    $mock->method('export')->willReturn($data);
  }

  /**
   * @param \Closure $closure
   * @param string $fqn
   */
  protected function assertWillThrow(
    \Closure $closure,
    $fqn = 'Exception') {

    try {
      call_user_func($closure);
    } catch (\Exception $e) {
      $this->assertTrue(
        is_a($e, $fqn),
        'Expected exception of type '.$fqn.': '.get_class($e).' received');

      return;
    }

    $this->fail('Expected exception didn\'t throw: '.$fqn);
  }
}


<?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;

use FacebookAds\Http\Adapter\AdapterInterface;
use FacebookAds\Http\Adapter\Curl\CurlInterface;
use FacebookAds\Http\Client;
use FacebookAds\Http\Headers;
use FacebookAds\Http\Parameters;
use FacebookAds\Http\RequestInterface;
use FacebookAds\Http\ResponseInterface;
use FacebookAds\Logger\LoggerInterface;
use FacebookAds\Session;
use PHPUnit_Framework_MockObject_Builder_InvocationMocker as Mocker;
use PHPUnit_Framework_MockObject_MockObject as Mock;

/**
 * @method Mocker|Mock getMock($fqn, $methods = array(), $arguments = array())
 */
abstract class AbstractUnitTestCase extends AbstractTestCase {

  /**
   * @var string
   */
  const FQN_ADAPTER_INTERFACE = '\FacebookAds\Http\Adapter\AdapterInterface';

  /**
   * @var string
   */
  const FQN_CLIENT = '\FacebookAds\Http\Client';

  /**
   * @var string
   */
  const FQN_CURL_INTERFACE = '\FacebookAds\Http\Adapter\Curl\CurlInterface';

  /**
   * @var string
   */
  const FQN_HEADERS = '\FacebookAds\Http\Headers';

  /**
   * @var string
   */
  const FQN_LOGGER_INTERFACE = '\FacebookAds\Logger\LoggerInterface';

  /**
   * @var string
   */
  const FQN_PARAMETERS = '\FacebookAds\Http\Parameters';

  /**
   * @var string
   */
  const FQN_JSON_AWARE_PARAMETERS
    = '\FacebookAds\Logger\CurlLogger\JsonAwareParameters';

  /**
   * @var string
   */
  const FQN_REQUEST_INTERFACE = '\FacebookAds\Http\RequestInterface';

  /**
   * @var string
   */
  const FQN_RESPONSE_INTERFACE = '\FacebookAds\Http\ResponseInterface';

  /**
   * @var string
   */
  const FQN_SESSION = '\FacebookAds\Session';

  /**
   * @var string
   */
  const VALUE_SESSION_APP_ID = '<APP_ID>';

  /**
   * @var string
   */
  const VALUE_SESSION_APP_SECRET = '<APP_SECRET>';

  /**
   * @var string
   */
  const VALUE_SESSION_ACCESS_TOKEN = '<ACCESS_TOKEN>';

  /**
   * @return Mocker|Mock|ResponseInterface
   */
  protected function createResponseMock() {
    return $this->createMock(static::FQN_RESPONSE_INTERFACE);
  }

  /**
   * @return Mocker|Mock|Client
   */
  protected function createClientMock() {
    return $this->createMock(static::FQN_CLIENT);
  }

  /**
   * @return Mocker|Mock|CurlInterface
   */
  protected function createCurlMock() {
    return $this->createMock(static::FQN_CURL_INTERFACE);
  }

  /**
   * @return Mocker|Mock|Headers
   */
  protected function createHeadersMock() {
    return $this->createMock(static::FQN_HEADERS);
  }

  /**
   * @return Mocker|Mock|LoggerInterface
   */
  protected function createLoggerMock() {
    return $this->createMock(static::FQN_LOGGER_INTERFACE);
  }

  /**
   * @return Mocker|Mock|Parameters
   */
  protected function createParametersMock() {
    return $this->createMock(static::FQN_PARAMETERS);
  }

  /**
   * @return Mocker|Mock|Parameters
   */
  protected function createJsonAwareParametersMock() {
    return $this->createMock(static::FQN_JSON_AWARE_PARAMETERS);
  }

  /**
   * @return Mocker|Mock|RequestInterface
   */
  protected function createRequestMock() {
    return $this->createMock(static::FQN_REQUEST_INTERFACE);
  }

  /**
   * @return Mocker|Mock|AdapterInterface
   */
  protected function createAdapterMock() {
    return $this->createMock(static::FQN_ADAPTER_INTERFACE);
  }

  /**
   * @return Mocker|Mock|Session
   */
  protected function createSessionMock() {
    return $this->getMockBuilder(static::FQN_SESSION)
                ->setConstructorArgs(array(
                  static::VALUE_SESSION_APP_ID,
                  static::VALUE_SESSION_APP_SECRET,
                  static::VALUE_SESSION_ACCESS_TOKEN,
                ))
                ->getMock();
  }
}


<?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;

use FacebookAds\Api;
use FacebookAds\Http\RequestInterface;
use FacebookAds\Http\ResponseInterface;
use FacebookAds\Logger\NullLogger;

class ApiTest extends AbstractUnitTestCase {

  /**
   * @return Api
   */
  protected function createApi() {
    return new Api($this->createClientMock(), $this->createSessionMock());
  }

  public function testInstance() {
    $this->assertNull(Api::instance());

    $api = $this->createApi();
    Api::setInstance($api);
    $this->assertTrue($api === Api::instance());

    $newApi = $this->createApi();
    Api::setInstance($newApi);
    $this->assertTrue($newApi === Api::instance());
    $this->assertFalse($api === Api::instance());
  }

  public function testInit() {
    $api = Api::init(
      static::VALUE_SESSION_APP_ID,
      static::VALUE_SESSION_APP_SECRET,
      static::VALUE_SESSION_ACCESS_TOKEN,
      false
    );
    $this->assertTrue($api instanceof Api);
    $this->assertTrue($api === Api::instance());
    $this->assertEquals(
      static::VALUE_SESSION_APP_ID, $api->getSession()->getAppId());
    $this->assertEquals(
      static::VALUE_SESSION_APP_SECRET, $api->getSession()->getAppSecret());
    $this->assertEquals(
      static::VALUE_SESSION_ACCESS_TOKEN, $api->getSession()->getAccessToken());
  }

  public function testGetters() {
    $client = $this->createClientMock();
    $session = $this->createSessionMock();
    $api = new Api($client, $session);
    $this->assertTrue($api->getHttpClient() === $client);
    $this->assertTrue($api->getSession() === $session);
  }

  public function testLogger() {
    $api = $this->createApi();
    $logger = $this->createLoggerMock();
    $api->setLogger($logger);
    $this->assertTrue($logger === $api->getLogger());

    // Test default
    $api = $this->createApi();
    $this->assertTrue($api->getLogger() instanceof NullLogger);
  }

  public function testDefaultGraphVersion() {
    $api = $this->createApi();
    $api->setDefaultGraphVersion('<VERSION>');
    $this->assertEquals('<VERSION>', $api->getDefaultGraphVersion());

    // Test default
    $api = $this->createApi();
    $this->assertTrue(is_string($api->getDefaultGraphVersion()));
    $this->assertRegExp('/^\d+\.\d+$/', $api->getDefaultGraphVersion());
  }

  public function testCall() {
    $request = $this->createRequestMock();
    $request->method('execute')->willReturn($this->createResponseMock());
    $request->method('getQueryParams')
      ->willReturn($this->createParametersMock());
    $request->method('getBodyParams')
      ->willReturn($this->createParametersMock());
    $request->expects($this->exactly(2))->method('setMethod')
      ->with($this->logicalOr(
        RequestInterface::METHOD_GET,
        RequestInterface::METHOD_POST));
    $request->expects($this->exactly(2))->method('setGraphVersion')
      ->with($this->equalTo($this->createApi()->getDefaultGraphVersion()));
    $request->expects($this->exactly(2))->method('setPath')
      ->with($this->equalTo('/<PATH>'));

    $client = $this->createClientMock();
    $client->method('createRequest')->willReturn($request);

    $session = $this->createSessionMock();
    $session->method('getAppSecretProof')->willReturn('<APP_SECRET_PROOF>');
    $session->method('getRequestParameters')->willReturn([]);

    $logger = $this->createLoggerMock();
    $logger->expects($this->exactly(2))->method('logRequest');
    $logger->expects($this->exactly(2))->method('logResponse');

    $api = new Api($client, $session);
    $api->setLogger($logger);

    // HTTP GET request
    $request->expects($this->exactly(1))->method('getQueryParams');

    $response = $api->call('/<PATH>');
    $this->assertTrue($response instanceof ResponseInterface);

    // HTTP POST request
    $request->expects($this->exactly(1))->method('getBodyParams');

    $api->call(
      '/<PATH>', RequestInterface::METHOD_POST, array('param' => 'value'));
    $this->assertTrue($response instanceof ResponseInterface);
  }

  public function testBase64UrlEncode() {
    $this->assertEquals('MTIzNDU', Api::base64UrlEncode('12345'));
  }
}


<?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;

use FacebookAds\Cursor;

class CursorDegradationTest extends CursorTest {

  /**
   * @return string
   */
  protected function getUniquePageId() {
    return (string) (microtime(true) * 1000000);
  }

  /**
   * @return array
   */
  protected function createSampleResponseContent() {
    $url_fmt = $this->createUnparameterizedUrl()
      .'?offset=%s';

    $content = parent::createSampleResponseContent();
    $content['paging'] = array(
      'next' => sprintf($url_fmt, $this->getUniquePageId()),
      'previous' => sprintf($url_fmt, $this->getUniquePageId()),
    );

    return $content;
  }

  public function testRequestParamReset() {
    $response = $this->createResponseChainMock(1);
    $cursor = new Cursor($response, $this->objectPrototype);
    $params = $cursor->getLastResponse()->getRequest()->getQueryParams();
    $params->offsetSet('offset', $this->getUniquePageId());

    $cursor->fetchAfter();
    $params2 = $cursor->getLastResponse()->getRequest()->getQueryParams();

    $this->assertNotEquals(
      $params->offsetGet('offset'), $params2->offsetGet('offset'));
  }

  public function testGetters() {
    $response = $this->createResponseChainMock(1);
    $cursor = new Cursor($response, $this->objectPrototype);

    $this->assertTrue($response === $cursor->getResponse());
    $this->assertTrue($response === $cursor->getLastResponse());
    $this->assertNull($cursor->getAfter());
    $this->assertNull($cursor->getBefore());
  }
}


<?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;

use FacebookAds\Http\Client;
use FacebookAds\Http\Parameters;
use FacebookAds\Http\Request;
use FacebookAds\Http\RequestInterface;
use FacebookAds\Http\ResponseInterface;
use FacebookAds\Object\AbstractCrudObject;
use FacebookAds\Object\AbstractObject;
use FacebookAds\Cursor;
use FacebookAdsTest\Object\EmptyObject;
use \PHPUnit_Framework_MockObject_Builder_InvocationMocker as Mock;

class CursorTest extends AbstractUnitTestCase {
  /**
   * @var EmptyObject
   */
  protected $objectPrototype;

  /**
   * @return array
   */
  protected function createEmptyResponseContent() {
    return array('data' => array());
  }

  /**
   * @return string
   */
  protected function getUniquePageId() {
    return uniqid();
  }

  /**
   * @return array
   */
  protected function createSampleResponseContent() {
    $content = array(
      'paging' => array(
        'cursors' => array(
          'after' => $this->getUniquePageId(),
          'before' => $this->getUniquePageId(),
        ),
      ),
    ) + $this->createEmptyResponseContent();

    $count = rand(2, 5);
    for ($i = 0; $i < $count; $i++) {
      $content['data'][] = array(
        AbstractCrudObject::FIELD_ID => $i,
      );
    }

    return $content;
  }

  /**
   * @return string
   */
  protected function createUnparameterizedUrl() {
    return Request::PROTOCOL_HTTPS
      .Client::DEFAULT_LAST_LEVEL_DOMAIN
      .'.'.Client::DEFAULT_GRAPH_BASE_DOMAIN
      .'/node/edge';
  }

  /**
   * @param int $num_pages
   * @param RequestInterface|null $prev
   * @return Mock|ResponseInterface
   */
  protected function createResponseChainMock(
    $num_pages, RequestInterface $prev = null) {

    $query_params = $prev ? clone $prev->getQueryParams() : new Parameters();
    $sample_content = $this->createSampleResponseContent();

    $request = $this->createRequestMock();
    $request->method('getMethod')->willReturn(RequestInterface::METHOD_GET);
    $request->method('getQueryParams')->willReturn($query_params);

    $response = $this->createResponseMock();
    $response->method('getRequest')->willReturn($request);

    $request->method('execute')->willReturn($response);

    $callback = function() use ($num_pages, $sample_content) {
      return $num_pages > 0
        ? $sample_content
        : $this->createEmptyResponseContent();
    };

    $clone_callback = function() use ($num_pages, $request) {
      return $this->createResponseChainMock(
        $num_pages - 1, $request)->getRequest();
    };

    $url_callback = function() use ($query_params) {
      return $this->createUnparameterizedUrl().'?'
        .http_build_query($query_params->getArrayCopy());
    };

    $response->method('getContent')->willReturnCallback($callback);
    $request->method('createClone')->willReturnCallback($clone_callback);
    $request->method('getUrl')->willReturnCallback($url_callback);

    return $response;
  }

  /**
   * @return Mock|ResponseInterface
   */
  protected function createEmptyResponseMock() {
    $response = $this->createResponseMock();
    $response->method('getContent')->willReturn(array(
      'data' => array(),
    ));

    return $response;
  }

  public function setup(): void {
    parent::setup();
    $this->objectPrototype = new EmptyObject();
  }

  public function tearDown(): void {
    $this->objectPrototype = null;
    parent::tearDown();
  }

  public function testGetters() {
    $response = $this->createResponseChainMock(1);
    $cursor = new Cursor($response, $this->objectPrototype);

    $this->assertTrue($response === $cursor->getResponse());
    $this->assertTrue($response === $cursor->getLastResponse());
    $this->assertTrue(is_string($cursor->getAfter()));
    $this->assertTrue(is_string($cursor->getBefore()));
    $this->assertNotEquals($cursor->getBefore(), $cursor->getAfter());
  }

  /**
   * @return array
   */
  public function responseDataStructureProvider() {
    return array(
      array(array()),
      array(array('data' => null)),
      array(array('data' => 1)),
    );
  }

  /**
   * @dataProvider responseDataStructureProvider
   * @param mixed $content
   */
  public function testResponseDataStructure($content) {
    $response = $this->createResponseMock();
    $response->method('getContent')->willReturn($content);

    $this->expectException(\InvalidArgumentException::class);

    new Cursor($response, $this->objectPrototype);
  }

  public function testIterator() {
    $cursor = new Cursor(
      $this->createResponseChainMock(1), $this->objectPrototype);

    $this->assertTrue($cursor instanceof \Iterator);

    $k = 0;

    foreach ($cursor as $key => $value) {
      if ($key != $k) {
        $this->fail('iteration count missmatch $key');
      }
      ++$k;
    }

    $this->assertEquals($k, count($cursor));

    $cursor->rewind();

    $this->assertEquals(0, $cursor->key());
    $cursor->next();
    $this->assertEquals(1, $cursor->key());
    $cursor->prev();
    $this->assertEquals(0, $cursor->key());

    $this->assertEquals($cursor->getIndexLeft(), 0);
    $this->assertEquals($cursor->getIndexRight(), count($cursor) - 1);
  }

  public function testCountable() {
    $response = $this->createResponseChainMock(1);
    $cursor = new Cursor($response, $this->objectPrototype);

    $this->assertTrue($cursor instanceof \Countable);
    $this->assertEquals($cursor->count(), count($cursor));
    $this->assertEquals(
      $cursor->count(), count($response->getContent()['data']));
  }

  public function testArrayAccess() {
    $response = $this->createResponseChainMock(1);
    $test_index = rand(1, count($response->getContent()) - 1);

    $cursor = new Cursor($response, $this->objectPrototype);

    $this->assertTrue($cursor instanceof \arrayaccess);

    $subject = new EmptyObject();
    $subject->setData($response->getContent()['data'][$test_index]);

    // Checking offsetGet
    $this->assertEquals($cursor[$test_index]->getData(), $subject->getData());
    // Checking offsetExists
    $this->assertFalse(isset($cursor[count($cursor)]));
    // Checking offsetUnset
    unset($cursor[$test_index]);
    $this->assertNull($cursor[$test_index]);
    // Checking offsetSet
    $cursor->offsetSet($test_index, $subject);
    $this->assertEquals($cursor[$test_index]->getData(), $subject->getData());
    // Checking offsetSet - append
    $count = count($cursor);
    $cursor->offsetSet(null, new EmptyObject());
    $this->assertEquals(count($cursor), $count + 1);
  }

  public function testUnneededFetch() {
    $response = $this->createEmptyResponseMock();
    $cursor = new Cursor($response, $this->objectPrototype);
    $this->assertNull($cursor->createBeforeRequest());
    $this->assertNull($cursor->createAfterRequest());

    // Reset for proper fetching
    $response = $this->createEmptyResponseMock();
    $cursor = new Cursor($response, $this->objectPrototype);
    $length = $cursor->count();
    $cursor->fetchBefore();
    $this->assertEquals($length, $cursor->count());
    $cursor->fetchAfter();
    $this->assertEquals($length, $cursor->count());
  }

  public function testIterability() {
    $response = $this->createResponseChainMock(1);
    $cursor = new Cursor($response, $this->objectPrototype);

    $cursor->next();
    $cursor->rewind();
    $this->assertEquals($cursor->getIndexLeft(), $cursor->key());

    $cursor->end();
    $this->assertEquals($cursor->getIndexRight(), $cursor->key());

    $index = rand($cursor->getIndexLeft(), $cursor->getIndexRight());
    $cursor->seekTo($index);
    $this->assertEquals($index, $cursor->key());

    // Fetch after
    $cursor = new Cursor($response, $this->objectPrototype);
    $cursor->fetchAfter();
    $this->assertFalse($response === $cursor->getLastResponse());
  }

  public function testRequestParamReset() {
    $response = $this->createResponseChainMock(1);
    $cursor = new Cursor($response, $this->objectPrototype);
    $params = $cursor->getLastResponse()->getRequest()->getQueryParams();
    $params->offsetSet('after', $this->getUniquePageId());
    $params->offsetSet('before', $this->getUniquePageId());

    $cursor->fetchAfter();
    $params2 = $cursor->getLastResponse()->getRequest()->getQueryParams();
    $this->assertNotEquals(
      $params->offsetGet('after'), $params2->offsetGet('after'));
  }

  public function testImplicitFetch() {
    // Test setters/getters
    $response = $this->createEmptyResponseMock();
    $cursor = new Cursor($response, $this->objectPrototype);

    $this->assertFalse(Cursor::getDefaultUseImplicitFetch());
    $this->assertFalse($cursor->getUseImplicitFetch());
    $cursor->setUseImplicitFetch(true);
    $this->assertTrue($cursor->getUseImplicitFetch());

    Cursor::setDefaultUseImplicitFetch(true);

    $response = $this->createEmptyResponseMock();
    $cursor = new Cursor($response, $this->objectPrototype);
    $this->assertTrue(Cursor::getDefaultUseImplicitFetch());
    $this->assertTrue($cursor->getUseImplicitFetch());

    // Test ordered iteration
    // f() lower interval * min repetition > upper interval
    // Min repetition > upper interval / lower interval -> f(x): x > 5 / 2 -> 3
    $response = $this->createResponseChainMock(3);
    $cursor = new Cursor($response, $this->objectPrototype);
    while ($cursor->valid()) {
      $cursor->next();
    }

    // Min upper boundary = upper interval + 1 = 5 + 1 = 6
    $this->assertGreaterThanOrEqual(6, $cursor->count());

    // Test rervese iteration
    // same f()
    $response = $this->createResponseChainMock(3);
    $cursor = new Cursor($response, $this->objectPrototype);

    $count = 0;
    while ($cursor->valid()) {
      $cursor->prev();
    }

    $this->assertGreaterThanOrEqual(6, $cursor->count());

    // Force the array out of boundaries
    $response = $this->createResponseChainMock(1);
    $cursor = new Cursor($response, $this->objectPrototype);
    $cursor->setUseImplicitFetch(false);
    $cursor->prev();

    // Restore static behaviour
    Cursor::setDefaultUseImplicitFetch(false);
  }

  public function testExportability() {
    $response = $this->createResponseChainMock(1);
    $cursor = new Cursor($response, $this->objectPrototype);
    $array_copy = $cursor->getArrayCopy();

    $this->assertTrue(is_array($array_copy));
    $this->assertEquals($cursor->getArrayCopy(), $cursor->getObjects());
    $this->assertEquals(
      count($array_copy), count($response->getContent()['data']));

    foreach ($array_copy as $object) {
      if (!$object instanceof AbstractObject) {
        $this->fail("Wrong instance in array copy");
      }
    }

    $cursor->fetchAfter();
    $cursor->fetchBefore();

    $index = $cursor->getIndexLeft();
    // Test in-memory order while exporting
    foreach ($cursor->getArrayCopy(true) as $key => $object) {
      if ($key < $index) {
        $this->fail("Wrong order in sorted array copy");
      }
    }
  }
}


<?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;

use FacebookAds\Session;

class SessionTest extends AbstractUnitTestCase {

  /**
   * @return Session
   */
  protected function createSession() {
    return new Session(
      static::VALUE_SESSION_APP_ID,
      static::VALUE_SESSION_APP_SECRET,
      static::VALUE_SESSION_ACCESS_TOKEN);
  }

  public function testGetters() {
    $session = $this->createSession();

    $this->assertEquals(
      static::VALUE_SESSION_APP_ID, $session->getAppId());
    $this->assertEquals(
      static::VALUE_SESSION_APP_SECRET, $session->getAppSecret());
    $this->assertEquals(
      static::VALUE_SESSION_ACCESS_TOKEN, $session->getAccessToken());
  }

  public function testAppSecretProof() {
    $session = $this->createSession();
    $proof = $session->getAppSecretProof();

    // Assert SHA-2 > 256 bits > 64 chars
    $this->assertTrue(strlen($proof) == 64);
  }
}


<?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\Bootstrap;

use FacebookAdsTest\Config\Config;

class Bootstrap {

  /**
   * @var self
   */
  private static $instance;

  /**
   * @var bool
   */
  private $isIntialized = false;

  /**
   * @var array|null
   */
  protected $configData;

  /**
   * @var Config|null
   */
  protected $config;

  /**
   * @var mixed
   */
  protected $autoloader;

  /**
   * @throws \LogicException
   */
  final public function __construct() {
    if (self::$instance !== null) {
      throw new \LogicException("Bootstrap already instanciated");
    }

    self::$instance = $this;
  }

  /**
   * @return string
   */
  protected function getComposerAutoloadPath() {
    return __DIR__.'/../../../vendor/autoload.php';
  }

  /**
   * @return mixed
   */
  public function getAutoloader() {
    if ($this->autoloader === null) {
      $autoload_path = $this->getComposerAutoloadPath();
      if (!is_readable($autoload_path)) {
        throw new \RuntimeException("Could not read ".$autoload_path);
      }
      $this->autoloader = include $autoload_path;
      $this->autoloader->addPsr4('FacebookAdsTest\\', __DIR__.'/../');
    }

    return $this->autoloader;
  }

  /**
   * Simplifies the common pattern of checking for an index in an array
   * and selecting a default value if it does not exist
   *
   * @param array $array
   * @param string|int $key
   * @param mixed $default
   * @return mixed
   */
  protected function idx(array $array, $key, $default = null) {
    return array_key_exists($key, $array) && $array[$key] !== ''
      ? $array[$key]
      : $default;
  }

  /**
   * Simplifies the common pattern of checking for an index in an array
   * and throw an exception if not
   *
   * @param array $array
   * @param string|int $key
   * @return mixed
   * @throws \Exception
   */
  protected function idxt(array $array, $key) {
    if (!array_key_exists($key, $array) || !$array[$key]) {
      throw new \Exception("Missing mandatory config '{$key}'");
    }

    return $array[$key];
  }

  /**
   * @return Config
   */
  public function getConfig() {
    if ($this->config === null) {
      $this->config = new Config();
      $this->config->testRunId
        = md5($this->idx($_SERVER, 'LOGNAME', uniqid(true)).microtime(true));
      $this->config->testImagePath = __DIR__.'/../../misc/image.png';
      $this->config->testZippedImagesPath = __DIR__.'/../../misc/images.zip';
      $this->config->testVideoPath = __DIR__.'/../../misc/video.mp4';
    }

    return $this->config;
  }

  /**
   * @throws \LogicException
   */
  public function init() {
    if ($this->isIntialized) {
      throw new \LogicException("Bootstrap already initialized");
    }

    $this->getAutoloader();
    Config::setInstance($this->getConfig());
  }
}


<?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\Bootstrap;

use FacebookAdsTest\Config\Config;
use FacebookAdsTest\Config\SkippableFeaturesManager;

class IntegrationBootstrap extends Bootstrap {

  /**
   * @param string $file_path
   * @return array
   * @throws \RuntimeException
   */
  protected function loadConfigData($file_path) {
    if (!is_readable($file_path)) {
      throw new \RuntimeException("Could not read {$file_path}");
    }

    $data = require $file_path;
    if (!is_array($data)) {
      throw new \RuntimeException("Invalid config structure");
    }

    return $data;
  }

  /**
   * @return array
   */
  protected function getConfigData() {
    if ($this->configData === null) {
      $this->configData = $this->loadConfigData(__DIR__.'/../../config.php');
    }

    return $this->configData;
  }

  /**
   * @param string|int $key
   * @param mixed $default
   * @return mixed
   */
  protected function confx($key, $default = null) {
    return $this->idx($this->getConfigData(), $key, $default);
  }

  /**
   * @param string|int $key
   * @return mixed
   * @throws \Exception
   */
  protected function confxt($key) {
    return $this->idxt($this->getConfigData(), $key);
  }

  /**
   * @return Config
   */
  protected function getUnitConfig() {
    return parent::getConfig();
  }

  /**
   * @return Config
   */
  public function getConfig() {
    if ($this->config === null) {
      $this->config = parent::getConfig();
      $this->config->appId = $this->confx('app_id');
      $this->config->appSecret = $this->confx('app_secret');
      $this->config->accessToken = $this->confx('access_token');
      $this->config->accountId = $this->confx('act_id');
      $this->config->pageId = $this->confx('page_id');
      $this->config->appUrl = $this->confx('app_url');
      $this->config->businessId = $this->confx('business_id');
      $this->config->instagramActorId = $this->confx('instagram_actor_id');

      // Optionals: Override unit config
      $this->config->testRunId = $this->confx(
        'test_run_id', $this->config->testRunId);
      $this->config->testImagePath = $this->confx(
        'test_image_path', $this->config->testImagePath);
      $this->config->testZippedImagesPath = $this->confx(
        'test_zipped_images_path', $this->config->testZippedImagesPath);
      $this->config->testVideoPath = $this->confx(
        'test_video_path', $this->config->testVideoPath);

      // Optionals
      $this->config->secondaryBusinessId
        = $this->confx('secondary_business_id', '');
      $this->config->secondaryAccountId
        = $this->confx('secondary_account_id', '');
      $this->config->secondaryPageId = $this->confx('secondary_page_id', '');
      $this->config->secondaryAppId = $this->confx('secondary_app_id', '');
      $this->config->graphBaseDomain = $this->confx('graph_base_domain');
      $this->config->skipSslVerification
        = $this->confx('skip_ssl_verification', false);
      $this->config->curlLogger = $this->confx('curl_logger');

      SkippableFeaturesManager::setInstance(
        new SkippableFeaturesManager($this->confx('skip_if', array())));
    }

    return $this->config;
  }
}


<?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\Config;

final class Config {

  /**
   * @var self
   */
  protected static $instance;

  /**
   * @var string
   */
  public $testRunId;

  /**
   * @var string
   */
  public $testImagePath;

  /**
   * @var string
   */
  public $testZippedImagesPath;

  /**
   * @var string
   */
  public $testVideoPath;

  /**
   * @var string
   */
  public $curlLogger;

  /**
   * @var string
   */
  public $appId;

  /**
   * @var string
   */
  public $appSecret;

  /**
   * @var string
   */
  public $accessToken;

  /**
   * @var string
   */
  public $businessId;

  /**
   * @var string
   */
  public $accountId;

  /**
   * @var string
   */
  public $pageId;

  /**
   * @var string
   */
  public $appUrl;

  /**
   * @var string
   */
  public $instagramActorId;

  /**
   * @var string
   */
  public $secondaryBusinessId;

  /**
   * @var string
   */
  public $secondaryPageId;

  /**
   * @var string
   */
  public $secondaryAccountId;

  /**
   * @var string
   */
  public $secondaryAppId;

  /**
   * @var string
   */
  public $graphBaseDomain;

  /**
   * @var bool
   */
  public $skipSslVerification;

  /**
   * @return Config
   */
  public static function instance() {
    return self::$instance ?: (self::$instance = new self());
  }

  /**
   * @param Config $config
   */
  public static function setInstance(Config $config) {
    self::$instance = $config;
  }

  /**
   * @param string $key
   * @param string $value
   */
  public function __set($key, $value) {
    throw new \RuntimeException("Unsupported key: {$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\Config;

use FacebookAdsTest\AbstractTestCase;

final class SkippableFeaturesManager {

  /**
   * @var SkippableFeaturesManager
   */
  private static $instance;

  /**
   * @var array
   */
  protected $data = array();

  /**
   * @return SkippableFeaturesManager
   */
  public static function instance() {
    return self::$instance ?: (self::$instance = new self());
  }

  /**
   * @param SkippableFeaturesManager $manager
   */
  public static function setInstance(SkippableFeaturesManager $manager) {
    self::$instance = $manager;
  }

  /**
   * @param array $data
   */
  public function __construct(array $data = array()) {
    $this->setData($data);
  }

  public function setData(array $data = array()) {
    $this->data = $data;
  }

  /**
   * @return array
   */
  public function getData() {
    return $this->data;
  }

  /**
   * @param $key
   * @return bool
   */
  public function isSkipKey($key) {
    return array_key_exists($key, $this->data) && $this->data[$key];
  }

  /**
   * @param AbstractTestCase $test
   * @return bool
   */
  public function enforceSkipTest(AbstractTestCase $test) {
    if ($test instanceof SkippableFeatureTestInterface) {
      foreach ($test->skipIfAny() as $key) {
        if ($this->isSkipKey($key)) {
          /** @var AbstractTestCase $test */
          $test->markTestSkipped("Reason: skipped by config '{$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\Config;

interface SkippableFeatureTestInterface {

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


<?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\Enum;

use FacebookAds\Enum\AbstractEnum;

class DummyEnum extends AbstractEnum {

  const NAME_1 = 'VALUE_1';
  const NAME_2 = 'VALUE_2';
}


<?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\Enum;

use FacebookAds\Enum\EmptyEnum;
use FacebookAdsTest\AbstractUnitTestCase;

class EnumTest extends AbstractUnitTestCase {

  public function testSingleton() {
    $this->assertTrue(DummyEnum::getInstance() === DummyEnum::getInstance());
  }

  public function testAccess() {
    $this->assertEquals(DummyEnum::className(), get_class(new DummyEnum()));

    $enum = DummyEnum::getInstance();
    $copy = $enum->getArrayCopy();
    $names = $enum->getNames();
    $values = $enum->getValues();
    $values_map = $enum->getValuesMap();

    $this->assertEquals(2, count($copy));
    $this->assertArrayHasKey('NAME_1', $copy);
    $this->assertEquals(DummyEnum::NAME_1, $copy['NAME_1']);

    $this->assertEquals(2, count($names));
    $this->assertTrue(in_array('NAME_1', $names));

    $this->assertEquals(2, count($values));
    $this->assertTrue(in_array(DummyEnum::NAME_1, $values));

    $this->assertEquals(2, count($values_map));
    $this->assertArrayHasKey(DummyEnum::NAME_1, $values_map);

    $this->assertEquals(DummyEnum::NAME_1, $enum->getValueForName('NAME_1'));
  }

  public function testLazyLoading() {
    $enum = DummyEnum::getInstance();

    $this->assertTrue($enum->getArrayCopy() === $enum->getArrayCopy());
    $this->assertTrue($enum->getNames() === $enum->getNames());
    $this->assertTrue($enum->getValues() === $enum->getValues());
    $this->assertTrue($enum->getValuesMap() === $enum->getValuesMap());
  }

  public function testValidation() {
    $enum = DummyEnum::getInstance();

    $this->assertTrue($enum->isValid('NAME_1'));
    $this->assertFalse($enum->isValid('NAME_ND'));
    $this->assertTrue($enum->isValidValue(DummyEnum::NAME_1));
    $this->assertFalse($enum->isValidValue('VALUE_ND'));
  }

  public function testAssurance() {
    $enum = DummyEnum::getInstance();

    $this->assertEquals(DummyEnum::NAME_1, $enum->assureValueForName('NAME_1'));
    $this->assertWillThrow(function() use ($enum) {
      $enum->assureValueForName('NAME_ND');
    }, 'InvalidArgumentException');

    $enum->assureIsValid('NAME_1');
    $this->assertWillThrow(function() use ($enum) {
      $enum->assureIsValid('NAME_ND');
    }, 'InvalidArgumentException');

    $enum->assureIsValidValue(DummyEnum::NAME_1);
    $this->assertWillThrow(function() use ($enum) {
      $enum->assureIsValidValue('VALUE_ND');
    }, 'InvalidArgumentException');
  }

  public function testEmptyEnum() {
    $enum = EmptyEnum::getInstance();

    $this->assertEquals(array(), $enum->getArrayCopy());
    $this->assertEquals(array(), $enum->getNames());
    $this->assertEquals(array(), $enum->getValues());
    $this->assertEquals(array(), $enum->getValuesMap());
  }
}


<?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\Exception;

use FacebookAds\Http\Exception\RequestException;

class PHPUnitRequestExceptionWrapper
  extends \PHPUnit_Framework_ExceptionWrapper {

  /**
   * @var RequestException
   */
  protected $wrappedException;

  /**
   * @param RequestException $e
   */
  public function __construct(RequestException $e) {
    $this->wrappedException = $e;
    parent::__construct($e);
  }

  /**
   * @return RequestException
   */
  public function getWrappedException() {
    return $this->wrappedException;
  }

  protected function requestToString(RequestException $e) {
    if ($e->getResponse() === null) {
      return '-';
    }

    $request = $e->getResponse()->getRequest();

    return sprintf(
      "%s %s\n%s",
      $request->getMethod(),
      $request->getUrl(),
      "    ".str_replace("\n", "\n    ", json_encode(
        $request->getFileParams()->getArrayCopy()
          + $request->getBodyParams()->getArrayCopy(),
        JSON_PRETTY_PRINT)));
  }

  /**
   * @return string
   */
  protected function blameFieldSpecsToString() {
    return implode(", ", array_map(function($value) {
      return $value[0];
    }, $this->getWrappedException()->getErrorBlameFieldSpecs()));
  }

  /**
   * @return string
   */
  public function __toString() {
    $string = \PHPUnit_Framework_TestFailure::exceptionToString($this);

    $e = $this->getWrappedException();

    $string .= "\n  Request: ".$this->requestToString($e)."\n"
      ."  HTTP status Code: ".$e->getHttpStatusCode()."\n"
      ."  Is transient: ".($e->isTransient() ? 'true' : 'false')."\n"
      ."  Code: ".$e->getCode()."\n"
      ."  Error Subcode: ".$e->getErrorSubcode()."\n"
      ."  Error User Title: ".$e->getErrorUserTitle()."\n"
      ."  Error User Message: ".$e->getErrorUserMessage()."\n";

    if ($e->getErrorBlameFieldSpecs()) {
      $string .= "  Error Blame Fields: ".$this->blameFieldSpecsToString()."\n";
    }

    if ($trace = \PHPUnit_Util_Filter::getFilteredStacktrace($this)) {
      $string .= "\n" . $trace;
    }

    if ($this->previous) {
      $string .= "\nCaused by\n" . $this->previous;
    }

    return $string;
  }
}