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

namespace FacebookAdsTest\Object\ServerSide;

use FacebookAdsTest\AbstractUnitTestCase;
use FacebookAds\Api;
use FacebookAds\ApiConfig;
use FacebookAds\Object\AbstractObject;
use FacebookAds\Object\ServerSide\Event;
use FacebookAds\Object\ServerSide\EventRequest;
use FacebookAds\Object\ServerSide\EventResponse;
use FacebookAds\Object\ServerSide\HttpServiceClientConfig;
use FacebookAds\Object\ServerSide\Util;
use Mockery as m;

class EventRequestTest extends AbstractUnitTestCase {
  protected function setUp(): void {
    $this->expected_pixel_id = 'pixel-1000';
    $this->expected_url = 'https://graph.facebook.com/v'
      . ApiConfig::APIVersion
      . '/'
      . $this->expected_pixel_id
      . '/events';
    $this->expected_headers = array(
      'User-Agent' => 'fbbizsdk-php-v' . ApiConfig::SDKVersion,
      'Accept-Encoding' => '*',
    );
    $this->expected_access_token = 'a-test-token';
    $this->expected_curl_options = array(
      CURLOPT_CONNECTTIMEOUT => 10,
      CURLOPT_TIMEOUT => 60,
      CURLOPT_RETURNTRANSFER => true,
      CURLOPT_HEADER => true,
      CURLOPT_CAINFO => Util::getCaBundlePath(),
    );
    HttpServiceClientConfig::getInstance()->setAccessToken(null);
    HttpServiceClientConfig::getInstance()->setClient(null);
    HttpServiceClientConfig::getInstance()->setAppsecret(null);
    Api::init(null, null, null, false);
  }

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

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

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

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

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

  public function testDefaultHttpService() {
    $mock_ads_pixel = m::mock('overload:FacebookAds\Object\AdsPixel');
    $mock_ads_pixel
      ->shouldReceive('__construct')
      ->once()
      ->with($this->expected_pixel_id);
    $event_response_contents = array('data' => array('events_received' => 1));
    $expected_event_response = new EventResponse($event_response_contents);
    $create_response_mock = $this->createMock(AbstractObject::class);
    $create_response_mock
      ->expects($this->once())
      ->method('exportAllData')
      ->willReturn($event_response_contents);
    $event_request = new EventRequest($this->expected_pixel_id);
    $event_request->setEvents(array(new Event(array('event_name' => 'event-123'))));
    $mock_ads_pixel
      ->shouldReceive('createEvent')
      ->once()
      ->with(array(), $event_request->normalize())
      ->andReturn($create_response_mock);
    $actual_event_response = $event_request->execute();

    $this->assertEquals($expected_event_response, $actual_event_response);
  }

  public function testSetHttpClient() {
    $appsecret = 'appsecret-012';
    Api::init(null, $appsecret, $this->expected_access_token, false);
    $mock_client = m::mock('FacebookAdsTest\Object\ServerSide\TestHelpers\FakeHttpService');
    $expected_event_response = new EventResponse(
      array(
        'data' => array('events_received' => 1)
      )
    );
    $event_request = new EventRequest($this->expected_pixel_id);
    $event_request->setEvents(array(new Event(array('event_name' => 'event-123'))));
    $event_request->setHttpClient($mock_client);
    $mock_client
      ->shouldReceive('executeRequest')
      ->once()
      ->with(
        $this->expected_url,
        'POST',
        $this->expected_curl_options,
        $this->expected_headers,
        $this->normalize_and_merge($event_request, $this->expected_access_token, $appsecret)
      )
      ->andReturn($expected_event_response);
    $actual_event_response = $event_request->execute();

    $this->assertEquals($expected_event_response, $actual_event_response);
  }

  public function testSetHttpClientClientConfig() {
    $mock_client = m::mock('FacebookAdsTest\Object\ServerSide\TestHelpers\FakeHttpService');
    $expected_event_response = new EventResponse(
      array(
        'data' => array('events_received' => 1)
      )
    );
    $event_request = new EventRequest($this->expected_pixel_id);
    $event_request->setEvents(array(new Event(array('event_name' => 'event-123'))));
    $mock_client
      ->shouldReceive('executeRequest')
      ->once()
      ->with(
        $this->expected_url,
        'POST',
        $this->expected_curl_options,
        $this->expected_headers,
        $this->normalize_and_merge($event_request, $this->expected_access_token, null)
      )
      ->andReturn($expected_event_response);
    HttpServiceClientConfig::getInstance()->setClient($mock_client);
    HttpServiceClientConfig::getInstance()->setAccessToken($this->expected_access_token);
    $actual_event_response = $event_request->execute();

    $this->assertEquals($expected_event_response, $actual_event_response);
  }

  public function testEventRequestHttpClientOverridesClientConfig() {
    $appsecret = 'appsecret-012';
    Api::init(null, 'a-different-app-secret', 'a-different-access-token', false);
    $mock_used_client = m::mock('FacebookAdsTest\Object\ServerSide\TestHelpers\AnotherHttpService');
    $mock_unused_client = m::mock('FacebookAdsTest\Object\ServerSide\TestHelpers\AnotherHttpService');
    $expected_event_response = new EventResponse(
      array(
        'data' => array('events_received' => 1)
      )
    );
    $event_request = new EventRequest($this->expected_pixel_id);
    $event_request->setEvents(array(new Event(array('event_name' => 'event-123'))));
    $event_request->setHttpClient($mock_used_client);
    $mock_used_client
      ->shouldReceive('executeRequest')
      ->once()
      ->with(
        $this->expected_url,
        'POST',
        $this->expected_curl_options,
        $this->expected_headers,
        $this->normalize_and_merge($event_request, $this->expected_access_token, $appsecret)
      )
      ->andReturn($expected_event_response);
    HttpServiceClientConfig::getInstance()->setClient($mock_unused_client);
    HttpServiceClientConfig::getInstance()->setAccessToken($this->expected_access_token);
    HttpServiceClientConfig::getInstance()->setAppsecret($appsecret);
    $actual_event_response = $event_request->execute();

    $this->assertEquals($expected_event_response, $actual_event_response);
  }

  // Test helper functions

  protected function normalize_and_merge($event_request, $access_token, $appsecret) {
    $normalized_merged = $event_request->normalize();
    $normalized_merged['access_token'] = $access_token;
    if ($appsecret != null) {
      $normalized_merged['appsecret_proof'] = Util::getAppsecretProof($access_token, $appsecret);
    }
    return $normalized_merged;
  }
}


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

namespace FacebookAdsTest\Object\ServerSide;

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

class EventTest extends AbstractUnitTestCase {
  public function testBuilder() {
    $user_data = new UserData(array('email' => 'eg@test.com'));
    $custom_data = new CustomData(array('order_id' => '123'));
    $expected = array(
      'event_name' => 'event_name-0',
      'event_time' => 1234,
      'event_source_url' => 'event_source_url-2',
      'opt_out' => false,
      'event_id' => 'event_id-3',
      'user_data' => $user_data->normalize(),
      'custom_data' => $custom_data->normalize(),
      'data_processing_options' => array('1', '2'),
      'data_processing_options_country' => 1,
      'data_processing_options_state' => 2,
      'action_source' => ActionSource::WEBSITE,
    );

    $event = (new Event())
      ->setEventName($expected['event_name'])
      ->setEventTime($expected['event_time'])
      ->setEventSourceUrl($expected['event_source_url'])
      ->setOptOut($expected['opt_out'])
      ->setEventId($expected['event_id'])
      ->setUserData($user_data)
      ->setCustomData($custom_data)
      ->setDataProcessingOptions($expected['data_processing_options'])
      ->setDataProcessingOptionsCountry($expected['data_processing_options_country'])
      ->setDataProcessingOptionsState($expected['data_processing_options_state'])
      ->setActionSource($expected['action_source']);

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

  public function testWhenOptOutIsTrue() {
    $event = (new Event())->setOptOut(true);

    $this->assertEquals(array('opt_out' => true), $event->normalize());
  }

  public function testInvalidActionSource() {
    $action_source = 'invalid action source';
    $event = (new Event())->setActionSource($action_source);

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

    $this->assertTrue($has_thrown_exception);
  }

  public function testActionSourceGetsNormalized() {
    $event = (new Event())->setActionSource('Email');
    $normalized_payload = $event->normalize();

    $this->assertEquals($normalized_payload['action_source'], 'email');
  }

  public function testActionSourceIsNull() {
    $event = (new Event());
    $normalized_payload = $event->normalize();

    $this->assertFalse(array_key_exists('action_source', $normalized_payload));
  }
}


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

namespace FacebookAdsTest\Object;

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

class ServerSideNormalizeTest extends AbstractUnitTestCase {

  public function testEventData(){
    $testName = 'Test123Event';
    $testUrl = 'www.example.com';
    $testTime = time();

    $event = (new Event())
      ->setEventName($testName)
      ->setEventTime($testTime)
      ->setEventSourceUrl($testUrl);

    $normalized_array = $event->normalize();
    $this->assertEquals($normalized_array['event_name'], $testName);
    $this->assertEquals($normalized_array['event_time'], $testTime);
    $this->assertEquals($normalized_array['event_source_url'], $testUrl);
  }

  public function testEmptyLDUData(){
    $event = (new Event())
      ->setEventName('TestEvent')
      ->setDataProcessingOptions([]);

    $normalized_array = $event->normalize();

    $this->assertEquals($normalized_array['data_processing_options'], array());
  }

  public function testDefaultLDUData(){
    $event = (new Event())
      ->setEventName('TestEvent')
      ->setDataProcessingOptions(['LDU'])
      ->setDataProcessingOptionsCountry(0)
      ->setDataProcessingOptionsState(0);

    $normalized_array = $event->normalize();

    $this->assertEquals($normalized_array['data_processing_options'], array("LDU"));
    $this->assertEquals($normalized_array['data_processing_options_state'], "0");
    $this->assertEquals($normalized_array['data_processing_options_country'], "0");
  }

  public function testValidLDUStateCountryData(){
    $event = (new Event())
      ->setEventName('TestEvent')
      ->setDataProcessingOptions(['LDU'])
      ->setDataProcessingOptionsCountry(1)
      ->setDataProcessingOptionsState(1000);

    $normalized_array = $event->normalize();

    $this->assertEquals($normalized_array['data_processing_options'], array("LDU"));
    $this->assertEquals($normalized_array['data_processing_options_state'], "1000");
    $this->assertEquals($normalized_array['data_processing_options_country'], "1");
  }
}


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

namespace FacebookAdsTest\Object;

use FacebookAdsTest\AbstractUnitTestCase;
use FacebookAds\Object\ServerSide\Normalizer;

class ServerSideNormalizeTest extends AbstractUnitTestCase {

  /**
   * Test cases for Email Normalization
   */
  public function emailNormalizeData() {
    return array(
      array(
        "foo(.bar)@baz.com/",
        'foo.bar@baz.com',
      ),
      array(
        'foo"@bar.com',
        'foo@bar.com',
      ),
      array(
        'foo()@bar.com',
        'foo@bar.com',
      ),
    );
  }

  /**
   * @dataProvider emailNormalizeData
   */
  public function testEmailNormalize($input, $expected) {
    $this->assertEquals(
      $expected,
      Normalizer::normalize('em', $input));
  }

  /**
   * Test cases for Phone Normalization
   */
  public function phoneNormalizeData() {
    return array(
      array(
        '123-456-7890',
        '1234567890',
      ),
      array(
        '777 747 (3515)',
        '7777473515',
      ),
      array(
        '+442071838750',
        '442071838750',
      ),
      array(
        '44-12390821300A',
        '4412390821300',
      )
    );
  }

  /**
   * @dataProvider phoneNormalizeData
   */
  public function testPhoneNormalize($input, $expected) {
    $this->assertEquals(
      $expected,
      Normalizer::normalize('ph', $input));
  }

  /**
   * Test cases for Postal Code Normalization
   */
  public function postalCodeNormalizeData() {
    return array(
      array(
        '  98121',
        '98121',
      ),
      array(
        '98121-4892',
        '98121',
      ),
      array(
        'NR9 5AL',
        'nr95al',
      ),
      array(
        '98-121-4892',
        '98',
      ),
    );
  }

  /**
   * @dataProvider postalCodeNormalizeData
   */
  public function testPostalCodeNormalize($input, $expected) {
    $this->assertEquals(
      $expected,
      Normalizer::normalize('zp', $input));
  }

  /**
   * Test cases for City Normalization
   */
  public function cityNormalizeData() {
    return array(
      array(
        'Menlo Park',
        'menlopark',
      ),
      array(
        'Seattle-98121',
        'seattle',
      ),
      array(
        'Washington D.C',
        'washingtondc',
      ),
    );
  }

  /**
   * @dataProvider cityNormalizeData
   */
  public function testCityNormalize($input, $expected) {
    $this->assertEquals(
      $expected,
      Normalizer::normalize('ct', $input));
  }

  /**
   * Test cases for Country Normalization
   */
  public function countryNormalizeData() {
    return array(
      array(
        '   US   ',
        'us',
      ),
      array(
        '*****UU*****', // Can't validate, just normalizes
        'uu',
      ),
    );
  }

  /**
   * @dataProvider countryNormalizeData
   */
  public function testCountryNormalize($input, $expected) {
    $this->assertEquals(
      $expected,
      Normalizer::normalize('country', $input));
  }

  /**
   * Test cases for Currency Normalization
   */
  public function currencyNormalizeData() {
    return array(
      array(
        '   ABC   ', // Can't validate the data, just normalizes.
        'abc',
      ),
      array(
        'INR',
        'inr',
      ),
    );
  }

  /**
   * @dataProvider currencyNormalizeData
   */
  public function testCurrencyNormalize($input, $expected) {
    $this->assertEquals(
      $expected,
      Normalizer::normalize('currency', $input));
  }

  /**
   * test for asserting valid exception is thrown for invalid (ISO)currency format
   */
  public function testCurrencyException() {
    $has_throw_exception = false;
    try {
      Normalizer::normalize('currency', 'Us Dollar');
    } catch (\Exception $e) {
      $has_throw_exception = true;
    }
    $this->assertTrue($has_throw_exception);
  }

  /**
   * test for asserting valid exception is thrown for invalid (ISO)country format
   */
  public function testCountryException() {
    $has_throw_exception = false;
    try {
      Normalizer::normalize('country', 'United States of America');
    } catch (\Exception $e) {
      $has_throw_exception = true;
    }
    $this->assertTrue($has_throw_exception);
  }

  /**
   * test for asserting valid exception is thrown for invalid Email format
   */
  public function testEmailException() {
    $has_throw_exception = false;
    try {
      Normalizer::normalize('em', '324342@@@@bar.com');
    } catch (\Exception $e) {
      $has_throw_exception = true;
    }
    $this->assertTrue($has_throw_exception);
  }

  public function f5firstData() {
    return array(
      array(
        'George',
        'georg',
      ),
      array(
        'John',
        'john',
      ),
      array(
        '',
        '',
      ),
      array(
        null,
        null,
      ),
    );
  }

  /**
   * @dataProvider f5firstData
   */
  public function testF5first($input, $expected) {
    $this->assertEquals(
      $expected,
      Normalizer::normalize('f5first', $input)
    );
  }

  public function f5lastData() {
    return array(
      array(
        'Washington',
        'washi',
      ),
      array(
        'Adams',
        'adams',
      ),
      array(
        '',
        '',
      ),
      array(
        null,
        null,
      ),
    );
  }

  /**
   * @dataProvider f5lastData
   */
  public function testF5last($input, $expected) {
    $this->assertEquals(
      $expected,
      Normalizer::normalize('f5last', $input)
    );
  }

  public function fiData() {
    return array(
      array(
        'GW',
        'g',
      ),
      array(
        'j',
        'j',
      ),
      array(
        '',
        '',
      ),
      array(
        null,
        null,
      ),
    );
  }

  /**
   * @dataProvider fiData
   */
  public function testFi($input, $expected) {
    $this->assertEquals(
      $expected,
      Normalizer::normalize('fi', $input)
    );
  }

  public function dobdData() {
    return array(
      array(
        '1',
        '01',
      ),
      array(
        '9',
        '09',
      ),
      array(
        '31',
        '31',
      ),
      array(
        '',
        '',
      ),
      array(
        null,
        null,
      ),
    );
  }

  /**
   * @dataProvider dobdData
   */
  public function testDobd($input, $expected) {
    $this->assertEquals(
      $expected,
      Normalizer::normalize('dobd', $input)
    );
  }

  public function testDobdException() {
    $failure_cases = array(
      '-1',
      '0',
      '32',
      '2b',
      'ab',
    );
    $exceptions_counter = 0;
    $has_throw_exception = false;
    foreach ($failure_cases as $case) {
      try {
        Normalizer::normalize('dobd', $case);
      } catch (\Exception $e) {
        $exceptions_counter += 1;
      }
    }
    $this->assertEquals(count($failure_cases), $exceptions_counter);
  }

  public function dobmData() {
    return array(
      array(
        '1',
        '01',
      ),
      array(
        '5',
        '05',
      ),
      array(
        '12',
        '12',
      ),
      array(
        '',
        '',
      ),
      array(
        null,
        null,
      ),
    );
  }

  /**
   * @dataProvider dobmData
   */
  public function testDobm($input, $expected) {
    $this->assertEquals(
      $expected,
      Normalizer::normalize('dobm', $input)
    );
  }

  public function testDobmException() {
    $failure_cases = array(
      '-1',
      '0',
      '13',
      '1a',
      'May',
      'oc',
    );
    $exceptions_counter = 0;
    $has_throw_exception = false;
    foreach ($failure_cases as $case) {
      try {
        Normalizer::normalize('dobm', $case);
      } catch (\Exception $e) {
        $exceptions_counter += 1;
      }
    }
    $this->assertEquals(count($failure_cases), $exceptions_counter);
  }

  public function dobyData() {
    return array(
      array(
        '1995',
        '1995',
      ),
      array(
        '9999',
        '9999',
      ),
      array(
        '1000',
        '1000',
      ),
      array(
        '',
        '',
      ),
      array(
        null,
        null,
      ),
    );
  }

  /**
   * @dataProvider dobyData
   */
  public function testDoby($input, $expected) {
    $this->assertEquals(
      $expected,
      Normalizer::normalize('doby', $input)
    );
  }

  public function testDobyException() {
    $failure_cases = array(
      '-1',
      '0',
      '20',
      '12345',
      'nineteen-eighty',
    );
    $exceptions_counter = 0;
    $has_throw_exception = false;
    foreach ($failure_cases as $case) {
      try {
        Normalizer::normalize('doby', $case);
      } catch (\Exception $e) {
        $exceptions_counter += 1;
      }
    }
    $this->assertEquals(count($failure_cases), $exceptions_counter);
  }

  /**
   * Test cases for DeliveryCategory Normalization
   */
  public function deliveryCategoryNormalizeData() {
    return array(
      array(
        'home_delivery',
        'home_delivery',
      ),
      array(
        'CURBSIDE',
        'curbside',
      ),
      array(
        ' IN_STORE ',
        'in_store',
      ),
    );
  }

  /**
   * @dataProvider deliveryCategoryNormalizeData
   */
  public function testDeliveryCategoryNormalize($input, $expected) {
    $this->assertEquals(
      $expected,
      Normalizer::normalize('delivery_category', $input));
  }
}


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

namespace FacebookAdsTest\Object\ServerSide;

use PHPUnit\Framework\TestCase;
use FacebookAds\Object\ServerSide\Util;

class ServerSideUtilTest extends TestCase {

  public function setUp(): void {
    $_SERVER = [];
    $_COOKIE = [];
  }

  public function testNewEventTakesIpAddressFromHttpClientIP() {
    $_SERVER["HTTP_CLIENT_IP"] = "HTTP_CLIENT_IP_VALUE";
    $_SERVER["HTTP_X_FORWARDED_FOR"] = "HTTP_X_FORWARDED_FOR_VALUE";
    $_SERVER["REMOTE_ADDR"] = "REMOTE_ADDR";
    $this->assertEquals("HTTP_CLIENT_IP_VALUE",
      Util::getIpAddress());
  }

  public function testNewEventTakesIpAddressFromHttpXForwardedFor() {
    $_SERVER["HTTP_X_FORWARDED_FOR"] = "HTTP_X_FORWARDED_FOR_VALUE";
    $_SERVER["REMOTE_ADDR"] = "REMOTE_ADDR";
    $this->assertEquals("HTTP_X_FORWARDED_FOR_VALUE",
      Util::getIpAddress());
  }

  public function testNewEventTakesIpAddressFromRemoteAddr() {
    $_SERVER["REMOTE_ADDR"] = "REMOTE_ADDR_VALUE";
    $this->assertEquals("REMOTE_ADDR_VALUE",
      Util::getIpAddress());
  }

  public function testNewEventHasUserAgent() {
    $_SERVER["HTTP_USER_AGENT"] = "HTTP_USER_AGENT_VALUE";

    $this->assertEquals("HTTP_USER_AGENT_VALUE",
      Util::getHttpUserAgent());
  }

  public function testNewEventHasEventSourceUrlWithHttps() {
    $_SERVER["HTTPS"] = "anyvalue";
    $_SERVER["HTTP_HOST"] = "www.pikachu.com";
    $_SERVER["REQUEST_URI"] = "/index.php";

    $this->assertEquals("https://www.pikachu.com/index.php", Util::getRequestUri());
  }

  public function testNewEventHasEventSourceUrlWithHttp() {
    $_SERVER["HTTPS"] = "";
    $_SERVER["HTTP_HOST"] = "www.pikachu.com";
    $_SERVER["REQUEST_URI"] = "/index.php";

    $this->assertEquals("http://www.pikachu.com/index.php", Util::getRequestUri());
  }

  public function testNewEventHasEventSourceUrlWithHttpsOff() {
    $_SERVER["HTTPS"] = "off";
    $_SERVER["HTTP_HOST"] = "www.pikachu.com";
    $_SERVER["REQUEST_URI"] = "/index.php";

    $this->assertEquals("http://www.pikachu.com/index.php", Util::getRequestUri());
  }

  public function testNewEventHasFbc() {
    $_COOKIE["_fbc"] = "_fbc_value";

    $this->assertEquals("_fbc_value", Util::getFbc());
  }

  public function testNewEventHasFbp() {
    $_COOKIE["_fbp"] = "_fbp_value";

    $this->assertEquals("_fbp_value", Util::getFbp());
  }

  public function testGetCaBundlePath() {
    $this->assertTrue(file_exists(Util::getCaBundlePath()));
  }

  public function testGetAppsecretProof() {
    $access_token = 'accesstoken0';
    $appsecret = 'appsecret1';
    $expected_appsecret_proof = hash_hmac(
      'sha256',
      $access_token,
      $appsecret
    );

    $this->assertEquals(
      Util::getAppsecretProof($access_token, $appsecret),
      $expected_appsecret_proof
    );
  }
}


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

namespace FacebookAdsTest\Object;

use FacebookAdsTest\AbstractUnitTestCase;
use FacebookAds\Object\ServerSide\UserData;
use FacebookAds\Object\ServerSide\Util;
use InvalidArgumentException;

class UserDataTest extends AbstractUnitTestCase {
  public function testBuilderAndConstructor() {
    $initial_state = array(
      'email' => 'email-0@test.com',
      'phone' => '1234567890',
      'gender' => 'f',
      'date_of_birth' => '01/01/2001',
      'last_name' => 'last_name-4',
      'first_name' => 'first_name-5',
      'city' => 'city',
      'state' => 'state',
      'country_code' => 'us',
      'zip_code' => '12345',
      'external_id' => 'external_id-10',
      'client_ip_address' => 'client_ip_address-11',
      'client_user_agent' => 'client_user_agent-12',
      'fbc' => 'fbc-13',
      'fbp' => 'fbp-14',
      'subscription_id' => 'subscription_id-15',
      'fb_login_id' => 'fb_login_id-16',
      'lead_id' => 'lead_id-17',
      'f5first' => 'f5fir',
      'f5last' => 'f5las',
      'fi' => 'f',
      'dobd' => '01',
      'dobm' => '01',
      'doby' => '2001'
    );
    $expected = array(
      'em' => array(Util::hash($initial_state['email'])),
      'ph' => array(Util::hash($initial_state['phone'])),
      'ge' => array(Util::hash($initial_state['gender'])),
      'db' => array(Util::hash($initial_state['date_of_birth'])),
      'ln' => array(Util::hash($initial_state['last_name'])),
      'fn' => array(Util::hash($initial_state['first_name'])),
      'ct' => array(Util::hash($initial_state['city'])),
      'st' => array(Util::hash($initial_state['state'])),
      'country' => array(Util::hash($initial_state['country_code'])),
      'zp' => array(Util::hash($initial_state['zip_code'])),
      'external_id' => array('external_id-10'),
      'client_ip_address' => 'client_ip_address-11',
      'client_user_agent' => 'client_user_agent-12',
      'fbc' => 'fbc-13',
      'fbp' => 'fbp-14',
      'subscription_id' => 'subscription_id-15',
      'fb_login_id' => 'fb_login_id-16',
      'lead_id' => 'lead_id-17',
      'f5first' => Util::hash($initial_state['f5first']),
      'f5last' => Util::hash($initial_state['f5last']),
      'fi' => Util::hash($initial_state['fi']),
      'dobd' => Util::hash($initial_state['dobd']),
      'dobm' => Util::hash($initial_state['dobm']),
      'doby' => Util::hash($initial_state['doby'])
    );
    $builder = (new UserData())
      ->setEmail($initial_state['email'])
      ->setPhone($initial_state['phone'])
      ->setGender($initial_state['gender'])
      ->setDateOfBirth($initial_state['date_of_birth'])
      ->setLastName($initial_state['last_name'])
      ->setFirstName($initial_state['first_name'])
      ->setCity($initial_state['city'])
      ->setState($initial_state['state'])
      ->setCountryCode($initial_state['country_code'])
      ->setZipCode($initial_state['zip_code'])
      ->setExternalId($initial_state['external_id'])
      ->setClientIpAddress($initial_state['client_ip_address'])
      ->setClientUserAgent($initial_state['client_user_agent'])
      ->setFbc($initial_state['fbc'])
      ->setFbp($initial_state['fbp'])
      ->setSubscriptionId($initial_state['subscription_id'])
      ->setFbLoginId($initial_state['fb_login_id'])
      ->setLeadId($initial_state['lead_id'])
      ->setF5first($initial_state['f5first'])
      ->setF5last($initial_state['f5last'])
      ->setFi($initial_state['fi'])
      ->setDobd($initial_state['dobd'])
      ->setDobm($initial_state['dobm'])
      ->setDoby($initial_state['doby']);

    $this->assertEquals($expected, $builder->normalize());

    $constructor = new UserData($initial_state);
    $this->assertEquals($expected, $constructor->normalize());

    // Make sure single value getters still work, since we store these fields as arrays internally.
    $this->assertEquals($initial_state['email'], $constructor->getEmail());
    $this->assertEquals($initial_state['phone'], $constructor->getPhone());
    $this->assertEquals($initial_state['gender'], $constructor->getGender());
    $this->assertEquals($initial_state['date_of_birth'], $constructor->getDateOfBirth());
    $this->assertEquals($initial_state['last_name'], $constructor->getLastName());
    $this->assertEquals($initial_state['first_name'], $constructor->getFirstName());
    $this->assertEquals($initial_state['city'], $constructor->getCity());
    $this->assertEquals($initial_state['state'], $constructor->getState());
    $this->assertEquals($initial_state['country_code'], $constructor->getCountryCode());
    $this->assertEquals($initial_state['zip_code'], $constructor->getZipCode());
    $this->assertEquals($initial_state['external_id'], $constructor->getExternalId());
  }

  public function testMultiValueFieldsGettersAndSetters() {
    $initial_state = array(
      'emails' => array('email-0@test.com', 'email-1@eg.com'),
      'phones' => array('1234567890', '10000000000'),
      'genders' => array('f', 'm'),
      'dates_of_birth' => array('01/01/2001', '02/09/2008'),
      'last_names' => array('last_name-4', 'smith'),
      'first_names' => array('first_name-5', 'joe'),
      'cities' => array('seattle', 'san fransisco'),
      'states' => array('WA', 'CA'),
      'country_codes' => array('us', 'ca'),
      'zip_codes' => array('12345', '00000'),
      'external_ids' => array('external_id-10', '123')
    );

    $userData = (new UserData())
      ->setEmails($initial_state['emails'])
      ->setPhones($initial_state['phones'])
      ->setGenders($initial_state['genders'])
      ->setDatesOfBirth($initial_state['dates_of_birth'])
      ->setLastNames($initial_state['last_names'])
      ->setFirstNames($initial_state['first_names'])
      ->setCities($initial_state['cities'])
      ->setStates($initial_state['states'])
      ->setCountryCodes($initial_state['country_codes'])
      ->setZipCodes($initial_state['zip_codes'])
      ->setExternalIds($initial_state['external_ids']);

    $this->assertEquals($initial_state['emails'], $userData->getEmails());
    $this->assertEquals($initial_state['phones'], $userData->getPhones());
    $this->assertEquals($initial_state['genders'], $userData->getGenders());
    $this->assertEquals($initial_state['dates_of_birth'], $userData->getDatesOfBirth());
    $this->assertEquals($initial_state['last_names'], $userData->getLastNames());
    $this->assertEquals($initial_state['first_names'], $userData->getFirstNames());
    $this->assertEquals($initial_state['cities'], $userData->getCities());
    $this->assertEquals($initial_state['states'], $userData->getStates());
    $this->assertEquals($initial_state['country_codes'], $userData->getCountryCodes());
    $this->assertEquals($initial_state['zip_codes'], $userData->getZipCodes());
    $this->assertEquals($initial_state['external_ids'], $userData->getExternalIds());
  }

  public function testConstructorWithBothSingularAndPluralParams() {
    $params = array(
      array('email', 'emails'),
      array('phone', 'phones'),
      array('gender', 'genders'),
      array('date_of_birth', 'dates_of_birth'),
      array('last_name', 'last_names'),
      array('first_name', 'first_names'),
      array('city', 'cities'),
      array('state', 'states'),
      array('country_code', 'country_codes'),
      array('zip_code', 'zip_codes'),
      array('external_id', 'external_ids')
    );

    $exception_count = 0;
    foreach ($params as $p){
      $initial_state = array(
        $p[0] => 'testStr1',
        $p[1] => array('testStr2', 'testStr3')
      );
      try {
        $userData = new UserData($initial_state);
      } catch(InvalidArgumentException $e) {
        $exception_count++;
      }
    }
    self::assertEquals(count($params), $exception_count);
  }

  public function testConstructorWithOnlyPluralParams() {
    $initial_state = array(
      'emails' => array('email-0@test.com', 'email-1@eg.com'),
      'phones' => array('1234567890', '10000000000'),
      'genders' => array('f', 'm'),
      'dates_of_birth' => array('01/01/2001', '02/09/2008'),
      'last_names' => array('last_name-4', 'smith'),
      'first_names' => array('first_name-5', 'joe'),
      'cities' => array('seattle', 'san fransisco'),
      'states' => array('WA', 'CA'),
      'country_codes' => array('us', 'ca'),
      'zip_codes' => array('12345', '00000'),
      'external_ids' => array('external_id-10', '123')
    );

    $userData = new UserData($initial_state);

    $this->assertEquals($initial_state['emails'], $userData->getEmails());
    $this->assertEquals($initial_state['phones'], $userData->getPhones());
    $this->assertEquals($initial_state['genders'], $userData->getGenders());
    $this->assertEquals($initial_state['dates_of_birth'], $userData->getDatesOfBirth());
    $this->assertEquals($initial_state['last_names'], $userData->getLastNames());
    $this->assertEquals($initial_state['first_names'], $userData->getFirstNames());
    $this->assertEquals($initial_state['cities'], $userData->getCities());
    $this->assertEquals($initial_state['states'], $userData->getStates());
    $this->assertEquals($initial_state['country_codes'], $userData->getCountryCodes());
    $this->assertEquals($initial_state['zip_codes'], $userData->getZipCodes());
    $this->assertEquals($initial_state['external_ids'], $userData->getExternalIds());
  }

  public function testGettersAndSettersWithNull() {
    $userData = (new UserData())
      ->setEmail(null)
      ->setPhone(null)
      ->setGender(null)
      ->setDateOfBirth(null)
      ->setLastName(null)
      ->setFirstName(null)
      ->setCity(null)
      ->setState(null)
      ->setCountryCode(null)
      ->setZipCode(null)
      ->setExternalId(null);

    $this->assertEquals(null, $userData->getEmail());
    $this->assertEquals(null, $userData->getPhone());
    $this->assertEquals(null, $userData->getGender());
    $this->assertEquals(null, $userData->getDateOfBirth());
    $this->assertEquals(null, $userData->getLastName());
    $this->assertEquals(null, $userData->getFirstName());
    $this->assertEquals(null, $userData->getCity());
    $this->assertEquals(null, $userData->getState());
    $this->assertEquals(null, $userData->getCountryCode());
    $this->assertEquals(null, $userData->getZipCode());
    $this->assertEquals(null, $userData->getExternalId());
  }

  public function testGettersAndSettersWithEmpty() {
    $userData = (new UserData())
      ->setEmails(array())
      ->setPhones(array())
      ->setGenders(array())
      ->setDatesOfBirth(array())
      ->setLastNames(array())
      ->setFirstNames(array())
      ->setCities(array())
      ->setStates(array())
      ->setCountryCodes(array())
      ->setZipCodes(array())
      ->setExternalIds(array());

    $this->assertEquals(null, $userData->getEmail());
    $this->assertEquals(null, $userData->getPhone());
    $this->assertEquals(null, $userData->getGender());
    $this->assertEquals(null, $userData->getDateOfBirth());
    $this->assertEquals(null, $userData->getLastName());
    $this->assertEquals(null, $userData->getFirstName());
    $this->assertEquals(null, $userData->getCity());
    $this->assertEquals(null, $userData->getState());
    $this->assertEquals(null, $userData->getCountryCode());
    $this->assertEquals(null, $userData->getZipCode());
    $this->assertEquals(null, $userData->getExternalId());
  }

  public function testMultiValueFieldsDeduplication() {
    $initial_state = array(
      'emails' => array('email-0@test.com', 'email-1@eg.com', 'email-1@eg.com'),
      'phones' => array('1234567890', '10000000000', '10000000000'),
      'genders' => array('f', 'm', 'm'),
      'dates_of_birth' => array('01/01/2001', '02/09/2008', '02/09/2008'),
      'last_names' => array('last_name-4', 'smith', 'smith'),
      'first_names' => array('first_name-5', 'joe', 'first_name-5'),
      'cities' => array('seattle', 'sanfransisco', 'seattle'),
      'states' => array('wa', 'ca', 'wa'),
      'country_codes' => array('us', 'ca', 'us'),
      'zip_codes' => array('12345', '00000', '12345'),
      'external_ids' => array('external_id-10', '123', 'external_id-10')
    );

    $userData = (new UserData())
      ->setEmails($initial_state['emails'])
      ->setPhones($initial_state['phones'])
      ->setGenders($initial_state['genders'])
      ->setDatesOfBirth($initial_state['dates_of_birth'])
      ->setLastNames($initial_state['last_names'])
      ->setFirstNames($initial_state['first_names'])
      ->setCities($initial_state['cities'])
      ->setStates($initial_state['states'])
      ->setCountryCodes($initial_state['country_codes'])
      ->setZipCodes($initial_state['zip_codes'])
      ->setExternalIds($initial_state['external_ids']);

    $normalized = $userData->normalize();

    $this->assertEquals(2, count($normalized['em']));
    $this->assertEquals(2, count($normalized['ph']));
    $this->assertEquals(2, count($normalized['ge']));
    $this->assertEquals(2, count($normalized['db']));
    $this->assertEquals(2, count($normalized['ln']));
    $this->assertEquals(2, count($normalized['fn']));
    $this->assertEquals(2, count($normalized['ct']));
    $this->assertEquals(2, count($normalized['st']));
    $this->assertEquals(2, count($normalized['country']));
    $this->assertEquals(2, count($normalized['zp']));
    $this->assertEquals(2, count($normalized['external_id']));
  }

  public function testNormalizeMultiValueFields() {
    $initial_state = array(
      'email' => array('email-0@test.com', 'email-1@eg.com'),
      'phone' => array('1234567890', '10000000000'),
      'gender' => array('f', 'm'),
      'date_of_birth' => array('01/01/2001', '02/09/2008'),
      'last_name' => array('last_name-4', 'smith'),
      'first_name' => array('first_name-5', 'joe'),
      'city' => array('seattle', 'sanfransisco'),
      'state' => array('wa', 'ca'),
      'country_code' => array('us', 'ca'),
      'zip_code' => array('12345', '00000'),
      'external_id' => array('external_id-10', '123')
    );

    $userData = (new UserData())
      ->setEmails($initial_state['email'])
      ->setPhones($initial_state['phone'])
      ->setGenders($initial_state['gender'])
      ->setDatesOfBirth($initial_state['date_of_birth'])
      ->setLastNames($initial_state['last_name'])
      ->setFirstNames($initial_state['first_name'])
      ->setCities($initial_state['city'])
      ->setStates($initial_state['state'])
      ->setCountryCodes($initial_state['country_code'])
      ->setZipCodes($initial_state['zip_code'])
      ->setExternalIds($initial_state['external_id']);

    $expected = array(
      'em' => $this->hashList($initial_state['email']),
      'ph' => $this->hashList($initial_state['phone']),
      'ge' => $this->hashList($initial_state['gender']),
      'db' => $this->hashList($initial_state['date_of_birth']),
      'ln' => $this->hashList($initial_state['last_name']),
      'fn' => $this->hashList($initial_state['first_name']),
      'ct' => $this->hashList($initial_state['city']),
      'st' => $this->hashList($initial_state['state']),
      'country' => $this->hashList($initial_state['country_code']),
      'zp' => $this->hashList($initial_state['zip_code']),
      'external_id' => $initial_state['external_id']
    );

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

  public function testMultiValueFieldsCanNormalizeEmpty() {
    $userData = new UserData();
    $normalized = $userData->normalize();

    $this->assertEquals(array(), $normalized);
  }

  private function hashList($arr){
    return array_map(
      function($val){
        return Util::hash($val);
      },
      $arr);
  }
}


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

namespace FacebookAdsTest\Object\ServerSide\TestHelpers;
use FacebookAds\Object\ServerSide\HttpServiceInterface;

class AnotherHttpService implements HttpServiceInterface {
  public function executeRequest($url, $method, array $curl_options, array $headers, array $params) {
    return null;
  }
}


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

namespace FacebookAdsTest\Object\ServerSide\TestHelpers;
use FacebookAds\Object\ServerSide\HttpServiceInterface;

class FakeHttpService implements HttpServiceInterface {
  public function executeRequest($url, $method, array $curl_options, array $headers, array $params) {
    return null;
  }
}


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

namespace FacebookAdsTest\Object\Signal;

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

class EventTest extends AbstractUnitTestCase {
  public function testBuilder() {
    $user_data = new UserData(array('email' => 'aaa@fb.com'));
    $billing_contact = new UserData(array('email' => 'bbb@fb.com'));
    $shipping_contact = new UserData(array('email' => 'ccc@fb.com'));
    $custom_data = (new CustomData())
    ->setOrderId('order_id')
    ->setBillingContact($billing_contact)
    ->setShippingContact($shipping_contact);
    $expected = array(
      'event_name' => 'event_name',
      'event_time' => 1234,
      'event_id' => 'event_id',
      'data_processing_options' => array('LDU'),
      'data_processing_options_country' => 1,
      'data_processing_options_state' => 1000,
    );

    $event = (new Event())
      ->setEventName($expected['event_name'])
      ->setEventTime($expected['event_time'])
      ->setEventId($expected['event_id'])
      ->setUserData($user_data)
      ->setCustomData($custom_data)
      ->setDataProcessingOptions($expected['data_processing_options'])
      ->setDataProcessingOptionsCountry($expected['data_processing_options_country'])
      ->setDataProcessingOptionsState($expected['data_processing_options_state']);

    $expected['user_data'] = $user_data->getBusinessDataUserData()->toJson();
    $expected['custom_data'] = $custom_data->getBusinessDataCustomData()->toJson();
    $this->assertEquals($expected, $event->getBusinessDataEvent()->toJson());
    $this->assertEquals('order_id', $event->getBusinessDataEvent()->getCustomData()->getOrderId());
    $this->assertEquals('ccc@fb.com', $event->getBusinessDataEvent()->getCustomData()->getShippingContact()->getEmail());
    $this->assertEquals('bbb@fb.com', $event->getBusinessDataEvent()->getCustomData()->getBillingContact()->getEmail());
    $this->assertEquals('aaa@fb.com', $event->getBusinessDataEvent()->getUserData()->getEmail());

    $expected['user_data'] = $user_data->getServerSideUserData()->normalize();
    $expected['custom_data'] = $custom_data->getServerSideCustomData()->normalize();
    $this->assertEquals($expected, $event->getServerSideEvent()->normalize());
    $this->assertEquals('order_id', $event->getServerSideEvent()->getCustomData()->getOrderId());
    $this->assertEquals('aaa@fb.com', $event->getServerSideEvent()->getUserData()->getEmail());

  }
}


<?hh
/**
 * Autogenerated by Thrift
 *
 * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
 *  @generated
 */

namespace facebook\thrift\test;

/**
 * Original thrift service:-
 * AdapterService
 */
<<\ThriftTypeInfo(shape('uri' => 'facebook.com/thrift/test/AdapterService'))>>
interface AdapterServiceAsyncIf extends \IThriftAsyncIf {
  /**
   * Original thrift definition:-
   * CountingStruct
   *   count();
   */
  public function count(): Awaitable<\facebook\thrift\test\CountingStruct>;

  /**
   * Original thrift definition:-
   * HeapAllocated
   *   adaptedTypes(1: HeapAllocated arg);
   */
  public function adaptedTypes(?\facebook\thrift\test\HeapAllocated $arg): Awaitable<\facebook\thrift\test\HeapAllocated>;
}

/**
 * Original thrift service:-
 * AdapterService
 */
<<\ThriftTypeInfo(shape('uri' => 'facebook.com/thrift/test/AdapterService'))>>
interface AdapterServiceIf extends \IThriftSyncIf {
  /**
   * Original thrift definition:-
   * CountingStruct
   *   count();
   */
  public function count(): \facebook\thrift\test\CountingStruct;

  /**
   * Original thrift definition:-
   * HeapAllocated
   *   adaptedTypes(1: HeapAllocated arg);
   */
  public function adaptedTypes(?\facebook\thrift\test\HeapAllocated $arg): \facebook\thrift\test\HeapAllocated;
}

/**
 * Original thrift service:-
 * AdapterService
 */
<<\ThriftTypeInfo(shape('uri' => 'facebook.com/thrift/test/AdapterService'))>>
interface AdapterServiceAsyncClientIf extends AdapterServiceAsyncIf {
}

/**
 * Original thrift service:-
 * AdapterService
 */
<<\ThriftTypeInfo(shape('uri' => 'facebook.com/thrift/test/AdapterService'))>>
interface AdapterServiceClientIf extends \IThriftSyncIf {
  /**
   * Original thrift definition:-
   * CountingStruct
   *   count();
   */
  public function count(): Awaitable<\facebook\thrift\test\CountingStruct>;

  /**
   * Original thrift definition:-
   * HeapAllocated
   *   adaptedTypes(1: HeapAllocated arg);
   */
  public function adaptedTypes(?\facebook\thrift\test\HeapAllocated $arg): Awaitable<\facebook\thrift\test\HeapAllocated>;
}

/**
 * Original thrift service:-
 * AdapterService
 */
trait AdapterServiceClientBase {
  require extends \ThriftClientBase;

}

class AdapterServiceAsyncClient extends \ThriftClientBase implements AdapterServiceAsyncClientIf {
  use AdapterServiceClientBase;

  /**
   * Original thrift definition:-
   * CountingStruct
   *   count();
   */
  public async function count(): Awaitable<\facebook\thrift\test\CountingStruct> {
    $hh_frame_metadata = $this->getHHFrameMetadata();
    if ($hh_frame_metadata !== null) {
      \HH\set_frame_metadata($hh_frame_metadata);
    }
    $rpc_options = $this->getAndResetOptions() ?? \ThriftClientBase::defaultOptions();
    $args = \facebook\thrift\test\AdapterService_count_args::withDefaultValues();
    await $this->asyncHandler_->genBefore("AdapterService", "count", $args);
    $currentseqid = $this->sendImplHelper($args, "count", false);
    return await $this->genAwaitResponse(\facebook\thrift\test\AdapterService_count_result::class, "count", false, $currentseqid, $rpc_options);
  }

  /**
   * Original thrift definition:-
   * HeapAllocated
   *   adaptedTypes(1: HeapAllocated arg);
   */
  public async function adaptedTypes(?\facebook\thrift\test\HeapAllocated $arg): Awaitable<\facebook\thrift\test\HeapAllocated> {
    $hh_frame_metadata = $this->getHHFrameMetadata();
    if ($hh_frame_metadata !== null) {
      \HH\set_frame_metadata($hh_frame_metadata);
    }
    $rpc_options = $this->getAndResetOptions() ?? \ThriftClientBase::defaultOptions();
    $args = \facebook\thrift\test\AdapterService_adaptedTypes_args::fromShape(shape(
      'arg' => $arg,
    ));
    await $this->asyncHandler_->genBefore("AdapterService", "adaptedTypes", $args);
    $currentseqid = $this->sendImplHelper($args, "adaptedTypes", false);
    return await $this->genAwaitResponse(\facebook\thrift\test\AdapterService_adaptedTypes_result::class, "adaptedTypes", false, $currentseqid, $rpc_options);
  }

}

class AdapterServiceClient extends \ThriftClientBase implements AdapterServiceClientIf {
  use AdapterServiceClientBase;

  /**
   * Original thrift definition:-
   * CountingStruct
   *   count();
   */
  public async function count(): Awaitable<\facebook\thrift\test\CountingStruct> {
    $hh_frame_metadata = $this->getHHFrameMetadata();
    if ($hh_frame_metadata !== null) {
      \HH\set_frame_metadata($hh_frame_metadata);
    }
    $rpc_options = $this->getAndResetOptions() ?? \ThriftClientBase::defaultOptions();
    $args = \facebook\thrift\test\AdapterService_count_args::withDefaultValues();
    await $this->asyncHandler_->genBefore("AdapterService", "count", $args);
    $currentseqid = $this->sendImplHelper($args, "count", false);
    return await $this->genAwaitResponse(\facebook\thrift\test\AdapterService_count_result::class, "count", false, $currentseqid, $rpc_options);
  }

  /**
   * Original thrift definition:-
   * HeapAllocated
   *   adaptedTypes(1: HeapAllocated arg);
   */
  public async function adaptedTypes(?\facebook\thrift\test\HeapAllocated $arg): Awaitable<\facebook\thrift\test\HeapAllocated> {
    $hh_frame_metadata = $this->getHHFrameMetadata();
    if ($hh_frame_metadata !== null) {
      \HH\set_frame_metadata($hh_frame_metadata);
    }
    $rpc_options = $this->getAndResetOptions() ?? \ThriftClientBase::defaultOptions();
    $args = \facebook\thrift\test\AdapterService_adaptedTypes_args::fromShape(shape(
      'arg' => $arg,
    ));
    await $this->asyncHandler_->genBefore("AdapterService", "adaptedTypes", $args);
    $currentseqid = $this->sendImplHelper($args, "adaptedTypes", false);
    return await $this->genAwaitResponse(\facebook\thrift\test\AdapterService_adaptedTypes_result::class, "adaptedTypes", false, $currentseqid, $rpc_options);
  }

  /* send and recv functions */
  public function send_count(): int {
    $args = \facebook\thrift\test\AdapterService_count_args::withDefaultValues();
    return $this->sendImplHelper($args, "count", false);
  }
  public function recv_count(?int $expectedsequenceid = null): \facebook\thrift\test\CountingStruct {
    return $this->recvImplHelper(\facebook\thrift\test\AdapterService_count_result::class, "count", false, $expectedsequenceid);
  }
  public function send_adaptedTypes(?\facebook\thrift\test\HeapAllocated $arg): int {
    $args = \facebook\thrift\test\AdapterService_adaptedTypes_args::fromShape(shape(
      'arg' => $arg,
    ));
    return $this->sendImplHelper($args, "adaptedTypes", false);
  }
  public function recv_adaptedTypes(?int $expectedsequenceid = null): \facebook\thrift\test\HeapAllocated {
    return $this->recvImplHelper(\facebook\thrift\test\AdapterService_adaptedTypes_result::class, "adaptedTypes", false, $expectedsequenceid);
  }
}

// HELPER FUNCTIONS AND STRUCTURES

class AdapterService_count_args implements \IThriftSyncStruct, \IThriftStructMetadata, \IThriftShapishSyncStruct {
  use \ThriftSerializationTrait;

  const \ThriftStructTypes::TSpec SPEC = dict[
  ];
  const dict<string, int> FIELDMAP = dict[
  ];

  const type TConstructorShape = shape(
  );

  const type TShape = shape(
  );
  const int STRUCTURAL_ID = 957977401221134810;

  public function __construct()[] {
  }

  public static function withDefaultValues()[]: this {
    return new static();
  }

  public static function fromShape(self::TConstructorShape $shape)[]: this {
    return new static(
    );
  }

  public function getName()[]: string {
    return 'AdapterService_count_args';
  }

  public function clearTerseFields()[write_props]: void {
  }

  public static function getStructMetadata()[]: \tmeta_ThriftStruct {
    return \tmeta_ThriftStruct::fromShape(
      shape(
        "name" => "module.count_args",
        "is_union" => false,
      )
    );
  }

  public static function getAllStructuredAnnotations()[write_props]: \TStructAnnotations {
    return shape(
      'struct' => dict[],
      'fields' => dict[
      ],
    );
  }

  public static function __fromShape(self::TShape $shape)[]: this {
    return new static(
    );
  }

  public function __toShape()[]: self::TShape {
    return shape(
    );
  }
  public function getInstanceKey()[write_props]: string {
    return \TCompactSerializer::serialize($this);
  }

  public function readFromJson(string $jsonText): void {
    $parsed = json_decode($jsonText, true);

    if ($parsed === null || !($parsed is KeyedContainer<_, _>)) {
      throw new \TProtocolException("Cannot parse the given json string.");
    }

  }

}

class AdapterService_count_result extends \ThriftSyncStructWithResult implements \IThriftStructMetadata {
  use \ThriftSerializationTrait;

  const type TResult = \facebook\thrift\test\CountingStruct;

  const \ThriftStructTypes::TSpec SPEC = dict[
    0 => shape(
      'var' => 'success',
      'type' => \TType::STRUCT,
      'class' => \facebook\thrift\test\CountingStruct::class,
    ),
  ];
  const dict<string, int> FIELDMAP = dict[
    'success' => 0,
  ];

  const type TConstructorShape = shape(
    ?'success' => ?this::TResult,
  );

  const int STRUCTURAL_ID = 361061362707289990;
  public ?this::TResult $success;

  public function __construct(?this::TResult $success = null)[] {
    $this->success = $success;
  }

  public static function withDefaultValues()[]: this {
    return new static();
  }

  public static function fromShape(self::TConstructorShape $shape)[]: this {
    return new static(
      Shapes::idx($shape, 'success'),
    );
  }

  public function getName()[]: string {
    return 'AdapterService_count_result';
  }

  public function clearTerseFields()[write_props]: void {
  }

  public static function getStructMetadata()[]: \tmeta_ThriftStruct {
    return \tmeta_ThriftStruct::fromShape(
      shape(
        "name" => "module.AdapterService_count_result",
        "fields" => vec[
          \tmeta_ThriftField::fromShape(
            shape(
              "id" => 0,
              "type" => \tmeta_ThriftType::fromShape(
                shape(
                  "t_struct" => \tmeta_ThriftStructType::fromShape(
                    shape(
                      "name" => "module.CountingStruct",
                    )
                  ),
                )
              ),
              "name" => "success",
            )
          ),
        ],
        "is_union" => false,
      )
    );
  }

  public static function getAllStructuredAnnotations()[write_props]: \TStructAnnotations {
    return shape(
      'struct' => dict[],
      'fields' => dict[
      ],
    );
  }

  public function getInstanceKey()[write_props]: string {
    return \TCompactSerializer::serialize($this);
  }

  public function readFromJson(string $jsonText): void {
    $parsed = json_decode($jsonText, true);

    if ($parsed === null || !($parsed is KeyedContainer<_, _>)) {
      throw new \TProtocolException("Cannot parse the given json string.");
    }

    if (idx($parsed, 'success') !== null) {
      $_tmp0 = \json_encode(HH\FIXME\UNSAFE_CAST<mixed, \facebook\thrift\test\CountingStruct>($parsed['success']));
      $_tmp1 = \facebook\thrift\test\CountingStruct::withDefaultValues();
      $_tmp1->readFromJson($_tmp0);
      $this->success = $_tmp1;
    }
  }

}

class AdapterService_adaptedTypes_args implements \IThriftSyncStruct, \IThriftStructMetadata, \IThriftShapishSyncStruct {
  use \ThriftSerializationTrait;

  const \ThriftStructTypes::TSpec SPEC = dict[
    1 => shape(
      'var' => 'arg',
      'type' => \TType::STRUCT,
      'class' => \facebook\thrift\test\HeapAllocated::class,
    ),
  ];
  const dict<string, int> FIELDMAP = dict[
    'arg' => 1,
  ];

  const type TConstructorShape = shape(
    ?'arg' => ?\facebook\thrift\test\HeapAllocated,
  );

  const type TShape = shape(
    ?'arg' => ?\facebook\thrift\test\HeapAllocated::TShape,
  );
  const int STRUCTURAL_ID = 270071957836224163;
  public ?\facebook\thrift\test\HeapAllocated $arg;

  public function __construct(?\facebook\thrift\test\HeapAllocated $arg = null)[] {
    $this->arg = $arg;
  }

  public static function withDefaultValues()[]: this {
    return new static();
  }

  public static function fromShape(self::TConstructorShape $shape)[]: this {
    return new static(
      Shapes::idx($shape, 'arg'),
    );
  }

  public function getName()[]: string {
    return 'AdapterService_adaptedTypes_args';
  }

  public function clearTerseFields()[write_props]: void {
  }

  public static function getStructMetadata()[]: \tmeta_ThriftStruct {
    return \tmeta_ThriftStruct::fromShape(
      shape(
        "name" => "module.adaptedTypes_args",
        "fields" => vec[
          \tmeta_ThriftField::fromShape(
            shape(
              "id" => 1,
              "type" => \tmeta_ThriftType::fromShape(
                shape(
                  "t_struct" => \tmeta_ThriftStructType::fromShape(
                    shape(
                      "name" => "module.HeapAllocated",
                    )
                  ),
                )
              ),
              "name" => "arg",
            )
          ),
        ],
        "is_union" => false,
      )
    );
  }

  public static function getAllStructuredAnnotations()[write_props]: \TStructAnnotations {
    return shape(
      'struct' => dict[],
      'fields' => dict[
        'arg' => shape(
          'field' => dict[],
          'type' => dict[
            '\facebook\thrift\annotation\cpp\Adapter' => \facebook\thrift\annotation\cpp\Adapter::fromShape(
              shape(
                "name" => "::apache::thrift::test::MoveOnlyAdapter",
                "moveOnly" => true,
              )
            ),
          ],
        ),
      ],
    );
  }

  public static function __fromShape(self::TShape $shape)[]: this {
    return new static(
      Shapes::idx($shape, 'arg') === null ? null : (\facebook\thrift\test\HeapAllocated::__fromShape($shape['arg'])),
    );
  }

  public function __toShape()[]: self::TShape {
    return shape(
      'arg' => $this->arg?->__toShape(),
    );
  }
  public function getInstanceKey()[write_props]: string {
    return \TCompactSerializer::serialize($this);
  }

  public function readFromJson(string $jsonText): void {
    $parsed = json_decode($jsonText, true);

    if ($parsed === null || !($parsed is KeyedContainer<_, _>)) {
      throw new \TProtocolException("Cannot parse the given json string.");
    }

    if (idx($parsed, 'arg') !== null) {
      $_tmp0 = \json_encode(HH\FIXME\UNSAFE_CAST<mixed, \facebook\thrift\test\HeapAllocated>($parsed['arg']));
      $_tmp1 = \facebook\thrift\test\HeapAllocated::withDefaultValues();
      $_tmp1->readFromJson($_tmp0);
      $this->arg = $_tmp1;
    }
  }

}

class AdapterService_adaptedTypes_result extends \ThriftSyncStructWithResult implements \IThriftStructMetadata {
  use \ThriftSerializationTrait;

  const type TResult = \facebook\thrift\test\HeapAllocated;

  const \ThriftStructTypes::TSpec SPEC = dict[
    0 => shape(
      'var' => 'success',
      'type' => \TType::STRUCT,
      'class' => \facebook\thrift\test\HeapAllocated::class,
    ),
  ];
  const dict<string, int> FIELDMAP = dict[
    'success' => 0,
  ];

  const type TConstructorShape = shape(
    ?'success' => ?this::TResult,
  );

  const int STRUCTURAL_ID = 8969067960420042186;
  public ?this::TResult $success;

  public function __construct(?this::TResult $success = null)[] {
    $this->success = $success;
  }

  public static function withDefaultValues()[]: this {
    return new static();
  }

  public static function fromShape(self::TConstructorShape $shape)[]: this {
    return new static(
      Shapes::idx($shape, 'success'),
    );
  }

  public function getName()[]: string {
    return 'AdapterService_adaptedTypes_result';
  }

  public function clearTerseFields()[write_props]: void {
  }

  public static function getStructMetadata()[]: \tmeta_ThriftStruct {
    return \tmeta_ThriftStruct::fromShape(
      shape(
        "name" => "module.AdapterService_adaptedTypes_result",
        "fields" => vec[
          \tmeta_ThriftField::fromShape(
            shape(
              "id" => 0,
              "type" => \tmeta_ThriftType::fromShape(
                shape(
                  "t_struct" => \tmeta_ThriftStructType::fromShape(
                    shape(
                      "name" => "module.HeapAllocated",
                    )
                  ),
                )
              ),
              "name" => "success",
            )
          ),
        ],
        "is_union" => false,
      )
    );
  }

  public static function getAllStructuredAnnotations()[write_props]: \TStructAnnotations {
    return shape(
      'struct' => dict[],
      'fields' => dict[
        'success' => shape(
          'field' => dict[],
          'type' => dict[
            '\facebook\thrift\annotation\cpp\Adapter' => \facebook\thrift\annotation\cpp\Adapter::fromShape(
              shape(
                "name" => "::apache::thrift::test::MoveOnlyAdapter",
                "moveOnly" => true,
              )
            ),
          ],
        ),
      ],
    );
  }

  public function getInstanceKey()[write_props]: string {
    return \TCompactSerializer::serialize($this);
  }

  public function readFromJson(string $jsonText): void {
    $parsed = json_decode($jsonText, true);

    if ($parsed === null || !($parsed is KeyedContainer<_, _>)) {
      throw new \TProtocolException("Cannot parse the given json string.");
    }

    if (idx($parsed, 'success') !== null) {
      $_tmp0 = \json_encode(HH\FIXME\UNSAFE_CAST<mixed, \facebook\thrift\test\HeapAllocated>($parsed['success']));
      $_tmp1 = \facebook\thrift\test\HeapAllocated::withDefaultValues();
      $_tmp1->readFromJson($_tmp0);
      $this->success = $_tmp1;
    }
  }

}

class AdapterServiceStaticMetadata implements \IThriftServiceStaticMetadata {
  public static function getServiceMetadata()[]: \tmeta_ThriftService {
    return \tmeta_ThriftService::fromShape(
      shape(
        "name" => "module.AdapterService",
        "functions" => vec[
          \tmeta_ThriftFunction::fromShape(
            shape(
              "name" => "count",
              "return_type" => \tmeta_ThriftType::fromShape(
                shape(
                  "t_struct" => \tmeta_ThriftStructType::fromShape(
                    shape(
                      "name" => "module.CountingStruct",
                    )
                  ),
                )
              ),
            )
          ),
          \tmeta_ThriftFunction::fromShape(
            shape(
              "name" => "adaptedTypes",
              "return_type" => \tmeta_ThriftType::fromShape(
                shape(
                  "t_struct" => \tmeta_ThriftStructType::fromShape(
                    shape(
                      "name" => "module.HeapAllocated",
                    )
                  ),
                )
              ),
              "arguments" => vec[
                \tmeta_ThriftField::fromShape(
                  shape(
                    "id" => 1,
                    "type" => \tmeta_ThriftType::fromShape(
                      shape(
                        "t_struct" => \tmeta_ThriftStructType::fromShape(
                          shape(
                            "name" => "module.HeapAllocated",
                          )
                        ),
                      )
                    ),
                    "name" => "arg",
                  )
                ),
              ],
            )
          ),
        ],
      )
    );
  }

  public static function getServiceMetadataResponse()[]: \tmeta_ThriftServiceMetadataResponse {
    return \tmeta_ThriftServiceMetadataResponse::fromShape(
      shape(
        'context' => \tmeta_ThriftServiceContext::fromShape(
          shape(
            'service_info' => self::getServiceMetadata(),
            'module' => \tmeta_ThriftModuleContext::fromShape(
              shape(
                'name' => 'module',
              )
            ),
          )
        ),
        'metadata' => \tmeta_ThriftMetadata::fromShape(
          shape(
            'enums' => dict[
            ],
            'structs' => dict[
              'module.CountingStruct' => \facebook\thrift\test\CountingStruct::getStructMetadata(),
              'module.HeapAllocated' => \facebook\thrift\test\HeapAllocated::getStructMetadata(),
            ],
            'exceptions' => dict[
            ],
            'services' => dict[
            ],
          )
        ),
      )
    );
  }

  public static function getAllStructuredAnnotations()[write_props]: \TServiceAnnotations {
    return shape(
      'service' => dict[],
      'functions' => dict[
      ],
    );
  }
}