Skip to content
This repository was archived by the owner on Nov 17, 2023. It is now read-only.

Commit 81612df

Browse files
author
Alan Rubin
authored
Merge pull request #90 from FowlerLab/develop
1.3.0-alpha
2 parents 56f1d9d + d534ae5 commit 81612df

File tree

20 files changed

+660
-264
lines changed

20 files changed

+660
-264
lines changed

api/tests/test_views.py

Lines changed: 163 additions & 180 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
import io
21
import json
3-
import csv
42
from datetime import timedelta
53

64
from django.test import TestCase, RequestFactory, mock
75
from django.contrib.auth import get_user_model
6+
from django.core import exceptions
7+
from django.http import HttpResponse
88

99
from rest_framework import exceptions
1010

@@ -17,7 +17,7 @@
1717
ScoreSetFactory, ExperimentFactory, ExperimentSetFactory
1818
)
1919

20-
from variant.factories import dna_hgvs, protein_hgvs
20+
from variant.factories import VariantFactory
2121
from variant.models import Variant
2222

2323
from .. import views
@@ -268,6 +268,148 @@ def test_list_includes_private_when_authenticated(self):
268268
self.assertContains(response, instance2.urn)
269269

270270

271+
class TestFormatCSVRows(TestCase):
272+
def test_dicts_include_urn(self):
273+
vs = [VariantFactory() for _ in range(5)]
274+
rows = views.format_csv_rows(
275+
vs, columns=['score', 'urn', ],
276+
dtype=constants.variant_score_data
277+
)
278+
for v, row in zip(vs, rows):
279+
self.assertEqual(v.urn, row['urn'])
280+
281+
def test_dicts_include_nt_hgvs(self):
282+
vs = [VariantFactory() for _ in range(5)]
283+
rows = views.format_csv_rows(
284+
vs, columns=['score', constants.hgvs_nt_column, ],
285+
dtype=constants.variant_score_data
286+
)
287+
for v, row in zip(vs, rows):
288+
self.assertEqual(v.hgvs_nt, row[constants.hgvs_nt_column])
289+
290+
def test_dicts_include_pro_hgvs(self):
291+
vs = [VariantFactory() for _ in range(5)]
292+
rows = views.format_csv_rows(
293+
vs, columns=['score', constants.hgvs_pro_column, ],
294+
dtype=constants.variant_score_data
295+
)
296+
for v, row in zip(vs, rows):
297+
self.assertEqual(v.hgvs_pro, row[constants.hgvs_pro_column])
298+
299+
def test_dicts_include_data_columns_as_strings(self):
300+
vs = [VariantFactory(data={
301+
constants.variant_score_data: {'score': 1, 'se': 2.12}})
302+
for _ in range(5)
303+
]
304+
rows = views.format_csv_rows(
305+
vs, columns=['score', 'se', ],
306+
dtype=constants.variant_score_data
307+
)
308+
for v, row in zip(vs, rows):
309+
self.assertEqual('1', row['score'])
310+
self.assertEqual('2.12', row['se'])
311+
312+
313+
class TestValidateRequest(TestCase):
314+
def setUp(self):
315+
self.factory = RequestFactory()
316+
self.user = UserFactory()
317+
self.request = self.factory.get('/')
318+
self.request.user = self.user
319+
self.instance = ScoreSetFactory(private=True)
320+
321+
def test_returns_404_response_when_urn_model_not_found(self):
322+
response = views.validate_request(self.request, 'urn')
323+
self.assertEqual(response.status_code, 404)
324+
325+
@mock.patch('api.views.validate_request')
326+
def test_calls_authenticate(self, patch):
327+
views.validate_request(self.request, self.instance.urn)
328+
patch.assert_called()
329+
330+
@mock.patch('api.views.validate_request')
331+
def test_calls_check_permission(self, patch):
332+
views.validate_request(self.request, self.instance.urn)
333+
patch.assert_called()
334+
335+
336+
class TestFormatResponse(TestCase):
337+
def setUp(self):
338+
self.user = UserFactory()
339+
self.instance = ScoreSetFactory(private=True)
340+
self.response = HttpResponse(content_type='text/csv')
341+
342+
def test_adds_comments_to_response(self):
343+
response = views.format_response(
344+
self.response, self.instance, dtype='scores')
345+
content = response.content.decode()
346+
self.assertIn("# URN: {}".format(self.instance.urn), content)
347+
self.assertIn("# Downloaded (UTC):", content)
348+
self.assertIn("# Licence: {}".format(
349+
self.instance.licence.long_name), content)
350+
self.assertIn("# Licence URL: {}".format(
351+
self.instance.licence.link), content)
352+
353+
def test_raises_valueerror_unknown_dtype(self):
354+
with self.assertRaises(ValueError):
355+
views.format_response(self.response, self.instance, dtype='---')
356+
357+
@mock.patch("api.views.format_csv_rows")
358+
def test_calls_format_csv_correct_call_dtype_is_scores(self, patch):
359+
self.instance.dataset_columns = {
360+
constants.score_columns: ['score', 'se']}
361+
self.instance.save()
362+
for i in range(5):
363+
data = {constants.variant_score_data: {'score': i, 'se': 2*i}}
364+
VariantFactory(scoreset=self.instance, data=data)
365+
366+
_ = views.format_response(
367+
self.response, self.instance, dtype='scores')
368+
369+
called_dtype = patch.call_args[1]['dtype']
370+
called_columns = patch.call_args[1]['columns']
371+
expected_columns = ['urn'] + self.instance.score_columns
372+
self.assertEqual(called_dtype, constants.variant_score_data)
373+
self.assertListEqual(called_columns, expected_columns)
374+
375+
@mock.patch("api.views.format_csv_rows")
376+
def test_calls_format_csv_correct_call_dtype_is_counts(self, patch):
377+
self.instance.dataset_columns = {
378+
constants.count_columns: ['count', 'se']}
379+
self.instance.save()
380+
for i in range(5):
381+
data = {constants.variant_count_data: {'count': i, 'se': 2*i}}
382+
VariantFactory(scoreset=self.instance, data=data)
383+
384+
_ = views.format_response(
385+
self.response, self.instance, dtype='counts')
386+
387+
called_dtype = patch.call_args[1]['dtype']
388+
called_columns = patch.call_args[1]['columns']
389+
expected_columns = ['urn'] + self.instance.count_columns
390+
self.assertEqual(called_dtype, constants.variant_count_data)
391+
self.assertListEqual(called_columns, expected_columns)
392+
393+
@mock.patch("api.views.format_csv_rows")
394+
def test_returns_empty_csv_when_no_additional_columns_present(self, patch):
395+
_ = views.format_response(
396+
self.response, self.instance, dtype='scores')
397+
patch.assert_not_called()
398+
399+
def test_double_quotes_column_values_containing_commas(self):
400+
self.instance.dataset_columns = {
401+
constants.score_columns: ['hello,world',]}
402+
403+
for i in range(5):
404+
data = {constants.variant_score_data: {'hello,world': i}}
405+
VariantFactory(scoreset=self.instance, data=data)
406+
407+
response = views.format_response(
408+
self.response, self.instance, dtype='scores')
409+
content = response.content.decode()
410+
self.assertIn('"hello,world"', content)
411+
412+
271413
class TestScoreSetAPIViews(TestCase):
272414
factory = ScoreSetFactory
273415
url = 'scoresets'
@@ -388,183 +530,24 @@ def test_OK_private_download_meta_when_authenticated(self):
388530
def test_404_not_found(self):
389531
response = self.client.get("/api/scoresets/dddd/")
390532
self.assertEqual(response.status_code, 404)
391-
392-
def test_can_download_scores(self):
393-
scs = self.factory()
394-
scs = publish_dataset(scs)
395-
scs.refresh_from_db()
396-
scs.dataset_columns = {
397-
constants.score_columns: ["score"],
398-
constants.count_columns: ["count"]
399-
}
400-
scs.save()
401-
variant = Variant.objects.create(
402-
hgvs_nt=dna_hgvs[0], hgvs_pro=protein_hgvs[0],
403-
scoreset=scs, data={
404-
constants.variant_score_data: {"score": "1"},
405-
constants.variant_count_data: {"count": "1"}
406-
}
407-
)
408-
409-
response = self.client.get("/api/scoresets/{}/scores/".format(scs.urn))
410-
rows = list(
411-
csv.reader(
412-
io.TextIOWrapper(
413-
io.BytesIO(response.content), encoding='utf-8')))
414-
415-
header = [constants.hgvs_nt_column, constants.hgvs_pro_column, 'score']
416-
data = [variant.hgvs_nt, variant.hgvs_pro, '1']
417-
self.assertEqual(rows, [header, data])
418-
419-
def test_comma_in_value_enclosed_by_quotes(self):
420-
scs = self.factory()
421-
scs = publish_dataset(scs)
422-
scs.refresh_from_db()
423-
scs.dataset_columns = {
424-
constants.score_columns: ["score"],
425-
constants.count_columns: ["count,count"]
426-
}
427-
scs.save(save_parents=True)
428-
variant = Variant.objects.create(
429-
hgvs_nt=dna_hgvs[0], hgvs_pro=protein_hgvs[0],
430-
scoreset=scs, data={
431-
constants.variant_score_data: {"score": "1"},
432-
constants.variant_count_data: {"count,count": "4"}
433-
}
434-
)
435-
response = self.client.get("/api/scoresets/{}/counts/".format(scs.urn))
436-
rows = list(
437-
csv.reader(
438-
io.TextIOWrapper(
439-
io.BytesIO(response.content), encoding='utf-8')))
440-
441-
header = [constants.hgvs_nt_column, constants.hgvs_pro_column, 'count,count']
442-
data = [variant.hgvs_nt, variant.hgvs_pro, '4']
443-
self.assertEqual(rows, [header, data])
444-
445-
def test_can_download_counts(self):
446-
scs = self.factory()
447-
scs = publish_dataset(scs)
448-
scs.refresh_from_db()
449-
scs.dataset_columns = {
450-
constants.score_columns: ["score"],
451-
constants.count_columns: ["count"]
452-
}
453-
scs.save(save_parents=True)
454-
variant = Variant.objects.create(
455-
hgvs_nt=dna_hgvs[0], hgvs_pro=protein_hgvs[0],
456-
scoreset=scs, data={
457-
constants.variant_score_data: {"score": "1"},
458-
constants.variant_count_data: {"count": "4"}
459-
}
460-
)
461-
response = self.client.get("/api/scoresets/{}/counts/".format(scs.urn))
462-
rows = list(
463-
csv.reader(
464-
io.TextIOWrapper(
465-
io.BytesIO(response.content), encoding='utf-8')))
466-
467-
header = [constants.hgvs_nt_column, constants.hgvs_pro_column, 'count']
468-
data = [variant.hgvs_nt, variant.hgvs_pro, '4']
469-
self.assertEqual(rows, [header, data])
470-
471-
def test_none_hgvs_written_as_blank(self):
472-
scs = self.factory()
473-
scs = publish_dataset(scs)
474-
scs.refresh_from_db()
475-
scs.dataset_columns = {
476-
constants.score_columns: ["score"],
477-
constants.count_columns: ["count"]
478-
}
479-
scs.save(save_parents=True)
480-
variant = Variant.objects.create(
481-
hgvs_nt=dna_hgvs[0], hgvs_pro=None,
482-
scoreset=scs,
483-
data={
484-
constants.variant_score_data: {"score": "1"},
485-
constants.variant_count_data: {"count": "4"}
486-
}
487-
)
488-
response = self.client.get("/api/scoresets/{}/scores/".format(scs.urn))
489-
rows = list(
490-
csv.reader(
491-
io.TextIOWrapper(
492-
io.BytesIO(response.content), encoding='utf-8')))
493-
494-
header = [constants.hgvs_nt_column, constants.hgvs_pro_column, 'score']
495-
data = [variant.hgvs_nt, '', '1']
496-
self.assertEqual(rows, [header, data])
497-
498-
def test_no_variants_empty_file(self):
499-
scs = self.factory()
500-
scs = publish_dataset(scs)
501-
scs.refresh_from_db()
502-
scs.dataset_columns = {
503-
constants.score_columns: ["score"],
504-
constants.count_columns: ["count"]
505-
}
506-
scs.save(save_parents=True)
507-
scs.children.delete()
508-
509-
response = self.client.get("/api/scoresets/{}/scores/".format(scs.urn))
510-
rows = list(
511-
csv.reader(
512-
io.TextIOWrapper(
513-
io.BytesIO(response.content), encoding='utf-8')))
514-
self.assertEqual(rows, [])
515-
516-
response = self.client.get("/api/scoresets/{}/counts/".format(scs.urn))
517-
rows = list(
518-
csv.reader(
519-
io.TextIOWrapper(
520-
io.BytesIO(response.content), encoding='utf-8')))
521-
self.assertEqual(rows, [])
522-
523-
def test_empty_scores_returns_empty_file(self):
524-
scs = self.factory()
525-
scs = publish_dataset(scs)
526-
scs.refresh_from_db()
527-
scs.dataset_columns = {
528-
constants.score_columns: [],
529-
constants.count_columns: ['count']
530-
}
531-
scs.save(save_parents=True)
532-
_ = Variant.objects.create(
533-
hgvs_nt=dna_hgvs[0], hgvs_pro=protein_hgvs[0],
534-
scoreset=scs, data={
535-
constants.variant_score_data: {},
536-
constants.variant_count_data: {"count": "4"}
537-
}
538-
)
539-
response = self.client.get("/api/scoresets/{}/scores/".format(scs.urn))
540-
rows = list(
541-
csv.reader(
542-
io.TextIOWrapper(
543-
io.BytesIO(response.content), encoding='utf-8')))
544-
self.assertEqual(rows, [])
545-
546-
def test_empty_counts_returns_empty_file(self):
547-
scs = self.factory()
548-
scs = publish_dataset(scs)
549-
scs.refresh_from_db()
550-
scs.dataset_columns = {
551-
constants.score_columns: ["score"],
552-
constants.count_columns: []
553-
}
554-
scs.save(save_parents=True)
555-
_ = Variant.objects.create(
556-
hgvs_nt=dna_hgvs[0], hgvs_pro=protein_hgvs[0],
557-
scoreset=scs, data={
558-
constants.variant_score_data: {"score": "1"},
559-
constants.variant_count_data: {}
560-
}
561-
)
562-
response = self.client.get("/api/scoresets/{}/counts/".format(scs.urn))
563-
rows = list(
564-
csv.reader(
565-
io.TextIOWrapper(
566-
io.BytesIO(response.content), encoding='utf-8')))
567-
self.assertEqual(rows, [])
533+
534+
@mock.patch("api.views.format_response")
535+
def test_calls_format_response_with_dtype_scores(self, patch):
536+
request = RequestFactory().get('/')
537+
request.user = UserFactory()
538+
instance = self.factory(private=False)
539+
instance.add_viewers(request.user)
540+
views.scoreset_score_data(request, instance.urn)
541+
self.assertEqual(patch.call_args[1]['dtype'], 'scores')
542+
543+
@mock.patch("api.views.format_response")
544+
def test_calls_format_response_with_dtype_counts(self, patch):
545+
request = RequestFactory().get('/')
546+
request.user = UserFactory()
547+
instance = self.factory(private=False)
548+
instance.add_viewers(request.user)
549+
views.scoreset_count_data(request, instance.urn)
550+
self.assertEqual(patch.call_args[1]['dtype'], 'counts')
568551

569552
def test_can_download_metadata(self):
570553
scs = self.factory(private=False)

0 commit comments

Comments
 (0)