Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 34 additions & 1 deletion courseProjectDocs/Metrics/README.md
Original file line number Diff line number Diff line change
@@ -1 +1,34 @@
This shows how to recreate the results generated via Metrics code.
This shows how to recreate the results generated via Metrics code and Test Metrics.

## Library

The libraries used were a mixture of **lizard** and **pygount**. Although, the script was written in Python, these libraries support the analysis of many languages via source code from files.

### Steps to Recreate:
#### Prequistes
- pip install lizard
- pip install pygount
1. main()
- Get the root dir path os.path.abs(path(os.curdir))
- Get all paths that have 'src' folders, save as a list
- Create a for loop that iterates through the path list
2. Filter files
- Filter files in that src folder to disregard any resources (.png, .tff, etc.)
- Return this list to the main for loop
3. Evaluate files
- This is the heartbeat of the program that computes the metrics.
```python

for file in files:
i = lizard.analyze_file(file)
loc = i.__dict__.get("nloc")
analyze = SourceAnalysis.from_file(file, "pygount")
comments = analyze.documentation_count # typeof int
for func in i.function_list:
cc = func.__dict__.get('cyclomatic_complexity')
return dict
```
- Then calculate the comment density, LOC, and cyclomatic complexity
4. Print results
- Use CSV library to print the list of dictionaries
5. Run the testMetrics.py file using any python interpreter. Results will be output into the terminal. Current number of tests = 3643
94 changes: 94 additions & 0 deletions courseProjectDocs/Metrics/metrics.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import os
import re
import glob

import lizard
from pygount import SourceAnalysis
import csv

# 1. LOC (per file/module)
# 2. comment density : comments / total lines
# 3. cyclomatic complexity


standalone_paths = []

def print_results(results):
with open('results.csv', 'w', newline='') as csvfile:
fieldnames = ['Module', 'loc', 'density', 'complexity']
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
writer.writeheader()
for result in results:
writer.writerow(result)

def get_all_src_paths(root_dir): # This function grabs all paths that have 'src' for modules to count metrics.
path_list = []
for path, names, file in os.walk(root_dir):
for name in names:
if 'src' in name:
full_path = os.path.join(path, name)
path_list.append(full_path)
dir_name = os.path.dirname(full_path)
standalone_paths.append(os.path.basename(dir_name))
return path_list

def get_all_files(directory):
all_files = []
for root, dirs, files in os.walk(directory):
for file in files:
if '.' not in file:
continue # Exclude any file without file extension (verfied txt files no major contribution to src code)
file_path = os.path.join(root, file)
abs_path = os.path.abspath(file_path)
all_files.append(abs_path)
return all_files

def evaluate_files(files, index):
total_loc = 0
total_comments = 0
total_density = 0.0
total_cc = 0
for file in files:
i = lizard.analyze_file(file)
loc = i.__dict__.get("nloc") # typeof int
analyze = SourceAnalysis.from_file(file, "pygount")
comments = analyze.documentation_count # typeof int
big_cc = 0
if i.function_list:
for func in i.function_list:
cc = func.__dict__.get('cyclomatic_complexity')
big_cc = big_cc + cc
total_cc = big_cc + total_cc
total_loc = loc + total_loc
total_comments = comments + total_comments
try:
total_density = total_loc / total_comments
except ZeroDivisionError:
total_density = -1 # Module has 0 LOC?? check.
file_dict = {
'Module':standalone_paths[index], 'loc':total_loc, 'density':total_density, 'complexity':total_cc
}
return file_dict

def main():
root_dir = os.path.abspath(os.curdir) # glob_pattern = "/.*/src/*.java" or ".kts" (java or kotlin)
paths = get_all_src_paths(root_dir) # args_ignore = ".*"
exclude_exts = ('.tff', '.xsl', '.fxml', '.properties', '.blg', '.gitignore', '.tex', '.layout',
'.md', '.terms', '.readme', '.json', '.jstyle', '.jks', '.aux', '.csl', '.bst',
'.cff', '.enw', '.ctv6bak', '.txt', '.isi', '.nbib', '.ris', '.ref', '.docx',
'.g4', '.gitkeep', '.sh', '.ico', '.icns', '.svo', '.Writer', '.ResourceLocator',
'.IkonHandler', '.IkonProvider', '.ttf', '.bak', '.end', '.log', '.bib', '.pdf',
'.png', '.http', '.xml') # List of ext to exclude
results = []
print("Program now running .... ")
for i, dir in enumerate(paths):
single_dir = get_all_files(dir)
filtered_files = [f for f in single_dir if not f.endswith(exclude_exts)]
result = evaluate_files(filtered_files, i)
results.append(result)
print(str(result))
print_results(results)
print("Program done!") # print(results)

if __name__ == "__main__":
main()
Binary file added courseProjectDocs/Metrics/metrics_1_results.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 11 additions & 0 deletions courseProjectDocs/Metrics/results.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
Module,loc,density,complexity
build-logic,739,13.943396226415095,2
build-support,242,2.951219512195122,21
jabgui,85574,13.275519702140862,11578
jabkit,1457,31.67391304347826,137
jablib,129741,7.408268143664706,19775
jabls,622,62.2,95
jabls-cli,51,17.0,3
jabsrv,1857,13.170212765957446,216
jabsrv-cli,99,8.25,5
test-support,364,4.6075949367088604,39
29 changes: 29 additions & 0 deletions courseProjectDocs/Metrics/testMetrics.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import os
import re

def count_junit_tests():
script_dir = os.path.dirname(os.path.abspath(__file__))
project_root = os.path.abspath(os.path.join(script_dir, '..', '..'))

total = 0
for root, _, files in os.walk(project_root):
for file in files:
if file.endswith(".java"):
with open(os.path.join(root, file), 'r', encoding='utf-8') as f:
in_block_comment = False
for line in f:
line = line.strip()

if '/*' in line:
in_block_comment = True
if '*/' in line:
in_block_comment = False
continue
if in_block_comment or line.startswith('//'):
continue
if re.search(r'^\s*@Test\b', line):
total += 1
return total

if __name__ == "__main__":
print(count_junit_tests())
38 changes: 38 additions & 0 deletions courseProjectDocs/project-proposal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
## Project Overview
JabRef is an cross platform citation and reference managment tool design to help mangage and find bilibographic data. Key Features include:
- Collections: Users and import references for serveral online scientific catalogs such as Goog Scholar and PubMed, retrieve its metadata using DOI or ISBN,
- Organization: The software allows research to be filtering, manage duplication , add custom data fields and has advance surch features/ Users can allso attach related documents together
- Cite: With the intergrate of LaTeX editors, as more references are added , it can magemange the citations needed in serveral different styles
- Share: Allows users to exort their files with sharign services such as Dropbox, and allows different databases to be sync using a sql database

# Key Metrics:
## Code Structure:
### 1. LOC (per file/module)
### 2. Comment Density
### 3. Cyclomatic Complexity
### 4. Number of Unit Tests

## **Modules**:
| Module | Module |
| ------------- | ------------- |
| build-logic | build-support |
| jabgui | jabkit |
| jablib | jabls |
| jabsrv | jabsrv-cli |
| test-suport | jabls-cli |

#### + build-logic
#### + build-support
#### + jabgui
#### + jabkit
#### + jablib
#### + jabls
#### + jabls-cli
#### + jabsrv
#### + jabsrv-cli
#### + test-support

![The Module Results for code metrics](Metrics/metrics_1_results.png)

These *modules* were chosen as they contained the 'src' code for major contributions to the project, their file extensions include: .kts, .java, and .css