Skip to content

Commit 0aab821

Browse files
authored
Merge pull request #13 from AdrianEpi/doc
Doc
2 parents 93eaa1c + fccb2d4 commit 0aab821

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+2853
-237
lines changed

README.md

Lines changed: 143 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
# UMLConverter
2-
Repository for TFG code
2+
Repository for Thesis code
33

44
## TABLE OF CONTENTS
55
1. [Requirements](#REQUIREMENTS)
66
2. [Setting up (local enviroment)](#SETTING-UP-LOCAL-ENVIROMENT)
77

8+
89
## REQUIREMENTS
910
- Python3.10
1011
- Python3.10-venv `sudo apt install python3.10-venv`
1112

13+
1214
## SETTING UP LOCAL ENVIROMENT
1315

1416
In order to run the project for the first time:
@@ -43,6 +45,17 @@ In order to run the project for the first time:
4345
sudo apt-get install python3-tk
4446
```
4547

48+
## Exceute
49+
50+
1) Activate the virtual enviroment
51+
```sh
52+
source .venv/bin/activate
53+
```
54+
2) Run program
55+
```sh
56+
python UMLConverter/main.py
57+
```
58+
4659

4760
## TEST AND COVERAGE
4861

@@ -60,4 +73,133 @@ In order to run the project for the first time:
6073
2) Generate html version of coverage in `htmlcov/`
6174
```sh
6275
coverage html
76+
```
77+
78+
## Test log
79+
80+
```py
81+
===================================================== test session starts =====================================================
82+
platform linux -- Python 3.10.6, pytest-7.2.0, pluggy-1.0.0 -- /mnt/e/TFG/UMLConverter/.venv/bin/python3
83+
cachedir: .pytest_cache
84+
rootdir: /mnt/e/TFG/UMLConverter
85+
collected 74 items
86+
87+
tests/test_UMLConverter.py::test_AST[samples/Simple_Samples/AbstractMethods/main.py-samples/Simple_Samples/AbstractMethods/main.uml] PASSED [ 1%]
88+
tests/test_UMLConverter.py::test_AST[samples/Simple_Samples/AccessModifiers/Private/main.py-samples/Simple_Samples/AccessModifiers/Private/main.uml] PASSED [ 2%]
89+
tests/test_UMLConverter.py::test_AST[samples/Simple_Samples/AccessModifiers/Protected/main.py-samples/Simple_Samples/AccessModifiers/Protected/main.uml] PASSED [ 4%]
90+
tests/test_UMLConverter.py::test_AST[samples/Simple_Samples/AccessModifiers/Public/main.py-samples/Simple_Samples/AccessModifiers/Public/main.uml] PASSED [ 5%]
91+
tests/test_UMLConverter.py::test_AST[samples/Simple_Samples/Attributes/main.py-samples/Simple_Samples/Attributes/main.uml] PASSED [ 6%]
92+
tests/test_UMLConverter.py::test_AST[samples/Simple_Samples/MethodReturnType/main.py-samples/Simple_Samples/MethodReturnType/main.uml] PASSED [ 8%]
93+
tests/test_UMLConverter.py::test_AST[samples/Simple_Samples/MethodsWithoutParameters/main.py-samples/Simple_Samples/MethodsWithoutParameters/main.uml] PASSED [ 9%]
94+
tests/test_UMLConverter.py::test_AST[samples/Simple_Samples/MethodsWithParameters/main.py-samples/Simple_Samples/MethodsWithParameters/main.uml] PASSED [ 10%]
95+
tests/test_UMLConverter.py::test_AST[samples/Simple_Samples/StaticMethods/main.py-samples/Simple_Samples/StaticMethods/main.uml] PASSED [ 12%]
96+
tests/test_UMLConverter.py::test_AST[samples/Simple_Samples/Types/main.py-samples/Simple_Samples/Types/main.uml] PASSED [ 13%]
97+
tests/test_UMLConverter.py::test_AST[samples/testAST/ClassDef/complexClass.py-samples/testAST/ClassDef/complexClass.uml] PASSED [ 14%]
98+
tests/test_UMLConverter.py::test_AST[samples/testAST/ClassDef/inheritedClass.py-samples/testAST/ClassDef/inheritedClass.uml] PASSED [ 16%]
99+
tests/test_UMLConverter.py::test_AST[samples/testAST/ClassDef/simpleClass.py-samples/testAST/ClassDef/simpleClass.uml] PASSED [ 17%]
100+
tests/test_UMLConverter.py::test_AST[samples/testAST/Module/module.py-samples/testAST/Module/module.uml] PASSED [ 18%]
101+
tests/test_UMLConverter.py::test_getSetFileList PASSED [ 20%]
102+
tests/test_UMLConverter.py::test_getCode PASSED [ 21%]
103+
tests/test_UMLConverter.py::test_getSetOutput PASSED [ 22%]
104+
tests/test_UMLConverter.py::test_getSetLanguage PASSED [ 24%]
105+
tests/test_UMLConverter.py::test_getSetExtension PASSED [ 25%]
106+
tests/test_UMLConverter.py::test_getSetClassList PASSED [ 27%]
107+
tests/test_UMLConverter.py::test_getSetImports PASSED [ 28%]
108+
tests/test_file.py::test_getSetFileName PASSED [ 29%]
109+
tests/test_file.py::test_getSetData PASSED [ 31%]
110+
tests/test_file.py::test_readFileNotFoundError PASSED [ 32%]
111+
tests/test_file.py::test_readAndAnalyze PASSED [ 33%]
112+
tests/test_file.py::test_write PASSED [ 35%]
113+
tests/test_jsAST.py::test_AST[samples/JavaScript_Samples/Animal/Animal.js-samples/JavaScript_Samples/Animal/Animal.txt] PASSED [ 36%]
114+
tests/test_jsAST.py::test_AST[samples/JavaScript_Samples/Animal/Cat.js-samples/JavaScript_Samples/Animal/Cat.txt] PASSED [ 37%]
115+
tests/test_jsAST.py::test_AST[samples/JavaScript_Samples/School/Person.js-samples/JavaScript_Samples/School/Person.txt] PASSED [ 39%]
116+
tests/test_jsAST.py::test_AST[samples/JavaScript_Samples/School/Student.js-samples/JavaScript_Samples/School/Student.txt] PASSED [ 40%]
117+
tests/test_jsAST.py::test_AST[samples/JavaScript_Samples/School/Teacher.js-samples/JavaScript_Samples/School/Teacher.txt] PASSED [ 41%]
118+
tests/test_jsAST.py::test_setGetTree PASSED [ 43%]
119+
tests/test_jsAST.py::test_setGetDataList PASSED [ 44%]
120+
tests/test_line.py::test_getIndentation PASSED [ 45%]
121+
tests/test_line.py::test_getData PASSED [ 47%]
122+
tests/test_line.py::test_getRawData PASSED [ 48%]
123+
tests/test_line.py::test_getIndentationLevel PASSED [ 50%]
124+
tests/test_markdown.py::test_Markdown PASSED [ 51%]
125+
tests/test_pyAST.py::test_AST[samples/testAST/AnnAssign/arrayAnnAssign.py-samples/testAST/AnnAssign/arrayAnnAssign.txt] PASSED [ 52%]
126+
tests/test_pyAST.py::test_AST[samples/testAST/AnnAssign/attribAnnAssign.py-samples/testAST/AnnAssign/attribAnnAssign.txt] PASSED [ 54%]
127+
tests/test_pyAST.py::test_AST[samples/testAST/AnnAssign/complexAnnAssign.py-samples/testAST/AnnAssign/complexAnnAssign.txt] PASSED [ 55%]
128+
tests/test_pyAST.py::test_AST[samples/testAST/AnnAssign/simpleAnnAssign.py-samples/testAST/AnnAssign/simpleAnnAssign.txt] PASSED [ 56%]
129+
tests/test_pyAST.py::test_AST[samples/testAST/AnnAssign/typeAnnAssign.py-samples/testAST/AnnAssign/typeAnnAssign.txt] PASSED [ 58%]
130+
tests/test_pyAST.py::test_AST[samples/testAST/Assign/mutipleAssign1.py-samples/testAST/Assign/mutipleAssign1.txt] PASSED [ 59%]
131+
tests/test_pyAST.py::test_AST[samples/testAST/Assign/mutipleAssign2.py-samples/testAST/Assign/mutipleAssign2.txt] PASSED [ 60%]
132+
tests/test_pyAST.py::test_AST[samples/testAST/Assign/simpleAssign.py-samples/testAST/Assign/simpleAssign.txt] PASSED [ 62%]
133+
tests/test_pyAST.py::test_AST[samples/testAST/ClassDef/complexClass.py-samples/testAST/ClassDef/complexClass.txt] PASSED [ 63%]
134+
tests/test_pyAST.py::test_AST[samples/testAST/ClassDef/inheritedClass.py-samples/testAST/ClassDef/inheritedClass.txt] PASSED [ 64%]
135+
tests/test_pyAST.py::test_AST[samples/testAST/ClassDef/simpleClass.py-samples/testAST/ClassDef/simpleClass.txt] PASSED [ 66%]
136+
tests/test_pyAST.py::test_AST[samples/testAST/FunctionDef/argsFun.py-samples/testAST/FunctionDef/argsFun.txt] PASSED [ 67%]
137+
tests/test_pyAST.py::test_AST[samples/testAST/FunctionDef/complexFun.py-samples/testAST/FunctionDef/complexFun.txt] PASSED [ 68%]
138+
tests/test_pyAST.py::test_AST[samples/testAST/FunctionDef/nestedFunctions.py-samples/testAST/FunctionDef/nestedFunctions.txt] PASSED [ 70%]
139+
tests/test_pyAST.py::test_AST[samples/testAST/FunctionDef/returnFun.py-samples/testAST/FunctionDef/returnFun.txt] PASSED [ 71%]
140+
tests/test_pyAST.py::test_AST[samples/testAST/FunctionDef/simpleFun.py-samples/testAST/FunctionDef/simpleFun.txt] PASSED [ 72%]
141+
tests/test_pyAST.py::test_AST[samples/testAST/Import/multipleImport.py-samples/testAST/Import/multipleImport.txt] PASSED [ 74%]
142+
tests/test_pyAST.py::test_AST[samples/testAST/Import/simpleImport.py-samples/testAST/Import/simpleImport.txt] PASSED [ 75%]
143+
tests/test_pyAST.py::test_AST[samples/testAST/ImportFrom/complexImportFrom.py-samples/testAST/ImportFrom/complexImportFrom.txt]
144+
PASSED [ 77%]
145+
tests/test_pyAST.py::test_AST[samples/testAST/ImportFrom/importFrom.py-samples/testAST/ImportFrom/importFrom.txt] PASSED [ 78%]
146+
tests/test_pyAST.py::test_AST[samples/testAST/ImportFrom/longImport.py-samples/testAST/ImportFrom/longImport.txt] PASSED [ 79%]
147+
tests/test_pyAST.py::test_AST[samples/testAST/Module/module.py-samples/testAST/Module/module.txt] PASSED [ 81%]
148+
tests/test_pyAST.py::test_setGetTree PASSED [ 82%]
149+
tests/test_pyAST.py::test_setGetDataList PASSED [ 83%]
150+
tests/test_pythonNode.py::test_setgetNodeType PASSED [ 85%]
151+
tests/test_pythonNode.py::test_setgetName PASSED [ 86%]
152+
tests/test_pythonNode.py::test_setgetValue PASSED [ 87%]
153+
tests/test_pythonNode.py::test_setgetArgs PASSED [ 89%]
154+
tests/test_pythonNode.py::test_setgetBody PASSED [ 90%]
155+
tests/test_pythonNode.py::test_addArg PASSED [ 91%]
156+
tests/test_pythonNode.py::test_addBody PASSED [ 93%]
157+
tests/test_pythonNode.py::test_toString PASSED [ 94%]
158+
tests/test_pythonNode.py::test_toStringBodyException PASSED [ 95%]
159+
tests/test_searcher.py::test_lookForFiles PASSED [ 97%]
160+
tests/test_searcher.py::test_getFileList PASSED [ 98%]
161+
tests/test_searcher.py::test_fetDirList PASSED [100%]
162+
163+
===================================================== 74 passed in 7.69s ======================================================
164+
```
165+
166+
167+
## Coverage report
168+
169+
```py
170+
Name Stmts Miss Cover
171+
----------------------------------------------------------------
172+
app/__init__.py 0 0 100%
173+
app/modules/ast_module/AST.py 48 11 77%
174+
app/modules/ast_module/__init__.py 0 0 100%
175+
app/modules/ast_module/jsAST.py 152 26 83%
176+
app/modules/ast_module/line.py 29 0 100%
177+
app/modules/ast_module/pyAST.py 384 39 90%
178+
app/modules/ast_module/pythonNode.py 59 0 100%
179+
app/modules/file_module/__init__.py 0 0 100%
180+
app/modules/file_module/file.py 102 22 78%
181+
app/modules/file_module/markdown.py 104 3 97%
182+
app/modules/file_module/searcher.py 26 0 100%
183+
app/modules/interface_module/__init__.py 0 0 100%
184+
app/modules/interface_module/interface.py 108 89 18%
185+
app/modules/metric_module/__init__.py 0 0 100%
186+
app/modules/metric_module/metric.py 122 90 26%
187+
app/modules/metric_module/metricClass.py 123 52 58%
188+
app/modules/metric_module/metricPackage.py 72 34 53%
189+
app/modules/uml_module/UMLConverter.py 204 57 72%
190+
app/modules/uml_module/__init__.py 0 0 100%
191+
app/modules/uml_module/translator.py 131 26 80%
192+
app/modules/utils.py 6 0 100%
193+
tests/__init__.py 0 0 100%
194+
tests/test_UMLConverter.py 57 0 100%
195+
tests/test_file.py 41 2 95%
196+
tests/test_jsAST.py 18 0 100%
197+
tests/test_line.py 17 0 100%
198+
tests/test_markdown.py 28 2 93%
199+
tests/test_pyAST.py 19 0 100%
200+
tests/test_pythonNode.py 58 0 100%
201+
tests/test_searcher.py 15 0 100%
202+
tests/utils.py 39 0 100%
203+
----------------------------------------------------------------
204+
TOTAL 1962 453 77%
63205
```

app/modules/ast_module/jsAST.py

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
# @Email: adrianepi@gmail.com
88
# @GitHub: https://github.com/AdrianEpi
99
# @Last Modified by: Adrian Epifanio
10-
# @Last Modified time: 2023-02-02 12:26:05
10+
# @Last Modified time: 2023-03-18 11:03:49
1111
# @Description: This file describes a javaScript ast class
1212

1313
from app.modules.ast_module.pythonNode import PythonNode
@@ -104,10 +104,18 @@ def _AST__generateImport(self, pos = None, node = None) -> list or PythonNode:
104104
:returns: list of strings or pythonnodes or single pythonde
105105
:rtype: list or PythonNode
106106
"""
107-
n = PythonNode()
108-
n.setNodeType("Import")
109-
n.setName(node.expression.arguments.name)
110-
return n
107+
l = []
108+
for i in node.expression.arguments:
109+
n = PythonNode()
110+
n.setNodeType("Import")
111+
if i.name:
112+
n.setName(self.deleteExtention(i.name))
113+
elif i.value:
114+
n.setName(self.deleteExtention(i.value))
115+
l.append(n)
116+
if len(l) == 1:
117+
return l[0]
118+
return l
111119

112120

113121
def _AST__generateImportFrom(self, pos = None, node = None) -> PythonNode:
@@ -123,13 +131,13 @@ def _AST__generateImportFrom(self, pos = None, node = None) -> PythonNode:
123131
"""
124132
n = PythonNode()
125133
n.setNodeType("ImportFrom")
126-
n.setName(node.declarations[0].init.arguments.value)
134+
n.setName(self.deleteExtention(node.declarations[0].init.arguments.value))
127135
if node.id.type == "Identifier":
128136
n.setValue(node.declarations[0].init.arguments.value)
129137

130138
elif node.id.type == "ObjectPattern":
131139
imports = []
132-
n.setName(node.declarations[0].arguments.value)
140+
n.setName(self.deleteExtention(node.declarations[0].arguments.value))
133141
for i in node.declarations[0].id.properties:
134142
imports.append(i.key.name)
135143
n.setValue(imports)
@@ -270,7 +278,7 @@ def _AST__generateNode(self, pos = None, ntype = None, node = None) -> PythonNod
270278
elif ntype == "ClassDeclaration":
271279
return self._AST__generateClassDef(node = node)
272280
elif ntype == "ExpressionStatement":
273-
if node.expression.callee == "require":
281+
if (node.expression.callee != None) and (node.expression.callee.name == "require"):
274282
return self._AST__generateImport(node = node)
275283
elif node.expression.right != None:
276284
if node.expression.right.type == "ClassExpresssion":
@@ -290,3 +298,19 @@ def _AST__generateNode(self, pos = None, ntype = None, node = None) -> PythonNod
290298
return self.__generateMethodDef(node = node)
291299
else:
292300
return None # In case non necessary node
301+
302+
303+
def deleteExtention(self, s: str) -> str:
304+
"""
305+
Deletes the extention of a JavaScript file of the name and returns it.
306+
307+
:param s: file name
308+
:type s: str
309+
310+
:returns: String with the name of the file without extention
311+
:rtype: str
312+
"""
313+
if '.js' in s:
314+
return s[0:(len(s) - 3)]
315+
return s
316+

app/modules/ast_module/pythonNode.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
# @Email: adrianepi@gmail.com
88
# @GitHub: https://github.com/AdrianEpi
99
# @Last Modified by: Adrian Epifanio
10-
# @Last Modified time: 2023-01-31 13:18:12
11-
# @Description: ...
10+
# @Last Modified time: 2023-03-18 11:04:42
11+
# @Description: Generic node for the ast
1212

1313

1414
class PythonNode:

app/modules/file_module/file.py

Lines changed: 75 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@
77
# @Email: adrianepi@gmail.com
88
# @GitHub: https://github.com/AdrianEpi
99
# @Last Modified by: Adrian Epifanio
10-
# @Last Modified time: 2022-12-25 11:05:18
10+
# @Last Modified time: 2023-03-18 11:06:47
1111
# @Description: This file describes a file and its functionality
1212

1313
import sys
1414
import os
15+
from app.modules.utils import COMMENTS
1516

1617
class File:
1718
"""
@@ -20,6 +21,9 @@ class File:
2021

2122
fileName: str
2223
data: str
24+
nLines: int
25+
nCommentLines: int
26+
nCodeLines: int
2327

2428
def __init__(self, file: str):
2529
"""
@@ -30,7 +34,9 @@ def __init__(self, file: str):
3034
"""
3135
self.data = ""
3236
self.fileName = file
33-
37+
self.nLines = 0
38+
self.nCodeLines = 0
39+
self.nCommentLines = 0
3440

3541
def getFileName(self) -> str:
3642
"""
@@ -92,6 +98,60 @@ def read(self):
9298
self.data += i
9399

94100

101+
def readAndAnalyze(self, language: str):
102+
"""
103+
Reads and analyze a code for counting the codelines and the comments.
104+
105+
:param language: The language
106+
:type language: str
107+
108+
:raises Exception: Unexpected error
109+
:raises FileNotFoundError: If file not found
110+
:raises OSError: If OS error
111+
"""
112+
try:
113+
f = open(self.fileName, 'r')
114+
except FileNotFoundError:
115+
raise FileNotFoundError("Error, {} file not found.".format(self.fileName))
116+
except OSError:
117+
raise OSError("OS error trying to open {} file.".format(self.fileName))
118+
except Exception as err:
119+
raise Exception("Unexpected error with {} file.".format(self.fileName))
120+
else:
121+
single = COMMENTS[language]['single']
122+
multiStart = COMMENTS[language]['multiStart']
123+
multiEnd = COMMENTS[language]['multiEnd']
124+
with f:
125+
lines = f.readlines()
126+
f.close()
127+
insideComment = False
128+
for i in lines:
129+
self.nLines += 1
130+
self.data += i
131+
if insideComment == True:
132+
self.nCommentLines += 1
133+
if multiEnd in i:
134+
insideComment = False
135+
136+
elif multiStart in i:
137+
insideComment = True
138+
tmp = i.split(multiStart)
139+
self.nCommentLines += 1
140+
if len(tmp) > 1:
141+
self.nCodeLines += 1
142+
if (multiStart == multiEnd) and (i.count(multiStart) % 2 == 0):
143+
insideComment = False
144+
elif single in i:
145+
tmp = i.split(single)
146+
self.nCommentLines += 1
147+
if len(tmp) > 1:
148+
self.nCodeLines += 1
149+
else:
150+
if len(i.split()) > 1:
151+
self.nCodeLines += 1
152+
153+
154+
95155
def write(self, data: str):
96156
"""
97157
Writes the data into the file stored in self.fileName
@@ -136,3 +196,16 @@ def write(self, data: str):
136196
self.data = data
137197

138198

199+
def getLinesInfo(self) -> dict:
200+
"""
201+
Gets the lines information.
202+
203+
:returns: The lines information.
204+
:rtype: dict
205+
"""
206+
return {
207+
'nLines': self.nLines,
208+
'commentLines': self.nCommentLines,
209+
'codeLines': self.nCodeLines
210+
}
211+

0 commit comments

Comments
 (0)