Add functions to convert bytes to human readable form.

Binary and decimal modes are supported (MB and MiB ie.)
It supports i18n using gettext and locale.
Precision can be modified if needed, by default it is using 1 digit (if needed).

Extensive tests were written, the toughest was to make them work for
both default C locale and fr_FR.UTF-8 locale (ofc it is possible to test for more
locales...). If one locale isn't available on testing system, test is skipped.
fr locale was chosen because decimal point is replaced by a comma and byte units
becomes "octet" units (1.5 MB in english -> 1,5 Mo in french).
This commit is contained in:
Laurent Monin
2013-05-27 12:50:16 +02:00
parent 429242f1c8
commit 6de59d8ee9
5 changed files with 441 additions and 0 deletions

99
test/test_bytes2human.py Normal file
View File

@@ -0,0 +1,99 @@
import locale
import os.path
import shutil
import subprocess
import sys
import tempfile
import unittest
from picard.i18n import setup_gettext
from picard.util import bytes2human
class Testbytes2human(unittest.TestCase):
def setUp(self):
# we are using temporary locales for tests
self.tmp_path = tempfile.mkdtemp().decode("utf-8")
if sys.hexversion >= 0x020700F0:
self.addCleanup(shutil.rmtree, self.tmp_path)
self.localedir = os.path.join(self.tmp_path, 'locale')
test_locales = [('picard', 'fr', 'test/po/fr.po')]
for domain, locale, po in test_locales:
path = os.path.join(self.localedir, locale, 'LC_MESSAGES')
os.makedirs(path)
mo = os.path.join(path, '%s.mo' % domain)
assert(subprocess.call(['msgfmt', '-o', mo, po]) == 0)
def tearDown(self):
if sys.hexversion < 0x020700F0:
shutil.rmtree(self.tmp_path)
def test_00(self):
# testing with default C locale, english
lang = 'C'
setup_gettext(self.localedir, lang)
self.run_test(lang)
self.assertEqual(bytes2human.binary(45682), '44.6 KiB')
self.assertEqual(bytes2human.binary(-45682), '-44.6 KiB')
self.assertEqual(bytes2human.decimal(45682), '45.7 kB')
self.assertEqual(bytes2human.decimal(9223372036854775807), '9223.4 PB')
self.assertEqual(bytes2human.decimal(123.6), '123 B')
self.assertRaises(ValueError, bytes2human.decimal, 'xxx')
self.assertRaises(ValueError, bytes2human.decimal, '123.6')
self.assertRaises(ValueError, bytes2human.binary, 'yyy')
self.assertRaises(ValueError, bytes2human.binary, '456yyy')
try:
bytes2human.decimal(u'123')
except Exception as e:
self.fail('Unexpected exception: %s' % e)
def test_05(self):
# testing with french locale and translation
# 1.5 MiB -> 1,5 Mio
lang = 'fr_FR.UTF-8'
setup_gettext(self.localedir, lang)
self.run_test(lang)
def run_test(self, lang = 'C', create_test_data=False):
"""
Compare data generated with sample files
Setting create_test_data to True will generated sample files
from code execution (developper-only, check carefully)
"""
filename = os.path.join('test', 'data', 'b2h_test_%s.dat' % lang)
testlist = self._create_testlist()
if create_test_data:
self._save_expected_to(filename, testlist)
expected = self._read_expected_from(filename)
#self.maxDiff = None
self.assertEqual(testlist, expected)
if create_test_data:
# be sure it is disabled
self.fail('!!! UNSET create_test_data mode !!! (%s)' % filename)
def _create_testlist(self):
values = [0, 1]
for n in [1000, 1024]:
p = 1
for e in range(0,6):
p *= n
for x in [0.1, 0.5, 0.99, 0.9999, 1, 1.5]:
values.append(int(p*x))
l = []
for x in sorted(values):
l.append(";".join([str(x), bytes2human.decimal(x),
bytes2human.binary(x),
bytes2human.short_string(x, 1024, 2)]))
return l
def _save_expected_to(self, path, a_list):
with open(path, 'wb') as f:
f.writelines([l + "\n" for l in a_list])
f.close()
def _read_expected_from(self, path):
with open(path, 'rb') as f:
lines = [l.rstrip("\n") for l in f.readlines()]
f.close()
return lines