1- """Executor 单元测试:JavaGenerator 代码生成(不启动 JVM)。"""
1+ """Executor 单元测试:do_exec_from_file、COMSOLRunner/JavaAPIController 依赖(不启动 JVM)。"""
2+ import json
3+ import tempfile
4+ from pathlib import Path
5+
26import pytest
37from unittest .mock import patch , Mock
48
59from schemas .geometry import GeometryPlan , GeometryShape
6- from agent .executor .java_generator import JavaGenerator
7-
8-
9- @pytest .fixture
10- def mock_settings ():
11- with patch ("agent.executor.java_generator.get_settings" ) as m :
12- m .return_value .model_output_dir = "/tmp/models"
13- yield m
10+ from agent .run .actions import do_exec_from_file
1411
1512
1613@pytest .fixture
@@ -30,94 +27,31 @@ def sample_plan():
3027
3128
3229@pytest .fixture
33- def plan_with_circle ():
34- return GeometryPlan (
35- model_name = "circle_model" ,
36- units = "m" ,
37- shapes = [
38- GeometryShape (
39- type = "circle" ,
40- parameters = {"radius" : 0.3 },
41- position = {"x" : 0.0 , "y" : 0.0 },
42- name = "circ1" ,
43- )
44- ],
45- )
46-
47-
48- @pytest .fixture
49- def plan_with_ellipse ():
50- return GeometryPlan (
51- model_name = "ellipse_model" ,
52- units = "m" ,
53- shapes = [
54- GeometryShape (
55- type = "ellipse" ,
56- parameters = {"a" : 1.0 , "b" : 0.6 },
57- position = {"x" : 0.5 , "y" : 0.5 },
58- name = "ell1" ,
59- )
60- ],
61- )
62-
63-
64- class TestJavaGenerator :
65- """JavaGenerator:generate_from_plan、_generate_direct_code、_generate_shape_code"""
66-
67- def test_generate_from_plan_uses_direct_code_when_template_empty (self , mock_settings , sample_plan ):
68- with patch ("agent.executor.java_generator.prompt_loader" ) as mock_loader :
69- mock_loader .format .return_value = "" # 模拟模板返回空,走 _generate_direct_code
70- gen = JavaGenerator ()
71- code = gen .generate_from_plan (sample_plan , output_filename = "out.mph" )
72- assert "import com.comsol" in code
73- assert "geom1" in code
74- assert "rect1" in code or "Rectangle" in code
75- assert "model.save" in code or "save" in code
76-
77- def test_generate_shape_code_rectangle (self , mock_settings ):
78- gen = JavaGenerator ()
79- shape = GeometryShape (
80- type = "rectangle" ,
81- parameters = {"width" : 2.0 , "height" : 1.0 },
82- position = {"x" : 1.0 , "y" : 0.5 },
83- name = "r1" ,
84- )
85- code = gen ._generate_shape_code (shape , 1 )
86- assert "2.0" in code
87- assert "1.0" in code
88- assert "1.0" in code and "0.5" in code # pos
89-
90- def test_generate_shape_code_circle (self , mock_settings ):
91- gen = JavaGenerator ()
92- shape = GeometryShape (
93- type = "circle" ,
94- parameters = {"radius" : 0.3 },
95- position = {"x" : 0.0 , "y" : 0.0 },
96- name = "c1" ,
97- )
98- code = gen ._generate_shape_code (shape , 1 )
99- assert "0.3" in code
100- assert "Circle" in code or "circle" in code
101-
102- def test_generate_shape_code_ellipse (self , mock_settings ):
103- gen = JavaGenerator ()
104- shape = GeometryShape (
105- type = "ellipse" ,
106- parameters = {"a" : 1.0 , "b" : 0.6 },
107- position = {"x" : 0.0 , "y" : 0.0 },
108- name = "e1" ,
109- )
110- code = gen ._generate_shape_code (shape , 1 )
111- assert "1.0" in code
112- assert "0.6" in code
113- assert "Ellipse" in code or "ellipse" in code
114-
115- def test_generate_shape_code_unsupported_type_raises (self , mock_settings ):
116- gen = JavaGenerator ()
117- shape = Mock ()
118- shape .type = "unknown"
119- shape .parameters = {}
120- shape .position = {"x" : 0 , "y" : 0 }
121- shape .name = "x1"
122- with pytest .raises (ValueError , match = "不支持的形状类型" ):
123- gen ._generate_shape_code (shape , 1 )
30+ def plan_file (sample_plan , tmp_path ):
31+ path = tmp_path / "plan.json"
32+ path .write_text (json .dumps (sample_plan .to_dict (), ensure_ascii = False , indent = 2 ), encoding = "utf-8" )
33+ return path
34+
35+
36+ class TestDoExecFromFile :
37+ """do_exec_from_file:从 JSON 计划文件创建模型(不启动 JVM)。"""
38+
39+ def test_do_exec_from_file_success_when_runner_mocked (self , plan_file ):
40+ with patch ("agent.run.actions.COMSOLRunner" ) as mock_runner_cls :
41+ mock_runner_cls .return_value .create_model_from_plan .return_value = Path ("/tmp/out.mph" )
42+ ok , msg = do_exec_from_file (plan_file , output = None , verbose = False )
43+ assert ok is True
44+ assert "模型已生成" in msg or "out.mph" in msg
45+ mock_runner_cls .return_value .create_model_from_plan .assert_called_once ()
46+
47+ def test_do_exec_from_file_invalid_json_fails (self , tmp_path ):
48+ bad_file = tmp_path / "bad.json"
49+ bad_file .write_text ("not json" , encoding = "utf-8" )
50+ ok , msg = do_exec_from_file (bad_file , verbose = False )
51+ assert ok is False
52+ assert msg
53+
54+ def test_do_exec_from_file_nonexistent_fails (self , tmp_path ):
55+ ok , msg = do_exec_from_file (tmp_path / "nonexistent.json" , verbose = False )
56+ assert ok is False
57+ assert msg
0 commit comments