async def test_with_one_alternative_name(self): person = Person('P0') PersonName(person, 'Jane', 'Dough') name = PersonName(person, 'Janet', 'Doughnut') name.citations.append(Citation(None, Source(None, 'The Source'))) expected = '<div class="meta person-meta"><span class="aka">Also known as <span class="person-label" typeof="foaf:Person"><span property="foaf:individualName">Janet</span> <span property="foaf:familyName">Doughnut</span></span><a href="#reference-1" class="citation">[1]</a></span></div>' async with self._render(data={ 'person': person, }) as (actual, _): self.assertEqual(expected, actual)
async def test_with_multiple_alternative_names(self): person = Person('P0') PersonName(person, 'Jane', 'Dough') PersonName(person, 'Janet', 'Doughnut') PersonName(person, 'Janetar', 'Of Doughnuton') expected = '<div class="meta person-meta"><span class="aka">Also known as <span class="person-label" typeof="foaf:Person"><span property="foaf:individualName">Janet</span> <span property="foaf:familyName">Doughnut</span></span>, <span class="person-label" typeof="foaf:Person"><span property="foaf:individualName">Janetar</span> <span property="foaf:familyName">Of Doughnuton</span></span></span></div>' async with self._render(data={ 'person': person, }) as (actual, _): self.assertEqual(expected, actual)
async def test_embedded(self): person = Person('P0') Presence(person, Subject(), Event(None, Birth(), Date(1970))) PersonName(person, 'Jane', 'Dough') name = PersonName(person, 'Janet', 'Doughnut') name.citations.append(Citation(None, Source(None, 'The Source'))) expected = '<div class="meta person-meta"><span class="aka">Also known as <span class="person-label" typeof="foaf:Person"><span property="foaf:individualName">Janet</span> <span property="foaf:familyName">Doughnut</span></span></span><dl><div><dt>Birth</dt><dd>1970</dd></div></dl></div>' async with self._render(data={ 'person': person, 'embedded': True, }) as (actual, _): self.assertEqual(expected, actual)
def _load_person(loader: _Loader, element: ElementTree.Element): person_handle = element.get('handle') person = Person(element.get('id')) name_elements = sorted(_xpath(element, './ns:name'), key=lambda x: x.get('alt') == '1') names = [] for name_element in name_elements: is_alternative = name_element.get('alt') == '1' individual_name_element = _xpath1(name_element, './ns:first') individual_name = None if individual_name_element is None else individual_name_element.text surname_elements = [ surname_element for surname_element in _xpath(name_element, './ns:surname') if surname_element.text is not None ] if surname_elements: for surname_element in surname_elements: if not is_alternative: is_alternative = surname_element.get('prim') == '0' affiliation_name = surname_element.text surname_prefix = surname_element.get('prefix') if surname_prefix is not None: affiliation_name = '%s %s' % (surname_prefix, affiliation_name) person_name = PersonName(None, individual_name, affiliation_name) _load_citationref(loader, person_name, name_element) names.append((person_name, is_alternative)) elif individual_name is not None: person_name = PersonName(None, individual_name) _load_citationref(loader, person_name, name_element) names.append((person_name, is_alternative)) for person_name, _ in sorted(names, key=lambda x: x[1]): loader.add_entity(person_name) loader.add_association(Person, person_handle, 'names', PersonName, person_name.id) _load_eventrefs(loader, person_handle, element) if element.get('priv') == '1': person.private = True flattened_person = FlattenedEntity(person, person_handle) _load_citationref(loader, flattened_person, element) _load_objref(loader, flattened_person, element) _load_urls(person, element) _load_attribute_privacy(person, element, 'attribute') loader.add_entity(flattened_person)
async def test_with_affiliation_name(self): person = Person(None) name = PersonName(person, None, 'Dough') expected = '<span class="person-label" typeof="foaf:Person">… <span property="foaf:familyName">Dough</span></span>' async with self._render(data={ 'name': name, }) as (actual, _): self.assertEqual(expected, actual)
async def test_with_full_name(self): person = Person(None) name = PersonName(person, 'Jane', 'Dough') expected = '<span class="person-label" typeof="foaf:Person"><span property="foaf:individualName">Jane</span> <span property="foaf:familyName">Dough</span></span>' async with self._render(data={ 'name': name, }) as (actual, _): self.assertEqual(expected, actual)
def test_person(self) -> None: person = Person('1') sut = PersonName(person, 'Janet', 'Not a Girl') self.assertEquals(person, sut.person) self.assertCountEqual([sut], person.names) sut.person = None self.assertIsNone(sut.person) self.assertCountEqual([], person.names)
async def test_with_name(self): person = Person('P0') PersonName(person, 'Jane', 'Dough') expected = '<a href="/person/P0/index.html"><span class="person-label" typeof="foaf:Person"><span property="foaf:individualName">Jane</span> <span property="foaf:familyName">Dough</span></span></a>' async with self._render(data={ 'person': person, }) as (actual, _): self.assertEqual(expected, actual)
def test_names(self) -> None: sut = Person('1') name = PersonName(sut, 'Janet', 'Not a Girl') self.assertCountEqual([name], sut.names) self.assertEquals(sut, name.person) sut.names.remove(name) self.assertCountEqual([], sut.names) self.assertIsNone(name.person)
def test_should_remove_names(self) -> None: person = Person('P0') name = PersonName(person, 'Jane', 'Dough') source = Source('The Source') citation = Citation(None, source) name.citations.append(citation) anonymize_person(person) self.assertEquals(0, len(person.names)) self.assertEquals(0, len(citation.facts))
def test_should_remove_facts(self) -> None: source = Source('The Source') citation = Citation('C0', source) fact = PersonName(Person(None), 'Jane') citation.facts.append(fact) anonymous_source = AnonymousSource() anonymous_citation = AnonymousCitation(anonymous_source) anonymize_citation(citation, anonymous_citation) self.assertEquals(0, len(citation.facts)) self.assertIn(fact, anonymous_citation.facts)
async def test_with_citation(self): person = Person(None) name = PersonName(person, 'Jane') source = Source(None) citation = Citation(None, source) name.citations.append(citation) expected = '<span class="person-label" typeof="foaf:Person"><span property="foaf:individualName">Jane</span></span><a href="#reference-1" class="citation">[1]</a>' async with self._render(data={ 'name': name, }) as (actual, _): self.assertEqual(expected, actual)
async def test_post_parse(self) -> None: person = Person('P0') person.private = True PersonName(person, 'Jane', 'Dough') with TemporaryDirectory() as output_directory_path: configuration = Configuration(output_directory_path, 'https://example.com') configuration.extensions.add(ExtensionConfiguration(Anonymizer)) async with App(configuration) as app: app.ancestry.entities.append(person) await load(app) self.assertEquals(0, len(person.names))
async def test_embedded(self): person = Person(None) name = PersonName(person, 'Jane', 'Dough') source = Source(None) citation = Citation(None, source) name.citations.append(citation) expected = '<span class="person-label" typeof="foaf:Person"><span property="foaf:individualName">Jane</span> <span property="foaf:familyName">Dough</span></span>' async with self._render(data={ 'name': name, 'embedded': True, }) as (actual, _): self.assertEqual(expected, actual)
async def test_without_enclosing_places(self): person = Person('P0') partner_one = Person('P1') child_one = Person('P1C1') child_one.parents.append(person) child_one.parents.append(partner_one) PersonName(child_one, None, 'FamilyOneAssociationName') partner_two = Person('P2') child_two = Person('P2C2') child_two.parents.append(person) child_two.parents.append(partner_two) PersonName(child_two, None, 'FamilyTwoAssociationName') async with self._render( data={ 'page_resource': person, 'entity_type_name': 'person', 'person': person, }) as (actual, _): self.assertIn('Descendant names include FamilyOneAssociationName.', actual) self.assertIn('Descendant names include FamilyTwoAssociationName.', actual)
def test_clean_should_not_clean_source_with_citations(self) -> None: ancestry = Ancestry() source = Source('S0', 'The Source') ancestry.entities.append(source) citation = Citation('C0', source) citation.facts.append(PersonName(Person(None), 'Jane')) ancestry.entities.append(citation) clean(ancestry) self.assertEqual(source, ancestry.entities[Source][source.id]) self.assertEqual(source, citation.source) self.assertEqual(citation, ancestry.entities[Citation][citation.id])
def test_associated_files(self) -> None: file1 = Mock(File) file2 = Mock(File) file3 = Mock(File) file4 = Mock(File) file5 = Mock(File) file6 = Mock(File) sut = Person('1') sut.files = [file1, file2, file1] citation = Mock(Citation) citation.associated_files = [file3, file4, file2] name = PersonName(sut) name.citations = [citation] event = Mock(Event) event.associated_files = [file5, file6, file4] Presence(sut, Subject(), event) self.assertEquals([file1, file2, file3, file4, file5, file6], list(sut.associated_files))
def test_clean_should_not_clean_citation_with_facts(self) -> None: ancestry = Ancestry() source = Source('S0', 'The Source') ancestry.entities.append(source) citation = Citation('C0', source) citation.facts.append(PersonName(Person(None), 'Jane')) ancestry.entities.append(citation) fact = Person('P0') fact.citations.append(citation) ancestry.entities.append(fact) clean(ancestry) self.assertEqual(citation, ancestry.entities[Citation][citation.id]) self.assertIn(citation, fact.citations) self.assertEqual(fact, ancestry.entities[Person][fact.id])
async def test_private_person(self): person_id = 'P1' individual_name = 'Jane' person = Person(person_id) PersonName(person, individual_name) person.private = True with TemporaryDirectory() as output_directory_path: configuration = Configuration(output_directory_path, 'https://example.com') configuration.locales.replace([ LocaleConfiguration('en-US', 'en'), LocaleConfiguration('nl-NL', 'nl'), ]) async with App(configuration) as app: app.ancestry.entities.append(person) indexed = [item for item in Index(app).build()] self.assertEquals([], indexed)
async def test_person_with_affiliation_name(self, expected: str, locale: str): person_id = 'P1' affiliation_name = 'Doughnut' person = Person(person_id) PersonName(person, None, affiliation_name) with TemporaryDirectory() as output_directory_path: configuration = Configuration(output_directory_path, 'https://example.com') configuration.locales.replace([ LocaleConfiguration('en-US', 'en'), LocaleConfiguration('nl-NL', 'nl'), ]) async with App(configuration).with_locale(locale) as app: app.ancestry.entities.append(person) indexed = [item for item in Index(app).build()] self.assertEquals('doughnut', indexed[0]['text']) self.assertIn(expected, indexed[0]['result'])
async def load(self) -> None: amsterdam = Place('betty-demo-amsterdam', [PlaceName('Amsterdam')]) amsterdam.coordinates = Point(52.366667, 4.9) amsterdam.links.add(Link('https://nl.wikipedia.org/wiki/Amsterdam')) self._app.ancestry.entities.append(amsterdam) ilpendam = Place('betty-demo-ilpendam', [PlaceName('Ilpendam')]) ilpendam.coordinates = Point(52.465556, 4.951111) ilpendam.links.add(Link('https://nl.wikipedia.org/wiki/Ilpendam')) self._app.ancestry.entities.append(ilpendam) personal_accounts = Source('betty-demo-personal-accounts', 'Personal accounts') self._app.ancestry.entities.append(personal_accounts) cite_first_person_account = Citation('betty-demo-first-person-account', personal_accounts) self._app.ancestry.entities.append(cite_first_person_account) bevolkingsregister_amsterdam = Source( 'betty-demo-bevolkingsregister-amsterdam', 'Bevolkingsregister Amsterdam') bevolkingsregister_amsterdam.author = 'Gemeente Amsterdam' bevolkingsregister_amsterdam.publisher = 'Gemeente Amsterdam' self._app.ancestry.entities.append(bevolkingsregister_amsterdam) david_marinus_lankester = Person('betty-demo-david-marinus-lankester') PersonName(david_marinus_lankester, 'David Marinus', 'Lankester') self._app.ancestry.entities.append(david_marinus_lankester) geertruida_van_ling = Person('betty-demo-geertruida-van-ling') PersonName(geertruida_van_ling, 'Geertruida', 'Van Ling') self._app.ancestry.entities.append(geertruida_van_ling) marriage_of_dirk_jacobus_lankester_and_jannigje_palsen = Event( 'betty-demo-marriage-of-dirk-jacobus-lankester-and-jannigje-palsen', Marriage(), Date(1922, 7, 4)) marriage_of_dirk_jacobus_lankester_and_jannigje_palsen.place = ilpendam self._app.ancestry.entities.append( marriage_of_dirk_jacobus_lankester_and_jannigje_palsen) birth_of_dirk_jacobus_lankester = Event( 'betty-demo-birth-of-dirk-jacobus-lankester', Birth(), Date(1897, 8, 25)) birth_of_dirk_jacobus_lankester.place = amsterdam self._app.ancestry.entities.append(birth_of_dirk_jacobus_lankester) death_of_dirk_jacobus_lankester = Event( 'betty-demo-death-of-dirk-jacobus-lankester', Death(), Date(1986, 8, 18)) death_of_dirk_jacobus_lankester.place = amsterdam self._app.ancestry.entities.append(death_of_dirk_jacobus_lankester) dirk_jacobus_lankester = Person('betty-demo-dirk-jacobus-lankester') PersonName(dirk_jacobus_lankester, 'Dirk Jacobus', 'Lankester') Presence(dirk_jacobus_lankester, Subject(), birth_of_dirk_jacobus_lankester) Presence(dirk_jacobus_lankester, Subject(), death_of_dirk_jacobus_lankester) Presence(dirk_jacobus_lankester, Subject(), marriage_of_dirk_jacobus_lankester_and_jannigje_palsen) dirk_jacobus_lankester.parents.append(david_marinus_lankester, geertruida_van_ling) self._app.ancestry.entities.append(dirk_jacobus_lankester) birth_of_marinus_david_lankester = Event( 'betty-demo-birth-of-marinus-david', Birth(), DateRange(Date(1874, 1, 15), Date(1874, 3, 21), start_is_boundary=True, end_is_boundary=True)) birth_of_marinus_david_lankester.place = amsterdam self._app.ancestry.entities.append(birth_of_marinus_david_lankester) death_of_marinus_david_lankester = Event( 'betty-demo-death-of-marinus-david', Death(), Date(1971)) death_of_marinus_david_lankester.place = amsterdam self._app.ancestry.entities.append(death_of_marinus_david_lankester) marinus_david_lankester = Person('betty-demo-marinus-david-lankester') PersonName(marinus_david_lankester, 'Marinus David', 'Lankester') Presence(marinus_david_lankester, Subject(), birth_of_marinus_david_lankester) Presence(marinus_david_lankester, Subject(), death_of_marinus_david_lankester) marinus_david_lankester.parents.append(david_marinus_lankester, geertruida_van_ling) self._app.ancestry.entities.append(marinus_david_lankester) birth_of_jacoba_gesina_lankester = Event( 'betty-demo-birth-of-jacoba-gesina', Birth(), Date(1900, 3, 14)) birth_of_jacoba_gesina_lankester.place = amsterdam self._app.ancestry.entities.append(birth_of_jacoba_gesina_lankester) jacoba_gesina_lankester = Person('betty-demo-jacoba-gesina-lankester') PersonName(jacoba_gesina_lankester, 'Jacoba Gesina', 'Lankester') Presence(jacoba_gesina_lankester, Subject(), birth_of_jacoba_gesina_lankester) jacoba_gesina_lankester.parents.append(david_marinus_lankester, geertruida_van_ling) self._app.ancestry.entities.append(jacoba_gesina_lankester) jannigje_palsen = Person('betty-demo-jannigje-palsen') PersonName(jannigje_palsen, 'Jannigje', 'Palsen') Presence(jannigje_palsen, Subject(), marriage_of_dirk_jacobus_lankester_and_jannigje_palsen) self._app.ancestry.entities.append(jannigje_palsen) marriage_of_johan_de_boer_and_liberta_lankester = Event( 'betty-demo-marriage-of-johan-de-boer-and-liberta-lankester', Marriage(), Date(1953, 6, 19)) marriage_of_johan_de_boer_and_liberta_lankester.place = amsterdam self._app.ancestry.entities.append( marriage_of_johan_de_boer_and_liberta_lankester) cite_birth_of_liberta_lankester_from_bevolkingsregister_amsterdam = Citation( 'betty-demo-birth-of-liberta-lankester-from-bevolkingsregister-amsterdam', bevolkingsregister_amsterdam) cite_birth_of_liberta_lankester_from_bevolkingsregister_amsterdam.location = 'Amsterdam' self._app.ancestry.entities.append( cite_birth_of_liberta_lankester_from_bevolkingsregister_amsterdam) birth_of_liberta_lankester = Event( 'betty-demo-birth-of-liberta-lankester', Birth(), Date(1929, 12, 22)) birth_of_liberta_lankester.place = amsterdam birth_of_liberta_lankester.citations.append( cite_birth_of_liberta_lankester_from_bevolkingsregister_amsterdam) self._app.ancestry.entities.append(birth_of_liberta_lankester) death_of_liberta_lankester = Event( 'betty-demo-death-of-liberta-lankester', Death(), Date(2015, 1, 17)) death_of_liberta_lankester.place = amsterdam death_of_liberta_lankester.citations.append(cite_first_person_account) self._app.ancestry.entities.append(death_of_liberta_lankester) liberta_lankester = Person('betty-demo-liberta-lankester') PersonName(liberta_lankester, 'Liberta', 'Lankester') PersonName(liberta_lankester, 'Betty') Presence(liberta_lankester, Subject(), birth_of_liberta_lankester) Presence(liberta_lankester, Subject(), death_of_liberta_lankester) Presence(liberta_lankester, Subject(), marriage_of_johan_de_boer_and_liberta_lankester) liberta_lankester.parents.append(dirk_jacobus_lankester, jannigje_palsen) self._app.ancestry.entities.append(liberta_lankester) birth_of_johan_de_boer = Event('betty-demo-birth-of-johan-de-boer', Birth(), Date(1930, 6, 20)) birth_of_johan_de_boer.place = amsterdam self._app.ancestry.entities.append(birth_of_johan_de_boer) death_of_johan_de_boer = Event('betty-demo-death-of-johan-de-boer', Death(), Date(1999, 3, 10)) death_of_johan_de_boer.place = amsterdam death_of_johan_de_boer.citations.append(cite_first_person_account) self._app.ancestry.entities.append(death_of_johan_de_boer) johan_de_boer = Person('betty-demo-johan-de-boer') PersonName(johan_de_boer, 'Johan', 'De Boer') PersonName(johan_de_boer, 'Hans') Presence(johan_de_boer, Subject(), birth_of_johan_de_boer) Presence(johan_de_boer, Subject(), death_of_johan_de_boer) Presence(johan_de_boer, Subject(), marriage_of_johan_de_boer_and_liberta_lankester) self._app.ancestry.entities.append(johan_de_boer) parent_of_bart_feenstra_child_of_liberta_lankester = Person( 'betty-demo-parent-of-bart-feenstra-child-of-liberta-lankester') PersonName(parent_of_bart_feenstra_child_of_liberta_lankester, 'Bart\'s parent') parent_of_bart_feenstra_child_of_liberta_lankester.parents.append( johan_de_boer, liberta_lankester) self._app.ancestry.entities.append( parent_of_bart_feenstra_child_of_liberta_lankester) bart_feenstra = Person('betty-demo-bart-feenstra') PersonName(bart_feenstra, 'Bart', 'Feenstra') bart_feenstra.parents.append( parent_of_bart_feenstra_child_of_liberta_lankester) self._app.ancestry.entities.append(bart_feenstra)
def test_affiliation(self) -> None: person = Person('1') affiliation = 'Not a Girl' sut = PersonName(person, 'Janet', affiliation) self.assertEquals(affiliation, sut.affiliation)
def test_individual(self) -> None: person = Person('1') individual = 'Janet' sut = PersonName(person, individual, 'Not a Girl') self.assertEquals(individual, sut.individual)
def test_citations(self) -> None: person = Person('1') sut = PersonName(person, 'Janet', 'Not a Girl') self.assertCountEqual([], sut.citations)
def test_locale(self) -> None: person = Person('1') sut = PersonName(person, 'Janet', 'Not a Girl') self.assertIsNone(sut.locale)
class PersonNameTest(TestCase): def test_person(self) -> None: person = Person('1') sut = PersonName(person, 'Janet', 'Not a Girl') self.assertEquals(person, sut.person) self.assertCountEqual([sut], person.names) sut.person = None self.assertIsNone(sut.person) self.assertCountEqual([], person.names) def test_locale(self) -> None: person = Person('1') sut = PersonName(person, 'Janet', 'Not a Girl') self.assertIsNone(sut.locale) def test_citations(self) -> None: person = Person('1') sut = PersonName(person, 'Janet', 'Not a Girl') self.assertCountEqual([], sut.citations) def test_individual(self) -> None: person = Person('1') individual = 'Janet' sut = PersonName(person, individual, 'Not a Girl') self.assertEquals(individual, sut.individual) def test_affiliation(self) -> None: person = Person('1') affiliation = 'Not a Girl' sut = PersonName(person, 'Janet', affiliation) self.assertEquals(affiliation, sut.affiliation) @parameterized.expand([ (True, PersonName(Person('1'), 'Janet', 'Not a Girl'), PersonName(Person('1'), 'Janet', 'Not a Girl')), (True, PersonName(Person('1'), 'Janet'), PersonName(Person('1'), 'Janet')), (True, PersonName(Person('1'), None, 'Not a Girl'), PersonName(Person('1'), None, 'Not a Girl')), (False, PersonName(Person('1'), 'Janet'), PersonName(Person('1'), None, 'Not a Girl')), (False, PersonName(Person('1'), 'Janet', 'Not a Girl'), None), (False, PersonName(Person('1'), 'Janet', 'Not a Girl'), True), (False, PersonName(Person('1'), 'Janet', 'Not a Girl'), 9), (False, PersonName(Person('1'), 'Janet', 'Not a Girl'), object()), ]) def test_eq(self, expected: bool, left: PersonName, right: Any) -> None: self.assertEquals(expected, left == right) @parameterized.expand([ (False, PersonName(Person('1'), 'Janet', 'Not a Girl'), PersonName(Person('1'), 'Janet', 'Not a Girl')), (True, PersonName(Person('1'), 'Janet', 'Not a Girl'), PersonName(Person('1'), 'Not a Girl', 'Janet')), (True, PersonName(Person('1'), 'Janet', 'Not a Girl'), None), ]) def test_gt(self, expected: bool, left: PersonName, right: Any) -> None: self.assertEquals(expected, left > right)
def test_alternative_names(self) -> None: sut = Person('P1') PersonName(sut, 'Janet', 'Not a Girl') alternative_name = PersonName(sut, 'Janet', 'Still not a Girl') self.assertSequenceEqual([alternative_name], sut.alternative_names)
def test_name_with_names(self) -> None: sut = Person('P1') name = PersonName(sut) self.assertEquals(name, sut.name)
def test_person_should_include_name(self): person = self.ancestry.entities[Person]['I0000'] expected = PersonName(person, 'Jane', 'Doe') self.assertEquals(expected, person.name)
async def test_person_should_encode_full(self): parent_id = 'the_parent' parent = Person(parent_id) child_id = 'the_child' child = Person(child_id) sibling_id = 'the_sibling' sibling = Person(sibling_id) sibling.parents.append(parent) person_id = 'the_person' person_affiliation_name = 'Person' person_individual_name = 'The' person = Person(person_id) PersonName(person, person_individual_name, person_affiliation_name) person.parents.append(parent) person.children.append(child) person.private = False link = Link('https://example.com/the-person') link.label = 'The Person Online' person.links.add(link) person.citations.append(Citation('the_citation', Source('The Source'))) Presence(person, Subject(), Event('the_event', Birth())) expected = { '$schema': '/schema.json#/definitions/person', '@context': { 'parents': 'https://schema.org/parent', 'children': 'https://schema.org/child', 'siblings': 'https://schema.org/sibling', }, '@type': 'https://schema.org/Person', 'id': person_id, 'names': [ { '@context': { 'individual': 'https://schema.org/givenName', 'affiliation': 'https://schema.org/familyName', }, 'individual': person_individual_name, 'affiliation': person_affiliation_name, }, ], 'parents': [ '/en/person/the_parent/index.json', ], 'children': [ '/en/person/the_child/index.json', ], 'siblings': [ '/en/person/the_sibling/index.json', ], 'private': False, 'presences': [ { '@context': { 'event': 'https://schema.org/performerIn', }, 'role': 'subject', 'event': '/en/event/the_event/index.json', }, ], 'citations': [ '/en/citation/the_citation/index.json', ], 'links': [ { 'url': '/en/person/the_person/index.json', 'relationship': 'canonical', 'mediaType': 'application/json', }, { 'url': '/nl/person/the_person/index.json', 'relationship': 'alternate', 'locale': 'nl-NL', }, { 'url': '/en/person/the_person/index.html', 'relationship': 'alternate', 'mediaType': 'text/html', }, { 'url': 'https://example.com/the-person', 'label': 'The Person Online', }, ], } await self.assert_encodes(expected, person, 'person')