From 2aee98b8eb44b6d2a2daf81cf1238ea7b4f6a25f Mon Sep 17 00:00:00 2001
From: Piotr Gawron <piotr.gawron@uni.lu>
Date: Thu, 5 Nov 2020 11:55:05 +0100
Subject: [PATCH] boolean custom field implemented

---
 requirements-dev.txt                          |  1 +
 smash/web/api_views/serialization_utils.py    | 11 +++-
 smash/web/api_views/subject.py                | 34 ++++++++---
 .../forms/custom_study_subject_field_forms.py | 13 ++++
 smash/web/forms/study_subject_forms.py        | 23 +++++--
 smash/web/models/constants.py                 |  2 +
 smash/web/models/study_subject.py             |  2 +-
 smash/web/tests/api_views/test_subject.py     | 60 +++++++++++++++----
 .../test_CustomStudySubjectFieldAddForm.py    | 25 +++++---
 .../test_CustomStudySubjectFieldEditForm.py   | 26 +++++---
 .../tests/forms/test_StudySubjectAddForm.py   | 18 ++++--
 .../tests/forms/test_StudySubjectEditForm.py  | 18 ++++--
 12 files changed, 175 insertions(+), 58 deletions(-)

diff --git a/requirements-dev.txt b/requirements-dev.txt
index d3241ad8..8bfe3d4f 100644
--- a/requirements-dev.txt
+++ b/requirements-dev.txt
@@ -1,3 +1,4 @@
 coverage==5.3
 django-debug-toolbar==1.11
 mockito==1.2.2
+parameterized==0.7.4
diff --git a/smash/web/api_views/serialization_utils.py b/smash/web/api_views/serialization_utils.py
index e3a9483d..943fb7bb 100644
--- a/smash/web/api_views/serialization_utils.py
+++ b/smash/web/api_views/serialization_utils.py
@@ -3,14 +3,14 @@ import logging
 logger = logging.getLogger(__name__)
 
 
-def bool_to_yes_no(val):
+def bool_to_yes_no(val: bool):
     if val:
         return "YES"
     else:
         return "NO"
 
 
-def bool_to_yes_no_null(val):
+def bool_to_yes_no_null(val: bool):
     if val is None:
         return "N/A"
     if val:
@@ -19,6 +19,13 @@ def bool_to_yes_no_null(val):
         return "NO"
 
 
+def str_to_yes_no(val: str):
+    if val.lower() == 'true':
+        return "YES"
+    else:
+        return "NO"
+
+
 def virus_test_to_str(test, date):
     if test is None and date is not None:
         return "Inconclusive"
diff --git a/smash/web/api_views/subject.py b/smash/web/api_views/subject.py
index e04ed1b5..9aede96e 100644
--- a/smash/web/api_views/subject.py
+++ b/smash/web/api_views/subject.py
@@ -7,13 +7,13 @@ from django.db.models import Q
 from django.http import JsonResponse
 from django.urls import reverse
 
-from web.models.custom_data.custom_study_subject_field import get_study_subject_field_id
 from web.api_views.serialization_utils import bool_to_yes_no, flying_team_to_str, location_to_str, add_column, \
-    serialize_date, serialize_datetime, get_filters_for_data_table_request, virus_test_to_str
-from web.models import ConfigurationItem
-from web.models import StudySubject, Visit, Appointment, Subject, SubjectColumns, StudyColumns, Study, ContactAttempt
+    serialize_date, serialize_datetime, get_filters_for_data_table_request, virus_test_to_str, str_to_yes_no
+from web.models import ConfigurationItem, StudySubject, Visit, Appointment, Subject, SubjectColumns, StudyColumns, \
+    Study, ContactAttempt
 from web.models.constants import SUBJECT_TYPE_CHOICES, GLOBAL_STUDY_ID, VISIT_SHOW_VISIT_NUMBER_FROM_ZERO, \
-    CUSTOM_FIELD_TYPE_TEXT
+    CUSTOM_FIELD_TYPE_TEXT, CUSTOM_FIELD_TYPE_BOOLEAN
+from web.models.custom_data.custom_study_subject_field import get_study_subject_field_id, CustomStudySubjectField
 from web.models.study_subject_list import SUBJECT_LIST_GENERIC, SUBJECT_LIST_NO_VISIT, SUBJECT_LIST_REQUIRE_CONTACT, \
     StudySubjectList, SUBJECT_LIST_VOUCHER_EXPIRY
 from web.views import e500_error
@@ -129,6 +129,13 @@ def get_subject_columns(request, subject_list_type):
                        study_subject_columns,
                        "string_filter",
                        visible_param=False)
+        elif custom_study_subject_field.type == CUSTOM_FIELD_TYPE_BOOLEAN:
+            add_column(result,
+                       custom_study_subject_field.name,
+                       get_study_subject_field_id(custom_study_subject_field),
+                       study_subject_columns,
+                       "yes_no_filter",
+                       visible_param=False)
         else:
             raise NotImplementedError
 
@@ -395,8 +402,19 @@ def get_subjects_filtered(subjects_to_be_filtered, filters):
             result = filter_by_visit(result, visit_number, value)
         elif re.search(r'^custom_field-[0-9]$', column):
             field_id = int(column.replace("custom_field-", ""))
-            result = result.filter(customstudysubjectvalue__study_subject_field__id=field_id,
-                                   customstudysubjectvalue__value__icontains=value)
+            field = CustomStudySubjectField.objects.get(pk=field_id)
+            if field.type == CUSTOM_FIELD_TYPE_TEXT:
+                result = result.filter(customstudysubjectvalue__study_subject_field__id=field_id,
+                                       customstudysubjectvalue__value__icontains=value)
+            elif field.type == CUSTOM_FIELD_TYPE_BOOLEAN:
+                if value.lower() == 'true' or value.lower() == 'false':
+                    result = result.filter(customstudysubjectvalue__study_subject_field__id=field_id,
+                                           customstudysubjectvalue__value__icontains=value)
+                else:
+                    result = result.filter(customstudysubjectvalue__study_subject_field__id=field_id,
+                                           customstudysubjectvalue__value='')
+            else:
+                raise NotImplementedError
         elif column == "":
             pass
         else:
@@ -565,6 +583,8 @@ def serialize_subject(study_subject):
             if val is None:
                 val = ''
             result[get_study_subject_field_id(field_value.study_subject_field)] = val
+        elif field_value.study_subject_field.type == CUSTOM_FIELD_TYPE_BOOLEAN:
+            result[get_study_subject_field_id(field_value.study_subject_field)] = str_to_yes_no(field_value.value)
         else:
             raise NotImplementedError
 
diff --git a/smash/web/forms/custom_study_subject_field_forms.py b/smash/web/forms/custom_study_subject_field_forms.py
index 18d2bbf7..3970eca1 100644
--- a/smash/web/forms/custom_study_subject_field_forms.py
+++ b/smash/web/forms/custom_study_subject_field_forms.py
@@ -1,6 +1,7 @@
 from django.forms import ModelForm
 
 from web.models.custom_data import CustomStudySubjectField
+from web.models.constants import CUSTOM_FIELD_TYPE_BOOLEAN
 
 
 class CustomStudySubjectFieldForm(ModelForm):
@@ -8,6 +9,18 @@ class CustomStudySubjectFieldForm(ModelForm):
     def __init__(self, *args, **kwargs):
         super(CustomStudySubjectFieldForm, self).__init__(*args, **kwargs)
 
+    def clean(self):
+        cleaned_data = super(CustomStudySubjectFieldForm, self).clean()
+
+        if cleaned_data['default_value'] != '' \
+                and cleaned_data['default_value'] is not None:
+            if cleaned_data['type'] == CUSTOM_FIELD_TYPE_BOOLEAN \
+                    and cleaned_data['default_value'].lower() != 'false' \
+                    and cleaned_data['default_value'].lower() != 'true':
+                self.add_error('default_value',
+                               "Default value can be one of the following: 'true', 'false', ''.")
+        return cleaned_data
+
 
 class CustomStudySubjectFieldAddForm(CustomStudySubjectFieldForm):
     class Meta:
diff --git a/smash/web/forms/study_subject_forms.py b/smash/web/forms/study_subject_forms.py
index 644c9342..d5fe20f1 100644
--- a/smash/web/forms/study_subject_forms.py
+++ b/smash/web/forms/study_subject_forms.py
@@ -7,8 +7,8 @@ from django.forms import ModelForm
 from web.forms.forms import DATETIMEPICKER_DATE_ATTRS, get_worker_from_args
 from web.models import ConfigurationItem, StudySubject, Study, StudyColumns, VoucherType, Worker
 from web.models.constants import SCREENING_NUMBER_PREFIXES_FOR_TYPE, VISIT_SHOW_VISIT_NUMBER_FROM_ZERO, \
-    CUSTOM_FIELD_TYPE_TEXT
-from web.models.custom_data import CustomStudySubjectField
+    CUSTOM_FIELD_TYPE_TEXT, CUSTOM_FIELD_TYPE_BOOLEAN
+from web.models.custom_data import CustomStudySubjectField, CustomStudySubjectValue
 from web.models.custom_data.custom_study_subject_field import get_study_subject_field_id
 from web.models.worker_study_role import WORKER_HEALTH_PARTNER
 from web.widgets.secure_file_widget import SecuredFileWidget
@@ -16,10 +16,20 @@ from web.widgets.secure_file_widget import SecuredFileWidget
 logger = logging.getLogger(__name__)
 
 
-def create_field_for_custom_study_subject_field(study_subject_field: CustomStudySubjectField) -> forms.Field:
+def create_field_for_custom_study_subject_field(study_subject_field: CustomStudySubjectField,
+                                                field_value: CustomStudySubjectValue = None) -> forms.Field:
+    val = study_subject_field.default_value
+    if field_value is not None:
+        val = field_value.value
     if study_subject_field.type == CUSTOM_FIELD_TYPE_TEXT:
-        field = forms.CharField(label=study_subject_field.name, initial=study_subject_field.default_value,
+        field = forms.CharField(label=study_subject_field.name, initial=val,
                                 required=study_subject_field.obligatory, disabled=study_subject_field.readonly)
+    elif study_subject_field.type == CUSTOM_FIELD_TYPE_BOOLEAN:
+        initial = False
+        if val is not None and val.lower() == 'true':
+            initial = True
+        field = forms.BooleanField(label=study_subject_field.name, initial=initial,
+                                   required=study_subject_field.obligatory, disabled=study_subject_field.readonly)
     else:
         raise NotImplementedError
     return field
@@ -39,8 +49,7 @@ class StudySubjectForm(ModelForm):
         if instance:
             for value in instance.custom_data_values:
                 field_id = get_study_subject_field_id(value.study_subject_field)
-                self.fields[field_id] = create_field_for_custom_study_subject_field(value.study_subject_field)
-                self.fields[field_id].initial = value.value
+                self.fields[field_id] = create_field_for_custom_study_subject_field(value.study_subject_field, value)
         else:
             for field_type in CustomStudySubjectField.objects.filter(study=self.study):
                 field_id = get_study_subject_field_id(field_type)
@@ -203,6 +212,8 @@ def get_study_from_study_subject_instance(study_subject):
 def get_study_subject_field_value(field_type: CustomStudySubjectField, field: forms.BoundField):
     if field_type.type == CUSTOM_FIELD_TYPE_TEXT:
         return field.value()
+    elif field_type.type == CUSTOM_FIELD_TYPE_BOOLEAN:
+        return str(field.value())
     else:
         raise NotImplementedError
 
diff --git a/smash/web/models/constants.py b/smash/web/models/constants.py
index 082933b2..d4c439b9 100644
--- a/smash/web/models/constants.py
+++ b/smash/web/models/constants.py
@@ -142,6 +142,8 @@ VOUCHER_STATUS_CHOICES = (
 FILE_STORAGE = FileSystemStorage(location='uploads')
 
 CUSTOM_FIELD_TYPE_TEXT = "TEXT"
+CUSTOM_FIELD_TYPE_BOOLEAN = "BOOL"
 CUSTOM_FIELD_TYPE = (
     (CUSTOM_FIELD_TYPE_TEXT, "Text"),
+    (CUSTOM_FIELD_TYPE_BOOLEAN, "Boolean (True/False)"),
 )
diff --git a/smash/web/models/study_subject.py b/smash/web/models/study_subject.py
index 0527da75..3a16335d 100644
--- a/smash/web/models/study_subject.py
+++ b/smash/web/models/study_subject.py
@@ -382,7 +382,7 @@ class StudySubject(models.Model):
                                                    study_subject_field=field)
         return CustomStudySubjectValue.objects.filter(study_subject=self)
 
-    def set_custom_data_value(self, custom_study_subject_field, value):
+    def set_custom_data_value(self, custom_study_subject_field: CustomStudySubjectField, value: str):
         found = False
         for existing_value in self.customstudysubjectvalue_set.all():
             if existing_value.study_subject_field == custom_study_subject_field:
diff --git a/smash/web/tests/api_views/test_subject.py b/smash/web/tests/api_views/test_subject.py
index a992da5a..61105405 100644
--- a/smash/web/tests/api_views/test_subject.py
+++ b/smash/web/tests/api_views/test_subject.py
@@ -4,13 +4,14 @@ import json
 import logging
 
 from django.urls import reverse
+from parameterized import parameterized
 from six import ensure_str
 
 from web.api_views.subject import get_subjects_order, get_subjects_filtered, serialize_subject, get_subject_columns
 from web.importer.warning_counter import MsgCounterHandler
 from web.models import StudySubject, Appointment, Study, Worker, SubjectColumns, StudyColumns
 from web.models.constants import GLOBAL_STUDY_ID, SUBJECT_TYPE_CHOICES_PATIENT, SUBJECT_TYPE_CHOICES_CONTROL, \
-    CUSTOM_FIELD_TYPE_TEXT
+    CUSTOM_FIELD_TYPE_TEXT, CUSTOM_FIELD_TYPE_BOOLEAN
 from web.models.custom_data import CustomStudySubjectField
 from web.models.custom_data.custom_study_subject_field import get_study_subject_field_id
 from web.models.study_subject_list import SUBJECT_LIST_GENERIC, SUBJECT_LIST_NO_VISIT, SUBJECT_LIST_REQUIRE_CONTACT, \
@@ -716,14 +717,17 @@ class TestSubjectApi(LoggedInWithWorkerTestCase):
         self.check_subject_filtered([["virus_test_1", "false"]], [study_subject_negative])
         self.check_subject_filtered([["virus_test_1", "inconclusive"]], [study_subject_inconclusive])
 
-    def test_subjects_filter_by_custom_field(self):
-        field = CustomStudySubjectField.objects.create(study=get_test_study(), default_value="xyz",
-                                                       type=CUSTOM_FIELD_TYPE_TEXT)
+    @parameterized.expand([
+        ('text', CUSTOM_FIELD_TYPE_TEXT, 'bla'),
+        ('bool valid', CUSTOM_FIELD_TYPE_BOOLEAN, 'True')
+    ])
+    def test_subjects_filter_by_custom_field(self, _, field_type, value):
+        field = CustomStudySubjectField.objects.create(study=get_test_study(), default_value="", type=field_type)
         study_subject = create_study_subject(2)
-        study_subject.set_custom_data_value(field, "bla")
+        study_subject.set_custom_data_value(field, value)
 
-        self.check_subject_filtered([[get_study_subject_field_id(field), "bla"]], [study_subject])
-        self.check_subject_filtered([[get_study_subject_field_id(field), "bla-bla"]], [])
+        self.check_subject_filtered([[get_study_subject_field_id(field), value]], [study_subject])
+        self.check_subject_filtered([[get_study_subject_field_id(field), value + "-bla"]], [])
 
     def test_subjects_filter_by_two_custom_fields(self):
         field = CustomStudySubjectField.objects.create(study=get_test_study(), default_value="xyz",
@@ -739,14 +743,44 @@ class TestSubjectApi(LoggedInWithWorkerTestCase):
         self.check_subject_filtered([[get_study_subject_field_id(field), "bla"],
                                      [get_study_subject_field_id(field2), "abcs"]], [])
 
-    def test_subjects_sort_by_custom_fields(self):
-        field = CustomStudySubjectField.objects.create(study=get_test_study(), default_value="xyz",
-                                                       type=CUSTOM_FIELD_TYPE_TEXT)
+    @parameterized.expand([
+        ('text', CUSTOM_FIELD_TYPE_TEXT, 'bla', 'cla', 'dla'),
+        ('bool', CUSTOM_FIELD_TYPE_BOOLEAN, '', 'False', 'True')
+    ])
+    def test_subjects_sort_by_custom_fields(self, _, field_type, value1, value2, value3):
+        field = CustomStudySubjectField.objects.create(study=get_test_study(), default_value="", type=field_type)
         study_subject = self.study_subject
         study_subject2 = create_study_subject(3)
         study_subject3 = create_study_subject(4)
-        study_subject.set_custom_data_value(field, "bla")
-        study_subject2.set_custom_data_value(field, "dla")
-        study_subject3.set_custom_data_value(field, "cla")
+        study_subject.set_custom_data_value(field, value1)
+        study_subject2.set_custom_data_value(field, value3)
+        study_subject3.set_custom_data_value(field, value2)
 
         self.check_subject_ordered(get_study_subject_field_id(field), [study_subject, study_subject3, study_subject2])
+
+    @parameterized.expand([
+        ('text', CUSTOM_FIELD_TYPE_TEXT, 'bla'),
+        ('bool', CUSTOM_FIELD_TYPE_BOOLEAN, 'True')
+    ])
+    def test_subjects_columns_for_custom(self, _, field_type, value):
+        CustomStudySubjectField.objects.create(study=Study.objects.filter(id=GLOBAL_STUDY_ID)[0], default_value=value,
+                                               type=field_type)
+        response = self.client.get(
+            reverse('web.api.subjects.columns', kwargs={'subject_list_type': SUBJECT_LIST_GENERIC}))
+        self.assertEqual(response.status_code, 200)
+
+    @parameterized.expand([
+        ('text', CUSTOM_FIELD_TYPE_TEXT, 'bla'),
+        ('bool', CUSTOM_FIELD_TYPE_BOOLEAN, 'True')
+    ])
+    def test_serialize_subject_with_custom_field(self, _, field_type, value):
+        field = CustomStudySubjectField.objects.create(study=get_test_study(),
+                                                       default_value='',
+                                                       type=field_type)
+
+        study_subject = self.study_subject
+        study_subject.set_custom_data_value(field, value)
+
+        subject_json = serialize_subject(study_subject)
+        self.assertIsNotNone(subject_json[get_study_subject_field_id(field)])
+        self.assertTrue(subject_json[get_study_subject_field_id(field)] != '')
diff --git a/smash/web/tests/forms/test_CustomStudySubjectFieldAddForm.py b/smash/web/tests/forms/test_CustomStudySubjectFieldAddForm.py
index 3cf4c3d5..35a6cd99 100644
--- a/smash/web/tests/forms/test_CustomStudySubjectFieldAddForm.py
+++ b/smash/web/tests/forms/test_CustomStudySubjectFieldAddForm.py
@@ -1,23 +1,32 @@
 from django.test import TestCase
+from parameterized import parameterized
 
 from web.forms.custom_study_subject_field_forms import CustomStudySubjectFieldAddForm
-from web.models.constants import CUSTOM_FIELD_TYPE_TEXT
+from web.models.constants import CUSTOM_FIELD_TYPE_TEXT, CUSTOM_FIELD_TYPE_BOOLEAN
 from web.models.custom_data import CustomStudySubjectField
 from web.tests.functions import get_test_study
 
 
 class CustomStudySubjectFieldAddFormTest(TestCase):
 
-    def test_edit_field(self):
+    @parameterized.expand([
+        ('text', CUSTOM_FIELD_TYPE_TEXT, 'bla', True),
+        ('bool valid', CUSTOM_FIELD_TYPE_BOOLEAN, 'True', True),
+        ('bool invalid', CUSTOM_FIELD_TYPE_BOOLEAN, 'bla', False),
+    ])
+    def test_add_field(self, _, field_type, default_value, valid):
         sample_data = {
-            'default_value': "bla",
+            'default_value': default_value,
             'name': '1. name',
-            'type': CUSTOM_FIELD_TYPE_TEXT
+            'type': field_type
         }
 
         form = CustomStudySubjectFieldAddForm(sample_data, study=get_test_study())
-        self.assertTrue(form.is_valid())
-        field = form.save()
+        if valid:
+            self.assertTrue(form.is_valid())
+            field = form.save()
 
-        self.assertEquals(1, CustomStudySubjectField.objects.filter(id=field.id).count())
-        self.assertEquals("bla", field.default_value)
+            self.assertEquals(1, CustomStudySubjectField.objects.filter(id=field.id).count())
+            self.assertEquals(default_value, field.default_value)
+        else:
+            self.assertFalse(form.is_valid())
diff --git a/smash/web/tests/forms/test_CustomStudySubjectFieldEditForm.py b/smash/web/tests/forms/test_CustomStudySubjectFieldEditForm.py
index c34f1435..16f089d4 100644
--- a/smash/web/tests/forms/test_CustomStudySubjectFieldEditForm.py
+++ b/smash/web/tests/forms/test_CustomStudySubjectFieldEditForm.py
@@ -1,25 +1,33 @@
 from django.test import TestCase
+from parameterized import parameterized
 
 from web.forms.custom_study_subject_field_forms import CustomStudySubjectFieldEditForm
+from web.models.constants import CUSTOM_FIELD_TYPE_TEXT, CUSTOM_FIELD_TYPE_BOOLEAN
 from web.models.custom_data import CustomStudySubjectField
-from web.models.constants import CUSTOM_FIELD_TYPE_TEXT
 from web.tests.functions import get_test_study
 
 
 class CustomStudySubjectFieldEditFormTest(TestCase):
 
-    def test_edit_field(self):
-        field = CustomStudySubjectField.objects.create(study=get_test_study(), default_value="xyz",
-                                                       type=CUSTOM_FIELD_TYPE_TEXT)
+    @parameterized.expand([
+        ('text', CUSTOM_FIELD_TYPE_TEXT, 'bla', True),
+        ('bool valid', CUSTOM_FIELD_TYPE_BOOLEAN, 'True', True),
+        ('bool invalid', CUSTOM_FIELD_TYPE_BOOLEAN, 'bla', False),
+    ])
+    def test_edit_field(self, _, field_type, default_value, valid):
+        field = CustomStudySubjectField.objects.create(study=get_test_study(), default_value="", type=field_type)
 
         sample_data = {
-            'default_value': "bla",
+            'default_value': default_value,
             'name': '1. name',
-            'type': CUSTOM_FIELD_TYPE_TEXT
+            'type': field_type
         }
 
         form = CustomStudySubjectFieldEditForm(sample_data, instance=field)
-        self.assertTrue(form.is_valid())
-        form.save()
+        if valid:
+            self.assertTrue(form.is_valid())
+            form.save()
 
-        self.assertEquals("bla", field.default_value)
+            self.assertEquals(default_value, field.default_value)
+        else:
+            self.assertFalse(form.is_valid())
diff --git a/smash/web/tests/forms/test_StudySubjectAddForm.py b/smash/web/tests/forms/test_StudySubjectAddForm.py
index a10f2fcd..0e4fb6ba 100644
--- a/smash/web/tests/forms/test_StudySubjectAddForm.py
+++ b/smash/web/tests/forms/test_StudySubjectAddForm.py
@@ -1,8 +1,10 @@
 import logging
 
+from parameterized import parameterized
+
 from web.forms import StudySubjectAddForm
 from web.forms.study_subject_forms import get_new_screening_number, get_study_subject_field_id
-from web.models.constants import SUBJECT_TYPE_CHOICES_CONTROL, CUSTOM_FIELD_TYPE_TEXT
+from web.models.constants import SUBJECT_TYPE_CHOICES_CONTROL, CUSTOM_FIELD_TYPE_TEXT, CUSTOM_FIELD_TYPE_BOOLEAN
 from web.models.custom_data import CustomStudySubjectField, CustomStudySubjectValue
 from web.tests import LoggedInWithWorkerTestCase
 from web.tests.functions import create_study_subject, create_subject, get_test_study, create_empty_study
@@ -29,19 +31,23 @@ class StudySubjectAddFormTests(LoggedInWithWorkerTestCase):
         form.is_valid()
         self.assertTrue(form.is_valid())
 
-    def test_add_with_custom_field(self):
-        field = CustomStudySubjectField.objects.create(study=get_test_study(), default_value="xyz",
-                                                       type=CUSTOM_FIELD_TYPE_TEXT)
+    @parameterized.expand([
+        ('text', CUSTOM_FIELD_TYPE_TEXT, 'bla', 'bla'),
+        ('bool', CUSTOM_FIELD_TYPE_BOOLEAN, True, 'True'),
+    ])
+    def test_add_with_custom_field(self, _, field_type, value, expected_serialized_value):
+        field = CustomStudySubjectField.objects.create(study=get_test_study(), default_value="",
+                                                       type=field_type)
         count = CustomStudySubjectValue.objects.filter(study_subject_field=field).count()
 
-        self.sample_data[get_study_subject_field_id(field)] = "bla"
+        self.sample_data[get_study_subject_field_id(field)] = value
 
         form = StudySubjectAddForm(data=self.sample_data, user=self.user, study=self.study)
         form.instance.subject_id = create_subject().id
         subject = form.save()
 
         self.assertEqual(count + 1, CustomStudySubjectValue.objects.filter(study_subject_field=field).count())
-        self.assertEqual("bla", subject.get_custom_data_value(field).value)
+        self.assertEqual(expected_serialized_value, subject.get_custom_data_value(field).value)
 
     def test_validation_for_study_without_columns(self):
         form = StudySubjectAddForm(data=self.sample_data, user=self.user, study=create_empty_study())
diff --git a/smash/web/tests/forms/test_StudySubjectEditForm.py b/smash/web/tests/forms/test_StudySubjectEditForm.py
index bd83c8ce..4114afb8 100644
--- a/smash/web/tests/forms/test_StudySubjectEditForm.py
+++ b/smash/web/tests/forms/test_StudySubjectEditForm.py
@@ -1,8 +1,10 @@
 import logging
 
+from parameterized import parameterized
+
 from web.forms import StudySubjectEditForm
 from web.models import StudySubject
-from web.models.constants import CUSTOM_FIELD_TYPE_TEXT
+from web.models.constants import CUSTOM_FIELD_TYPE_TEXT, CUSTOM_FIELD_TYPE_BOOLEAN
 from web.models.custom_data import CustomStudySubjectField
 from web.models.custom_data.custom_study_subject_field import get_study_subject_field_id
 from web.tests import LoggedInWithWorkerTestCase
@@ -56,18 +58,22 @@ class StudySubjectEditFormTests(LoggedInWithWorkerTestCase):
         self.assertTrue("nd_number" in edit_form.errors)
         self.assertFalse(save_status)
 
-    def test_edit_with_custom_field(self):
-        field = CustomStudySubjectField.objects.create(study=get_test_study(), default_value="xyz",
-                                                       type=CUSTOM_FIELD_TYPE_TEXT)
+    @parameterized.expand([
+        ('text', CUSTOM_FIELD_TYPE_TEXT, 'bla', 'bla'),
+        ('bool', CUSTOM_FIELD_TYPE_BOOLEAN, True, 'True'),
+    ])
+    def test_edit_with_custom_field(self, _, field_type, value, expected_serialized_value):
+        field = CustomStudySubjectField.objects.create(study=get_test_study(), default_value="",
+                                                       type=field_type)
 
         self.assertEqual(field.default_value, self.study_subject.get_custom_data_value(field).value)
 
-        self.sample_data[get_study_subject_field_id(field)] = "bla"
+        self.sample_data[get_study_subject_field_id(field)] = value
 
         edit_form = StudySubjectEditForm(self.sample_data, instance=self.study_subject)
         subject = edit_form.save()
 
-        self.assertEqual("bla", subject.get_custom_data_value(field).value)
+        self.assertEqual(expected_serialized_value, subject.get_custom_data_value(field).value)
 
     def test_invalid_mpower_id_edit(self):
         self.study_subject.mpower_id = "mpower_002"
-- 
GitLab