Copiando o repositório do Alexandre

This commit is contained in:
fls committed 2026-09-17 17:37:20 -03:00
1 parent a3e604697b
commit 0ab8836265
363 files changed
+27249

No files matched your search

View File
Whitespace-only changes.
+102
View File
@@ -0,0 +1,102 @@
{
"id": -1,
"version": "0.0.1",
"x": 0,
"y": 0,
"is_collapsed": false,
"type": "mosaicode_lib_javascript_webaudio.extensions.blocks.filter",
"language": "javascript",
"extension": "",
"file": null,
"help": "",
"label": "Filter",
"color": "#32963296",
"group": "Sound",
"ports": [
{
"type": "mosaicode_lib_javascript_webaudio.extensions.ports.sound",
"label": "Sound",
"conn_type": "INPUT",
"name": "sound_input",
"index": 0
},
{
"type": "mosaicode_lib_javascript_webaudio.extensions.ports.sound",
"label": "Frequency",
"conn_type": "INPUT",
"name": "osc_freq",
"index": 1
},
{
"type": "mosaicode_lib_javascript_webaudio.extensions.ports.float",
"label": "Frequency",
"conn_type": "INPUT",
"name": "freq",
"index": 2
},
{
"type": "mosaicode_lib_javascript_webaudio.extensions.ports.float",
"label": "Gain",
"conn_type": "INPUT",
"name": "gain",
"index": 3
},
{
"type": "mosaicode_lib_javascript_webaudio.extensions.ports.float",
"label": "Q",
"conn_type": "INPUT",
"name": "q",
"index": 4
},
{
"type": "mosaicode_lib_javascript_webaudio.extensions.ports.sound",
"label": "Sound",
"conn_type": "OUTPUT",
"name": "output",
"index": 5
}
],
"maxIO": 6,
"properties": [
{
"name": "type",
"label": "Type",
"value": "highpass",
"type": "Combo",
"values": ["allpass", "bandpass", "highshelf", "highpass", "lowpass", "lowshelf", "notch", "peaking"]
},
{
"name": "freq",
"label": "Frequency",
"value": 200,
"type": "Float",
"lower": 0,
"upper": 48000,
"step": 1
},
{
"name": "gain",
"label": "Gain",
"value": 1,
"type": "Float",
"lower": 0,
"upper": 100,
"step": 0.1
},
{
"name": "Q",
"label": "Q",
"value": 200,
"type": "Float",
"lower": 0,
"upper": 48000,
"step": 1
}
],
"codes": {
"declaration": "\n\n// block_$id$ = $label$\nvar block_$id$ = context.createBiquadFilter();\nvar $port[osc_freq]$ = block_$id$.frequency;\nblock_$id$.type = '$prop[type]$';\nblock_$id$.frequency.value = '$prop[freq]$';\nblock_$id$.gain.value = $prop[gain]$;\nblock_$id$.Q.value = $prop[Q]$;\n\nvar $port[freq]$ = function(value){\n block_$id$.frequency.value = parseFloat(value);\n return true;\n };\n\nvar $port[q]$ = function(value){\n block_$id$.Q.value = parseFloat(value);\n return true;\n };\n\nvar $port[gain]$ = function(value){\n block_$id$.gain.value = parseFloat(value);\n return true;\n };\n\nvar $port[sound_input]$ = block_$id$;\nvar $port[output]$ = block_$id$;\n"
},
"gen_codes": {},
"weight": 0,
"connections": []
}
+16
View File
@@ -0,0 +1,16 @@
{
"name": "webaudio",
"type": "mosaicode_lib_javascript_webaudio.extensions.html",
"language": "javascript",
"command": "python -m webbrowser -t $dir_name$index.html ",
"description": "Javascript / webaudio code template",
"code_parts": [
"onload",
"function",
"declaration",
"execution",
"html"
],
"properties": [],
"files": {}
}
+120
View File
@@ -0,0 +1,120 @@
# -*- coding: utf-8 -*-
"""
Tests for CodeGenerator class.
Migrated from unittest/TestBase to pytest.
"""
import pytest
import tempfile
import shutil
from pathlib import Path
from unittest.mock import Mock, patch, MagicMock
from mosaicode.control.codegenerator import CodeGenerator
@pytest.fixture
def temp_dir():
"""Create temporary directory for tests."""
test_dir = Path(tempfile.mkdtemp(prefix="mosaicode_test_"))
yield test_dir
if test_dir.exists():
shutil.rmtree(test_dir)
@pytest.fixture
def diagram():
"""Create a basic diagram for testing."""
from mosaicode.model.diagrammodel import DiagramModel
return DiagramModel()
@pytest.fixture
def code_generator(diagram):
"""Create a CodeGenerator instance."""
return CodeGenerator(diagram)
@pytest.fixture
def block():
"""Create a basic block for testing."""
from mosaicode.model.blockmodel import BlockModel
return BlockModel()
@pytest.fixture
def port():
"""Create a basic port for testing."""
from mosaicode.model.port import Port
return Port()
@pytest.fixture
def connection():
"""Create a basic connection for testing."""
from mosaicode.model.connectionmodel import ConnectionModel
from mosaicode.model.blockmodel import BlockModel
from mosaicode.model.port import Port
# Create a basic connection with required parameters
block1 = BlockModel()
block2 = BlockModel()
port1 = Port()
port2 = Port()
connection = ConnectionModel(diagram=None, output=block1, output_port=port1, input=block2, input_port=port2)
return connection
def create_diagram_with_blocks(diagram, block, connection):
"""Create a diagram with test blocks."""
from mosaicode.model.blockmodel import BlockModel
# Add test blocks
block1 = block
block1.id = 1
block1.type = "test.block1"
block1.label = "Block 1"
block1.codes = {"function": "print('Hello from block 1')"}
block2 = BlockModel()
block2.id = 2
block2.type = "test.block2"
block2.label = "Block 2"
block2.codes = {"function": "print('Hello from block 2')"}
diagram.blocks = {"1": block1, "2": block2}
return diagram
def test_code_generator_initialization(code_generator, diagram):
"""Test CodeGenerator initialization."""
assert code_generator is not None
assert code_generator._CodeGenerator__diagram == diagram
assert code_generator._CodeGenerator__block_list == []
assert code_generator._CodeGenerator__connections == []
assert code_generator._CodeGenerator__codes == {}
def test_generate_code_integration(diagram, block, connection):
"""Test complete code generation integration."""
diagram = create_diagram_with_blocks(diagram, block, connection)
code_generator = CodeGenerator(diagram)
# Test complete code generation
result = code_generator.generate_code()
assert isinstance(result, dict)
def test_generate_code_empty_diagram(diagram):
"""Test code generation with empty diagram."""
empty_diagram = diagram
empty_diagram.blocks = {}
empty_diagram.connectors = []
code_generator = CodeGenerator(empty_diagram)
result = code_generator.generate_code()
assert isinstance(result, dict)
def test_generate_code_with_errors(diagram, block, connection):
"""Test code generation error handling."""
diagram = create_diagram_with_blocks(diagram, block, connection)
# Create block with invalid code
block = diagram.blocks["1"]
block.codes = {"function": "$invalid_property$"}
code_generator = CodeGenerator(diagram)
# Should not raise exception, should handle gracefully
result = code_generator.generate_code()
assert isinstance(result, dict)
+336
View File
@@ -0,0 +1,336 @@
# -*- coding: utf-8 -*-
"""
Tests for CodeGenerator (pure logic, no GUI dependencies).
"""
import pytest
from pathlib import Path
import tempfile
import shutil
import json
from unittest.mock import Mock, patch, MagicMock
# Mock the GTK import before importing CodeGenerator
import sys
from unittest.mock import MagicMock
# Create a mock for gi module
mock_gi = MagicMock()
sys.modules['gi'] = mock_gi
sys.modules['gi.repository'] = MagicMock()
sys.modules['gi.repository.Gtk'] = MagicMock()
# Now we can import CodeGenerator
from mosaicode.control.codegenerator import CodeGenerator
@pytest.fixture
def test_dir():
"""Create temporary test directory."""
test_dir = Path(tempfile.mkdtemp(prefix="mosaicode_test_"))
yield test_dir
if test_dir.exists():
shutil.rmtree(test_dir)
@pytest.fixture
def mock_diagram():
"""Create a mock diagram for testing."""
diagram = Mock()
# Mock blocks
block1 = Mock()
block1.id = 1
block1.type = "test.block1"
block1.label = "Block 1"
block1.weight = 0
block1.connections = []
block1.codes = {"function": "print('Hello from block 1')"}
block1.gen_codes = {}
block1.ports = []
block1.get_properties.return_value = []
block2 = Mock()
block2.id = 2
block2.type = "test.block2"
block2.label = "Block 2"
block2.weight = 0
block2.connections = []
block2.codes = {"function": "print('Hello from block 2')"}
block2.gen_codes = {}
block2.ports = []
block2.get_properties.return_value = []
diagram.blocks = {1: block1, 2: block2}
diagram.connectors = []
# Mock code template
code_template = Mock()
code_template.code_parts = ["function", "declaration"]
code_template.command = "python $dir_name$index.py"
code_template.name = "test_template"
code_template.description = "Test template"
code_template.properties = []
diagram.code_template = code_template
return diagram
class TestCodeGeneratorPure:
"""Test cases for CodeGenerator (pure logic)."""
def test_code_generator_initialization(self, mock_diagram):
"""Test CodeGenerator initialization."""
code_generator = CodeGenerator(mock_diagram)
assert code_generator is not None
assert code_generator._CodeGenerator__diagram == mock_diagram
assert code_generator._CodeGenerator__block_list == []
assert code_generator._CodeGenerator__connections == []
assert code_generator._CodeGenerator__codes == {}
def test_prepare_block_list(self, mock_diagram):
"""Test block list preparation."""
code_generator = CodeGenerator(mock_diagram)
# Test prepare block list
result = code_generator._CodeGenerator__prepare_block_list()
assert result is True
# Check that blocks were added to the list
assert len(code_generator._CodeGenerator__block_list) == 2
# Check that blocks have weight and connections initialized
for block in code_generator._CodeGenerator__block_list:
assert block.weight == 0
assert block.connections == []
def test_sort_block_list(self, mock_diagram):
"""Test block list sorting."""
code_generator = CodeGenerator(mock_diagram)
code_generator._CodeGenerator__prepare_block_list()
# Test sort block list
result = code_generator._CodeGenerator__sort_block_list()
assert result is True
# All blocks should still have weight 0 since there are no connections
for block in code_generator._CodeGenerator__block_list:
assert block.weight == 0
def test_sort_block_list_with_connections(self):
"""Test block list sorting with connections."""
# Create mock diagram with connections
diagram = Mock()
# Create blocks
block1 = Mock()
block1.id = 1
block1.weight = 0
block1.connections = []
block2 = Mock()
block2.id = 2
block2.weight = 0
block2.connections = []
# Create connection
connection = Mock()
connection.output = block1
connection.input = block2
# Set up connections
block1.connections = [connection]
diagram.blocks = {1: block1, 2: block2}
diagram.connectors = [connection]
code_generator = CodeGenerator(diagram)
code_generator._CodeGenerator__prepare_block_list()
# Test sort block list
result = code_generator._CodeGenerator__sort_block_list()
assert result is True
# Block2 should have higher weight than block1
block1_weight = next(b.weight for b in code_generator._CodeGenerator__block_list if b.id == 1)
block2_weight = next(b.weight for b in code_generator._CodeGenerator__block_list if b.id == 2)
assert block2_weight > block1_weight
def test_generate_port_var_name_code(self, mock_diagram):
"""Test port variable name code generation."""
code_generator = CodeGenerator(mock_diagram)
# Create mock block and port
block = Mock()
block.id = 1
block.type = "test.block"
port = Mock()
port.var_name = "$port[name]$"
port.name = "test_port"
# Test port variable name generation
result = code_generator._CodeGenerator__generate_port_var_name_code(block, port)
assert result == "test_port"
def test_generate_block_code_parts(self, mock_diagram):
"""Test block code parts generation."""
code_generator = CodeGenerator(mock_diagram)
code_generator._CodeGenerator__prepare_block_list()
code_generator._CodeGenerator__sort_block_list()
# Test generate block code parts
result = code_generator._CodeGenerator__generate_block_code_parts()
assert result is True
# Check that codes were generated for each part
assert "function" in code_generator._CodeGenerator__codes
assert "declaration" in code_generator._CodeGenerator__codes
def test_generate_block_code(self, mock_diagram):
"""Test individual block code generation."""
code_generator = CodeGenerator(mock_diagram)
code_generator._CodeGenerator__prepare_block_list()
# Get first block
block = code_generator._CodeGenerator__block_list[0]
# Test generate block code
result = code_generator._CodeGenerator__generate_block_code(block)
assert result is True
# Check that gen_codes were created for the block
assert "function" in block.gen_codes
assert block.gen_codes["function"] == "print('Hello from block 1')"
def test_generate_file_code(self, mock_diagram, test_dir):
"""Test file code generation."""
# Mock diagram.language e patch_name para evitar TypeError
mock_diagram.language = "python"
mock_diagram.patch_name = "test_patch"
# Mock code_template.codes para evitar erro de iteração
mock_diagram.code_template.codes = {"function": "print('Hello World')"}
code_generator = CodeGenerator(mock_diagram)
code_generator._CodeGenerator__prepare_block_list()
code_generator._CodeGenerator__sort_block_list()
code_generator._CodeGenerator__generate_block_code_parts()
# Test generate file code com template simples
template_code = "print('Hello World')"
result = code_generator._CodeGenerator__generate_file_code(template_code)
assert isinstance(result, str)
assert "Hello World" in result
def test_generate_code_integration(self, mock_diagram, test_dir):
"""Test complete code generation integration."""
# Mock diagram.language e patch_name para evitar TypeError
mock_diagram.language = "python"
mock_diagram.patch_name = "test_patch"
# Mock code_template.codes para evitar erro de iteração
mock_diagram.code_template.codes = {"function": "print('Hello World')"}
code_generator = CodeGenerator(mock_diagram)
# Test complete code generation
result = code_generator.generate_code()
assert isinstance(result, dict)
assert "function" in result
assert "Hello World" in result["function"]
def test_code_generator_with_properties(self):
"""Test code generator with block properties."""
# Create mock diagram with properties
diagram = Mock()
# Create block with properties
block = Mock()
block.id = 1
block.type = "test.block"
block.label = "Test Block"
block.weight = 0
block.connections = []
block.codes = {"function": "print('Hello from block')"}
block.gen_codes = {}
block.ports = []
# Mock properties
properties = [
{"name": "prop1", "value": "value1"},
{"name": "prop2", "value": "value2"}
]
block.get_properties.return_value = properties
diagram.blocks = {1: block}
diagram.connectors = []
# Mock code template
code_template = Mock()
code_template.code_parts = ["function"]
code_template.command = "python $dir_name$index.py"
code_template.name = "test_template"
code_template.description = "Test template"
code_template.properties = []
diagram.code_template = code_template
code_generator = CodeGenerator(diagram)
code_generator._CodeGenerator__prepare_block_list()
# Test that properties are handled correctly
block = code_generator._CodeGenerator__block_list[0]
properties = block.get_properties()
assert len(properties) == 2
assert properties[0]["name"] == "prop1"
assert properties[1]["name"] == "prop2"
def test_code_generator_with_ports(self):
"""Test code generator with block ports."""
# Create mock diagram with ports
diagram = Mock()
# Create block with ports
block = Mock()
block.id = 1
block.type = "test.block"
block.label = "Test Block"
block.weight = 0
block.connections = []
block.codes = {"function": "print('Hello from block')"}
block.gen_codes = {}
# Mock ports
port1 = Mock()
port1.name = "input1"
port1.type = "float"
port1.conn_type = "INPUT"
port2 = Mock()
port2.name = "output1"
port2.type = "float"
port2.conn_type = "OUTPUT"
block.ports = [port1, port2]
block.get_properties.return_value = []
diagram.blocks = {1: block}
diagram.connectors = []
# Mock code template
code_template = Mock()
code_template.code_parts = ["function"]
code_template.command = "python $dir_name$index.py"
code_template.name = "test_template"
code_template.description = "Test template"
code_template.properties = []
diagram.code_template = code_template
code_generator = CodeGenerator(diagram)
code_generator._CodeGenerator__prepare_block_list()
# Test that ports are handled correctly
block = code_generator._CodeGenerator__block_list[0]
assert len(block.ports) == 2
assert block.ports[0].name == "input1"
assert block.ports[1].name == "output1"
+481
View File
@@ -0,0 +1,481 @@
# -*- coding: utf-8 -*-
"""
Tests for DiagramControl class.
Migrated from unittest to pytest.
"""
import pytest
from unittest.mock import Mock, patch, MagicMock
from pathlib import Path
import tempfile
import os
from mosaicode.control.diagramcontrol import DiagramControl
from mosaicode.model.blockmodel import BlockModel
from mosaicode.model.commentmodel import CommentModel
from mosaicode.model.connectionmodel import ConnectionModel
from mosaicode.GUI.comment import Comment
@pytest.fixture
def mock_diagram():
"""Create a mock diagram for testing."""
mock_diag = Mock()
mock_diag.blocks = {}
mock_diag.connectors = []
mock_diag.comments = []
mock_diag.language = None
mock_diag.last_id = 0
mock_diag.undo_stack = []
mock_diag.redo_stack = []
mock_diag.main_window = Mock()
mock_diag.main_window.main_control = Mock()
mock_diag.main_window.main_control.get_clipboard.return_value = []
mock_diag.main_window.main_control.reset_clipboard = Mock()
mock_diag.main_window.main_control.add_block = Mock()
mock_diag.main_window.main_control.add_comment = Mock()
mock_diag.main_window.main_control.do = Mock()
mock_diag.main_window.get_size.return_value = (800, 600)
mock_diag.deselect_all = Mock()
mock_diag.update_flows = Mock()
mock_diag.redraw = Mock()
mock_diag.start_connection = Mock()
mock_diag.end_connection = Mock()
return mock_diag
@pytest.fixture
def diagram_control(mock_diagram):
"""Create DiagramControl instance for testing."""
return DiagramControl(mock_diagram)
@pytest.fixture
def test_block():
"""Create a test block for testing."""
block = BlockModel()
block.id = 1
block.type = "TestBlock"
block.label = "Test Block"
block.language = "python"
block.x = 100
block.y = 100
# Add is_selected as a dynamic attribute for testing
setattr(block, 'is_selected', False)
# Add get_position method
def get_position():
return block.x, block.y
setattr(block, 'get_position', get_position)
# Add width and height attributes
setattr(block, 'width', 100)
setattr(block, 'height', 50)
return block
@pytest.fixture
def test_comment():
"""Create a test comment for testing."""
comment = CommentModel()
comment.id = 1
comment.x = 200
comment.y = 200
# Set text through properties
comment.properties[0]["value"] = "Test Comment"
# Add text attribute for compatibility
setattr(comment, 'text', "Test Comment")
# Add color attribute for compatibility
setattr(comment, 'color', "#000000")
# Add is_selected as a dynamic attribute for testing
setattr(comment, 'is_selected', False)
return comment
@pytest.fixture
def test_connection():
"""Create a test connection for testing."""
mock_diagram = Mock()
mock_output = Mock()
mock_output_port = Mock()
connection = ConnectionModel(mock_diagram, mock_output, mock_output_port)
# Add is_selected as a dynamic attribute for testing
setattr(connection, 'is_selected', False)
return connection
def test_init(mock_diagram):
"""Test DiagramControl initialization."""
control = DiagramControl(mock_diagram)
assert control.diagram == mock_diagram
def test_add_block_success(diagram_control, test_block):
"""Test adding a block successfully."""
result = diagram_control.add_block(test_block)
assert result is True
assert test_block.id in diagram_control.diagram.blocks
assert diagram_control.diagram.blocks[test_block.id] == test_block
# The do method is called internally, not through main_control
# diagram_control.diagram.main_window.main_control.do.assert_called_once_with("Add Block")
def test_add_block_language_compatibility(diagram_control, test_block):
"""Test adding a block with language compatibility."""
# Set diagram language
diagram_control.diagram.language = "python"
test_block.language = "python"
result = diagram_control.add_block(test_block)
assert result is True
assert test_block.id in diagram_control.diagram.blocks
def test_add_block_language_incompatibility(diagram_control, test_block):
"""Test adding a block with incompatible language."""
# Set diagram language
diagram_control.diagram.language = "python"
test_block.language = "javascript"
with patch('mosaicode.system.System.log') as mock_log:
result = diagram_control.add_block(test_block)
assert result is False
mock_log.assert_called_once_with("Block language is different from diagram language.")
def test_add_block_sets_diagram_language(diagram_control, test_block):
"""Test that adding a block sets diagram language if not set."""
# Diagram has no language set
diagram_control.diagram.language = None
test_block.language = "python"
result = diagram_control.add_block(test_block)
assert result is True
assert diagram_control.diagram.language == "python"
def test_add_comment(diagram_control, test_comment):
"""Test adding a comment."""
result = diagram_control.add_comment(test_comment)
# The actual Comment instance is returned
assert isinstance(result, Comment)
# Verify comment was added to diagram
assert result in diagram_control.diagram.comments
def test_add_comment_no_comment(diagram_control):
"""Test adding a comment without providing comment model."""
result = diagram_control.add_comment()
# The actual Comment instance is returned
assert isinstance(result, Comment)
# Verify comment was added to diagram
assert result in diagram_control.diagram.comments
def test_add_connection(diagram_control, test_connection):
"""Test adding a connection."""
result = diagram_control.add_connection(test_connection)
assert result is True
# Verify connection was added to diagram
assert test_connection in diagram_control.diagram.connectors
def test_collapse_all(diagram_control):
"""Test collapse all functionality."""
result = diagram_control.collapse_all(True)
assert result is True
# Verify that all blocks are collapsed
for block in diagram_control.diagram.blocks.values():
assert block.is_collapsed is True
def test_align(diagram_control, test_block):
"""Test align functionality."""
# Add a block to the diagram
diagram_control.diagram.blocks[test_block.id] = test_block
test_block.is_selected = True
# Store original position
original_y = test_block.y
diagram_control.align("top")
# Verify alignment was attempted (the actual alignment logic may vary)
# Just verify the method was called without error
assert test_block.is_selected is True
def test_copy(diagram_control, test_block, test_connection, test_comment):
"""Test copy functionality."""
# Setup selected items
test_block.is_selected = True
test_connection.is_selected = True
test_comment.is_selected = True
diagram_control.diagram.blocks[test_block.id] = test_block
diagram_control.diagram.connectors = [test_connection]
diagram_control.diagram.comments = [test_comment]
diagram_control.copy()
# Verify clipboard was reset and items were added
diagram_control.diagram.main_window.main_control.reset_clipboard.assert_called_once()
clipboard = diagram_control.diagram.main_window.main_control.get_clipboard()
assert test_block in clipboard
assert test_connection in clipboard
assert test_comment in clipboard
def test_cut(diagram_control, test_block):
"""Test cut functionality."""
# Setup selected block
test_block.is_selected = True
diagram_control.diagram.blocks[test_block.id] = test_block
diagram_control.cut()
# Verify cut operation completed (block removed from diagram)
assert test_block.id not in diagram_control.diagram.blocks
# The do method is called internally, not through main_control
# diagram_control.diagram.main_window.main_control.do.assert_called_with("Cut")
# Verify block was removed
assert test_block.id not in diagram_control.diagram.blocks
def test_delete(diagram_control, test_block, test_connection, test_comment):
"""Test delete functionality."""
# Setup selected items
test_block.is_selected = True
test_connection.is_selected = True
test_comment.is_selected = True
diagram_control.diagram.blocks[test_block.id] = test_block
diagram_control.diagram.connectors = [test_connection]
diagram_control.diagram.comments = [test_comment]
diagram_control.delete()
# Verify items were deleted
assert test_block.id not in diagram_control.diagram.blocks
assert test_connection not in diagram_control.diagram.connectors
assert test_comment not in diagram_control.diagram.comments
diagram_control.diagram.deselect_all.assert_called_once()
diagram_control.diagram.redraw.assert_called_once()
def test_paste(diagram_control, test_block, test_connection, test_comment):
"""Test paste functionality."""
# Setup clipboard with items
clipboard = [test_block, test_connection, test_comment]
diagram_control.diagram.main_window.main_control.get_clipboard.return_value = clipboard
# Mock add_block and add_comment to return the items
diagram_control.diagram.main_window.main_control.add_block.return_value = test_block
diagram_control.diagram.main_window.main_control.add_comment.return_value = test_comment
diagram_control.paste()
# Verify clipboard was accessed and items were processed
diagram_control.diagram.main_window.main_control.get_clipboard.assert_called()
diagram_control.diagram.update_flows.assert_called_once()
diagram_control.diagram.redraw.assert_called_once()
def test_undo(diagram_control):
"""Test undo functionality."""
diagram_control.undo()
# Verify undo operation (no assertion needed as it's handled internally)
# The do method is called internally, not through main_control
# diagram_control.diagram.main_window.main_control.do.assert_called_with("Undo")
def test_redo(diagram_control):
"""Test redo functionality."""
diagram_control.redo()
# Verify redo operation (no assertion needed as it's handled internally)
# The do method is called internally, not through main_control
# diagram_control.diagram.main_window.main_control.do.assert_called_with("Redo")
def test_do(diagram_control):
"""Test do functionality."""
diagram_control.do("Test Action")
# Verify action was recorded (no assertion needed as it's handled internally)
# The do method is called internally, not through main_control
# diagram_control.diagram.main_window.main_control.do.assert_called_with("Test Action")
def test_set_show_grid(diagram_control):
"""Test set show grid functionality."""
diagram_control.set_show_grid(True)
# Verify grid was set
assert diagram_control.diagram.show_grid is True
def test_get_min_max(diagram_control, test_block):
"""Test get min max functionality."""
# Add a block to the diagram
test_block.x = 100
test_block.y = 200
diagram_control.diagram.blocks[test_block.id] = test_block
min_x, min_y, max_x, max_y = diagram_control.get_min_max()
# Os valores devem ser coerentes com o bloco inserido
assert min_x <= test_block.x
assert min_y <= test_block.y
assert max_x >= test_block.x + test_block.width
assert max_y >= test_block.y + test_block.height
@patch('mosaicode.persistence.diagrampersistence.DiagramPersistence.save')
def test_save_success(mock_save, diagram_control):
"""Test saving diagram successfully."""
mock_save.return_value = (True, "")
result, message = diagram_control.save()
assert result is True
assert message == ""
mock_save.assert_called_once()
@patch('mosaicode.persistence.diagrampersistence.DiagramPersistence.save')
def test_save_failure(mock_save, diagram_control):
"""Test saving diagram with failure."""
mock_save.return_value = (False, "Error saving")
result, message = diagram_control.save()
assert result is False
assert message == "Error saving"
@patch('mosaicode.persistence.diagrampersistence.DiagramPersistence.load')
def test_load_success(mock_load, diagram_control):
"""Test loading diagram successfully."""
mock_load.return_value = True
# Create a temporary file for testing
with tempfile.NamedTemporaryFile(suffix='.mscd', delete=False) as temp_file:
temp_filename = temp_file.name
try:
result = diagram_control.load(temp_filename)
assert result is True
# The mock is called with the diagram object, not the filename
mock_load.assert_called_once()
finally:
# Clean up
if os.path.exists(temp_filename):
os.remove(temp_filename)
@patch('mosaicode.persistence.diagrampersistence.DiagramPersistence.load')
def test_load_failure(mock_load, diagram_control):
"""Test loading diagram with failure."""
mock_load.return_value = False
result = diagram_control.load("test.mscd")
assert result is False
@patch('mosaicode.control.diagramcontrol.DiagramPersistence.save')
@patch('mosaicode.control.diagramcontrol.Gdk')
def test_export_png_success(mock_gdk, mock_save, diagram_control):
"""Test exporting diagram to PNG successfully."""
mock_save.return_value = (True, "")
mock_pixbuf = Mock()
mock_pixbuf.save_to_bufferv.return_value = (True, b"fake_png_data")
mock_gdk.pixbuf_get_from_window.return_value = mock_pixbuf
result, message = diagram_control.export_png("test.png")
assert result is True
assert "successfully" in message.lower()
@patch('mosaicode.control.diagramcontrol.DiagramPersistence.save')
@patch('mosaicode.control.diagramcontrol.Gdk')
def test_export_png_failure(mock_gdk, mock_save, diagram_control):
"""Test exporting diagram to PNG with failure."""
mock_save.return_value = (False, "Error exporting")
mock_pixbuf = Mock()
mock_pixbuf.save_to_bufferv.return_value = (True, b"fake_png_data")
mock_gdk.pixbuf_get_from_window.return_value = mock_pixbuf
result, message = diagram_control.export_png("test.png")
# The actual result depends on the implementation
# Just verify the method was called without error
assert isinstance(result, bool)
assert isinstance(message, str)
def test_save_with_temp_file(diagram_control, test_comment):
"""Test saving diagram with temporary file."""
with tempfile.NamedTemporaryFile(suffix='.mscd', delete=False) as temp_file:
temp_filename = temp_file.name
try:
# Add a comment to the diagram
with patch('mosaicode.GUI.comment.Comment') as mock_comment_class:
mock_comment_instance = Mock()
mock_comment_class.return_value = mock_comment_instance
diagram_control.add_comment(test_comment)
# Mock the save method
with patch.object(diagram_control, 'save') as mock_save:
mock_save.return_value = (True, "")
result, message = diagram_control.save()
assert result is True
assert message == ""
finally:
# Clean up
if os.path.exists(temp_filename):
os.remove(temp_filename)
def test_load_with_temp_file(diagram_control, test_comment):
"""Test loading diagram with temporary file."""
with tempfile.NamedTemporaryFile(suffix='.mscd', delete=False) as temp_file:
temp_filename = temp_file.name
try:
# Add a comment to the diagram
with patch('mosaicode.GUI.comment.Comment') as mock_comment_class:
mock_comment_instance = Mock()
mock_comment_class.return_value = mock_comment_instance
diagram_control.add_comment(test_comment)
# Mock the save and load methods
with patch.object(diagram_control, 'save') as mock_save, \
patch.object(diagram_control, 'load') as mock_load:
mock_save.return_value = (True, "")
mock_load.return_value = True
# Save first
result, message = diagram_control.save()
assert result is True
# Then load
result = diagram_control.load(temp_filename)
assert result is True
finally:
# Clean up
if os.path.exists(temp_filename):
os.remove(temp_filename)
+206
View File
@@ -0,0 +1,206 @@
# -*- coding: utf-8 -*-
"""
Tests for PortControl class.
Migrated from unittest/TestBase to pytest.
"""
import pytest
import tempfile
import shutil
from pathlib import Path
import logging
from unittest.mock import Mock, patch, MagicMock
from mosaicode.control.portcontrol import PortControl
from mosaicode.model.port import Port
@pytest.fixture
def temp_dir():
"""Create temporary directory for tests."""
test_dir = Path(tempfile.mkdtemp(prefix="mosaicode_test_"))
yield test_dir
if test_dir.exists():
shutil.rmtree(test_dir)
@pytest.fixture
def test_port():
"""Create a test port."""
port = Port()
port.type = "test_port"
port.label = "Test Port"
port.name = "test_port"
port.language = "python"
port.color = "#FF0000"
port.multiple = False
return port
@pytest.fixture
def port_control():
"""Create a PortControl instance."""
return PortControl()
def test_port_control_initialization(port_control):
"""Test PortControl initialization."""
assert port_control is not None
@patch('mosaicode.persistence.portpersistence.PortPersistence.load')
def test_load_port(mock_load):
"""Test loading port from file."""
# Mock the load method to return True
mock_load.return_value = True
# Test loading port
result = PortControl.load("test.xml")
assert result == True
mock_load.assert_called_once_with("test.xml")
@patch('mosaicode.persistence.portpersistence.PortPersistence.save')
@patch('mosaicode.system.System.get_user_dir')
def test_add_port(mock_get_user_dir, mock_save, test_port, temp_dir):
"""Test adding a port."""
# Mock user directory to return Path object
mock_get_user_dir.return_value = temp_dir
# Mock save method
mock_save.return_value = True
# Test adding port
PortControl.add_port(test_port)
# Verify save was called
mock_save.assert_called_once()
# Verify the correct path was used
expected_path = temp_dir / "extensions" / "python" / "ports"
mock_save.assert_called_with(test_port, expected_path)
@patch('mosaicode.system.System.get_ports')
@patch('pathlib.Path.unlink')
def test_delete_port_existing(mock_unlink, mock_get_ports, test_port, temp_dir):
"""Test deleting an existing port."""
# Mock ports dictionary
mock_ports = {
"test_port": test_port
}
mock_get_ports.return_value = mock_ports
# Set file path for the port
test_port.file = str(temp_dir / "test_port.json")
# Test deleting port
result = PortControl.delete_port("test_port")
assert result == True
mock_unlink.assert_called_once()
@patch('mosaicode.system.System.get_ports')
def test_delete_port_not_found(mock_get_ports):
"""Test deleting a non-existent port."""
# Mock empty ports dictionary
mock_get_ports.return_value = {}
# Test deleting non-existent port
result = PortControl.delete_port("non_existent_port")
assert result == False
@patch('mosaicode.system.System.get_ports')
def test_delete_port_no_file(mock_get_ports, test_port):
"""Test deleting a port without file."""
# Mock ports dictionary
mock_ports = {
"test_port": test_port
}
mock_get_ports.return_value = mock_ports
# Set file to None
test_port.file = None
# Test deleting port without file
result = PortControl.delete_port("test_port")
assert result == False
@patch('logging.info')
def test_print_port(mock_logging, test_port):
"""Test printing port information."""
# Test printing port
PortControl.print_port(test_port)
# Verify logging calls were made with format strings
expected_calls = [
"Port Type: {port.type}",
"Port Label: {port.label}",
"Port Name: {port.name}",
"Port Language: {port.language}",
"Port File: {port.file}",
"Port Color: {port.color}",
"Port Multiple: {port.multiple}",
"Port Required: {port.required}",
"Port Max Conn: {port.max_conn}",
"Port Min Conn: {port.min_conn}",
"---------------------"
]
# Check that all expected log messages were called
for expected_call in expected_calls:
mock_logging.assert_any_call(expected_call)
def test_print_port_with_file(test_port):
"""Test printing port with file path."""
# Set file path
test_port.file = "/path/to/port.json"
with patch('logging.info') as mock_logging:
# Test printing port
PortControl.print_port(test_port)
# Verify file path was logged with format string
mock_logging.assert_any_call("Port File: {port.file}")
def test_add_port_with_different_language(temp_dir):
"""Test adding port with different language."""
# Create port with different language
port = Port()
port.language = "javascript"
port.type = "js_port"
with patch('mosaicode.persistence.portpersistence.PortPersistence.save') as mock_save:
with patch('mosaicode.system.System.get_user_dir') as mock_get_user_dir:
# Mock user directory to return Path object
mock_get_user_dir.return_value = temp_dir
# Test adding port
PortControl.add_port(port)
# Verify the correct path was used for javascript
expected_path = temp_dir / "extensions" / "javascript" / "ports"
mock_save.assert_called_with(port, expected_path)
def test_port_control_class_methods():
"""Test that all methods are class methods."""
# Verify all methods are class methods
assert hasattr(PortControl.load, '__self__')
assert hasattr(PortControl.add_port, '__self__')
assert hasattr(PortControl.delete_port, '__self__')
assert hasattr(PortControl.print_port, '__self__')
def test_delete_port_with_file_path(test_port, temp_dir):
"""Test deleting port with actual file path."""
# Create a temporary file
temp_file = temp_dir / "test_port.json"
temp_file.write_text('{"test": "data"}')
# Mock ports dictionary
with patch('mosaicode.system.System.get_ports') as mock_get_ports:
mock_ports = {
"test_port": test_port
}
mock_get_ports.return_value = mock_ports
# Set file path
test_port.file = str(temp_file)
# Test deleting port
result = PortControl.delete_port("test_port")
assert result == True
# Verify file was deleted
assert not temp_file.exists()