Spaces:
Sleeping
Sleeping
| """Tests for VerirlEnvironment.""" | |
| import pytest | |
| from verirl_env.models import VerirlAction | |
| from verirl_env.server.verirl_env_environment import VerirlEnvironment | |
| class TestEnvironmentReset: | |
| """Test environment reset.""" | |
| def test_reset_mac_unit(self, environment): | |
| obs = environment.reset(task_id="mac_unit") | |
| assert obs.task_spec != "" | |
| assert "mac" in obs.task_spec.lower() | |
| assert obs.compile_ok is False | |
| assert obs.tests_passed == 0 | |
| assert obs.turn_number == 0 | |
| assert obs.turns_remaining == 8 | |
| assert obs.done is False | |
| def test_reset_axi_fifo(self, environment): | |
| obs = environment.reset(task_id="axi_fifo") | |
| assert obs.task_spec != "" | |
| assert "fifo" in obs.task_spec.lower() | |
| assert obs.turns_remaining == 10 | |
| def test_reset_systolic_array(self, environment): | |
| obs = environment.reset(task_id="systolic_array") | |
| assert obs.task_spec != "" | |
| assert "systolic" in obs.task_spec.lower() | |
| assert obs.turns_remaining == 12 | |
| def test_reset_random_task(self, environment): | |
| obs = environment.reset(task_id=None) | |
| assert obs.task_spec != "" | |
| assert obs.turns_remaining > 0 | |
| class TestEnvironmentStep: | |
| """Test environment steps.""" | |
| def test_write_file_step(self, environment): | |
| environment.reset(task_id="mac_unit") | |
| obs = environment.step(VerirlAction( | |
| action_type="write_file", | |
| verilog_src="module mac_unit (input a); endmodule" | |
| )) | |
| assert obs.current_verilog is not None | |
| assert obs.turn_number == 1 | |
| assert obs.turns_remaining == 7 | |
| def test_write_empty_file(self, environment): | |
| environment.reset(task_id="mac_unit") | |
| obs = environment.step(VerirlAction( | |
| action_type="write_file", | |
| verilog_src="" | |
| )) | |
| assert "ERROR" in obs.tool_stderr | |
| def test_run_compile_no_file(self, environment): | |
| environment.reset(task_id="mac_unit") | |
| obs = environment.step(VerirlAction(action_type="run_compile")) | |
| assert "ERROR" in obs.tool_stderr | |
| def test_run_compile_after_write(self, environment, mac_reference_verilog, requires_iverilog): | |
| environment.reset(task_id="mac_unit") | |
| environment.step(VerirlAction( | |
| action_type="write_file", | |
| verilog_src=mac_reference_verilog | |
| )) | |
| obs = environment.step(VerirlAction(action_type="run_compile")) | |
| assert obs.compile_ok is True | |
| assert "successful" in obs.tool_stdout.lower() | |
| def test_run_sim_without_compile(self, environment, mac_reference_verilog): | |
| environment.reset(task_id="mac_unit") | |
| environment.step(VerirlAction( | |
| action_type="write_file", | |
| verilog_src=mac_reference_verilog | |
| )) | |
| obs = environment.step(VerirlAction(action_type="run_sim")) | |
| assert "ERROR" in obs.tool_stderr | |
| def test_run_sim_after_compile(self, environment, mac_reference_verilog, requires_eda_tools): | |
| environment.reset(task_id="mac_unit") | |
| environment.step(VerirlAction( | |
| action_type="write_file", | |
| verilog_src=mac_reference_verilog | |
| )) | |
| environment.step(VerirlAction(action_type="run_compile")) | |
| obs = environment.step(VerirlAction(action_type="run_sim")) | |
| assert obs.tests_total > 0 | |
| assert obs.tests_passed > 0 | |
| def test_write_file_resets_compile_ok(self, environment, mac_reference_verilog, requires_iverilog): | |
| """Rewriting code must clear compile_ok so stale state is never observed.""" | |
| environment.reset(task_id="mac_unit") | |
| # Write good code and compile — compile_ok becomes True | |
| environment.step(VerirlAction(action_type="write_file", verilog_src=mac_reference_verilog)) | |
| obs = environment.step(VerirlAction(action_type="run_compile")) | |
| assert obs.compile_ok is True | |
| # Overwrite with a different module — compile_ok must reset immediately | |
| obs = environment.step(VerirlAction( | |
| action_type="write_file", | |
| verilog_src="module mac_unit (input clk); endmodule" | |
| )) | |
| assert obs.compile_ok is False | |
| def test_write_file_resets_sim_state(self, environment, mac_reference_verilog, requires_eda_tools): | |
| """Rewriting code must clear tests_passed/tests_total from any previous sim.""" | |
| environment.reset(task_id="mac_unit") | |
| environment.step(VerirlAction(action_type="write_file", verilog_src=mac_reference_verilog)) | |
| environment.step(VerirlAction(action_type="run_compile")) | |
| obs = environment.step(VerirlAction(action_type="run_sim")) | |
| assert obs.tests_passed > 0 | |
| # Overwrite — sim state must be cleared | |
| obs = environment.step(VerirlAction( | |
| action_type="write_file", | |
| verilog_src="module mac_unit (input clk); endmodule" | |
| )) | |
| assert obs.tests_passed == 0 | |
| assert obs.tests_total == 0 | |
| class TestEnvironmentReward: | |
| """Test reward calculation.""" | |
| def test_reward_write_file(self, environment, mac_reference_verilog): | |
| environment.reset(task_id="mac_unit") | |
| obs = environment.step(VerirlAction( | |
| action_type="write_file", | |
| verilog_src=mac_reference_verilog | |
| )) | |
| assert obs.reward > 0 # should get positive reward for writing | |
| def test_reward_compile(self, environment, mac_reference_verilog, requires_iverilog): | |
| environment.reset(task_id="mac_unit") | |
| environment.step(VerirlAction( | |
| action_type="write_file", | |
| verilog_src=mac_reference_verilog | |
| )) | |
| obs = environment.step(VerirlAction(action_type="run_compile")) | |
| assert obs.reward > 0.02 # compile adds to reward | |
| def test_reward_sim_passing(self, environment, mac_reference_verilog, requires_eda_tools): | |
| environment.reset(task_id="mac_unit") | |
| environment.step(VerirlAction( | |
| action_type="write_file", | |
| verilog_src=mac_reference_verilog | |
| )) | |
| environment.step(VerirlAction(action_type="run_compile")) | |
| obs = environment.step(VerirlAction(action_type="run_sim")) | |
| assert obs.reward > 0.0 # Should have some reward from sim/tests | |
| class TestEnvironmentDone: | |
| """Test episode termination.""" | |
| def test_submit_ends_episode(self, environment, mac_reference_verilog): | |
| environment.reset(task_id="mac_unit") | |
| environment.step(VerirlAction( | |
| action_type="write_file", | |
| verilog_src=mac_reference_verilog | |
| )) | |
| environment.step(VerirlAction(action_type="run_compile")) | |
| obs = environment.step(VerirlAction(action_type="submit")) | |
| assert obs.done is True | |
| assert obs.final_score is not None | |
| def test_max_turns_expires(self, environment, mac_reference_verilog): | |
| env = VerirlEnvironment(max_turns=2) | |
| env.reset(task_id="mac_unit") | |
| env.step(VerirlAction(action_type="write_file", verilog_src=mac_reference_verilog)) | |
| obs = env.step(VerirlAction(action_type="run_compile")) | |
| assert obs.done is True # episode expires at max_turns | |
| assert obs.final_score is not None | |
| class TestTaskSelection: | |
| """Test task metadata and selection.""" | |
| def test_list_tasks(self, environment): | |
| tasks = environment.list_tasks() | |
| assert "mac_unit" in tasks | |
| assert "axi_fifo" in tasks | |
| assert "systolic_array" in tasks | |
| def test_num_tasks(self, environment): | |
| assert environment.num_tasks == 10 | |
| def test_invalid_task_id(self, environment): | |
| with pytest.raises(ValueError): | |
| environment.reset(task_id="invalid_task") | |