1# -*- coding: utf-8 -*-
2# MolMod is a collection of molecular modelling tools for python.
3# Copyright (C) 2007 - 2019 Toon Verstraelen <Toon.Verstraelen@UGent.be>, Center
4# for Molecular Modeling (CMM), Ghent University, Ghent, Belgium; all rights
5# reserved unless otherwise stated.
6#
7# This file is part of MolMod.
8#
9# MolMod is free software; you can redistribute it and/or
10# modify it under the terms of the GNU General Public License
11# as published by the Free Software Foundation; either version 3
12# of the License, or (at your option) any later version.
13#
14# MolMod is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with this program; if not, see <http://www.gnu.org/licenses/>
21#
22# --
23
24
25import unittest
26import pickle
27
28import numpy as np
29
30from molmod import *
31
32
33__all__ = ["UtilsTestCase"]
34
35
36class Example(ReadOnly):
37    a = ReadOnlyAttribute(none=False)
38    b = ReadOnlyAttribute()
39
40    def __init__(self, a, b=None):
41        self.a = a
42        self.b = b
43
44
45class TypeCheckExample(ReadOnly):
46    a = ReadOnlyAttribute(int)
47    b = ReadOnlyAttribute(np.ndarray)
48    c = ReadOnlyAttribute(np.ndarray, npdim=2)
49    d = ReadOnlyAttribute(np.ndarray, npshape=(None,3))
50    e = ReadOnlyAttribute(np.ndarray, npdtype=np.floating)
51
52
53class CustomCheckExample(ReadOnly):
54    def check_b(self, b):
55        if len(b) != self.a:
56            raise TypeError()
57
58    a = ReadOnlyAttribute(int, none=False)
59    b = ReadOnlyAttribute(np.ndarray, check=check_b, npdim=1, npdtype=np.integer)
60
61    def __init__(self, a, b=None):
62        self.a = a
63        self.b = b
64
65class SubExample(Example):
66    pass
67
68
69class UtilsTestCase(unittest.TestCase):
70    def test_pickle_read_only1(self):
71        test1 = Example(5)
72        s = pickle.dumps(test1)
73        test2 = pickle.loads(s)
74        self.assertEqual(test1.a, test2.a)
75        self.assertEqual(test1.b, None)
76        self.assertEqual(test2.b, None)
77        test1.b = "foo"
78        self.assertEqual(test1.b, "foo")
79
80    def test_pickle_read_only2(self):
81        test1 = Example(5, 3)
82        s = pickle.dumps(test1)
83        test2 = pickle.loads(s)
84        self.assertEqual(test1.a, test2.a)
85        self.assertEqual(test1.b, test2.b)
86
87    def check_type_error(self, fn, *args, **kwargs):
88        try:
89            test = fn(*args, **kwargs)
90            self.fail("Should have raised a TypeError")
91        except TypeError as e:
92            #print e
93            pass
94        except Exception as e:
95            self.fail("Should have raised a TypeError. Got %s" % e)
96
97    def test_assign_none(self):
98        self.check_type_error(Example, None)
99
100    def test_copy_with(self):
101        test1 = Example(5,4)
102        test2 = test1.copy_with(a=2)
103        assert(test2.a == 2)
104        assert(test2.b == 4)
105
106    def test_type_checking_correct(self):
107        test = TypeCheckExample()
108        test.a = 5
109        test.b = np.array([5, 3])
110        test.c = np.identity(2)
111        test.d = np.array([[[1.2], [3.5], [10.0]], [[7.1], [0.1], [0.2]]])
112        test.e = np.array([4.2, 3.1])
113
114    def test_type_checking_wrong(self):
115        test = TypeCheckExample()
116        self.check_type_error(setattr, test, "a", "foo")
117        self.check_type_error(setattr, test, "b", test)
118        self.check_type_error(setattr, test, "c", np.array([2, 3]))
119        self.check_type_error(setattr, test, "d", np.array([2, 3]))
120        test.c = np.identity(2)
121        test.d = np.array([[1.2, 3.5, 10.0], [7.1, 0.1, 0.2]])
122        test.e = np.array([4.2, 3.1])
123
124    def test_assign_list(self):
125        self.check_type_error(Example, [4, 5])
126
127    def test_custon_check_correct(self):
128        test = CustomCheckExample(5)
129        test.b = np.zeros(5, int)
130
131    def test_custon_check_wrong(self):
132        test = CustomCheckExample(5)
133        self.check_type_error(setattr, test, "b", np.zeros(4, int))
134
135    def test_sub(self):
136        test1 = SubExample(5)
137        s = pickle.dumps(test1)
138        test2 = pickle.loads(s)
139        self.assertEqual(test1.a, test2.a)
140        self.assertEqual(test1.b, None)
141        self.assertEqual(test2.b, None)
142        test1.b = "foo"
143        self.assertEqual(test1.b, "foo")
144        test2 = test1.copy_with(a=3)
145        self.assertEqual(test2.a, 3)
146        self.assertEqual(test1.b, test1.b)
147