# Copyright (c) 2000-2004 LOGILAB S.A. (Paris, FRANCE).
# http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
"""unit tests for narval.reader and Recipe / Action handlers
"""

__revision__ = '$Id: readers.py,v 1.35 2004/04/02 10:06:46 syt Exp $'

import unittest

from logilab.common import testlib

from narval.reader import AL_NS, REGISTRY, HandlerNotDefined, Registry
from narval.recipe import RecipeElement, RecipeXMLHandler
from narval.action import ActionElement, ActionXMLHandler

DATA1 = """<memory>
  <mailbox path="/var/spool/mail/syt"/>
  <email_addr mine="yes">syt@logilab.org</email_addr>
  <server-socket1 port="7776" recipe="pia.PDA"/>
</memory>"""

DATA2 = """<?xml version='1.0' encoding='iso-8859-1'?>
<al:cookbook xmlns:al='http://www.logilab.org/namespaces/Narval/1.2' group='test'>
  <al:recipe name='update_bmf' group='bkmonitor' restart='no'>
    <al:description lang='en'>create or update the xbel bookmark file from
    different formats</al:description>
    <al:step id='Update_bmf.0.Bookmarks.parse_bmf' type='action' target='Bookmarks.parse_bmf'>
      <al:label lang='en'>convert original bookmarks file into an xbel element</al:label>
      <al:output id='output'>
        <al:match>xbel</al:match>
      </al:output>
    </al:step>
    <al:step id='Update_bmf.1.Bookmarks.update_bmf' type='action' target='Bookmarks.update_bmf'>
      <al:label lang='en'>Update the old xbel file</al:label>
      <al:arguments>
        <bookmark-file type='xbel'>$NARVAL_HOME/data/bookmarks.xbel</bookmark-file>
      </al:arguments>
    </al:step>
    <al:transition id='Update_bmf.2'>
      <al:in idref='Update_bmf.0.Bookmarks.parse_bmf'/>
      <al:out idref='Update_bmf.1.Bookmarks.update_bmf'/>
      <al:time seconds="0,30"/>
    </al:transition>
  </al:recipe>
  
  <al:recipe name='false' group='false'>
  </al:recipe>
  
  <al:action name='naughty_action_2' func='non_existent_f'>
          <al:output id='output' list='yes'><al:match>element</al:match></al:output>
  </al:action>
</al:cookbook>"""

def empty_registry():
    # this is a singleton, force handlers unregistering manualy
    REGISTRY.elmts = {}
    REGISTRY.global_context = {}
    return REGISTRY

class RegistryTC(unittest.TestCase):    

    def setUp(self):
        self.reader = empty_registry()
        
    def test_singleton(self):
        self.reader.register_class(RecipeElement)
        reader = Registry()
        self.assert_(self.reader is reader)
        self.assert_(isinstance(reader.get_class(AL_NS, 'recipe'), RecipeElement))

    def test_handlers_management(self):
        self.reader.register_class(RecipeElement)
        self.assert_(isinstance(self.reader.get_class(AL_NS, 'recipe'), RecipeElement))
        self.assertRaises(AssertionError,
                          self.reader.register_class, RecipeElement)
        self.assertRaises(HandlerNotDefined,
                          self.reader.get_class, AL_NS, 'action')

    def test_match_context(self):
        self.reader.register_class(RecipeElement)
        class IToto: pass
        self.reader.register_interface(IToto)
        self.assertEquals(self.reader.global_context, {'RecipeElement' : RecipeElement,
                                                       'IToto' : IToto})
        self.assert_(self.reader.match_expression('RecipeElement', {}))
        self.assert_(self.reader.match_expression('IToto', {}))
        self.assertRaises(NameError, self.reader.match_expression, 'ActionElement', {})
        self.assert_(self.reader.match_expression('isinstance(elmt, IToto)', {'elmt': IToto()}))
        
    def test_known_values(self):
        self.reader.register_class(RecipeElement)
        self.reader.register_class(ActionElement)
##         p.parse(self.DATA1)
##         self.assert_(len(dh.elements) == 1, 'Wrong elements number')
##         self.assert_(isinstance(dh.elements[0], Element))
        # suite 
        elements = self.reader.from_string(DATA2, 1)
        self.assert_(len(elements) == 3, 'Wrong elements number')
        correct = (RecipeElement, RecipeElement, ActionElement)
        for i in range(len(elements)):
            element = elements[i]
            self.assert_(isinstance(element, correct[i]))
            # FIXME: test objects+prototype and reader


class RecipeElementTC(testlib.TestCase):
    ELMT_STRING = '''<al:recipe xmlns:type="uri:memory:type" xmlns:al="http://www.logilab.org/namespaces/Narval/1.2" decay="50" group="bkmonitor" name="update_bmf" al:persist="no">
<al:description lang="en">create or update the xbel bookmark file from  different formats</al:description>
<al:step foreach="" id="Update_bmf.0.Bookmarks.parse_bmf" target="Bookmarks.parse_bmf" type="action">
<al:label>convert original bookmarks file into an xbel element</al:label>
<al:output id="output">
<al:match>element</al:match>
</al:output>
</al:step>
<al:step foreach="" id="Update_bmf.1.Bookmarks.update_bmf" target="Bookmarks.update_bmf" type="action">
<al:label>Update the old xbel file</al:label>
<al:arguments>
<al:recipe xmlns:al="http://www.logilab.org/namespaces/Narval/1.2" al:persist="yes"  restart="yes" decay="90" group="arguments" name="toto"></al:recipe>
</al:arguments>
</al:step>
<al:transition id="Update_bmf.2">
<al:in idref="Update_bmf.0.Bookmarks.parse_bmf" onError="no"/>
<al:out idref="Update_bmf.1.Bookmarks.update_bmf"/>
<al:time seconds="0,30" minutes="*" hours="*" monthdays="*" months="*" weekdays="*"/>
</al:transition>
</al:recipe>'''

    KLASS = RecipeElement
    
    def setUp(self):
        self.reader = reader = empty_registry()
        reader.register_class(self.KLASS)
        self.elmt = reader.from_string(self.ELMT_STRING)[0]
        
    def test_as_xml(self):
        self.assertListEquals(self.elmt.as_xml().splitlines(),
                              self.ELMT_STRING.splitlines())
        

class ActionElementTC(RecipeElementTC):
    ELMT_STRING = '''<al:action xmlns:type="uri:memory:type" xmlns:al="http://www.logilab.org/namespaces/Narval/1.2" func="non_existent_f" group="" name="naughty_action_2" al:persist="no">
<al:output id="output" list="yes">
<al:match>element</al:match>
</al:output>
<al:output id="output-no-match"/>
</al:action>'''
    KLASS = ActionElement

    def test_prototype(self):
        a_proto = self.elmt.prototype
        self.assertEquals( [a_p.id for a_p in a_proto.output_prototype()],
                           ['output', 'output-no-match'])
        
if __name__ == '__main__':
    unittest.main()
