Skip to content
Open
Show file tree
Hide file tree
Changes from 57 commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
71f2697
adicionado nova tool para gerar testes
nathaliafab May 13, 2024
52ad4a2
gera outputs para diferentes branches
nathaliafab May 14, 2024
77a5566
alterações nas funções
nathaliafab May 17, 2024
e585dba
Add try except block on compile test suite method
nathaliafab May 28, 2024
a5aeba5
Add some functions for better compilation work
nathaliafab May 28, 2024
cec679a
removed print
nathaliafab May 29, 2024
4ee7db1
added/fixed logging
nathaliafab May 29, 2024
aa84b01
fix class and test naming
nathaliafab Jun 14, 2024
ddf12e7
change test not found result
nathaliafab Jun 14, 2024
b5c8f1b
removed unused functions and cleaned the code
nathaliafab Jun 14, 2024
655d95d
simply not include not found tests
nathaliafab Jun 14, 2024
f4a6e29
remove unused imports
nathaliafab Jun 14, 2024
1d427f1
varias coisa
nathaliafab Jun 21, 2024
4db60de
calledprocesserror
nathaliafab Aug 21, 2024
e28295d
update requirements
nathaliafab Aug 21, 2024
8a7c153
varias refatoração
nathaliafab Aug 21, 2024
973adc3
é o refatoras
nathaliafab Aug 27, 2024
b70c052
melhor logging e mudança no path do output
nathaliafab Sep 3, 2024
e25abcb
reports nao sao sobrescritos
nathaliafab Sep 3, 2024
131d001
conserto de varios bugs
nathaliafab Sep 3, 2024
e42e1b7
fix jar type search
nathaliafab Sep 17, 2024
ae8badc
update logging
nathaliafab Sep 30, 2024
660838a
calc time
nathaliafab Sep 30, 2024
6dfed76
better output
nathaliafab Sep 30, 2024
8c88634
update req
nathaliafab Oct 1, 2024
ea9df20
a
nathaliafab Oct 1, 2024
fad3c28
fix: "targets" attr type
nathaliafab Nov 19, 2024
44c3ff6
remove ignored modules from logging
nathaliafab Nov 19, 2024
7169eeb
feat(model): migrate from local codellama-7b to API-based codellama-7…
nathaliafab Nov 20, 2024
5fcc7ec
change test template logic and prompt messages
nathaliafab Dec 10, 2024
083f140
update dependencies versions
nathaliafab Jan 8, 2025
cbedd6a
fixed var types
nathaliafab Jan 8, 2025
4e2a94b
use the current repo name
nathaliafab Jan 8, 2025
0453c4d
fixed some stylistic issues
nathaliafab Jan 8, 2025
344d54d
parametrização dos dados da api
nathaliafab Mar 12, 2025
e132acc
creates a file to store compilation outputs
nathaliafab Mar 12, 2025
db8be5c
fixed get_config() function to support dicts inside dicts
nathaliafab Mar 25, 2025
9d1f85e
move functions to utils
nathaliafab Apr 15, 2025
038f41b
created api class
nathaliafab Apr 15, 2025
e8ad444
fixed scenario infos format and remove useless function
nathaliafab Apr 15, 2025
8ba504d
conserto da lógica
nathaliafab Apr 22, 2025
3f36b79
conserto de lógica + saída em arquivo json
nathaliafab Apr 22, 2025
9195e6f
small fix logging message
nathaliafab Jun 19, 2025
e17eed8
get seed from config
nathaliafab Jun 19, 2025
4e49187
remove version from requirements
nathaliafab Jun 19, 2025
94003b0
typing issues
nathaliafab Jun 19, 2025
6bc007c
change logic - special codellama
nathaliafab Jun 19, 2025
a19fb60
update config params
nathaliafab Jun 19, 2025
32da8ca
dealing with paths - evosuite
nathaliafab Jun 19, 2025
2c3237d
remove unused globals
nathaliafab Jun 20, 2025
5f38ba8
remove implicit optional
nathaliafab Jun 20, 2025
04b1d79
Merge pull request #1 from nathaliafab/new-prompts
nathaliafab Jun 20, 2025
e4643fd
Merge branch 'master' into codellama-integration
nathaliafab Jun 21, 2025
cfb8b62
Update nimrod/utils.py
nathaliafab Oct 30, 2025
433eec2
Update nimrod/test_suites_execution/test_suite_executor.py
nathaliafab Oct 30, 2025
dda0c87
Update nimrod/test_suite_generation/generators/codellama_test_suite_g…
nathaliafab Oct 30, 2025
5e6c389
Update nimrod/output_generation/semantic_conflicts_output_generator.py
nathaliafab Oct 30, 2025
3fb1a94
refactor: rename codellama to ollama
nathaliafab Nov 16, 2025
0c46b5f
docs: add docstrings for data loading and writing methods
nathaliafab Nov 16, 2025
4210022
Update nimrod/test_suite_generation/generators/ollama_test_suite_gene…
nathaliafab Nov 16, 2025
f6dc6bc
Update nimrod/test_suites_execution/test_suite_executor.py
nathaliafab Nov 16, 2025
cca64e7
fix(tests): update compile timeout and standardize assertion methods
nathaliafab Nov 16, 2025
5a05435
feat: add PromptManager class and prompt templates
nathaliafab Dec 18, 2025
5784994
fix: update paths for compilation and execution results to use report…
nathaliafab Dec 18, 2025
7f435b5
feat: enhance OllamaTestSuiteGenerator to support configurable model …
nathaliafab Dec 18, 2025
e99d5d0
feat: implement LLMOutputProcessor for output sanitization in OllamaT…
nathaliafab Dec 18, 2025
d7b02da
fix: update requirements.txt for specific tree_sitter versions and im…
nathaliafab Dec 18, 2025
bba8cf6
chore: update GitHub Actions workflow to use Python 3.10 and Java Tem…
nathaliafab Dec 18, 2025
ecbad7c
fix: update Maven setup action version and adjust env-config.json cre…
nathaliafab Dec 18, 2025
65bf193
fix: update env-config.json creation to use dynamic MAVEN_HOME path
nathaliafab Dec 18, 2025
74a3cc0
feat: add Docker support with Dockerfile and docker-compose.yml for c…
nathaliafab Dec 18, 2025
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
5 changes: 3 additions & 2 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,12 @@ jobs:
uses: stCarolas/setup-maven@v4.1
- name: Creating env-config.json
run: |
cd /home/runner/work/SMAT/SMAT/nimrod/tests/
repo_name=$(basename $GITHUB_REPOSITORY)
cd /home/runner/work/$repo_name/$repo_name/nimrod/tests/
java_path="/opt/hostedtoolcache/Java_Adopt_jdk/$(ls /opt/hostedtoolcache/Java_Adopt_jdk)/x64"
contents="$(jq --arg java_path "$java_path" '.java_home=$java_path | .maven_home = "/opt/hostedtoolcache/maven/3.5.4/x64"' env-config.json)"
echo "${contents}" > env-config.json
cd /home/runner/work/SMAT/SMAT
cd /home/runner/work/$repo_name/$repo_name
- name: Test with pytest
run: |
pytest -k 'not test_general_behavior_study_semantic_conflict'
7 changes: 5 additions & 2 deletions nimrod/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from nimrod.test_suite_generation.generators.randoop_test_suite_generator import RandoopTestSuiteGenerator
from nimrod.test_suite_generation.generators.evosuite_differential_test_suite_generator import EvosuiteDifferentialTestSuiteGenerator
from nimrod.test_suite_generation.generators.evosuite_test_suite_generator import EvosuiteTestSuiteGenerator
from nimrod.test_suite_generation.generators.codellama_test_suite_generator import CodellamaTestSuiteGenerator
from nimrod.test_suite_generation.generators.project_test_suite_generator import ProjectTestSuiteGenerator
from nimrod.test_suites_execution.main import TestSuitesExecution, TestSuiteExecutor
from nimrod.tools.bin import MOD_RANDOOP, RANDOOP
Expand All @@ -26,7 +27,7 @@

def get_test_suite_generators(config: Dict[str, str]) -> List[TestSuiteGenerator]:
config_generators = config.get(
'test_suite_generators', ['randoop', 'randoop-modified', 'evosuite', 'evosuite-differential', 'project'])
'test_suite_generators', ['randoop', 'randoop-modified', 'evosuite', 'evosuite-differential', 'codellama', 'project'])
generators: List[TestSuiteGenerator] = list()

if 'randoop' in config_generators:
Expand All @@ -38,6 +39,8 @@ def get_test_suite_generators(config: Dict[str, str]) -> List[TestSuiteGenerator
generators.append(EvosuiteTestSuiteGenerator(Java()))
if 'evosuite-differential' in config_generators:
generators.append(EvosuiteDifferentialTestSuiteGenerator(Java()))
if 'codellama' in config_generators:
generators.append(CodellamaTestSuiteGenerator(Java()))
if 'project' in config_generators:
generators.append(ProjectTestSuiteGenerator(Java()))

Expand Down Expand Up @@ -95,7 +98,7 @@ def main():
if scenario.run_analysis:
smat.run_tool_for_semmantic_conflict_detection(scenario)
else:
logging.info(f"Skipping tool execution for project f{scenario.project_name}")
logging.info(f"Skipping tool execution for project {scenario.project_name}")


if __name__ == '__main__':
Expand Down
4 changes: 2 additions & 2 deletions nimrod/core/merge_scenario_under_analysis.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from typing import List, Dict
from typing import List, Dict, Union


class MergeScenarioUnderAnalysis:
def __init__(self, project_name: str, run_analysis: bool, scenario_commits: "ScenarioInformation", targets: "Dict[str, List[str]]", scenario_jars: "ScenarioInformation", jar_type: str):
def __init__(self, project_name: str, run_analysis: bool, scenario_commits: "ScenarioInformation", targets: "Dict[str, Union[List[Dict[str, str]], List[str]]]", scenario_jars: "ScenarioInformation", jar_type: str):
self.project_name = project_name
self.run_analysis = run_analysis
self.scenario_commits = scenario_commits
Expand Down
27 changes: 23 additions & 4 deletions nimrod/output_generation/output_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@


class OutputGenerator(ABC, Generic[T]):
REPORTS_DIRECTORY = path.join(get_base_output_path(), "reports")
parent_dir = path.dirname(get_base_output_path())
REPORTS_DIRECTORY = path.join(parent_dir, "reports")

def __init__(self, report_name: str) -> None:
super().__init__()
Expand All @@ -27,9 +28,27 @@ def write_report(self, context: OutputGeneratorContext) -> None:
file_path = path.join(self.REPORTS_DIRECTORY, self._report_name)

logging.info(f"Starting data processing of {self._report_name} report")
data = self._generate_report_data(context)
new_data = self._generate_report_data(context)
logging.info(f"Finished data processing of {self._report_name} report")

with open(file_path, "w") as write:
json.dump(data, write)
existing_data = self._load_existing_data(file_path)

if not isinstance(existing_data, list):
existing_data = [existing_data] if existing_data else []
existing_data.append(new_data)

self._write_json(file_path, existing_data)
logging.info(f"Finished generation of {self._report_name} report")

def _load_existing_data(self, file_path: str):
if not path.exists(file_path):
return []
try:
with open(file_path, "r") as read_file:
return json.load(read_file)
except json.JSONDecodeError:
return []

def _write_json(self, file_path: str, data) -> None:
with open(file_path, "w") as write_file:
json.dump(data, write_file, indent=4)
78 changes: 47 additions & 31 deletions nimrod/output_generation/semantic_conflicts_output_generator.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
from typing import Dict, List, TypedDict
from typing import Dict, List, TypedDict, Union
from nimrod.output_generation.output_generator import OutputGenerator, OutputGeneratorContext
from nimrod.test_suites_execution.main import TestSuitesExecution
from os import path
from bs4 import BeautifulSoup
import logging


class SemanticConflictsOutput(TypedDict):
Expand All @@ -12,7 +13,7 @@ class SemanticConflictsOutput(TypedDict):
test_case_name: str
test_case_results: Dict[str, str]
test_suite_path: str
scenario_targets: Dict[str, List[str]]
scenario_targets: Dict[str, Union[List[Dict[str, str]], List[str]]]
exercised_targets: Dict[str, List[str]]


Expand All @@ -26,40 +27,51 @@ def _generate_report_data(self, context: OutputGeneratorContext) -> List[Semanti

for semantic_conflict in context.semantic_conflicts:
# We need to detect which targets from the input were exercised in this conflict.
coverage_report_root = self._test_suites_execution.execute_test_suite_with_coverage(
test_suite=semantic_conflict.detected_in.test_suite,
target_jar=context.scenario.scenario_jars.merge,
test_cases=[semantic_conflict.detected_in.name]
)

exercised_targets = self._extract_exercised_targets_from_coverage_report(
coverage_report_root=coverage_report_root,
targets=context.scenario.targets
)

report_data.append({
"project_name": context.scenario.project_name,
"scenario_commits": context.scenario.scenario_commits.__dict__,
"criteria": semantic_conflict._satisfying_criteria.__class__.__name__,
"test_case_name": semantic_conflict.detected_in.name,
"test_case_results": {
"base": semantic_conflict.detected_in.base,
"left": semantic_conflict.detected_in.left,
"right": semantic_conflict.detected_in.right,
"merge": semantic_conflict.detected_in.merge
},
"test_suite_path": semantic_conflict.detected_in.test_suite.path,
"scenario_targets": context.scenario.targets,
"exercised_targets": exercised_targets
})
exercised_targets: Dict[str, List[str]] = dict()
try:
coverage_report_root = self._test_suites_execution.execute_test_suite_with_coverage(
test_suite=semantic_conflict.detected_in.test_suite,
target_jar=context.scenario.scenario_jars.merge,
test_cases=[semantic_conflict.detected_in.name]
)

exercised_targets = self._extract_exercised_targets_from_coverage_report(
coverage_report_root=coverage_report_root,
targets=context.scenario.targets
)

except Exception as e:
# If we cannot execute the test suite with coverage, we log the error and continue.
logging.error("Error executing test suite with coverage for semantic conflict: %s", e)

finally:
report_data.append({
"project_name": context.scenario.project_name,
"scenario_commits": context.scenario.scenario_commits.__dict__,
"criteria": semantic_conflict._satisfying_criteria.__class__.__name__,
"test_case_name": semantic_conflict.detected_in.name,
"test_case_results": {
"base": semantic_conflict.detected_in.base,
"left": semantic_conflict.detected_in.left,
"right": semantic_conflict.detected_in.right,
"merge": semantic_conflict.detected_in.merge
},
"test_suite_path": semantic_conflict.detected_in.test_suite.path,
"scenario_targets": context.scenario.targets,
"exercised_targets": exercised_targets
})

return report_data

def _extract_exercised_targets_from_coverage_report(self, coverage_report_root: str, targets: Dict[str, List[str]]):
def _extract_exercised_targets_from_coverage_report(self, coverage_report_root: str, targets: Dict[str, Union[List[Dict[str, str]], List[str]]]):
exercised_targets: Dict[str, List[str]] = dict()

for class_name in targets.keys():
for method_name in targets[class_name]:
for method_item in targets[class_name]:
if isinstance(method_item, dict):
method_name = method_item.get("method", "")
else:
method_name = method_item
if self._was_target_exercised(coverage_report_root, class_name, method_name):
exercised_targets[class_name] = exercised_targets.get(
class_name, []) + [method_name]
Expand All @@ -80,7 +92,11 @@ def _was_target_exercised(self, coverage_report_root: str, fqcn: str, method_sig
# We itereate in each method row
for method_row in method_report_rows:
if method_row.get_text().find(method_name) != -1:
if method_row.select_one('td:nth-last-child(2)').get_text() == '0':
tag = method_row.select_one('td:nth-last-child(2)')
if tag is None:
continue
# If the second last column is 0, it means the method was not executed
if tag.get_text() == "0":
return True

return False
4 changes: 3 additions & 1 deletion nimrod/output_generation/test_suites_output_generator.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import List, TypedDict
from typing import List, TypedDict, Dict, Union
from nimrod.dynamic_analysis.behavior_change import BehaviorChange
from nimrod.dynamic_analysis.semantic_conflict import SemanticConflict
from nimrod.output_generation.output_generator import OutputGenerator, OutputGeneratorContext
Expand All @@ -7,6 +7,7 @@

class TestSuitesOutput(TypedDict):
project_name: str
targets: Dict[str, Union[List[Dict[str, str]], List[str]]]
generator_name: str
path: str
detected_semantic_conflicts: bool
Expand All @@ -23,6 +24,7 @@ def _generate_report_data(self, context: OutputGeneratorContext) -> List[TestSui
for test_suite in context.test_suites:
report_data.append({
"project_name": context.scenario.project_name,
"targets": context.scenario.targets,
"generator_name": test_suite.generator_name,
"path": test_suite.path,
"detected_semantic_conflicts": self._has_detected_semantic_conflicts_in_test_suite(test_suite, context.semantic_conflicts),
Expand Down
3 changes: 0 additions & 3 deletions nimrod/report_metrics/coverage/coverage_report.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,6 @@ def get_valid_test_suite(self, toolSuites, first_entry, last_entry):
return None

def retornaDadosParaAnalise(self, evo, path_suite, suite_merge, jacoco, classeTarget, listaPacoteMetodoClasse, targets: "dict[str, list[str]]"):
global tagAClasseTarget
global tagSpanMetodoTarget

print("Classe Target ", classeTarget)

listaJar = evo.project_dep.mergeDir.split(
Expand Down
3 changes: 2 additions & 1 deletion nimrod/setup_tools/tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ class Tools(Enum):
RANDOOP='RANDOOP'
RANDOOP_MOD='RANDOOP-MODIFIED'
EVOSUITE='EVOSUITE'
DIFF_EVOSUITE='DIFFERENTIAL-EVOSUITE'
DIFF_EVOSUITE='DIFFERENTIAL-EVOSUITE'
CODELLAMA='CODELLAMA'
Loading
Loading