You are here

AgreementHandlerTest.php in Agreement 3.0.x

Same filename and directory in other branches
  1. 8.2 tests/src/Unit/AgreementHandlerTest.php

File

tests/src/Unit/AgreementHandlerTest.php
View source
<?php

namespace Drupal\Tests\agreement\Unit;

use Drupal\agreement\AgreementHandler;
use Drupal\agreement\Entity\Agreement;
use Drupal\Core\Database\DatabaseExceptionWrapper;
use Drupal\Core\Path\PathMatcher;
use Drupal\Tests\UnitTestCase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;

/**
 * Tests logic in the agreement handler service.
 *
 * @group agreement
 */
class AgreementHandlerTest extends UnitTestCase {

  /**
   * Asserts that database operation errors are handled.
   *
   * @param bool $expected
   *   The expected return value.
   * @param string $errorDuring
   *   The expected cause of the error.
   *
   * @dataProvider agreeProvider
   */
  public function testAgree($expected, $errorDuring = NULL) {
    $entityTypeManagerProphet = $this
      ->prophesize('\\Drupal\\Core\\Entity\\EntityTypeManagerInterface');
    $pathMatcherProphet = $this
      ->prophesize('\\Drupal\\Core\\Path\\PathMatcherInterface');
    $accountProphet = $this
      ->prophesize('\\Drupal\\Core\\Session\\AccountProxyInterface');
    $accountProphet
      ->isAnonymous()
      ->willReturn(FALSE);
    $accountProphet
      ->id()
      ->willReturn(5);
    $agreementProphet = $this
      ->prophesize('\\Drupal\\agreement\\Entity\\Agreement');
    $agreementProphet
      ->id()
      ->willReturn('agreement');
    $transactionProphet = $this
      ->prophesize('\\Drupal\\Core\\Database\\Transaction');
    $transactionProphet
      ->rollback();
    $connectionProphet = $this
      ->prophesize('\\Drupal\\Core\\Database\\Connection');
    $connectionProphet
      ->startTransaction()
      ->willReturn($transactionProphet
      ->reveal());

    // Prophecy does not allow mocking objects that return $this because.
    $delete = $this
      ->getMockBuilder('\\Drupal\\Core\\Database\\Query\\Delete')
      ->disableOriginalConstructor()
      ->getMock();
    $delete
      ->expects($this
      ->any())
      ->method('condition')
      ->willReturnSelf();
    $delete
      ->expects($this
      ->any())
      ->method('execute')
      ->willReturnCallback(function () use ($expected, $errorDuring) {
      if (!$expected && $errorDuring === 'delete') {
        throw new DatabaseExceptionWrapper();
      }

      // SAVED_DELETED constant.
      return 3;
    });
    $insert = $this
      ->getMockBuilder('\\Drupal\\Core\\Database\\Query\\Insert')
      ->disableOriginalConstructor()
      ->getMock();
    $insert
      ->expects($this
      ->any())
      ->method('fields')
      ->willReturnSelf();
    $insert
      ->expects($this
      ->any())
      ->method('execute')
      ->willReturnCallback(function () use ($expected, $errorDuring) {
      if (!$expected && $errorDuring === 'insert') {
        throw new DatabaseExceptionWrapper();
      }

      // SAVED_NEW constant.
      return 1;
    });
    $connectionProphet
      ->delete('agreement')
      ->willReturn($delete);
    $connectionProphet
      ->insert('agreement')
      ->willReturn($insert);
    $timeProphet = $this
      ->prophesize('\\Drupal\\Component\\Datetime\\TimeInterface');
    $timeProphet
      ->getRequestTime()
      ->willReturn(time());
    $requestStack = new RequestStack();
    $requestStack
      ->push(Request::create('/'));
    $handler = new AgreementHandler($connectionProphet
      ->reveal(), $entityTypeManagerProphet
      ->reveal(), $pathMatcherProphet
      ->reveal(), $timeProphet
      ->reveal(), $requestStack);
    $this
      ->assertEquals($expected, $handler
      ->agree($agreementProphet
      ->reveal(), $accountProphet
      ->reveal()));
  }

  /**
   * Provides expected values for the agree method.
   *
   * @return array
   *   An array of test arguments.
   */
  public function agreeProvider() {
    return [
      'without error' => [
        TRUE,
        NULL,
      ],
      'with error in delete' => [
        FALSE,
        'delete',
      ],
      'with error in insert' => [
        FALSE,
        'insert',
      ],
    ];
  }

  /**
   * Asserts agreement discovery.
   *
   * @param \Drupal\agreement\Entity\Agreement|false $expected
   *   The expected return value for this test.
   * @param \Drupal\agreement\Entity\Agreement[] $agreements
   *   A list of agreements.
   * @param array $roles
   *   An indexed array of user roles to apply to the mock user.
   * @param int|null $agreed
   *   The agreement state for the user.
   * @param string $path
   *   The path to test.
   *
   * @dataProvider getAgreementProvider
   */
  public function testGetAgreementByUserAndPath($expected, array $agreements, array $roles, $agreed, $path) {

    // Mocks Config, ConfigFactory, and RouteMatch for PathMatcher.
    $siteConfigProphet = $this
      ->prophesize('\\Drupal\\Core\\Config\\ImmutableConfig');
    $siteConfigProphet
      ->get('page.front')
      ->willReturn('/');
    $configFactoryProphet = $this
      ->prophesize('\\Drupal\\Core\\Config\\ConfigFactoryInterface');
    $configFactoryProphet
      ->get('system.site')
      ->willReturn($siteConfigProphet
      ->reveal());
    $routeMatchProphet = $this
      ->prophesize('\\Drupal\\Core\\Routing\\RouteMatchInterface');

    // Mocks account interface with configurable roles based on data.
    $accountProphet = $this
      ->prophesize('\\Drupal\\Core\\Session\\AccountProxyInterface');
    $accountProphet
      ->isAnonymous()
      ->willReturn(FALSE);
    $accountProphet
      ->id()
      ->willReturn(5);
    $accountProphet
      ->getRoles()
      ->willReturn($roles);
    $statementProphet = $this
      ->prophesize('\\Drupal\\Core\\Database\\StatementInterface');
    $statementProphet
      ->fetchField()
      ->willReturn($agreed);

    // Mocks select query using mock object because prophecy.
    $select = $this
      ->getMockBuilder('\\Drupal\\Core\\Database\\Query\\SelectInterface')
      ->disableOriginalConstructor()
      ->getMock();
    $select
      ->expects($this
      ->any())
      ->method('fields')
      ->willReturnSelf();
    $select
      ->expects($this
      ->any())
      ->method('condition')
      ->willReturnSelf();
    $select
      ->expects($this
      ->any())
      ->method('range')
      ->willReturnSelf();
    $select
      ->expects($this
      ->any())
      ->method('execute')
      ->willReturn($statementProphet
      ->reveal());
    $connectionProphet = $this
      ->prophesize('\\Drupal\\Core\\Database\\Connection');
    $connectionProphet
      ->select('agreement')
      ->willReturn($select);

    // Mocks storage and entity type manager.
    $storageProphet = $this
      ->prophesize('\\Drupal\\Core\\Config\\Entity\\ConfigEntityStorageInterface');
    $storageProphet
      ->loadMultiple()
      ->willReturn($agreements);
    $entityTypeManagerProphet = $this
      ->prophesize('\\Drupal\\Core\\Entity\\EntityTypeManagerInterface');
    $entityTypeManagerProphet
      ->getStorage('agreement')
      ->willReturn($storageProphet
      ->reveal());

    // Creates an actual PathMatcher dependency because the logic needs to be
    // tested as part of this. This could be an indication that this needs to
    // be its own class/service.
    $pathMatcher = new PathMatcher($configFactoryProphet
      ->reveal(), $routeMatchProphet
      ->reveal());
    $timeProphet = $this
      ->prophesize('\\Drupal\\Component\\Datetime\\TimeInterface');
    $timeProphet
      ->getRequestTime()
      ->willReturn(time());
    $requestStack = new RequestStack();
    $requestStack
      ->push(Request::create('/'));
    $handler = new AgreementHandler($connectionProphet
      ->reveal(), $entityTypeManagerProphet
      ->reveal(), $pathMatcher, $timeProphet
      ->reveal(), $requestStack);
    $agreement = $handler
      ->getAgreementByUserAndPath($accountProphet
      ->reveal(), $path);
    $this
      ->assertEquals($expected, $agreement);
  }

  /**
   * Provides test arguments for the testGetAgreementByUserAndPath().
   *
   * @return array
   *   An indexed array of test arguments.
   */
  public function getAgreementProvider() {
    $defaults = [
      'id' => 'default',
      'label' => 'Default agreement',
      'path' => '/agreement',
      'settings' => [
        'visibility' => [
          'settings' => 0,
          'pages' => [],
        ],
        'roles' => [
          'authenticated',
        ],
        'frequency' => -1,
        'title' => 'Our Agreement',
        'checkbox' => 'I agree.',
        'submit' => 'Submit',
        'success' => 'Thank you for accepting our agreement.',
        'revoked' => 'You have successfully revoked your acceptance of our agreement.',
        'failure' => 'You must accept our agreement to continue.',
        'destination' => '',
        'recipient' => '',
        'reset_date' => 0,
        'format' => 'plain_text',
      ],
      'agreement' => '',
    ];
    $defaultAgreement = new Agreement($defaults, 'agreement');
    $visibilityValues = $defaults;
    $visibilityValues['id'] = 'node_one';
    $visibilityValues['label'] = 'Node one agreement';
    $visibilityValues['settings']['visibility']['settings'] = 1;
    $visibilityValues['settings']['visibility']['pages'] = [
      '/node/1',
    ];
    $visibilityAgreement = new Agreement($visibilityValues, 'agreement');
    return [
      [
        $defaultAgreement,
        [
          'default' => $defaultAgreement,
        ],
        [
          'authenticated',
        ],
        NULL,
        '<front>',
      ],
      [
        FALSE,
        [
          'default' => $defaultAgreement,
        ],
        [
          'authenticated',
        ],
        1,
        '<front>',
      ],
      [
        FALSE,
        [
          'default' => $defaultAgreement,
        ],
        [
          'authenticated',
        ],
        1,
        '/user/logout',
      ],
      [
        $defaultAgreement,
        [
          'default' => $defaultAgreement,
        ],
        [
          'authenticated',
        ],
        0,
        '<front>',
      ],
      [
        FALSE,
        [
          'default' => $defaultAgreement,
        ],
        [
          'anonymous',
        ],
        NULL,
        '<front>',
      ],
      [
        FALSE,
        [
          'node_one' => $visibilityAgreement,
        ],
        [
          'authenticated',
        ],
        NULL,
        '<front>',
      ],
      [
        $visibilityAgreement,
        [
          'node_one' => $visibilityAgreement,
        ],
        [
          'authenticated',
        ],
        NULL,
        '/node/1',
      ],
      [
        FALSE,
        [
          'node_one' => $visibilityAgreement,
        ],
        [
          'authenticated',
        ],
        1,
        '/node/1',
      ],
      [
        $defaultAgreement,
        [
          'default' => $defaultAgreement,
          'node_one' => $visibilityAgreement,
        ],
        [
          'authenticated',
        ],
        NULL,
        '<front>',
      ],
    ];
  }

}

Classes

Namesort descending Description
AgreementHandlerTest Tests logic in the agreement handler service.