from django_evolution.tests.utils import test_sql_mapping

tests = r"""
>>> from django.db import models

>>> from django_evolution.mutations import ChangeField
>>> from django_evolution.tests.utils import test_proj_sig, execute_test_sql, register_models, deregister_models
>>> from django_evolution.diff import Diff

>>> import copy

# Use Cases:
# Setting a null constraint
# -- without an initial value
# -- with a null initial value
# -- with a good initial value (constant)
# -- with a good initial value (callable)
# Removing a null constraint
# Invoking a no-op change field
# Changing the max_length of a character field
# -- increasing the max_length
# -- decreasing the max_length
# Renaming a column
# Changing the db_table of a many to many relationship
# Adding an index
# Removing an index
# Adding a unique constraint
# Removing a unique constraint
# Redundant attributes. (Some attribute have changed, while others haven't but are specified anyway.)
# Changing more than one attribute at a time (on different fields)
# Changing more than one attribute at a time (on one field)


### This one is a bit dubious because changing the primary key of a model will mean
### that all referenced foreign keys and M2M relationships need to be updated
# Adding a primary key constraint
# Removing a Primary Key (Changing the primary key column)



# Options that apply to all fields:
# DB related options
# null
# db_column
# db_index
# db_tablespace (Ignored)
# primary_key
# unique
# db_table (only for many to many relationships)
# -- CharField
# max_length

# Non-DB options
# blank
# core
# default
# editable
# help_text
# radio_admin
# unique_for_date
# unique_for_month
# unique_for_year
# validator_list

# I don't know yet
# choices

>>> class ChangeSequenceFieldInitial(object):
...     def __init__(self, suffix):
...         self.suffix = suffix
...
...     def __call__(self):
...         from django.db import connection
...         qn = connection.ops.quote_name
...         return qn('char_field')

# Now, a useful test model we can use for evaluating diffs
>>> class ChangeAnchor1(models.Model):
...     value = models.IntegerField()

>>> class ChangeBaseModel(models.Model):
...     my_id = models.AutoField(primary_key=True)
...     alt_pk = models.IntegerField()
...     int_field = models.IntegerField(db_column='custom_db_column')
...     int_field1 = models.IntegerField(db_index=True)
...     int_field2 = models.IntegerField(db_index=False)
...     int_field3 = models.IntegerField(unique=True)
...     int_field4 = models.IntegerField(unique=False)
...     char_field = models.CharField(max_length=20)
...     char_field1 = models.CharField(max_length=25, null=True)
...     char_field2 = models.CharField(max_length=30, null=False)
...     m2m_field1 = models.ManyToManyField(ChangeAnchor1, db_table='change_field_non-default_m2m_table')

# Store the base signatures
>>> anchors = [('ChangeAnchor1', ChangeAnchor1)]
>>> test_model = ('TestModel', ChangeBaseModel)

>>> start = register_models(*anchors)
>>> start.update(register_models(test_model))
>>> start_sig = test_proj_sig(test_model, *anchors)

# Setting a null constrai
nt without an initial value
>>> class SetNotNullChangeModel(models.Model):
...     my_id = models.AutoField(primary_key=True)
...     alt_pk = models.IntegerField()
...     int_field = models.IntegerField(db_column='custom_db_column')
...     int_field1 = models.IntegerField(db_index=True)
...     int_field2 = models.Integ
erField(db_index=False)
...     int_field3 = models.IntegerField(unique=True)
...     int_field4 = models.IntegerField(unique=False)
...     char_field = models.CharField(max_length=20)
...     char_field1 = models.CharField(max_length=25, null=False)
...     char_field2 = models.CharField(max_length=30, null=False)
...     m2m_field1 = models.ManyToManyField(ChangeAnchor1, db_table='change_field_non-default_m2m_table')

>>> end = register_models(('TestModel', SetNotNullChangeModel), *anchors)
>>> end_sig = test_proj_sig(('TestModel', SetNotNullChangeModel), *anchors)
>>> d = Diff(start_sig, end_sig)
>>> print d
In model tests.TestModel:
    In field 'char_field1':
        Property 'null' has changed

>>> print [str(e) for e in d.evolution()['tests']] # SetNotNullChangeModel
["ChangeField('TestModel', 'char_field1', initial=<<USER VALUE REQUIRED>>, null=False)"]

# Without an initial value
>>> evolution = [ChangeField('TestModel', 'char_field1', null=False)]
>>> test_sig = copy.deepcopy(start_sig)
>>> test_sql = []
>>> for mutation in evolution:
...     test_sql.extend(mutation.mutate('tests', test_sig))
...     mutation.simulate('tests', test_sig)
Traceback (most recent call last):
...
SimulationFailure: Cannot change column 'char_field1' on 'tests.TestModel' without a non-null initial value.

# With a null initial value
>>> evolution = [ChangeField('TestModel', 'char_field1', null=False, initial=None)]
>>> test_sig = copy.deepcopy(start_sig)
>>> test_sql = []
>>> for mutation in evolution:
...     test_sql.extend(mutation.mutate('tests', test_sig))
...     mutation.simulate('tests', test_sig)
Traceback (most recent call last):
...
SimulationFailure: Cannot change column 'char_field1' on 'tests.TestModel' without a non-null initial value.

# With a good initial value (constant)
>>> evolution = [ChangeField('TestModel', 'char_field1', null=False, initial="abc's xyz")]
>>> test_sig = copy.deepcopy(start_sig)
>>> test_sql = []
>>> for mutation in evolution:
...     test_sql.extend(mutation.mutate('tests', test_sig))
...     mutation.simulate('tests', test_sig)

>>> Diff(test_sig, end_sig).is_empty()
True

>>> execute_test_sql(start, end, test_sql)
%(SetNotNullChangeModelWithConstant)s
 
# With a good initial value (callable)
>>> evolution = [ChangeField('TestModel', 'char_field1', null=False, initial=ChangeSequenceFieldInitial('SetNotNullChangeModel'))]
>>> test_sig = copy.deepcopy(start_sig)
>>> test_sql = []
>>> for mutation in evolution:
...     test_sql.extend(mutation.mutate('tests', test_sig))
...     mutation.simulate('tests', test_sig)

>>> Diff(test_sig, end_sig).is_empty()
True

>>> execute_test_sql(start, end, test_sql)
%(SetNotNullChangeModelWithCallable)s

# Removing a null constraint
>>> class SetNullChangeModel(models.Model):
...     my_id = models.AutoField(primary_key=True)
...     alt_pk = models.IntegerField()
...     int_field = models.IntegerField(db_column='custom_db_column')
...     int_field1 = models.IntegerField(db_index=True)
...     int_field2 = models.IntegerField(db_index=False)
...     int_field3 = models.IntegerField(unique=True)
...     int_field4 = models.IntegerField(unique=False)
...     char_field = models.CharField(max_length=20)
...     char_field1 = models.CharField(max_length=25, null=True)
...     char_field2 = models.CharField(max_length=30, null=True)
...     m2m_field1 = models.ManyToManyField(ChangeAnchor1, db_table='change_field_non-default_m2m_table')

>>> end = register_models(('TestModel', SetNullChangeModel), *anchors)
>>> end_sig = test_proj_sig(('TestModel', SetNullChangeModel), *anchors)
>>> d = Diff(start_sig, end_sig)
>>> print d
In model tests.TestModel:
    In field 'char_field2':
        Property 'null' has changed
    
>>> print [str(e) for e in d.evolution()['tests']] # SetNullChangeModel
["ChangeField('TestModel', 'char_field2', initial=None, null=True)"]

>>> test_sig = copy.deepcopy(start_sig)
>>> test_sql = []
>>> for mutation in d.evolution()['tests']:
...     test_sql.extend(mutation.mutate('tests', test_sig))
...     mutation.simulate('tests', test_sig)

>>> Diff(test_sig, end_sig).is_empty()
True

>>> execute_test_sql(start, end, test_sql) # SetNullChangeModel
%(SetNullChangeModel)s

# Removing a null constraint
>>> class NoOpChangeModel(models.Model):
...     my_id = models.AutoField(primary_key=True)
...     alt_pk = models.IntegerField()
...     int_field = models.IntegerField(db_column='custom_db_column')
...     int_field1 = models.IntegerField(db_index=True)
...     int_field2 = models.IntegerField(db_index=False)
...     int_field3 = models.IntegerField(unique=True)
...     int_field4 = models.IntegerField(unique=False)
...     char_fie