#!/usr/bin/env python
########################################
# The contents of this file are subject to the MLX PUBLIC LICENSE version
# 1.0 (the "License"); you may not use this file except in
# compliance with the License.
# 
# Software distributed under the License is distributed on an "AS IS"
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See
# the License for the specific language governing rights and limitations
# under the License.
# 
# The Original Source Code is "compClust", released 2003 September 03.
# 
# The Original Source Code was developed by the California Institute of
# Technology (Caltech).  Portions created by Caltech are Copyright (C)
# 2002-2003 California Institute of Technology. All Rights Reserved.
########################################
#
#        Author: Diane Trout
# Last Modified: $Date: 2004/01/16 23:24:47 $
#

"""Make sure mixin interface works correctly
"""
import unittest
from compClust.util.Mixin import Mixin

# define a simple class hierarchy
class Calpha(object, Mixin):
  def __init__(self):
    self.alpha = 'a'
#
  def getAlpha(self):
    return self.alpha
        
class Cbeta(Calpha):
  def __init__(self):
    self.beta = 'b'
    super(Cbeta, self).__init__()

  def getBeta(self):
    return self.beta
        
class Cdelta(Cbeta):
  def __init__(self, base):
    super(Cdelta, self).__init__()
    self.delta = 'd'
    self.copyMixins(base)

class Cgamma(Cdelta):
  def __init__(self, base):
    super(Cgamma, self).__init__(base)

class mixin1:
  def testMixin1(self):
    return "mixin1"
    
  def setMixinValue(self, value):
    self.value = value
        
  def getMixinValue(self, defaultValue=None):
    return self.__dict__.get('value', defaultValue)
    
class mixin2:
  def testMixin2(self):
    return "mixin2"

  def setMixinValue(self, value):
    self.value = value*2

  def getMixinValue(self, defaultValue=None):
    return self.__dict__.get('value', defaultValue)
    

class MixinTestCases(unittest.TestCase):
  def testAddRemoveMixin(self):
    """Test adding and removing mixins
    """
    a = Calpha()
    self.failUnless('getAlpha' in dir(a))
    self.failIf('testMixin1' in dir(a))
    a.addMixin(mixin1)
    self.failUnless(a.testMixin1() == mixin1().testMixin1())
    a.removeMixin(mixin1)
    self.failIf('testMixin1' in dir(a))

    self.failUnlessRaises(ValueError, a.removeMixin, mixin1)
    
  def testNonContamination(self):
    """Test that adding mixin doesn't contaiminate other instances
    """
    a1 = Calpha()
    a2 = Calpha().addMixin(mixin1)
    a3 = Calpha()
    a4 = Calpha().addMixin(mixin2)

    self.failIf('testMixin1' in dir(a1))
    self.failUnless(a2.testMixin1() == mixin1().testMixin1())
    self.failIf('testMixin1' in dir(a3))
    self.failIf('testMixin1' in dir(a4))
    self.failUnless(a4.testMixin2() == mixin2().testMixin2())

  def testDirectSubclassMixin(self):
    """Add mixin from another class
    """
    a0 = Calpha()
    a1 = Calpha().addMixin(mixin1)
    a2 = Calpha().addMixin(mixin2)
    
    delta1 = Cdelta(a1)
    delta2 = Cdelta(a2)

    self.failIf('testMixin2' in dir(delta1))
    self.failIf('testMixin1' in dir(delta2))
    self.failUnless(delta1.testMixin1() == mixin1().testMixin1())
    self.failUnless(delta2.testMixin2() == mixin2().testMixin2())

    # does the value modification work?
    delta1.setMixinValue(3)
    self.failUnless(delta1.getMixinValue() == 3)
    delta2.setMixinValue(3)
    self.failUnless(delta2.getMixinValue() == 6)

  def testDeepSubclssMixin(self):
    a1 = Calpha().addMixin(mixin1)
    a2 = Calpha().addMixin(mixin2)

    gamma1 = Cgamma(a1)
    gamma2 = Cgamma(a2)

    self.failIf('testMixin2' in dir(gamma1))
    self.failIf('testMixin1' in dir(gamma2))
    self.failUnless(gamma1.testMixin1() == mixin1().testMixin1())
    self.failUnless(gamma2.testMixin2() == mixin2().testMixin2())

  def testIsMixinInstance(self):
    a1 = Calpha().addMixin(mixin1)
    a2 = Calpha().addMixin(mixin2)

    gamma1 = Cgamma(a1)
    gamma2 = Cgamma(a2)

    self.failUnless(a1.isMixinInstance(mixin1))
    self.failIf(a1.isMixinInstance(mixin2))
    self.failUnless(a2.isMixinInstance(mixin2))
    self.failIf(a2.isMixinInstance(mixin1))
    self.failUnless(gamma1.isMixinInstance(mixin1))
    self.failIf(gamma1.isMixinInstance(mixin2))
    self.failUnless(gamma2.isMixinInstance(mixin2))
    self.failIf(gamma2.isMixinInstance(mixin1))
    self.failIf(a1.isMixinInstance(None))
    
def suite(**kw):
  return unittest.defaultTestLoader.loadTestsFromTestCase(MixinTestCases)

if __name__ == "__main__":
  unittest.main(defaultTest="suite")
