#!/usr/bin/python

import unittest
import rng
import copy
#from Ft.Lib.pDomlette import PyExpatReader
from xml.sax import make_parser, parseString, parse
from Ft.Xml import InputSource
from Ft.Xml.Domlette import NonvalidatingReader


"""
The contents of this file are subject to the Mozilla Public License  Version 1.1 (the "License"); you may not use this file except in  compliance with the License. 
You may obtain a copy of the License at http://www.mozilla.org/MPL/ 
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 Code is available at http://downloads.xmlschemata.org/python/xvif/

The Initial Developer of the Original Code is Eric van der Vlist. Portions  created by Eric van der Vlist are Copyright (C) 2002. All Rights Reserved. 

Relax NG is a specification edited by the OASIS RELAX NG Technical Committee:
http://www.oasis-open.org/committees/relax-ng/

This implementation uses the implementation notes written by James Clark:
http://www.thaiopensource.com/relaxng/implement.html

Contributor(s): 
"""


class TestRelaxNg(unittest.TestCase):
	
	def schemaParser(self, schemaString, valid=1, display=0):
		parser = make_parser()
		schema = rng.RngParser()
		parser.setContentHandler(schema)
		parser.setFeature("http://xml.org/sax/features/namespaces", 1)
		factory = InputSource.DefaultFactory
		isrc=factory.fromString(schemaString, "dummy")
		exception = 0
		display=1
		if display:
			print "-------------------------"
			print schemaString
		msg=""
		try:
			parser.parse(isrc.stream)
			if display:
				print schema
		except (rng.RngSchemaInvalidException, rng.RngSchemaInvalidRecursionException), msg:
			exception=1
		if valid:
			self.failUnless(exception==0,
				'the schema %s should be valid (%s)' % (schemaString, msg))
		else:
			self.failUnless(exception==1,
				'the schema %s should be invalid' % schemaString)
		return schema

	def validateInstance(self, schema, instanceString, valid):
		reader = NonvalidatingReader
		doc = reader.parseString(instanceString, "dummy")
		s = copy.deepcopy(schema.grammar)
		deriv = s.deriv(doc.firstChild)
		if valid:
			self.failUnless(deriv.nullable(),
				'Should be valid (%s, %s)' % (instanceString, deriv))
		else:
			self.failUnless(not deriv.nullable(),
				'Should not be valid (%s, %s)' % (instanceString, deriv))
		return deriv

	def test1grammar(self):
		self.schemaParser("<grammar xmlns='http://relaxng.org/ns/structure/1.0'/>", 0)
		
	def test2start(self):
		self.schemaParser("<grammar xmlns='http://relaxng.org/ns/structure/1.0'><start/></grammar>", 0)
		
	def test3element(self):
		schema = self.schemaParser("<grammar xmlns='http://relaxng.org/ns/structure/1.0'><start><element name='foo'><empty/></element></start></grammar>")
		self.validateInstance(schema, "<foo/>", 1)
		self.validateInstance(schema, "<foo xmlns='bar'/>", 0)
		self.validateInstance(schema, "<foo1/>", 0)
		self.validateInstance(schema, "<foo bar='bar'/>", 0)
		self.validateInstance(schema, "<foo><bar/></foo>", 0)
		self.validateInstance(schema, "<foo></foo>", 1)
		self.validateInstance(schema, "<foo> \n </foo>", 1)
		self.validateInstance(schema, "<foo><!--comment--></foo>", 1)
		self.validateInstance(schema, "<foo><?pi foo='bar'?></foo>", 1)
		
	def test4element(self):
		schema = self.schemaParser("<grammar xmlns='http://relaxng.org/ns/structure/1.0'><start><element name='foo'><attribute name='bar'/></element></start></grammar>", 1, 1)
		self.validateInstance(schema, "<foo/>", 0)
		self.validateInstance(schema, "<foo xmlns='bar' bar='bar'/>", 0)
		self.validateInstance(schema, "<foo1 bar='bar'/>", 0)
		self.validateInstance(schema, "<foo bar='bar'/>", 1)
		self.validateInstance(schema, "<foo bar='bar'><bar/></foo>", 0)
		
	def test4biselement(self):
		schema = self.schemaParser("<grammar xmlns='http://relaxng.org/ns/structure/1.0'><start><element name='foo'><element name='bar'><empty/></element></element></start></grammar>")
		self.validateInstance(schema, "<foo/>", 0)
		self.validateInstance(schema, "<foo><bar/></foo>", 1)
		self.validateInstance(schema, "<foo><bar1/></foo>", 0)
		self.validateInstance(schema, "<foo><bar/><bar/></foo>", 0)
		self.validateInstance(schema, "<foo bar='bar'/>", 0)
		self.validateInstance(schema, "<foo bar='bar'><bar/></foo>", 0)
		
	def test5element(self):
		schema = self.schemaParser("<grammar xmlns='http://relaxng.org/ns/structure/1.0'><start><element name='foo'><oneOrMore><element name='bar'><empty/></element></oneOrMore></element></start></grammar>", 1, 1)
		self.validateInstance(schema, "<foo><bar/><bar/></foo>", 1)
		self.validateInstance(schema, "<foo/>", 0)
		self.validateInstance(schema, "<foo><bar/></foo>", 1)
		self.validateInstance(schema, "<foo><bar1/></foo>", 0)
		self.validateInstance(schema, "<foo bar='bar'/>", 0)
		self.validateInstance(schema, "<foo bar='bar'><bar/></foo>", 0)
		
	def test6element(self):
		schema = self.schemaParser("<grammar xmlns='http://relaxng.org/ns/structure/1.0'><start><element name='foo'><oneOrMore><element name='bar'><empty/></element><element name='bar2'><empty/></element></oneOrMore></element></start></grammar>")
		self.validateInstance(schema, "<foo/>", 0)
		self.validateInstance(schema, "<foo><bar/><bar2/></foo>", 1)
		self.validateInstance(schema, "<foo><bar1/></foo>", 0)
		self.validateInstance(schema, "<foo><bar/><bar2/><bar/><bar2/></foo>", 1)
		self.validateInstance(schema, "<foo bar='bar'/>", 0)
		self.validateInstance(schema, "<foo bar='bar'><bar/></foo>", 0)
		
	def test7element(self):
		schema = self.schemaParser("<grammar xmlns='http://relaxng.org/ns/structure/1.0'><start><element name='foo'><text/></element></start></grammar>")
		self.validateInstance(schema, "<foo/>", 1)
		self.validateInstance(schema, "<foo>text</foo>", 1)
		self.validateInstance(schema, "<foo><![CDATA[text]]></foo>", 1)
		self.validateInstance(schema, "<foo>t<![CDATA[ex]]>t</foo>", 1)
		self.validateInstance(schema, "<foo>text<bar1/></foo>", 0)
		self.validateInstance(schema, "<foo><bar/><bar2/><bar/><bar2/></foo>", 0)
		self.validateInstance(schema, "<foo bar='bar'>text</foo>", 0)
		self.validateInstance(schema, "<foo bar='bar'><bar/></foo>", 0)
		self.validateInstance(schema, "<foo>text<bar/>text</foo>", 0)

	def test8element(self):
		schema = self.schemaParser("<grammar xmlns='http://relaxng.org/ns/structure/1.0'><start><element name='foo'><choice><text/><element name='bar'><empty/></element></choice></element></start></grammar>", 1, 0)
		self.validateInstance(schema, "<foo/>", 1)
		self.validateInstance(schema, "<foo>text</foo>", 1)
		self.validateInstance(schema, "<foo>text<bar/></foo>", 0)
		self.validateInstance(schema, "<foo><bar/>text</foo>", 0)
		self.validateInstance(schema, "<foo><bar/></foo>", 1)
		self.validateInstance(schema, "<foo><bar/><bar2/><bar/><bar2/></foo>", 0)
		self.validateInstance(schema, "<foo bar='bar'>text</foo>", 0)
		self.validateInstance(schema, "<foo bar='bar'><bar/></foo>", 0)
		self.validateInstance(schema, "<foo>text<bar/>text</foo>", 0)
		
	def test9element(self):
		schema = self.schemaParser("<grammar xmlns='http://relaxng.org/ns/structure/1.0'><start><element name='foo'><oneOrMore><choice><text/><element name='bar'><empty/></element></choice></oneOrMore></element></start></grammar>", 1, 0)
		self.validateInstance(schema, "<foo/>", 1)
		self.validateInstance(schema, "<foo>text</foo>", 1)
		self.validateInstance(schema, "<foo>text<bar/></foo>", 1)
		self.validateInstance(schema, "<foo><bar/>text</foo>", 1)
		self.validateInstance(schema, "<foo><bar/></foo>", 1)
		self.validateInstance(schema, "<foo><bar/><bar2/><bar/><bar2/></foo>", 0)
		self.validateInstance(schema, "<foo bar='bar'>text</foo>", 0)
		self.validateInstance(schema, "<foo bar='bar'><bar/></foo>", 0)
		self.validateInstance(schema, "<foo>text<bar/>text</foo>", 1)
		
	def test10element(self):
		schema = self.schemaParser("<grammar xmlns='http://relaxng.org/ns/structure/1.0'><start><element name='foo'><mixed><element name='bar'><empty/></element></mixed></element></start></grammar>")
		self.validateInstance(schema, "<foo/>", 0)
		self.validateInstance(schema, "<foo>text</foo>", 0)
		self.validateInstance(schema, "<foo>text<bar/></foo>", 1)
		self.validateInstance(schema, "<foo><bar/>text</foo>", 1)
		self.validateInstance(schema, "<foo>text<bar/>text</foo>", 1)
		self.validateInstance(schema, "<foo>text<bar/>text<bar/></foo>", 0)
		self.validateInstance(schema, "<foo><bar/></foo>", 1)
		self.validateInstance(schema, "<foo><bar/><bar2/><bar/><bar2/></foo>", 0)
		self.validateInstance(schema, "<foo bar='bar'>text</foo>", 0)
		self.validateInstance(schema, "<foo bar='bar'><bar/></foo>", 0)
		
	def test11element(self):
		schema = self.schemaParser("<grammar xmlns='http://relaxng.org/ns/structure/1.0'><start><element name=' foo '><empty/></element></start></grammar>")
		self.validateInstance(schema, "<foo/>", 1)
		self.validateInstance(schema, "<foo xmlns='bar'/>", 0)
		self.validateInstance(schema, "<foo1/>", 0)
		self.validateInstance(schema, "<foo bar='bar'/>", 0)
		self.validateInstance(schema, "<foo><bar/></foo>", 0)
		
	def test12element(self):
		schema = self.schemaParser("<grammar ns='bar' xmlns='http://relaxng.org/ns/structure/1.0'><start><element name='foo'><empty/></element></start></grammar>")
		self.validateInstance(schema, "<foo/>", 0)
		self.validateInstance(schema, "<foo xmlns='bar'/>", 1)
		self.validateInstance(schema, "<ns:foo xmlns:ns='bar'/>", 1)
		
	def test13element(self):
		schema = self.schemaParser("<grammar ns='bar' xmlns='http://relaxng.org/ns/structure/1.0'><start><element name='foo'><attribute name='bar'/></element></start></grammar>")
		self.validateInstance(schema, "<foo/>", 0)
		self.validateInstance(schema, "<foo xmlns='bar' bar='bar'/>", 1)
		self.validateInstance(schema, "<ns:foo xmlns:ns='bar' bar='bar'/>", 1)
		self.validateInstance(schema, "<ns:foo xmlns:ns='bar' ns:bar='bar'/>", 0)
		
	def test14element(self):
		schema = self.schemaParser("<grammar ns='bar' xmlns='http://relaxng.org/ns/structure/1.0'><start><element name='foo'><attribute name='bar'/><attribute name='barns' ns='bar'/><element name='bar'><empty/></element><element name='barnons' ns=''><empty/></element></element></start></grammar>")
		self.validateInstance(schema, "<foo/>", 0)
		self.validateInstance(schema, "<ns:foo xmlns:ns='bar' bar='bar' ns:barns='bar'><ns:bar/><barnons/></ns:foo>", 1)
		
	def test15element(self):
		schema = self.schemaParser("<grammar xmlns:b='bar' xmlns='http://relaxng.org/ns/structure/1.0'><start><element name='b:foo'><attribute name='bar'/></element></start></grammar>")
		self.validateInstance(schema, "<foo/>", 0)
		self.validateInstance(schema, "<foo xmlns='bar' bar='bar'/>", 1)
		self.validateInstance(schema, "<ns:foo xmlns:ns='bar' bar='bar'/>", 1)
		self.validateInstance(schema, "<ns:foo xmlns:ns='bar' ns:bar='bar'/>", 0)
		
	def test16element(self):
		schema = self.schemaParser("<grammar xmlns:b='bar' xmlns='http://relaxng.org/ns/structure/1.0'><start><element name='b:foo'><attribute name='bar'/><attribute name='b:barns'/><element name='b:bar'><empty/></element><element name='barnons'><empty/></element></element></start></grammar>")
		self.validateInstance(schema, "<foo/>", 0)
		self.validateInstance(schema, "<ns:foo xmlns:ns='bar' bar='bar' ns:barns='bar'><ns:bar/><barnons/></ns:foo>", 1)
		
	def test17define(self):
		schema = self.schemaParser("<grammar xmlns='http://relaxng.org/ns/structure/1.0'><define name='def'><element name='foo'><empty/></element></define><start><ref name='def'/></start></grammar>")
		self.validateInstance(schema, "<foo/>", 1)
		self.validateInstance(schema, "<ns:foo xmlns:ns='bar' bar='bar' ns:barns='bar'><ns:bar/><barnons/></ns:foo>", 0)
		
		
	def test18define(self):
		schema = self.schemaParser("<grammar xmlns='http://relaxng.org/ns/structure/1.0'><define name='def'><element name='foo'><zeroOrMore><ref name='def'/></zeroOrMore></element></define><start><ref name='def'/></start></grammar>")
		self.validateInstance(schema, "<foo/>", 1)
		self.validateInstance(schema, "<ns:foo xmlns:ns='bar' bar='bar' ns:barns='bar'><ns:bar/><barnons/></ns:foo>", 0)
		self.validateInstance(schema, "<foo><foo/></foo>", 1)
		self.validateInstance(schema, "<foo><foo/><foo/></foo>", 1)
		self.validateInstance(schema, "<foo><foo><foo/></foo><foo/></foo>", 1)

	def test19define(self):
		schema = self.schemaParser("<grammar xmlns='http://relaxng.org/ns/structure/1.0'><define name='def'><zeroOrMore><choice><ref name='def'/><element name='foo19'/></choice></zeroOrMore></define><start><element name='bar'><ref name='def'/></element></start></grammar>", 0)
		
	def test20optional(self):
		schema = self.schemaParser("<grammar xmlns='http://relaxng.org/ns/structure/1.0'><start><element name='foo'><optional><element name='optional'><empty/></element></optional></element></start></grammar>")
		self.validateInstance(schema, "<foo/>", 1)
		self.validateInstance(schema, "<ns:foo xmlns:ns='bar' bar='bar' ns:barns='bar'><ns:bar/><barnons/></ns:foo>", 0)
		self.validateInstance(schema, "<foo><optional/></foo>", 1)
		self.validateInstance(schema, "<foo><optional/><optional/></foo>", 0)

	def test21optional(self):
		schema = self.schemaParser("<grammar xmlns='http://relaxng.org/ns/structure/1.0'><start><element name='foo'><optional><attribute name='optional'/></optional></element></start></grammar>")
		self.validateInstance(schema, "<foo/>", 1)
		self.validateInstance(schema, "<ns:foo xmlns:ns='bar' bar='bar' ns:barns='bar'><ns:bar/><barnons/></ns:foo>", 0)
		self.validateInstance(schema, "<foo><optional/></foo>", 0)
		self.validateInstance(schema, "<foo optional='bar'/>", 1)

	def test21optionalDefine(self):
		schema = self.schemaParser("<grammar xmlns='http://relaxng.org/ns/structure/1.0'><define name='att'><optional><attribute name='optional21'/></optional></define><start><element name='foo'><ref name='att'/></element></start></grammar>")
		self.validateInstance(schema, "<foo/>", 1)
		self.validateInstance(schema, "<ns:foo xmlns:ns='bar' bar='bar' ns:barns='bar'><ns:bar/><barnons/></ns:foo>", 0)
		self.validateInstance(schema, "<foo><optional/></foo>", 0)
		self.validateInstance(schema, "<foo optional21='bar'/>", 1)

	def test22optional(self):
		schema = self.schemaParser("<grammar xmlns='http://relaxng.org/ns/structure/1.0'><start><element name='foo'><optional><attribute name='bar'/></optional><element name='foo'><empty/></element></element></start></grammar>", 1, 0)
		self.validateInstance(schema, "<foo/>", 0)
		self.validateInstance(schema, "<ns:foo xmlns:ns='bar' bar='bar' ns:barns='bar'><ns:bar/><barnons/></ns:foo>", 0)
		self.validateInstance(schema, "<foo><foo/></foo>", 1)
		self.validateInstance(schema, "<foo><foo/><foo/></foo>", 0)
		self.validateInstance(schema, "<foo><foo><foo/></foo><foo/></foo>", 0)
		self.validateInstance(schema, "<foo bar='bar'/>", 0)

	def test23define(self):
		schema = self.schemaParser("<grammar xmlns='http://relaxng.org/ns/structure/1.0'><define name='att'><optional><attribute name='bar'/></optional></define><define name='def'><element name='foo'><ref name='att'/><zeroOrMore><ref name='def'/></zeroOrMore></element></define><start><ref name='def'/></start></grammar>", 1, 0)
		self.validateInstance(schema, "<foo/>", 1)
		self.validateInstance(schema, "<ns:foo xmlns:ns='bar' bar='bar' ns:barns='bar'><ns:bar/><barnons/></ns:foo>", 0)
		self.validateInstance(schema, "<foo><foo/></foo>", 1)
		self.validateInstance(schema, "<foo><foo/><foo/></foo>", 1)
		self.validateInstance(schema, "<foo><foo><foo/></foo><foo/></foo>", 1)
		self.validateInstance(schema, "<foo bar='bar'/>", 1)
	
	def test24define(self):
		schema = self.schemaParser("<grammar xmlns='http://relaxng.org/ns/structure/1.0'><start><ref name='def'/></start><define name='att'><optional><attribute name='bar'/></optional></define><define name='def'><element name='foo'><ref name='att'/><zeroOrMore><ref name='def'/></zeroOrMore></element></define></grammar>", 1, 0)
		self.validateInstance(schema, "<foo/>", 1)
		self.validateInstance(schema, "<ns:foo xmlns:ns='bar' bar='bar' ns:barns='bar'><ns:bar/><barnons/></ns:foo>", 0)
		self.validateInstance(schema, "<foo><foo/></foo>", 1)
		self.validateInstance(schema, "<foo><foo/><foo/></foo>", 1)
		self.validateInstance(schema, "<foo><foo><foo/></foo><foo/></foo>", 1)
		self.validateInstance(schema, "<foo bar='bar'/>", 1)

	def test25define(self):
		schema = self.schemaParser("""<?xml version="1.0" encoding="utf-8"  ?>
 <element xmlns="http://relaxng.org/ns/structure/1.0" name="library">
  <oneOrMore>
   <element name="book">
    <attribute name="id"/>
    <attribute name="available"/>
    <element name="isbn">
     <text/>
    </element>
    <element name="title">
     <attribute name="xml:lang"/>
     <text/>
    </element>
    <zeroOrMore>
     <element name="author">
      <attribute name="id"/>
      <element name="name">
       <text/>
      </element>
      <element name="born">
       <text/>
      </element>
      <optional>
       <element name="dead">
        <text/>
       </element>
      </optional>
     </element>
    </zeroOrMore>
    <zeroOrMore>
     <element name="character">
      <attribute name="id"/>
      <element name="name">
       <text/>
      </element>
      <element name="born">
       <text/>
      </element>
      <element name="qualification">
       <text/>
      </element>
     </element>
    </zeroOrMore>
   </element>
  </oneOrMore>
 </element>""", 1, 0)
		self.validateInstance(schema, """<?xml version="1.0"?>
 <library>
  <book id="b0836217462" available="true">
   <isbn>0836217462</isbn>
   <title xml:lang="en">Being a Dog Is a Full-Time Job</title>
  </book>
 </library>""", 1)
		self.validateInstance(schema, """<?xml version="1.0"?>
 <library>
  <book id="b0836217462" available="true">
   <isbn>0836217462</isbn>
   <title xml:lang="en">Being a Dog Is a Full-Time Job</title>
   <character id="PP">
    <name>Peppermint Patty</name>
    <born>1966-08-22</born>
    <qualification>bold, brash and tomboyish</qualification>
    </character>
   <character id="Snoopy">
    <name>Snoopy</name>
    <born>1950-10-04</born>
    <qualification>extroverted beagle</qualification>
   </character>
   <character id="Schroeder">
    <name>Schroeder</name>
    <born>1951-05-30</born>
    <qualification>brought classical music to the Peanuts strip</qualification>
   </character>
   <character id="Lucy">
    <name>Lucy</name>
    <born>1952-03-03</born>
    <qualification>bossy, crabby and selfish</qualification>
   </character>
  </book>
 </library>""", 1)
		self.validateInstance(schema, """<?xml version="1.0"?>
 <library>
  <book id="b0836217462" available="true">
   <isbn>0836217462</isbn>
   <title xml:lang="en">Being a Dog Is a Full-Time Job</title>
   <author id="CMS">
    <name>Charles M Schulz</name>
    <born>1922-11-26</born>
    <dead>2000-02-12</dead>
   </author>
   <character id="PP">
    <name>Peppermint Patty</name>
    <born>1966-08-22</born>
    <qualification>bold, brash and tomboyish</qualification>
    </character>
  </book>
 </library>""", 1)
		self.validateInstance(schema, """<?xml version="1.0"?>
 <library>
  <book id="b0836217462" available="true">
   <isbn>0836217462</isbn>
   <title xml:lang="en">Being a Dog Is a Full-Time Job</title>
   <author id="CMS">
    <name>Charles M Schulz</name>
    <born>1922-11-26</born>
    <dead>2000-02-12</dead>
   </author>
   <character id="PP">
    <name>Peppermint Patty</name>
    <born>1966-08-22</born>
    <qualification>bold, brash and tomboyish</qualification>
    </character>
   <character id="Snoopy">
    <name>Snoopy</name>
    <born>1950-10-04</born>
    <qualification>extroverted beagle</qualification>
   </character>
   <character id="Schroeder">
    <name>Schroeder</name>
    <born>1951-05-30</born>
    <qualification>brought classical music to the Peanuts strip</qualification>
   </character>
   <character id="Lucy">
    <name>Lucy</name>
    <born>1952-03-03</born>
    <qualification>bossy, crabby and selfish</qualification>
   </character>
  </book>
 </library>""", 1)

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


