diff --git a/setup.py b/setup.py
new file mode 100644
index 0000000..8a52596
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,52 @@
+#
+# Sam Hadow - Huffman-py
+# Copyright (C) 2023
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+
+from setuptools import setup, find_packages
+
+
+# 'pip install .' in project directory to install
+setup(
+ name='huffman_py',
+ version='1.0',
+ author='Sam Hadow',
+ author_email='sam.hadow@inbox.lv',
+ license='GPLv3+',
+ description='Huffman algorithm implementation in Python, QT GUI',
+ package_dir={'huffman_py':'huffman_py'},
+ entry_points={
+ 'console_scripts': [
+ 'huffman_py=huffman_py.main:main',
+ ],
+ },
+ classifiers=[
+ 'Programming Language :: Python :: 3',
+ 'Programming Language :: Python :: 3.10',
+ ],
+ python_requires='>=3.10',
+ install_requires=[
+ 'graphviz>=0.20',
+ 'PyQt5>=5.15.9',
+ 'PyQt5-Qt5>=5.15.2',
+ 'PyQt5-sip>=12.11.1',
+ ],
+ options={
+ 'bdist_wheel': {
+ 'universal': True,
+ },
+ },
+)
diff --git a/test_huffman.py b/test_huffman.py
new file mode 100644
index 0000000..933aa8e
--- /dev/null
+++ b/test_huffman.py
@@ -0,0 +1,141 @@
+#
+# Sam Hadow - Huffman-py
+# Copyright (C) 2023
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+
+import unittest
+from huffman_py.Sommets import *
+from huffman_py.Arbre import *
+from huffman_py.fonctions.encode import *
+from huffman_py.fonctions.decode import *
+from huffman_py.fonctions.occurence import *
+
+# pour lancer les tests utilisez:
+# python -m unittest discover
+
+class TestUtils(unittest.TestCase):
+ def test_Arbre_id(self):
+ a = Sommets(10, 'a')
+ b = Sommets(8,'b')
+ r1 = Sommets(18,'',left=b,right=a)
+
+ arbre1 = Arbre(r1)
+
+ # vérification affectation d'un identifiant unique en créant l'arbre
+ liste_id = []
+ verification_id = True
+ for elem in arbre1.sommets:
+ liste_id.append(elem.identifiant)
+ if len(liste_id) > len(set(liste_id)):
+ verification_id = False
+
+ self.assertTrue(verification_id)
+
+ def test_Arbre_fusion(self):
+ # fusion des arbres
+ # on doit retrouver les éléments des 2 arbres + une nouvelle racine
+ # les identifiants doivent toujours être uniques
+ a = Sommets(10, 'a')
+ b = Sommets(8,'b')
+ r1 = Sommets(18,'',left=b,right=a)
+ c = Sommets(15, 'c')
+ d = Sommets(20,'d')
+ r2 = Sommets(18,'',left=d,right=c)
+
+ arbre1 = Arbre(r1)
+ arbre2 = Arbre(r2)
+
+ l1 = len(arbre1.sommets)
+ l2 = len(arbre2.sommets)
+ arbre1 += arbre2
+ verification_fusion = True
+ if l1+l2+1 != len(arbre1.sommets):
+ verification_fusion = False
+
+ liste_id2 = []
+ verification_id2 = True
+ for elem in arbre1.sommets:
+ liste_id2.append(elem.identifiant)
+ if len(liste_id2) > len(set(liste_id2)):
+ verification_id2 = False
+
+ self.assertTrue(verification_fusion)
+ self.assertTrue(verification_id2)
+
+ def test_Arbre_recherche(self):
+ # recherche de sommet
+ a = Sommets(10, 'a')
+ b = Sommets(8,'b')
+ r1 = Sommets(18,'',left=b,right=a)
+
+ arbre1 = Arbre(r1)
+
+ self.assertEqual(arbre1.recherche(a),a)
+ self.assertNotEqual(arbre1.recherche(b),a)
+
+ def test_Arbre_suppression(self):
+ a = Sommets(10, 'a')
+ b = Sommets(8,'b')
+ r1 = Sommets(18,'',left=b,right=a)
+ r2 = Sommets(18,'',left=None,right=r1)
+
+ arbre1 = Arbre(r2)
+
+ arbre1 -= r1
+ self.assertEqual(arbre1.recherche(a),None)
+ self.assertEqual(arbre1.recherche(b),None)
+ self.assertEqual(arbre1.recherche(r1),None)
+ self.assertEqual(arbre1.recherche(r2),r2)
+
+ def test_occurences(self):
+ o1 = calcul_occurence('aaabcc')
+ o2 = calcul_occurence('bacaac')
+ # dans les 2 cas on doit avoir le même dictionnaire
+ # 3 pour a, 2 pour c, 1 pour b
+ self.assertEqual(o1,o2)
+ self.assertEqual(o1['c'],2)
+ self.assertEqual(o1['b'],1)
+ self.assertEqual(o1['a'],3)
+
+
+ def test_encodage_huffman(self):
+ string = 'mouton'
+ string2 = 'vache'
+ (encodedOutput, racine, huffmanEncoding) = huffman_encode(string)
+ (encodedOutput2, racine2, huffmanEncoding2) = huffman_encode(string2)
+ # l'encodage doit être différent (les dictionnaires et arbres aussi)
+ self.assertNotEqual(huffmanEncoding, huffmanEncoding2)
+ self.assertNotEqual(encodedOutput, encodedOutput2)
+ self.assertNotEqual(Arbre(racine),Arbre(racine2))
+
+ def test_decodage_huffman(self):
+ string = 'chèvre'
+ (encodedOutput, racine, huffmanEncoding) = huffman_encode(string)
+ # on doit être capable de décoder avec la racine de l'arbre ou avec le dictionnaire
+ self.assertEqual(string,huffman_decode(encodedOutput,racine))
+ self.assertEqual(string,decode_from_dico(encodedOutput,huffmanEncoding))
+
+ # on doit être capable de détecter si le dictionnaire/arbre n'est pas celui correspondant à un texte encodé
+ string2 = 'poule'
+ (encodedOutput2, racine2, huffmanEncoding2) = huffman_encode(string2)
+ with self.assertRaises(ValueError):
+ decode_from_dico(encodedOutput2,huffmanEncoding)
+ with self.assertRaises(ValueError):
+ huffman_decode(encodedOutput2,racine)
+
+
+if __name__ == '__main__':
+ unittest.main()