Erik Grinaker is sharing code with you

Bitbucket is a code hosting site. Unlimited public and private repositories. Free for small teams.

Don't show this again

erikg / Revelation

Revelation is a password manager for the GNOME desktop, released under the GNU GPL license. It stores all your accounts and passwords in a single, secure place, and gives you access to it through a user-friendly graphical interface.

Clone this repository (size: 2.1 MB): HTTPS / SSH
hg clone https://bitbucket.org/erikg/revelation
hg clone ssh://hg@bitbucket.org/erikg/revelation

Revelation / test / util.py

commit
35864a73a048
parent
070d0062872f
branch
default
tags
revelation-0.4.3

bumped version number to 0.4.3

1
4b0901db17b8
#!/usr/bin/env python
2
4b0901db17b8
3
4b0901db17b8
#
4
35864a73a048
# Revelation 0.4.3 - a password manager for GNOME 2
5
4b0901db17b8
# http://oss.codepoet.no/revelation/
6
4b0901db17b8
# $Id$
7
4b0901db17b8
#
8
4b0901db17b8
# Unit tests for util module
9
4b0901db17b8
#
10
4b0901db17b8
#
11
07c1fb2b0c27
# Copyright (c) 2003-2005 Erik Grinaker
12
4b0901db17b8
#
13
4b0901db17b8
# This program is free software; you can redistribute it and/or
14
4b0901db17b8
# modify it under the terms of the GNU General Public License
15
4b0901db17b8
# as published by the Free Software Foundation; either version 2
16
4b0901db17b8
# of the License, or (at your option) any later version.
17
4b0901db17b8
#
18
4b0901db17b8
# This program is distributed in the hope that it will be useful,
19
4b0901db17b8
# but WITHOUT ANY WARRANTY; without even the implied warranty of
20
4b0901db17b8
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21
4b0901db17b8
# GNU General Public License for more details.
22
4b0901db17b8
#
23
4b0901db17b8
# You should have received a copy of the GNU General Public License
24
4b0901db17b8
# along with this program; if not, write to the Free Software
25
4b0901db17b8
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
26
4b0901db17b8
#
27
4b0901db17b8
28
844b1865225e
import os, sys, time, unittest, xml.dom.minidom
29
4b0901db17b8
30
4b0901db17b8
from revelation import util
31
4b0901db17b8
32
4b0901db17b8
33
4b0901db17b8
34
844b1865225e
class dom_text(unittest.TestCase):
35
844b1865225e
	"dom_text()"
36
844b1865225e
37
844b1865225e
	def test_children(self):
38
844b1865225e
		"dom_text() ignores children"
39
844b1865225e
40
844b1865225e
		dom = xml.dom.minidom.parseString("<?xml version=\"1.0\" ?><root>test<child>123</child>test</root>")
41
844b1865225e
		self.assertEquals(util.dom_text(dom.documentElement), "testtest")
42
844b1865225e
43
844b1865225e
44
844b1865225e
	def test_text(self):
45
844b1865225e
		"dom_text() returns text contents"
46
844b1865225e
47
844b1865225e
		dom = xml.dom.minidom.parseString("<?xml version=\"1.0\" ?><root>test123</root>")
48
844b1865225e
		self.assertEquals(util.dom_text(dom.documentElement), "test123")
49
844b1865225e
50
844b1865225e
51
844b1865225e
	def test_whitespace(self):
52
844b1865225e
		"dom_text() preserves whitespace"
53
844b1865225e
54
844b1865225e
		dom = xml.dom.minidom.parseString("<?xml version=\"1.0\" ?><root>\n\ttest123 \n</root>")
55
844b1865225e
		self.assertEquals(util.dom_text(dom.documentElement), "\n\ttest123 \n")
56
844b1865225e
57
844b1865225e
58
844b1865225e
59
4b0901db17b8
class escape_markup(unittest.TestCase):
60
4b0901db17b8
	"escape_markup()"
61
4b0901db17b8
62
4b0901db17b8
	def test_amp(self):
63
4b0901db17b8
		"escape_markup() replaces & with &amp;"
64
4b0901db17b8
65
4b0901db17b8
		self.assertEqual(
66
4b0901db17b8
			util.escape_markup("test&123"),
67
4b0901db17b8
			"test&123".replace("&", "&amp;")
68
4b0901db17b8
		)
69
4b0901db17b8
70
4b0901db17b8
71
4b0901db17b8
	def test_gt(self):
72
4b0901db17b8
		"escape_markup() replaces > with &gt;"
73
4b0901db17b8
74
4b0901db17b8
		self.assertEqual(
75
4b0901db17b8
			util.escape_markup("test>123"),
76
4b0901db17b8
			"test>123".replace(">", "&gt;")
77
4b0901db17b8
		)
78
4b0901db17b8
79
4b0901db17b8
80
4b0901db17b8
	def test_lt(self):
81
4b0901db17b8
		"escape_markup() replaces < with &lt;"
82
4b0901db17b8
83
4b0901db17b8
		self.assertEqual(
84
4b0901db17b8
			util.escape_markup("test<123"),
85
4b0901db17b8
			"test<123".replace("<", "&lt;")
86
4b0901db17b8
		)
87
4b0901db17b8
88
4b0901db17b8
89
4b0901db17b8
90
4b0901db17b8
class execute(unittest.TestCase):
91
4b0901db17b8
	"execute()"
92
4b0901db17b8
93
4b0901db17b8
	def test_output(self):
94
4b0901db17b8
		"execute() returns output"
95
4b0901db17b8
96
4b0901db17b8
		self.assertEqual(util.execute("echo -n test123")[0], "test123")
97
4b0901db17b8
98
4b0901db17b8
99
4b0901db17b8
	def test_run(self):
100
4b0901db17b8
		"execute() runs command"
101
4b0901db17b8
102
4b0901db17b8
		if os.access("/tmp/exectest", os.F_OK):
103
4b0901db17b8
			os.unlink("/tmp/exectest")
104
4b0901db17b8
105
4b0901db17b8
		util.execute("touch /tmp/exectest")
106
4b0901db17b8
107
4b0901db17b8
		self.assertEqual(os.access("/tmp/exectest", os.F_OK), True)
108
4b0901db17b8
109
4b0901db17b8
110
4b0901db17b8
	def test_status(self):
111
4b0901db17b8
		"execute() returns status code"
112
4b0901db17b8
113
4b0901db17b8
		self.assertEqual(util.execute("exit 0")[1], 0)
114
4b0901db17b8
		self.assertEqual(util.execute("exit 1")[1], 1)
115
4b0901db17b8
		self.assertEqual(util.execute("exit 52")[1], 52)
116
4b0901db17b8
117
4b0901db17b8
118
4b0901db17b8
119
4b0901db17b8
class execute_child(unittest.TestCase):
120
4b0901db17b8
	"execute_child()"
121
4b0901db17b8
122
4b0901db17b8
	def test_nowait(self):
123
4b0901db17b8
		"execute_child() doesn't wait"
124
4b0901db17b8
125
4b0901db17b8
		start = time.time()
126
4b0901db17b8
		util.execute_child("sleep 2")
127
4b0901db17b8
		self.assertEqual(start > time.time() - 1, True)
128
4b0901db17b8
129
4b0901db17b8
130
4b0901db17b8
	def test_pid(self):
131
4b0901db17b8
		"execute_child() returns process id"
132
4b0901db17b8
133
4b0901db17b8
		pid = util.execute_child("sleep 1")
134
4b0901db17b8
		waitdata = os.waitpid(pid, 0)
135
4b0901db17b8
136
4b0901db17b8
		self.assertEqual(pid, waitdata[0])
137
4b0901db17b8
138
4b0901db17b8
139
4b0901db17b8
	def test_run(self):
140
4b0901db17b8
		"execute_child() runs command"
141
4b0901db17b8
142
4b0901db17b8
		if os.access("/tmp/exectest", os.F_OK):
143
4b0901db17b8
			os.unlink("/tmp/exectest")
144
4b0901db17b8
145
4b0901db17b8
		util.execute_child("touch /tmp/exectest")
146
4b0901db17b8
		time.sleep(1)
147
4b0901db17b8
		self.assertEqual(os.access("/tmp/exectest", os.F_OK), True)
148
4b0901db17b8
149
4b0901db17b8
150
4b0901db17b8
151
4b0901db17b8
class generate_password(unittest.TestCase):
152
4b0901db17b8
	"generate_password()"
153
4b0901db17b8
154
4b0901db17b8
	def test_ambiguous(self):
155
4b0901db17b8
		"generate_password() avoids ambiguous chars when told"
156
4b0901db17b8
157
4b0901db17b8
		for i in range(100):
158
4b0901db17b8
			password = util.generate_password(256, True)
159
4b0901db17b8
160
4b0901db17b8
			for char in "0OIl1S5qg":
161
4b0901db17b8
				self.assertEqual(
162
4b0901db17b8
					char in password,
163
4b0901db17b8
					False
164
4b0901db17b8
				)
165
4b0901db17b8
166
4b0901db17b8
167
4b0901db17b8
	def test_digits(self):
168
4b0901db17b8
		"generate_password() always includes a digit"
169
4b0901db17b8
170
4b0901db17b8
		for i in range(100):
171
4b0901db17b8
			for char in util.generate_password(8):
172
4b0901db17b8
				if char.isdigit():
173
4b0901db17b8
					digit = True
174
4b0901db17b8
					break
175
4b0901db17b8
176
4b0901db17b8
			else:
177
4b0901db17b8
				digit = False
178
4b0901db17b8
179
4b0901db17b8
			self.assertEqual(digit, True)
180
4b0901db17b8
181
4b0901db17b8
182
4b0901db17b8
	def test_length(self):
183
4b0901db17b8
		"generate_password() returns string of correct length"
184
4b0901db17b8
185
4b0901db17b8
		for length in 1, 5, 17, 54, 270:
186
4b0901db17b8
			self.assertEqual(
187
4b0901db17b8
				len(util.generate_password(length)),
188
4b0901db17b8
				length
189
4b0901db17b8
			)
190
4b0901db17b8
191
4b0901db17b8
192
4b0901db17b8
	def test_lowercase(self):
193
4b0901db17b8
		"generate_password() always includes a lowercase char"
194
4b0901db17b8
195
4b0901db17b8
		for i in range(100):
196
4b0901db17b8
			for char in util.generate_password(8):
197
4b0901db17b8
				if char.islower():
198
4b0901db17b8
					lower = True
199
4b0901db17b8
					break
200
4b0901db17b8
201
4b0901db17b8
			else:
202
4b0901db17b8
				lower = False
203
4b0901db17b8
204
4b0901db17b8
			self.assertEqual(lower, True)
205
4b0901db17b8
206
4b0901db17b8
207
4b0901db17b8
	def test_random(self):
208
4b0901db17b8
		"generate_password() returns random string"
209
4b0901db17b8
210
4b0901db17b8
		for i in range(3):
211
4b0901db17b8
			self.assertNotEqual(
212
4b0901db17b8
				util.generate_password(8),
213
4b0901db17b8
				util.generate_password(8)
214
4b0901db17b8
			)
215
4b0901db17b8
216
4b0901db17b8
217
4b0901db17b8
	def test_uppercase(self):
218
4b0901db17b8
		"generate_password() always includes an uppercase char"
219
4b0901db17b8
220
4b0901db17b8
		for i in range(100):
221
4b0901db17b8
			for char in util.generate_password(8):
222
4b0901db17b8
				if char.isupper():
223
4b0901db17b8
					upper = True
224
4b0901db17b8
					break
225
4b0901db17b8
226
4b0901db17b8
			else:
227
4b0901db17b8
				upper = False
228
4b0901db17b8
229
4b0901db17b8
			self.assertEqual(upper, True)
230
4b0901db17b8
231
4b0901db17b8
232
500cdfa073b3
class pad_right(unittest.TestCase):
233
500cdfa073b3
	"pad_right()"
234
500cdfa073b3
235
500cdfa073b3
	def test_longstring(self):
236
500cdfa073b3
		"pad_right() returns entire string when too long"
237
500cdfa073b3
238
500cdfa073b3
		self.assertEquals(util.pad_right("jeje123", 5), "jeje123")
239
500cdfa073b3
240
500cdfa073b3
241
500cdfa073b3
	def test_none(self):
242
500cdfa073b3
		"pad_right() returns None when passed None"
243
500cdfa073b3
244
500cdfa073b3
		self.assertEquals(util.pad_right(None, 10), None)
245
500cdfa073b3
246
500cdfa073b3
247
500cdfa073b3
	def test_pad(self):
248
500cdfa073b3
		"pad_right() pads correctly"
249
500cdfa073b3
250
500cdfa073b3
		self.assertEquals(util.pad_right("jeje123", 10, "a"), "jeje123aaa")
251
500cdfa073b3
252
4b0901db17b8
253
355e05c49e3d
class parse_subst(unittest.TestCase):
254
355e05c49e3d
	"parse_subst()"
255
355e05c49e3d
256
355e05c49e3d
	def test_complex(self):
257
355e05c49e3d
		"parse_subst() handles complex expressions"
258
355e05c49e3d
259
355e05c49e3d
		map = {
260
355e05c49e3d
			"u" : "erikg",
261
355e05c49e3d
			"p" : "",
262
355e05c49e3d
			"h" : "localhost",
263
355e05c49e3d
			"d" : "test",
264
355e05c49e3d
			"D" : ""
265
355e05c49e3d
		}
266
355e05c49e3d
267
355e05c49e3d
		s = "/usr/bin/mysql %(-u %u%) %(--password=%p%) %(-H %h%) %d %?D"
268
355e05c49e3d
		r = "/usr/bin/mysql -u erikg  -H localhost test "
269
355e05c49e3d
270
355e05c49e3d
		self.assertEquals(util.parse_subst(s, map), r)
271
355e05c49e3d
272
355e05c49e3d
273
355e05c49e3d
	def test_empty(self):
274
355e05c49e3d
		"parse_subst() handles empty strings"
275
355e05c49e3d
276
355e05c49e3d
		self.assertEquals(util.parse_subst("", {}), "")
277
355e05c49e3d
278
355e05c49e3d
279
355e05c49e3d
	def test_inv_var(self):
280
355e05c49e3d
		"parse_subst() raises SubstFormatError on unknown variable"
281
355e05c49e3d
282
355e05c49e3d
		self.assertRaises(util.SubstFormatError, util.parse_subst, "test %a 123", { "b": "item" })
283
355e05c49e3d
		self.assertRaises(util.SubstFormatError, util.parse_subst, "test %?a 123", { "b": "item" })
284
355e05c49e3d
		self.assertRaises(util.SubstFormatError, util.parse_subst, "test%( %a%) 123", { "b": "item" })
285
355e05c49e3d
286
355e05c49e3d
287
355e05c49e3d
	def test_inv_value(self):
288
355e05c49e3d
		"parse_subst() raises SubstValueError on empty variable value"
289
355e05c49e3d
290
355e05c49e3d
		self.assertRaises(util.SubstValueError, util.parse_subst, "test %a 123", { "a": "" })
291
355e05c49e3d
292
355e05c49e3d
293
355e05c49e3d
	def test_inv_substring(self):
294
355e05c49e3d
		"parse_subst() raises FormatError on non-closed substring"
295
355e05c49e3d
296
355e05c49e3d
		self.assertRaises(util.SubstFormatError, util.parse_subst, "test%( %a 123", { "b": "item" })
297
355e05c49e3d
298
355e05c49e3d
299
355e05c49e3d
	def test_escape(self):
300
355e05c49e3d
		"parse_subst() handles % escapes"
301
355e05c49e3d
302
355e05c49e3d
		self.assertEquals(util.parse_subst("te%%st", {}), "te%st")
303
355e05c49e3d
304
355e05c49e3d
305
355e05c49e3d
	def test_normal(self):
306
355e05c49e3d
		"parse_subst() ignores normal characters"
307
355e05c49e3d
308
355e05c49e3d
		s = "aBidU&72!78>,-4=*`-fui(Hd"
309
355e05c49e3d
		self.assertEquals(util.parse_subst(s, {}), s)
310
355e05c49e3d
311
355e05c49e3d
312
355e05c49e3d
	def test_optional(self):
313
355e05c49e3d
		"parse_subst() handles optional variables"
314
355e05c49e3d
315
355e05c49e3d
		self.assertEquals(
316
355e05c49e3d
			util.parse_subst(
317
355e05c49e3d
				"test %a %?b 123",
318
355e05c49e3d
				{ "a" : "item", "b" : "" }
319
355e05c49e3d
			),
320
355e05c49e3d
			"test item  123"
321
355e05c49e3d
		)
322
355e05c49e3d
323
355e05c49e3d
		self.assertEquals(
324
355e05c49e3d
			util.parse_subst(
325
355e05c49e3d
				"test %a %?b 123",
326
355e05c49e3d
				{ "a" : "item", "b" : "optional" }
327
355e05c49e3d
			),
328
355e05c49e3d
			"test item optional 123"
329
355e05c49e3d
		)
330
355e05c49e3d
331
355e05c49e3d
332
355e05c49e3d
	def test_subst(self):
333
355e05c49e3d
		"parse_subst() handles variable expansion"
334
355e05c49e3d
335
355e05c49e3d
		self.assertEquals(
336
355e05c49e3d
			util.parse_subst(
337
355e05c49e3d
				"test %a %b 123",
338
355e05c49e3d
				{ "a" : "item", "b" : "item2" }
339
355e05c49e3d
			),
340
355e05c49e3d
			"test item item2 123"
341
355e05c49e3d
		)
342
355e05c49e3d
343
355e05c49e3d
344
355e05c49e3d
	def test_substring(self):
345
355e05c49e3d
		"parse_subst() handles substring expansion"
346
355e05c49e3d
347
355e05c49e3d
		self.assertEquals(
348
355e05c49e3d
			util.parse_subst(
349
355e05c49e3d
				"test %a%( %b %%%) 123",
350
355e05c49e3d
				{ "a" : "item", "b" : "" }
351
355e05c49e3d
			),
352
355e05c49e3d
			"test item 123"
353
355e05c49e3d
		)
354
355e05c49e3d
355
355e05c49e3d
		self.assertEquals(
356
355e05c49e3d
			util.parse_subst(
357
355e05c49e3d
				"test %a%( %b %%%) 123",
358
355e05c49e3d
				{ "a" : "item", "b" : "optional" }
359
355e05c49e3d
			),
360
355e05c49e3d
			"test item optional % 123"
361
355e05c49e3d
		)
362
355e05c49e3d
363
355e05c49e3d
364
355e05c49e3d
365
4b0901db17b8
class random_string(unittest.TestCase):
366
4b0901db17b8
	"random_string()"
367
4b0901db17b8
368
4b0901db17b8
	def test_length(self):
369
4b0901db17b8
		"random_string() returns string of correct length"
370
4b0901db17b8
371
4b0901db17b8
		for length in 1, 5, 17, 54, 270:
372
4b0901db17b8
			self.assertEqual(
373
4b0901db17b8
				len(util.random_string(length)),
374
4b0901db17b8
				length
375
4b0901db17b8
			)
376
4b0901db17b8
377
4b0901db17b8
378
4b0901db17b8
	def test_random(self):
379
4b0901db17b8
		"random_string() returns a random string"
380
4b0901db17b8
381
4b0901db17b8
		for i in range(3):
382
4b0901db17b8
			self.assertNotEqual(
383
4b0901db17b8
				util.random_string(8),
384
4b0901db17b8
				util.random_string(8)
385
4b0901db17b8
			)
386
4b0901db17b8
387
4b0901db17b8
388
4b0901db17b8
389
4b0901db17b8
class time_period_rough(unittest.TestCase):
390
4b0901db17b8
	"time_period_rough()"
391
4b0901db17b8
392
4b0901db17b8
	def test_endfirst(self):
393
4b0901db17b8
		"time_period_rough() returns '0 seconds' when end-time is earliest"
394
4b0901db17b8
395
4b0901db17b8
		self.assertEqual(
396
4b0901db17b8
			util.time_period_rough(1098565803, 1098565800),
397
4b0901db17b8
			"0 seconds"
398
4b0901db17b8
		)
399
4b0901db17b8
400
4b0901db17b8
401
4b0901db17b8
	def test_results(self):
402
4b0901db17b8
		"time_period_rough() returns correct results"
403
4b0901db17b8
404
4b0901db17b8
		data = (
405
4b0901db17b8
406
4b0901db17b8
			# year intervals
407
4b0901db17b8
			( "2004-10-23 10:00:00", "2005-10-23 10:00:00", "1 year" ),
408
4b0901db17b8
			( "2004-10-23 10:00:00", "2006-10-23 09:59:59", "1 year" ),
409
4b0901db17b8
			( "2004-10-23 10:00:00", "2007-02-11 15:14:31", "2 years" ),
410
4b0901db17b8
			( "2004-10-23 10:00:00", "2015-12-11 15:14:31", "11 years" ),
411
4b0901db17b8
412
4b0901db17b8
			# month intervals
413
4b0901db17b8
			( "2004-10-23 10:00:00", "2004-11-23 10:00:00", "1 month" ),
414
b6859b8eb257
			( "2004-10-23 10:00:00", "2004-12-23 09:59:59", "1 month" ),
415
b6859b8eb257
			( "2004-02-01 10:00:00", "2004-03-01 10:00:00", "1 month" ),
416
4b0901db17b8
			( "2004-10-23 10:00:00", "2004-12-23 10:00:00", "2 months" ),
417
4b0901db17b8
			( "2004-10-23 10:00:00", "2005-03-07 23:11:42", "4 months" ),
418
4b0901db17b8
			( "2004-10-23 10:00:00", "2005-10-23 09:59:59", "11 months" ),
419
4b0901db17b8
420
4b0901db17b8
			# week intervals
421
4b0901db17b8
			( "2004-10-23 10:00:00", "2004-10-30 10:00:00", "1 week" ),
422
4b0901db17b8
			( "2004-10-23 10:00:00", "2004-10-31 15:41:11", "1 week" ),
423
4b0901db17b8
			( "2004-10-23 10:00:00", "2004-11-23 09:59:59", "4 weeks" ),
424
4b0901db17b8
			( "2004-10-23 10:00:00", "2004-11-06 18:11:21", "2 weeks" ),
425
4b0901db17b8
426
4b0901db17b8
			# day intervals
427
4b0901db17b8
			( "2004-10-23 10:00:00", "2004-10-24 10:00:00", "1 day" ),
428
4b0901db17b8
			( "2004-10-23 10:00:00", "2004-10-25 09:59:59", "1 day" ),
429
4b0901db17b8
			( "2004-10-23 10:00:00", "2004-10-25 10:00:00", "2 days" ),
430
4b0901db17b8
			( "2004-10-23 10:00:00", "2004-10-29 19:21:47", "6 days" ),
431
4b0901db17b8
			( "2004-10-30 10:00:00", "2004-11-03 04:13:17", "3 days" ),
432
4b0901db17b8
			( "2004-12-29 08:11:45", "2005-01-03 10:48:53", "5 days" ),
433
4b0901db17b8
434
4b0901db17b8
435
4b0901db17b8
			# hour intervals
436
4b0901db17b8
			( "2004-10-23 10:00:00", "2004-10-23 11:00:00", "1 hour" ),
437
4b0901db17b8
			( "2004-10-23 10:00:00", "2004-10-23 11:53:24", "1 hour" ),
438
4b0901db17b8
			( "2004-10-23 10:00:00", "2004-10-23 12:00:00", "2 hours" ),
439
4b0901db17b8
			( "2004-10-23 10:00:00", "2004-10-23 19:59:59", "9 hours" ),
440
4b0901db17b8
			( "2004-10-23 05:32:11", "2004-10-23 14:18:32", "8 hours" ),
441
4b0901db17b8
			( "2004-10-23 10:00:00", "2004-10-24 09:59:59", "23 hours" ),
442
4b0901db17b8
			( "2004-10-31 10:00:00", "2004-11-01 04:42:11", "18 hours" ),
443
4b0901db17b8
			( "2004-12-31 17:43:11", "2005-01-01 11:18:55", "17 hours" ),
444
4b0901db17b8
445
4b0901db17b8
			# minute intervals
446
4b0901db17b8
			( "2004-10-23 10:00:00", "2004-10-23 10:01:00", "1 minute" ),
447
4b0901db17b8
			( "2004-10-23 10:00:00", "2004-10-23 10:01:13", "1 minute" ),
448
4b0901db17b8
			( "2004-10-23 10:00:00", "2004-10-23 10:02:00", "2 minutes" ),
449
4b0901db17b8
			( "2004-10-23 10:00:00", "2004-10-23 10:24:41", "24 minutes" ),
450
4b0901db17b8
			( "2004-10-23 10:00:00", "2004-10-23 10:59:59", "59 minutes" ),
451
4b0901db17b8
			( "2004-10-23 10:42:28", "2004-10-23 11:18:04", "35 minutes" ),
452
4b0901db17b8
			( "2004-10-23 23:57:21", "2004-10-24 00:13:22", "16 minutes" ),
453
4b0901db17b8
			( "2004-10-31 23:57:21", "2004-11-01 00:13:22", "16 minutes" ),
454
4b0901db17b8
			( "2004-12-31 23:57:21", "2005-01-01 00:13:22", "16 minutes" ),
455
4b0901db17b8
456
4b0901db17b8
			# second intervals
457
4b0901db17b8
			( "2004-10-23 10:00:00", "2004-10-23 10:00:00", "0 seconds" ),
458
4b0901db17b8
			( "2004-10-23 10:00:00", "2004-10-23 10:00:01", "1 second" ),
459
4b0901db17b8
			( "2004-10-23 10:00:00", "2004-10-23 10:00:23", "23 seconds" ),
460
4b0901db17b8
			( "2004-10-23 10:00:00", "2004-10-23 10:00:59", "59 seconds" ),
461
4b0901db17b8
			( "2004-10-23 12:59:48", "2004-10-23 13:00:12", "24 seconds" ),
462
4b0901db17b8
			( "2004-10-23 23:59:43", "2004-10-24 00:00:22", "39 seconds" ),
463
4b0901db17b8
			( "2004-10-31 23:59:43", "2004-11-01 00:00:22", "39 seconds" ),
464
4b0901db17b8
			( "2004-12-31 23:59:43", "2005-01-01 00:00:22", "39 seconds" )
465
4b0901db17b8
		)
466
4b0901db17b8
467
4b0901db17b8
		for start, end, range in data:
468
4b0901db17b8
			start = time.mktime((int(start[0:4]), int(start[5:7]), int(start[8:10]), int(start[11:13]), int(start[14:16]), int(start[17:19]), 0, 1, 0))
469
4b0901db17b8
			end = time.mktime((int(end[0:4]), int(end[5:7]), int(end[8:10]), int(end[11:13]), int(end[14:16]), int(end[17:19]), 0, 1, 0))
470
4b0901db17b8
471
4b0901db17b8
			self.assertEqual(
472
4b0901db17b8
				util.time_period_rough(start, end),
473
4b0901db17b8
				range
474
4b0901db17b8
			)
475
4b0901db17b8
476
4b0901db17b8
477
4b0901db17b8
478
844b1865225e
class trace_exception(unittest.TestCase):
479
844b1865225e
	"trace_exception()"
480
844b1865225e
481
844b1865225e
	def test_exception(self):
482
844b1865225e
		"trace_exception() generates a traceback for an exception"
483
844b1865225e
484
844b1865225e
		try:
485
844b1865225e
			raise IOError
486
844b1865225e
487
844b1865225e
		except IOError:
488
844b1865225e
			type, value, tb = sys.exc_info()
489
844b1865225e
			self.assertEquals(util.trace_exception(type, value, tb) not in ( None, "" ), True)
490
844b1865225e
491
844b1865225e
492
844b1865225e
493
4b0901db17b8
if __name__ == "__main__":
494
4b0901db17b8
	unittest.main()
495
4b0901db17b8