import unittest
import frappe

from frappe.core.utils import find
from frappe.custom.doctype.property_setter.property_setter import make_property_setter


class TestDBUpdate(unittest.TestCase):
	def test_db_update(self):
		doctype = 'User'
		frappe.reload_doctype('User', force=True)
		frappe.model.meta.trim_tables('User')
		make_property_setter(doctype, 'bio', 'fieldtype', 'Text', 'Data')
		make_property_setter(doctype, 'enabled', 'default', '1', 'Int')

		frappe.db.updatedb(doctype)

		field_defs = get_field_defs(doctype)
		table_columns = frappe.db.get_table_columns_description('tab{}'.format(doctype))

		self.assertEqual(len(field_defs), len(table_columns))

		for field_def in field_defs:
			fieldname = field_def.get('fieldname')
			table_column = find(table_columns, lambda d: d.get('name') == fieldname)

			fieldtype = get_fieldtype_from_def(field_def)

			default = field_def.default if field_def.default is not None else 'NULL'

			self.assertEqual(fieldtype, table_column.type)
			self.assertIn(table_column.default or 'NULL', [default, "'{}'".format(default), '0'])

def get_fieldtype_from_def(field_def):
	fieldtuple = frappe.db.type_map.get(field_def.fieldtype, ('', 0))
	fieldtype = fieldtuple[0]
	if fieldtype in ('varchar', 'datetime', 'int'):
		fieldtype += '({})'.format(field_def.length or fieldtuple[1])
	return fieldtype

def get_field_defs(doctype):
	meta = frappe.get_meta(doctype, cached=False)
	field_defs = meta.get_fieldnames_with_value(True)
	field_defs += get_other_fields_meta(meta)
	return field_defs

def get_other_fields_meta(meta):
	default_fields_map = {
		'name': ('Data', 0),
		'owner': ('Data', 0),
		'parent': ('Data', 0),
		'parentfield': ('Data', 0),
		'modified_by': ('Data', 0),
		'parenttype': ('Data', 0),
		'creation': ('Datetime', 0),
		'modified': ('Datetime', 0),
		'idx': ('Int', 8),
		'docstatus': ('Int', 1)
	}

	optional_fields = frappe.db.OPTIONAL_COLUMNS
	if meta.track_seen:
		optional_fields.append('_seen')

	optional_fields_map = {field: ('Text', 0) for field in optional_fields}
	fields = dict(default_fields_map, **optional_fields_map)
	field_map =  [frappe._dict({'fieldname': field, 'fieldtype': _type, 'length': _length}) for field, (_type, _length) in fields.items()]

	return field_map
import unittest
import frappe

from frappe.core.utils import find
from frappe.custom.doctype.property_setter.property_setter import make_property_setter


class TestDBUpdate(unittest.TestCase):
	def test_db_update(self):
		doctype = 'User'
		frappe.reload_doctype('User', force=True)
		frappe.model.meta.trim_tables('User')
		make_property_setter(doctype, 'bio', 'fieldtype', 'Text', 'Data')
		make_property_setter(doctype, 'enabled', 'default', '1', 'Int')

		frappe.db.updatedb(doctype)

		field_defs = get_field_defs(doctype)
		table_columns = frappe.db.get_table_columns_description('tab{}'.format(doctype))

		self.assertEqual(len(field_defs), len(table_columns))

		for field_def in field_defs:
			fieldname = field_def.get('fieldname')
			table_column = find(table_columns, lambda d: d.get('name') == fieldname)

			fieldtype = get_fieldtype_from_def(field_def)

			fallback_default = '0' if field_def.get('fieldtype') in frappe.model.numeric_fieldtypes else 'NULL'
			default = field_def.default if field_def.default is not None else fallback_default

			self.assertEqual(fieldtype, table_column.type)
			self.assertIn(table_column.default or 'NULL', [default, "'{}'".format(default)])

def get_fieldtype_from_def(field_def):
	fieldtuple = frappe.db.type_map.get(field_def.fieldtype, ('', 0))
	fieldtype = fieldtuple[0]
	if fieldtype in ('varchar', 'datetime', 'int'):
		fieldtype += '({})'.format(field_def.length or fieldtuple[1])
	return fieldtype

def get_field_defs(doctype):
	meta = frappe.get_meta(doctype, cached=False)
	field_defs = meta.get_fieldnames_with_value(True)
	field_defs += get_other_fields_meta(meta)
	return field_defs

def get_other_fields_meta(meta):
	default_fields_map = {
		'name': ('Data', 0),
		'owner': ('Data', 0),
		'parent': ('Data', 0),
		'parentfield': ('Data', 0),
		'modified_by': ('Data', 0),
		'parenttype': ('Data', 0),
		'creation': ('Datetime', 0),
		'modified': ('Datetime', 0),
		'idx': ('Int', 8),
		'docstatus': ('Int', 1)
	}

	optional_fields = frappe.db.OPTIONAL_COLUMNS
	if meta.track_seen:
		optional_fields.append('_seen')

	optional_fields_map = {field: ('Text', 0) for field in optional_fields}
	fields = dict(default_fields_map, **optional_fields_map)
	field_map =  [frappe._dict({'fieldname': field, 'fieldtype': _type, 'length': _length}) for field, (_type, _length) in fields.items()]

	return field_map
Add a fallback default