853ID, EMail oder Passwort falsch';
$parser = $this->getParserInstance();
$response = $parser->parseXmlString(ApiClient::TYPE_NOTIFICATION, $content);
$this->assertEquals(853, $response->getCode());
$this->assertEquals('ID, EMail oder Passwort falsch', $response->getMessage());
$this->assertFalse($response->isSuccessful());
}
public function testParseSuccessfulProfileResponse(): void
{
$content = 'Adressdaten141747224526FrommeBjörnHerrM16.04.1972D119447Emilienstraße 5742853RemscheidDmail@fromme.orgFalse02191-4615837';
$parser = $this->getParserInstance();
$response = $parser->parseXmlString(ApiClient::TYPE_CUSTOMER_DATA, $content);
$this->assertInstanceOf(ProfileResponse::class, $response);
}
public function testParseSuccessfulCrmAttributesResponse(): void
{
$content = 'SelektionCRM141747224526';
$parser = $this->getParserInstance();
$response = $parser->parseXmlString(ApiClient::TYPE_CUSTOMER_DATA, $content);
$this->assertInstanceOf(CrmAttributesResponse::class, $response);
$this->assertCount(3, $response->getAttributeGroups());
$this->assertTrue($response->isTeamer());
}
/**
* BusPro always returns the full attribute tree and expresses the roles a person holds
* through the "auswahl" flag, so a revoked role arrives as a selection set to False,
* never as a missing group. The demotion path in BpnAuthenticator relies on that: it
* treats "no roles" as a revocation only when attribute groups are present.
*/
public function testParseCrmAttributesOfAUserHoldingEveryRole(): void
{
$parser = $this->getParserInstance();
$response = $parser->parseXmlString(ApiClient::TYPE_CUSTOMER_DATA, $this->loadFixture('crm_attributes_granted.xml'));
$this->assertInstanceOf(CrmAttributesResponse::class, $response);
$this->assertTrue($response->isTeamer());
$this->assertTrue($response->isAdmin());
$this->assertTrue($response->isManager());
$this->assertTrue($response->isHouseManager());
$this->assertSame(['DKS'], $response->getHotelCodes());
// "Preisrechner Admin" is matched by id, never by its label
$this->assertCount(3, $response->getAttributeGroups());
}
public function testParseCrmAttributesOfAUserWhoseRolesWereRevoked(): void
{
$parser = $this->getParserInstance();
$response = $parser->parseXmlString(ApiClient::TYPE_CUSTOMER_DATA, $this->loadFixture('crm_attributes_revoked.xml'));
$this->assertInstanceOf(CrmAttributesResponse::class, $response);
$this->assertFalse($response->isTeamer());
$this->assertFalse($response->isAdmin());
$this->assertFalse($response->isManager());
$this->assertFalse($response->isHouseManager());
$this->assertSame([], $response->getHotelCodes());
// the groups still arrive, so this is a revocation and not a degraded response
$this->assertCount(3, $response->getAttributeGroups());
}
public function testParseCrmAttributesOfAnEmptyResponse(): void
{
$content = 'SelektionCRM141747224526';
$parser = $this->getParserInstance();
$response = $parser->parseXmlString(ApiClient::TYPE_CUSTOMER_DATA, $content);
// indistinguishable from a revocation by the roles alone, which is why the empty
// group set is what the demotion path checks
$this->assertInstanceOf(CrmAttributesResponse::class, $response);
$this->assertFalse($response->isTeamer());
$this->assertSame([], $response->getAttributeGroups());
$this->assertSame([], $response->toArray());
}
public function testParseSuccessfulProfileUpdateResponseWithoutAddressData(): void
{
$content = 'Adressdaten_Ändern141747224526<änderung>Trueänderung>';
$parser = $this->getParserInstance();
$response = $parser->parseXmlString(ApiClient::TYPE_CUSTOMER_DATA, $content);
$this->assertInstanceOf(ProfileUpdateResponse::class, $response);
$this->assertSame(141747, $response->getAddressId());
$this->assertSame(224526, $response->getPersonId());
$this->assertTrue($response->isUpdated());
}
public function testParseSuccessfulPickupsResponse(): void
{
$content = 'KarlsruheA5 - Autohof BruchsalBUSFalseTrueTrueBonnBahnhofBUSFalseTrueTrue';
$parser = $this->getParserInstance();
$response = $parser->parseXmlString(ApiClient::TYPE_BASE_DATA_PICKUPS, $content);
$this->assertInstanceOf(BaseDataResponse::class, $response);
$pickups = $response->getItems();
$this->assertCount(2, $pickups);
$pickup = reset($pickups);
$this->assertInstanceOf(Pickup::class, $pickup);
$this->assertEquals(1, $pickup->getId());
$this->assertEquals(1, $pickup->getBusProId());
$this->assertEquals('298', $pickup->getCode());
$this->assertEquals('Karlsruhe', $pickup->getCity());
$this->assertEquals('A5 - Autohof Bruchsal', $pickup->getStreet());
}
public function testParseSuccessfulHotelsResponse(): void
{
$content = 'Berggasthof HöchstenMusterortMusterstr. 12303444/19100GaststätteTrueBrauereigasthof Zum LöwenMusterortMusterstr. 12303437/11133GaststätteTrue';
$parser = $this->getParserInstance();
$response = $parser->parseXmlString(ApiClient::TYPE_BASE_DATA_HOTELS, $content);
$this->assertInstanceOf(BaseDataResponse::class, $response);
$hotels = $response->getItems();
$this->assertCount(2, $hotels);
$hotel = reset($hotels);
$this->assertInstanceOf(Hotel::class, $hotel);
$this->assertEquals(1, $hotel->getId());
$this->assertEquals(202003, $hotel->getBusProId());
$this->assertEquals('HÖCHST', $hotel->getCode());
$this->assertEquals('Berggasthof Höchsten', $hotel->getName());
$this->assertEquals('Musterort', $hotel->getCity());
$this->assertEquals('Musterstr. 123', $hotel->getStreet());
$this->assertEquals('03444/19100', $hotel->getPhone());
$this->assertEquals('Gaststätte', $hotel->getType());
}
private function loadFixture(string $filename): string
{
return file_get_contents(__DIR__.'/../Resources/'.$filename);
}
private function getParserInstance(): ResponseParser
{
return new ResponseParser([
'bpn_crm_id_admin' => 1292,
'bpn_crm_id_manager' => 1293,
'bpn_crm_id_teamer' => 1070,
]);
}
}