Update Gemini response schema to extract detailed overview, logic steps, data dependencies, and consultation insights. Add pipeline processing logic and file categorization explanations to OVERVIEW.md.
120 lines
5.1 KiB
Python
120 lines
5.1 KiB
Python
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
from tempfile import TemporaryDirectory
|
|
import sys
|
|
import unittest
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
sys.path.insert(0, str(ROOT / "src"))
|
|
|
|
from uipath_explainator.pipeline import ProjectPipeline
|
|
from uipath_explainator.scanner import crawl_dependencies, extract_dependencies, strip_comment_out_blocks
|
|
|
|
|
|
MAIN_XAML = """<?xml version="1.0" encoding="utf-8"?>
|
|
<Activity xmlns="http://schemas.microsoft.com/netfx/2009/xaml/activities"
|
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
|
xmlns:ui="http://schemas.uipath.com/workflow/activities">
|
|
<Sequence>
|
|
<ui:InvokeWorkflowFile WorkflowFileName="Flows/Active.xaml" />
|
|
<ui:CommentOut>
|
|
<Sequence>
|
|
<ui:InvokeWorkflowFile WorkflowFileName="Flows/Old.xaml" />
|
|
</Sequence>
|
|
</ui:CommentOut>
|
|
</Sequence>
|
|
</Activity>
|
|
"""
|
|
|
|
ACTIVE_XAML = """<?xml version="1.0" encoding="utf-8"?>
|
|
<Activity xmlns="http://schemas.microsoft.com/netfx/2009/xaml/activities"
|
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
|
xmlns:ui="http://schemas.uipath.com/workflow/activities"
|
|
xmlns:sap2010="http://schemas.microsoft.com/netfx/2010/xaml/activities/presentation">
|
|
<Sequence>
|
|
<ui:InvokeVBA>
|
|
<ui:InvokeVBA.CodeFilePath>
|
|
<InArgument x:TypeArguments="x:String">["Scripts/Keep.bas"]</InArgument>
|
|
</ui:InvokeVBA.CodeFilePath>
|
|
</ui:InvokeVBA>
|
|
</Sequence>
|
|
</Activity>
|
|
"""
|
|
|
|
OLD_XAML = """<?xml version="1.0" encoding="utf-8"?>
|
|
<Activity xmlns="http://schemas.microsoft.com/netfx/2009/xaml/activities"
|
|
xmlns:ui="http://schemas.uipath.com/workflow/activities">
|
|
<Sequence>
|
|
<ui:InvokeVBA CodeFilePath="Scripts/Drop.bas" />
|
|
</Sequence>
|
|
</Activity>
|
|
"""
|
|
|
|
|
|
class StubAnalyzer:
|
|
def analyze(self, relative_path: Path, content: str) -> str:
|
|
return f"# {relative_path.as_posix()}\n\n{len(content)}"
|
|
|
|
|
|
class PipelineTests(unittest.TestCase):
|
|
def test_strip_comment_out_blocks_removes_nested_blocks(self) -> None:
|
|
source = "<root><ui:CommentOut><x/><ui:CommentOut><y/></ui:CommentOut></ui:CommentOut><z/></root>"
|
|
cleaned = strip_comment_out_blocks(source)
|
|
self.assertEqual(cleaned, "<root><z/></root>")
|
|
|
|
def test_extract_dependencies_reads_property_element_paths(self) -> None:
|
|
with TemporaryDirectory() as tmp:
|
|
root = Path(tmp)
|
|
flows = root / "Flows"
|
|
flows.mkdir()
|
|
(root / "Main.xaml").write_text(ACTIVE_XAML, encoding="utf-8")
|
|
(root / "Scripts").mkdir()
|
|
(root / "Scripts" / "Keep.bas").write_text("Sub Keep()", encoding="utf-8")
|
|
|
|
dependencies, warnings = extract_dependencies(root, root / "Main.xaml")
|
|
|
|
self.assertEqual(len(warnings), 0)
|
|
self.assertEqual(len(dependencies), 1)
|
|
self.assertEqual(dependencies[0].target, root / "Scripts" / "Keep.bas")
|
|
|
|
def test_pipeline_prunes_files_only_reachable_before_comment_cleanup(self) -> None:
|
|
with TemporaryDirectory() as tmp:
|
|
tmp_path = Path(tmp)
|
|
project_root = tmp_path / "project"
|
|
output_root = tmp_path / "workspace"
|
|
(project_root / "Flows").mkdir(parents=True)
|
|
(project_root / "Flows" / "Active.xaml").write_text(ACTIVE_XAML, encoding="utf-8")
|
|
(project_root / "Flows" / "Old.xaml").write_text(OLD_XAML, encoding="utf-8")
|
|
(project_root / "Scripts").mkdir()
|
|
(project_root / "Scripts" / "Keep.bas").write_text("Sub Keep()\nEnd Sub", encoding="utf-8")
|
|
(project_root / "Scripts" / "Drop.bas").write_text("Sub Drop()\nEnd Sub", encoding="utf-8")
|
|
(project_root / "main.xaml").write_text(MAIN_XAML, encoding="utf-8")
|
|
|
|
initial_scan = crawl_dependencies(project_root, project_root / "main.xaml")
|
|
initial_files = {path.relative_to(project_root).as_posix() for path in initial_scan.files}
|
|
self.assertIn("Flows/Old.xaml", initial_files)
|
|
self.assertIn("Scripts/Drop.bas", initial_files)
|
|
|
|
report = ProjectPipeline(project_root, output_root, "main.xaml", force=True).run(StubAnalyzer())
|
|
|
|
final_files = {path.as_posix() for path in report.final_files}
|
|
self.assertIn("main.xaml", final_files)
|
|
self.assertIn("Flows/Active.xaml", final_files)
|
|
self.assertIn("Scripts/Keep.bas", final_files)
|
|
self.assertNotIn("Flows/Old.xaml", final_files)
|
|
self.assertNotIn("Scripts/Drop.bas", final_files)
|
|
self.assertFalse((output_root / "Flows" / "Old.xaml").exists())
|
|
self.assertFalse((output_root / "Scripts" / "Drop.bas").exists())
|
|
self.assertTrue((output_root / "Flows" / "Active.xaml.analysis.md").exists())
|
|
|
|
overview = (output_root / "OVERVIEW.md").read_text(encoding="utf-8")
|
|
self.assertIn("## Processing Logic", overview)
|
|
self.assertIn("Initial Scan", overview)
|
|
self.assertIn("## How To Read This Output", overview)
|
|
self.assertIn("## Cleaned XAML Files", overview)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|