def test_returns_object_when_one_match(self):
        """Test that the object is returned when there is exactly one match."""
        expected_book = BookFactory(name='Summer')
        BookFactory.create_batch(2, name='Spring')

        book = get_queryset_object(Book.objects.all(), name='Summer')
        assert book == expected_book
 def test_raises_exception_when_not_one_match(self, get_name, expected_exception):
     """Test that exceptions are raised when no matches or multiple matches are found."""
     book_names = ['Spring', 'Spring', 'Summer']
     BookFactory.create_batch(
         len(book_names),
         name=factory.Iterator(book_names),
     )
     with pytest.raises(expected_exception):
         get_queryset_object(Book.objects.all(), name=get_name)
예제 #3
0
def test_get_choices_as_case_expression(genre):
    """
    Test that get_choices_as_case_expression() generates display names for a field with
    choices the same way that model_obj.get_FIELD_display() does.
    """
    book = BookFactory(genre=genre)
    queryset = Book.objects.annotate(genre_name=get_choices_as_case_expression(
        Book, 'genre'), )
    annotated_book = queryset.first()
    assert annotated_book.genre_name == book.get_genre_display()
예제 #4
0
    def test_relation_filter_mapping(self):
        """Test that relation_exclusion_filter_mapping excludes related objects as expected."""
        book_1 = BookFactory(name='book 1')
        BookFactory(name='book 2')
        # Proofreaders for book 1 are not considered as referenced, and hence should appear in
        # the query results
        queryset = get_unreferenced_objects_query(
            Person,
            relation_exclusion_filter_mapping={
                Person._meta.get_field('proofread_books'): Q(name=book_1.name),
            },
        )

        assert list(queryset) == [book_1.proofreader]
    def test_with_custom_outer_field(self):
        """
        Test that a PersonListItem query set can be annotated with the name of the most
        recently published book for the person in the list item.

        This involves two relationships:

        - a many-to-one relationship between Book and Person
        - a many-to-one relationship between PersonListItem and Person

        A custom value is used for the outer_field argument.
        """
        person_list_item = PersonListItemFactory()
        book_data = [
            {'name': 'oldest', 'published_on': date(2010, 1, 1)},
            {'name': 'in the middle', 'published_on': date(2013, 1, 1)},
            {'name': 'newest', 'published_on': date(2015, 1, 1)},
        ]
        shuffle(book_data)

        for item_data in book_data:
            BookFactory(proofreader=person_list_item.person, authors=[], **item_data)

        queryset = PersonListItem.objects.annotate(
            name_of_latest_book=get_top_related_expression_subquery(
                Book.proofreader.field,
                'name',
                ('-published_on',),
                outer_field='person__pk',
            ),
        )
        assert queryset.first().name_of_latest_book == 'newest'
 def test_none_for_none_relation(self):
     """Tests that None is returned for an unset foreign key."""
     BookFactory(proofreader=None)
     queryset = Book.objects.annotate(
         proofreader_name=get_full_name_expression('proofreader'),
     )
     assert queryset.first().proofreader_name is None
예제 #7
0
    def test_get_context_with_valid_value(self):
        """Tests get_context() when a valid value is supplied."""
        book = BookFactory()
        widget = RawIdWidget(Book)

        change_route_name = admin_urlname(Book._meta, 'change')
        change_url = reverse(change_route_name, args=(book.pk, ))

        changelist_route_name = admin_urlname(Book._meta, 'changelist')
        changelist_url = reverse(changelist_route_name)

        assert widget.get_context('test-widget', str(book.pk), {}) == {
            'link_label': str(book),
            'link_title': 'Look up book',
            'link_url': change_url,
            'related_url': f'{changelist_url}?_to_field=id',
            'widget': {
                'attrs': {
                    'class': 'vUUIDField',
                },
                'is_hidden': False,
                'name': 'test-widget',
                'required': False,
                'template_name': 'admin/widgets/foreign_key_raw_id.html',
                'type': 'text',
                'value': str(book.pk),
            },
        }
 def test_aggregates_as_array(self, names, distinct):
     """
     Test that the first names of all authors for each book can be aggregated into an array
     for various cases, and with distinct on and off.
     """
     authors = PersonFactory.create_batch(
         len(names),
         first_name=factory.Iterator(
             sample(names, len(names)),
         ),
     )
     BookFactory(authors=authors)
     queryset = Book.objects.annotate(
         author_names=get_array_agg_subquery(
             Book.authors.through,
             'book',
             'person__first_name',
             distinct=distinct,
         ),
     )
     actual_author_names = queryset.first().author_names
     if distinct:
         assert Counter(actual_author_names) == Counter(set(names))
     else:
         assert Counter(actual_author_names) == Counter(names)
    def test_with_default_outer_field(self, expression):
        """
        Test that a Person query set can annotated with the name of the most
        recently published book.

        This considers a single many-to-one relationship between Book and Person.
        """
        person = PersonFactory()
        book_data = [
            {'name': 'oldest', 'published_on': date(2010, 1, 1)},
            {'name': 'in the middle', 'published_on': date(2013, 1, 1)},
            {'name': 'newest', 'published_on': date(2015, 1, 1)},
        ]
        shuffle(book_data)

        for item_data in book_data:
            BookFactory(
                proofreader=person,
                authors=[],
                **item_data,
            )

        queryset = Person.objects.annotate(
            name_of_latest_book=get_top_related_expression_subquery(
                Book.proofreader.field, expression, ('-published_on',),
            ),
        )
        assert queryset.first().name_of_latest_book == 'newest'
def test_get_front_end_url_expression(monkeypatch):
    """Test that get_front_end_url_expression() generates URLs correctly."""
    monkeypatch.setitem(settings.DATAHUB_FRONTEND_URL_PREFIXES, 'book', 'http://test')

    book = BookFactory()
    queryset = Book.objects.annotate(
        url=get_front_end_url_expression('book', 'pk'),
    )
    assert queryset.first().url == f'http://test/{book.pk}'
 def test_admin_change_link_target_blank(self):
     """
     Test that admin_change_url() returns an anchor tag with target="_blank" to the change
     page for an object.
     """
     book = BookFactory.build(pk=uuid4())
     assert admin_change_link(book, True) == (
         f'<a href="/admin/support/book/{book.pk}/change/" target="_blank">{book}</a>'
     )
예제 #12
0
 def test_full_name_related_annotation(self):
     """
     Tests that a Book query set can be annotated with the full name of the proofreader
     of each book.
     """
     book = BookFactory()
     proofreader = book.proofreader
     queryset = Book.objects.annotate(
         proofreader_name=get_full_name_expression('proofreader'), )
     expected_name = f'{proofreader.first_name} {proofreader.last_name}'
     assert queryset.first().proofreader_name == expected_name
def test_get_string_agg_subquery(num_authors):
    """
    Test that get_string_agg_subquery() can be used to concatenate the first names of
    all authors for each book into one field.
    """
    authors = PersonFactory.create_batch(num_authors)
    BookFactory(authors=authors)
    queryset = Book.objects.annotate(author_names=get_string_agg_subquery(
        Book, 'authors__first_name'), )
    author_names_str = queryset.first().author_names
    actual_author_names = sorted(
        author_names_str.split(', ')) if author_names_str else []
    expected_author_names = sorted(author.first_name for author in authors)
    assert actual_author_names == expected_author_names
 def test_with_max_aggregate_expression(self, num_books):
     """
     Test that Max() can be used to calculate the maximum published-on date for the books a
     person has proofread.
     """
     proofreader = PersonFactory()
     books = BookFactory.create_batch(num_books, proofreader=proofreader)
     queryset = Person.objects.annotate(
         max_published=get_aggregate_subquery(Person, Max('proofread_books__published_on')),
     ).filter(
         pk=proofreader.pk,
     )
     actual_max_published = queryset.first().max_published
     expected_max_published = max(book.published_on for book in books) if num_books else None
     assert actual_max_published == expected_max_published
예제 #15
0
 def test_orders_results_when_ordering_specified(self, ordering,
                                                 expected_names):
     """Test that the values are ordered corrected when an ordering is specified."""
     names = ['Barbara', 'Claire', 'Samantha']
     authors = PersonFactory.create_batch(
         len(names),
         first_name=factory.Iterator(sample(names, len(names)), ),
     )
     BookFactory(authors=authors)
     queryset = Book.objects.annotate(author_names=get_array_agg_subquery(
         Book.authors.through,
         'book',
         'person__first_name',
         ordering=ordering,
     ), )
     actual_author_names = queryset.first().author_names
     assert actual_author_names == expected_names
예제 #16
0
 def test_full_name_related_annotation(self, include_country, country):
     """
     Tests that a Book query set can be annotated with the full name of the proofreader
     of each book.
     """
     book = BookFactory(proofreader__country=country)
     proofreader = book.proofreader
     bracketed_field_name = 'country' if include_country else None
     queryset = Book.objects.annotate(
         proofreader_name=get_full_name_expression(
             person_field_name='proofreader',
             bracketed_field_name=bracketed_field_name,
         ), )
     expected_name = f'{proofreader.first_name} {proofreader.last_name}'
     if country and include_country:
         expected_name += f' ({proofreader.country})'
     assert queryset.first().proofreader_name == expected_name
 def test_can_annotate_queryset(self, names, distinct, expected_result):
     """
     Test that the first names of all authors for each book can be concatenated into
     one field as a query set annotation for various cases.
     """
     authors = PersonFactory.create_batch(
         len(names),
         first_name=factory.Iterator(
             sample(names, len(names)),
         ),
     )
     BookFactory(authors=authors)
     queryset = Book.objects.annotate(
         author_names=get_string_agg_subquery(Book, 'authors__first_name', distinct=distinct),
     )
     actual_author_names = queryset.first().author_names
     assert actual_author_names == expected_result
예제 #18
0
 def test_aggregates_as_filtered_array(self, names, desired_names):
     """
     Test that the desired first names of authors for each book can be aggregated into an array
     for various cases.
     """
     authors = PersonFactory.create_batch(
         len(names),
         first_name=factory.Iterator(sample(names, len(names)), ),
     )
     BookFactory(authors=authors)
     queryset = Book.objects.annotate(author_names=get_array_agg_subquery(
         Book.authors.through,
         'book',
         'person__first_name',
         filter=Q(person__first_name__in=desired_names),
     ), )
     actual_author_names = queryset.first()
     assert set(actual_author_names.author_names) == set(desired_names)
def test_get_top_related_expression_subquery(expression):
    """
    Test that get_top_related_expression_subquery() can be used to get the name of the most
    recently published book.
    """
    person = PersonFactory()
    book_data = [
        {
            'name': 'oldest',
            'published_on': date(2010, 1, 1)
        },
        {
            'name': 'in the middle',
            'published_on': date(2013, 1, 1)
        },
        {
            'name': 'newest',
            'published_on': date(2015, 1, 1)
        },
    ]
    shuffle(book_data)

    for item_data in book_data:
        BookFactory(
            proofreader=person,
            authors=[],
            **item_data,
        )

    queryset = Person.objects.annotate(
        name_of_latest_book=get_top_related_expression_subquery(
            Book.proofreader.field,
            expression,
            ('-published_on', ),
        ), )
    assert queryset.first().name_of_latest_book == 'newest'
예제 #20
0
 def test_generates_urls_for_saved_objects(self):
     """Test that a valid change URL is generated."""
     book = BookFactory()
     assert get_change_url(book) == (
         f'/admin/support/book/{book.pk}/change/')
def test_admin_change_url():
    """Test that admin_change_url() returns the URL to the change page for an object."""
    book = BookFactory.build(pk=uuid4())
    assert admin_change_url(book) == f'/admin/support/book/{book.pk}/change/'
예제 #22
0
 def test_only_excludes_referenced_objects(self):
     """Test that only referenced objects are excluded."""
     unreferenced_person = PersonFactory()
     BookFactory()
     queryset = get_unreferenced_objects_query(Person)
     assert list(queryset) == [unreferenced_person]
    def test_loading(self, migration_apps):
        """
        Test that loading a yaml file updates the existing data.
        """
        yaml_content = """
# person with pk=1, last_name should change
- model: datahub.core.test.support.person
  pk: 1
  fields:
    first_name: Existing
    last_name: Person with changed surname

# person with pk=3, first_name should change, last_name shouldn't change
- model: datahub.core.test.support.person
  pk: 3
  fields:
    first_name: Another existing

# person with pk=10, a new record should be created
- model: datahub.core.test.support.person
  pk: 10
  fields:
    first_name: New
    last_name: Person

# book with pk=1, fk to person (proofreader) should change
- model: datahub.core.test.support.book
  pk: 1
  fields:
    name: Book name
    proofreader: 3
    published_on: '2010-01-01'
"""
        mocked_read = mock.mock_open(read_data=yaml_content)

        people = PersonFactory.create_batch(
            3,
            pk=factory.Iterator([1, 2, 3]),
            first_name='Existing',
            last_name='Person',
        )
        BookFactory(
            pk=1,
            name='Previous book name',
            proofreader=people[0],
            published_on=datetime.date(2010, 1, 1),
            authors=[],
        )

        with mock.patch('datahub.core.migration_utils.open', mocked_read, create=True):
            load_yaml_data_in_migration(migration_apps, 'path-to-file.yaml')

        qs = Person.objects.order_by('id').values('id', 'first_name', 'last_name')
        assert list(qs) == [
            {'id': 1, 'first_name': 'Existing', 'last_name': 'Person with changed surname'},
            {'id': 2, 'first_name': 'Existing', 'last_name': 'Person'},
            {'id': 3, 'first_name': 'Another existing', 'last_name': 'Person'},
            {'id': 10, 'first_name': 'New', 'last_name': 'Person'},
        ]

        qs = Book.objects.order_by('id').values('id', 'name', 'proofreader', 'published_on')
        assert list(qs) == [
            {
                'id': 1,
                'name': 'Book name',
                'proofreader': 3,
                'published_on': datetime.date(2010, 1, 1),
            },
        ]
예제 #24
0
 def test_generates_links_for_saved_objects(self):
     """Test that a valid change link is generated."""
     book = BookFactory()
     assert get_change_link(book) == (
         f'<a href="/admin/support/book/{book.pk}/change/">{book.name}</a>')
예제 #25
0
 def test_returns_empty_string_if_no_pk(self):
     """Test that if the object has no pk, an empty link is returned."""
     book = BookFactory.build()
     assert get_change_link(book) == ''
 def test_object_name_returned_for_existing_object(self):
     """Test the object name is returned for an existing object."""
     book = BookFactory()
     assert _get_object_name_for_pk(Book, book.pk) == str(book)