--------------
Bug Test Cases
--------------

Additional tests for verifying bug fixes. This doc is not particularly narrative.

Bootstrapping
-------------
set up the same type of stuff in the readme.txt doctest

  >>> import zope.interface, os
  >>> from datetime import datetime
 
Testing Database environment variable setup

  >>> db_url = os.environ.get('DATABASE_URL') or 'sqlite://'

This is the key that contentmirror expects to find its database
variable at

  >>> os.environ['CONTENTMIRROR_URI'] = db_url
  >>> from ore.contentmirror.testing import *
  >>> from ore.contentmirror import interfaces
  >>> from ore.contentmirror.schema import metadata
  >>> from ore.contentmirror import operation
  >>> from ore.contentmirror.loader import loader
  >>> import transaction 
  >>> from ore.contentmirror.session import Session
  >>> setUp(None)  


  >>> import sqlalchemy as rdb
  >>> from ore.contentmirror.schema import metadata
  >>> metadata.bind = rdb.create_engine( db_url )
  >>> engine=metadata.bind
  >>> session = Session()

Unicode Content
---------------

issue 22
http://code.google.com/p/contentmirror/issues/detail?id=22

This issue was not reproducible, as the following test worked
out of the box.

  >>> class UnicodeContent( BaseContent ):
  ...     portal_type = "Uni Content"
  ...     zope.interface.implements( interfaces.IMirrored )
  ...     schema = Schema((
  ...         StringField('name'),   
  ...         StringField('slug', required=True),   
  ...     ))


  >>> loader.load( UnicodeContent )
  >>> metadata.drop_all(checkfirst=True)
  >>> metadata.create_all(checkfirst=True)
  >>> uni1 = UnicodeContent( 'test', name= u'ﺎﻠﻋﺮﺒﻳﺓ', slug=u'简体中文' )
  >>> peer1 = interfaces.ISerializer( uni1 ).add()
  >>> transaction.commit()

Not let's modify it
  
  >>> uni1.name = u'Русский'
  >>> peer2 = interfaces.ISerializer( uni1 ).update()
  >>> transaction.commit()

Mixed Case Fields 
-----------------

issue 25
http://code.google.com/p/contentmirror/issues/detail?id=25

contentmirror doesn't handle multicase field names correctly, this was an invalid issue, as this
unit test worked out of the box.

  >>> class MixedCase( BaseContent ):
  ...     portal_type = "Mixed Case"
  ...     zope.interface.implements( interfaces.IMirrored )
  ...     schema = Schema((
  ...         StringField('Name'),   
  ...         StringField('Slug', required=True),   
  ...         StringField('contactEmail2', required=True),   
  ...     ))

  >>> loader.load( MixedCase )
  >>> metadata.drop_all(checkfirst=True)
  >>> metadata.create_all(checkfirst=True)

  >>> mixed1 = MixedCase( 'magic', Name="Magic", Slug="Woot", contactEmail2="zebra@example.com")
  >>> peer1 = interfaces.ISerializer( mixed1 ).add()
  >>> assert peer1.name == mixed1.Name
  >>> assert peer1.contactemail2 == mixed1.contactEmail2
  >>> transaction.commit()

  >>> mixed2 = MixedCase( 'rabbit', Name="Rabbit", Slug="Swallow Question",contactEmail2="zebra@example.com")
  >>> peer2 = interfaces.ISerializer( mixed2 ).add()
  >>> assert peer2.contactemail2 == mixed2.contactEmail2
  >>> transaction.commit()
  >>> object_map = dict( [ (o.id, o) for o in list( Session().query( peer1.__class__ ).all() )] )
  >>> assert object_map['magic'].contactemail2 == mixed1.contactEmail2
  >>> transaction.abort()


Deleting Files
--------------

issue 24
http://code.google.com/p/contentmirror/issues/detail?id=24

create an image or file and try to delete it, it fails with a sqlalchemy error. There were a couple of things going on here, files as named scalar values triggered some interesting problems with a sqlalchemy optimization as relates 

  >>> class FileContentTest( BaseContent ):
  ...     portal_type = "File Test"
  ...     zope.interface.implements( interfaces.IMirrored )
  ...     schema = Schema((
  ...                StringField('Name'),   
  ...                FileField('file_content', required=True),   
  ...     ))

  >>> loader.load( FileContentTest )
  >>> metadata.drop_all(checkfirst=True)
  >>> metadata.create_all(checkfirst=True)

  >>> file1 = FileContentTest('abc', Name="Rabbit", file_content=File("treaty.txt", "file text") )
  >>> peer1 = interfaces.ISerializer( file1 ).add()
  >>> transaction.commit()

Test Updating the File Content

  >>> file1.Name = "Tweak"
  >>> peer1 = interfaces.ISerializer( file1 ).update()
  >>> transaction.commit()

And verify deleting it, fixes the problem
 
  >>> interfaces.ISerializer( file1 ).delete()
  >>> transaction.commit()
  >>> assert list(engine.execute('select count(*) from files  ') )[0][0] == 0

Deleting References
-------------------

issue 29
http://code.google.com/p/contentmirror/issues/detail?id=29

We want to verify that references are deleted from the database when there deleted in Plone.

The only difference is multiValued=False is set on the type.  This means that the type should only
have a single value.
     
First let's clear out any previous db state

  >>> transaction.abort()

  >>> class MyAsset( BaseContent ):
  ...     portal_type = "My Asset"
  ...     zope.interface.implements( interfaces.IMirrored )
  ...     schema = Schema((
  ...         StringField('name'),   
  ...         StringField('slug', required=True),   
  ...         ReferenceField('related', relationship='ref',multiValued=False), 
  ...         ReferenceField('sim', relationship='sim'),
  ...         DateTimeField('discoveredDate')
  ...     ))

perform all of the necessary wiring to get the machinery working
  
  >>> loader.load( MyAsset )
  >>> metadata.drop_all(checkfirst=True)
  >>> metadata.create_all(checkfirst=True)

create some test instances

  >>> ref1 = MyAsset('ref1', name="Ref 1")
  >>> ref2 = MyAsset('ref2', name="Ref 2")
  >>> home_page = MyAsset( 'home-page', related=[ ref1 ] )
  >>> peer = interfaces.ISerializer( home_page ).add()
  >>> transaction.commit()

we create some lookup tables for testing verification due to the indeteriminate order these
will go into the database ( ie. the primary key changes from one test run to another as the 
session machinery utilizes a dict, and there is no definitive ordering determination for the inserts ).

  >>> id_pk_map = dict(list(engine.execute('select id, content_id from content order by id')))
  >>> pk_id_map = dict(list(engine.execute('select content_id, id from content order by id')))
  >>> assert 'home-page' in id_pk_map
  >>> assert 'ref1' in id_pk_map
  
the related item should be ref1

  >>> home_page.related[0].id
  'ref1'  
  >>> rel = list(engine.execute('select source_id, target_id from relations order by source_id'))[0]
  >>> pk_id_map[rel[0]]
  u'home-page'
  >>> pk_id_map[rel[1]]
  u'ref1'

 now change the related item to ref2.  This should remove the relation for ref1 and add one for ref2
  
  >>> home_page.related=ref2
  >>> peer = interfaces.ISerializer( home_page ).update()
  >>> transaction.commit()
  >>> id_pk_map = dict(list(engine.execute('select id, content_id from content order by id')))
  >>> pk_id_map = dict(list(engine.execute('select content_id, id from content order by id')))
  >>> sorted( id_pk_map.keys() )
  [u'home-page', u'ref1', u'ref2']
  >>> rel =list(engine.execute('select source_id,target_id from relations order by source_id'))[0]
  >>> pk_id_map[ rel[0] ]
  u'home-page'
  >>> pk_id_map[ rel[1] ]
  u'ref2'


Now retest with with multivalued relations

  >>> metadata.drop_all(checkfirst=True)
  >>> metadata.create_all(checkfirst=True)
 
Create a content object with two references
 
  >>> ref1 = MyAsset('ref1', name="Ref 1")
  >>> ref2 = MyAsset('ref2', name="Ref 2")
  >>> home_page = MyAsset( 'home-page', sim=[ ref1, ref2 ] )
  >>> peer = interfaces.ISerializer( home_page ).add()
  >>> transaction.commit()  
  
Update the content to have just one reference, and verify

  >>> home_page.sim = [ref1]
  >>> peer = interfaces.ISerializer( home_page ).update()
  >>> transaction.commit()
  >>> rels = list(engine.execute('select source_id,target_id from relations order by source_id'))
  >>> assert len(rels) == 1

100% Coverage
-------------

Test some silly things to get to 100% code coverage

  >>> from zope import component
  >>> registry = component.getUtility( interfaces.IPeerRegistry )
  >>> len(registry.items())
  4


  >>> from ore.contentmirror import operation
  >>> operation.Operation(None).process()
  Traceback (most recent call last):
  ...
  NotImplementedError: subclass responsibility
