#! /usr/bin/env python

import unittest
from pyprolog import Term
import types

class test_atom(unittest.TestCase):
    
    def setUp(self):
        self.a1 = Term.new_atom('a1')
        self.a2 = Term.new_atom('text\tatom')
        self.a3 = Term.new_atom('93')
    
    def test_repr(self): 
        msg = 'XXX'
        a1 = self.a1
        a2 = self.a2
        a3 = self.a3
        assert repr(a1) == 'Atom::a1'
        assert repr(a2) == 'Atom::text\tatom'
    
    def test_bool(self):
        a1 = self.a1
        a2 = self.a2
        a3 = self.a3
        assert a1.atom()
        assert a2.atom()
        assert a3.atom()
        assert not a2.string()
        assert not a2.integer()
        assert not a2.compound()
        assert not a2.var()
        assert not a2.list()
        assert not a3.string()
        assert not a3.integer()
        assert not a3.compound()
        assert not a3.var()
        assert not a3.list()
        assert a1.ground()
        assert a2.ground()
        assert a3.ground()
    
    def test_decompose(self): 
        a1 = self.a1
        a2 = self.a2
        a3 = self.a3
        assert a1.get_value() == 'a1'
        assert a2.get_value() == 'text\tatom'

def make_atom_suite():
    suite = unittest.TestSuite()
    suite.addTest(test_atom('test_repr'))
    suite.addTest(test_atom('test_bool'))
    suite.addTest(test_atom('test_decompose'))
    return suite

class test_integer(unittest.TestCase):
    
    def setUp(self):
        self.i1 = Term.new_integer(42)
        self.i2 = Term.new_integer(0)
        self.i3 = Term.new_integer(-12345)
    
    def test_repr(self): 
        assert repr(self.i1) == 'Integer::42'
        assert repr(self.i2) == 'Integer::0'
        assert repr(self.i3) == 'Integer::-12345'
    
    def test_bool(self): 
        i1 = self.i1
        i2 = self.i2
        i3 = self.i3
        
        assert not i1.atom()
        assert not i1.compound()
        assert i1.ground()
        assert i1.integer()
        assert not i1.var()
        assert not i1.list()
        assert not i1.string()
        
        assert not i2.atom()
        assert not i2.compound()
        assert i2.ground()
        assert i2.integer()
        assert not i2.var()
        assert not i2.list()
        assert not i2.string()
        
        assert not i3.atom()
        assert not i3.compound()
        assert i3.ground()
        assert i3.integer()
        assert not i3.var()
        assert not i3.list()
        assert not i3.string()
    
    def test_decompose(self): 
        i1 = self.i1
        assert self.i1.get_value() == 42
        assert self.i2.get_value() == 0
        assert self.i3.get_value() == -12345

def make_integer_suite():
    suite = unittest.TestSuite()
    suite.addTest(test_integer('test_repr'))
    suite.addTest(test_integer('test_bool'))
    suite.addTest(test_integer('test_decompose'))
    return suite

class test_variable(unittest.TestCase):
    
    def setUp(self):
        self.v1 = Term.new_variable()
    
    def test_repr(self): 
        assert repr(self.v1)[:12] == 'Variable::_G'
    
    def test_bool(self): 
        v1 = self.v1
        
        assert not v1.atom()
        assert not v1.compound()
        assert not v1.ground()
        assert not v1.integer()
        assert v1.var()
        assert not v1.list()
        assert not v1.string()
    
    def test_decompose(self): 
        assert self.v1.get_value()[:2] == '_G'

def make_variable_suite():
    suite = unittest.TestSuite()
    suite.addTest(test_variable('test_repr'))
    suite.addTest(test_variable('test_bool'))
    suite.addTest(test_variable('test_decompose'))
    return suite

class test_compound(unittest.TestCase):
    
    def setUp(self):
        self.f1 = Term.new_compound('f1', 1)
        X = self.X = Term.new_variable()
        g = self.g = Term.new_compound('g', 'a', 2, -3.14)
        self.f2 = Term.new_compound('f2', g, X, X)
        m = Term.new_list('alpha', 'beta', 'gamma')
        self.member = Term.new_compound('member', X, m)
    
    def test_repr(self): 
        assert repr(self.f1) == 'Compound::f1(1)'
        s = 'Compound::f2(g(a, 2, -3.14), '
        assert repr(self.f2)[:len(s)] == s
    
    def test_bool(self): 
        f1 = self.f1
        f2 = self.f2
        
        assert not f1.atom()
        assert f1.compound()
        assert f1.ground()
        assert not f1.integer()
        assert not f1.var()
        assert not f1.list()
        assert not f1.string()

        assert not f2.atom()
        assert f2.compound()
        assert not f2.ground()
        assert not f2.integer()
        assert not f2.var()
        assert not f2.list()
        assert not f2.string()
    
    def test_decompose(self): 
        assert self.f1.name_string() == 'f1'
        f = self.f1.functor()
        assert f.atom() and f.get_value() == 'f1'
        assert self.f1.arity() == 1
        
        assert self.f2.name_string() == 'f2'
        assert self.f2.arity() == 3
        g = self.f2.get_arg(1)
        assert g.compound()
        assert g.arity() == 3
        X1 = self.f2.get_arg(2)
        X2 = self.f2.get_arg(3)
        assert repr(X1) == repr(X2)
    
    def test_call(self): 
        s = 'Variable::_G'
        assert repr(self.X)[:len(s)] == s
        assert self.member()
        assert repr(self.X) == 'Variable::alpha'

def make_compound_suite():
    suite = unittest.TestSuite()
    suite.addTest(test_compound('test_repr'))
    suite.addTest(test_compound('test_bool'))
    suite.addTest(test_compound('test_decompose'))
    suite.addTest(test_compound('test_call'))
    return suite

class test_from_string(unittest.TestCase):
    
    def setUp(self):
    	self.t1 = Term.term_from_string('a')
        self.t2 = Term.term_from_string('1')
        self.t3 = Term.term_from_string('3.2')
        # string interpretation depends on prolog_flag/2
        self.t4 = Term.term_from_string('"a b c"')
        self.t5 = Term.term_from_string('X')
        self.t6 = Term.term_from_string('g(a, f(_X, 1), -2.1)')
        self.t7 = Term.term_from_string("'a b c'")
    
    def test_bool(self): 
        assert self.t1.atom()
        assert self.t2.integer()
        assert self.t3.float()
        assert self.t4.list() # TBD: make prolog string
        assert self.t5.var()
        assert self.t6.compound()
        assert self.t7.atom()
        
    def test_decompose(self): 
        assert self.t1.get_value() == 'a'
        assert self.t2.get_value() == 1
        assert self.t3.get_value() == 3.2

def make_from_string_suite():
    suite = unittest.TestSuite()
    suite.addTest(test_from_string('test_bool'))
    suite.addTest(test_from_string('test_decompose'))
    return suite


def make_suite():
    suite = unittest.TestSuite()
    suite.addTest(make_atom_suite())
    suite.addTest(make_integer_suite())
    suite.addTest(make_variable_suite())
    suite.addTest(make_compound_suite())
    suite.addTest(make_from_string_suite())
    return suite

def main():
    runner = unittest.TextTestRunner()
    suite = make_suite()
    runner.run(suite)

if __name__ == '__main__':
    main()
   
# Local Variables:          
# mode:python               
# indent-tabs-mode: nil     
# py-indent-offset: 4  
# py-smart-indentation: nil 
# End:                      
