Test Routinen als Unittest integriert
This commit is contained in:
@@ -0,0 +1,316 @@
|
||||
"""
|
||||
Unit tests for ezdxf helper functions in utils.py
|
||||
|
||||
Tests cover:
|
||||
- Attribute extraction from INSERT blocks
|
||||
- Layer creation and management
|
||||
- Geometry creation (rectangles, text)
|
||||
- Block reference operations
|
||||
- Entity querying
|
||||
"""
|
||||
|
||||
import pytest
|
||||
import ezdxf
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
# Add lib directory to path for imports
|
||||
sys.path.insert(0, str(Path(__file__).parent.parent / 'lib'))
|
||||
|
||||
from utils import (
|
||||
extract_insert_attributes,
|
||||
extract_insert_attributes_with_doc,
|
||||
extract_attributes_with_positions,
|
||||
ensure_layer_exists,
|
||||
add_rectangle_lwpolyline,
|
||||
add_text_with_alignment,
|
||||
add_blockref_with_attributes,
|
||||
query_entities_by_layer,
|
||||
create_layers_from_config
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def doc():
|
||||
"""Create a new DXF document for testing"""
|
||||
return ezdxf.new('R2010')
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def msp(doc):
|
||||
"""Get modelspace from document"""
|
||||
return doc.modelspace()
|
||||
|
||||
|
||||
class TestAttributeExtraction:
|
||||
"""Tests for attribute extraction functions"""
|
||||
|
||||
def test_extract_insert_attributes_with_doc_simple(self, doc, msp):
|
||||
"""Test extracting attributes from a simple block with direct attributes"""
|
||||
# Create block with attributes
|
||||
block = doc.blocks.new('TEST_BLOCK')
|
||||
block.add_attdef('IO', (0, 0), dxfattribs={'height': 2.5})
|
||||
block.add_attdef('KENNZEICHNUNG', (0, 5), dxfattribs={'height': 2.5})
|
||||
|
||||
# Insert block and set attributes
|
||||
insert = msp.add_blockref('TEST_BLOCK', (10, 10))
|
||||
insert.add_auto_attribs({'IO': 'MA0001', 'KENNZEICHNUNG': '=A01+UH00'})
|
||||
|
||||
# Extract attributes
|
||||
attrs = extract_insert_attributes_with_doc(doc, insert)
|
||||
|
||||
assert attrs['IO'] == 'MA0001'
|
||||
assert attrs['KENNZEICHNUNG'] == '=A01+UH00'
|
||||
|
||||
def test_extract_insert_attributes_empty_block(self, doc, msp):
|
||||
"""Test extracting attributes from block without attributes"""
|
||||
block = doc.blocks.new('EMPTY_BLOCK')
|
||||
insert = msp.add_blockref('EMPTY_BLOCK', (10, 10))
|
||||
|
||||
attrs = extract_insert_attributes_with_doc(doc, insert)
|
||||
|
||||
assert attrs == {}
|
||||
|
||||
def test_extract_insert_attributes_non_insert(self, doc, msp):
|
||||
"""Test that non-INSERT entities return empty dict"""
|
||||
line = msp.add_line((0, 0), (10, 10))
|
||||
|
||||
attrs = extract_insert_attributes_with_doc(doc, line)
|
||||
|
||||
assert attrs == {}
|
||||
|
||||
def test_extract_attributes_with_positions(self, doc, msp):
|
||||
"""Test extracting attributes with position information"""
|
||||
# Create block with attributes
|
||||
block = doc.blocks.new('POS_TEST')
|
||||
block.add_attdef('IO', (0, 0), dxfattribs={'height': 2.5})
|
||||
block.add_attdef('NAME', (0, 5), dxfattribs={'height': 2.5})
|
||||
|
||||
# Insert blocks
|
||||
insert1 = msp.add_blockref('POS_TEST', (100, 200))
|
||||
insert1.add_auto_attribs({'IO': 'MA0001', 'NAME': 'Motor1'})
|
||||
|
||||
insert2 = msp.add_blockref('POS_TEST', (300, 400))
|
||||
insert2.add_auto_attribs({'IO': 'MA0002', 'NAME': 'Motor2'})
|
||||
|
||||
# Extract with positions
|
||||
all_inserts, all_positions = extract_attributes_with_positions(msp)
|
||||
|
||||
assert len(all_inserts) == 2
|
||||
assert len(all_positions) == 2
|
||||
assert all_inserts[0]['IO'] == 'MA0001'
|
||||
assert all_inserts[1]['IO'] == 'MA0002'
|
||||
|
||||
|
||||
class TestLayerOperations:
|
||||
"""Tests for layer creation and management functions"""
|
||||
|
||||
def test_ensure_layer_exists_new_layer(self, doc):
|
||||
"""Test creating a new layer"""
|
||||
layer = ensure_layer_exists(doc, 'TEST_LAYER', color=5)
|
||||
|
||||
assert 'TEST_LAYER' in doc.layers
|
||||
assert doc.layers.get('TEST_LAYER').color == 5
|
||||
|
||||
def test_ensure_layer_exists_existing_layer(self, doc):
|
||||
"""Test that existing layer is returned unchanged"""
|
||||
# Create layer first
|
||||
doc.layers.add('EXISTING', color=1)
|
||||
|
||||
# Ensure it exists (should not error)
|
||||
layer = ensure_layer_exists(doc, 'EXISTING', color=3)
|
||||
|
||||
assert 'EXISTING' in doc.layers
|
||||
# Color should be updated
|
||||
assert doc.layers.get('EXISTING').color == 3
|
||||
|
||||
def test_ensure_layer_with_all_options(self, doc):
|
||||
"""Test creating layer with all options"""
|
||||
layer = ensure_layer_exists(
|
||||
doc, 'FULL_LAYER',
|
||||
color=5,
|
||||
linetype='DASHED',
|
||||
lineweight=25,
|
||||
description='Test layer description'
|
||||
)
|
||||
|
||||
assert 'FULL_LAYER' in doc.layers
|
||||
layer_obj = doc.layers.get('FULL_LAYER')
|
||||
assert layer_obj.color == 5
|
||||
assert layer_obj.dxf.linetype == 'DASHED'
|
||||
assert layer_obj.dxf.lineweight == 25
|
||||
|
||||
def test_create_layers_from_config(self, doc):
|
||||
"""Test creating multiple layers from configuration"""
|
||||
layer_config = {
|
||||
'ILS_MOTOR': {'color': 1, 'description': 'Motor layer'},
|
||||
'ILS_SENSOR': {'color': 3, 'lineweight': 25},
|
||||
'ILS_CABLE': {'color': 5}
|
||||
}
|
||||
|
||||
create_layers_from_config(doc, layer_config)
|
||||
|
||||
assert 'ILS_MOTOR' in doc.layers
|
||||
assert 'ILS_SENSOR' in doc.layers
|
||||
assert 'ILS_CABLE' in doc.layers
|
||||
assert doc.layers.get('ILS_MOTOR').color == 1
|
||||
assert doc.layers.get('ILS_SENSOR').color == 3
|
||||
assert doc.layers.get('ILS_CABLE').color == 5
|
||||
|
||||
|
||||
class TestGeometryCreation:
|
||||
"""Tests for geometry creation functions"""
|
||||
|
||||
def test_add_rectangle_lwpolyline_simple(self, doc, msp):
|
||||
"""Test adding a simple rectangle"""
|
||||
rect = add_rectangle_lwpolyline(msp, 0, 0, 100, 50)
|
||||
|
||||
assert rect.dxftype() == 'LWPOLYLINE'
|
||||
assert rect.closed is True
|
||||
assert len(list(rect.get_points())) == 4
|
||||
|
||||
def test_add_rectangle_with_color(self, doc, msp):
|
||||
"""Test adding rectangle with color"""
|
||||
rect = add_rectangle_lwpolyline(msp, 10, 10, 200, 100, color=5)
|
||||
|
||||
assert rect.dxf.color == 5
|
||||
|
||||
def test_add_rectangle_with_rgb(self, doc, msp):
|
||||
"""Test adding rectangle with RGB color"""
|
||||
rect = add_rectangle_lwpolyline(msp, 20, 20, 150, 75, rgb=(255, 0, 0))
|
||||
|
||||
assert rect.rgb == (255, 0, 0)
|
||||
|
||||
def test_add_rectangle_on_layer(self, doc, msp):
|
||||
"""Test adding rectangle on specific layer"""
|
||||
ensure_layer_exists(doc, 'TEST_LAYER')
|
||||
rect = add_rectangle_lwpolyline(msp, 0, 0, 100, 50, layer='TEST_LAYER')
|
||||
|
||||
assert rect.dxf.layer == 'TEST_LAYER'
|
||||
|
||||
def test_add_text_with_alignment_simple(self, doc, msp):
|
||||
"""Test adding simple text"""
|
||||
text = add_text_with_alignment(msp, "Test", 100, 100)
|
||||
|
||||
assert text.dxftype() == 'TEXT'
|
||||
assert text.dxf.text == "Test"
|
||||
|
||||
def test_add_text_with_rotation(self, doc, msp):
|
||||
"""Test adding text with rotation"""
|
||||
text = add_text_with_alignment(msp, "Rotated", 200, 200, rotation=45.0)
|
||||
|
||||
assert text.dxf.rotation == 45.0
|
||||
|
||||
def test_add_text_with_color_and_height(self, doc, msp):
|
||||
"""Test adding text with color and height"""
|
||||
text = add_text_with_alignment(msp, "Styled", 300, 300, height=75, color=3)
|
||||
|
||||
assert text.dxf.height == 75
|
||||
assert text.dxf.color == 3
|
||||
|
||||
|
||||
class TestBlockOperations:
|
||||
"""Tests for block reference operations"""
|
||||
|
||||
def test_add_blockref_without_attributes(self, doc, msp):
|
||||
"""Test adding block reference without attributes"""
|
||||
# Create a simple block
|
||||
block = doc.blocks.new('SIMPLE_BLOCK')
|
||||
block.add_line((0, 0), (10, 10))
|
||||
|
||||
# Add block reference
|
||||
insert = add_blockref_with_attributes(msp, 'SIMPLE_BLOCK', (100, 100))
|
||||
|
||||
assert insert.dxftype() == 'INSERT'
|
||||
assert insert.dxf.name == 'SIMPLE_BLOCK'
|
||||
|
||||
def test_add_blockref_with_attributes(self, doc, msp):
|
||||
"""Test adding block reference with attributes"""
|
||||
# Create block with attribute definitions
|
||||
block = doc.blocks.new('ATTR_BLOCK')
|
||||
block.add_attdef('IO', (0, 0))
|
||||
block.add_attdef('NAME', (0, 5))
|
||||
|
||||
# Add block reference with attributes
|
||||
attrs = {'IO': 'MA0001', 'NAME': 'Motor'}
|
||||
insert = add_blockref_with_attributes(
|
||||
msp, 'ATTR_BLOCK', (200, 200), attributes=attrs
|
||||
)
|
||||
|
||||
assert insert.dxf.name == 'ATTR_BLOCK'
|
||||
# Check attributes were set
|
||||
attrib_values = {a.dxf.tag: a.dxf.text for a in insert.attribs}
|
||||
assert attrib_values['IO'] == 'MA0001'
|
||||
assert attrib_values['NAME'] == 'Motor'
|
||||
|
||||
def test_add_blockref_with_scale_and_rotation(self, doc, msp):
|
||||
"""Test adding block reference with scale and rotation"""
|
||||
block = doc.blocks.new('TRANSFORM_BLOCK')
|
||||
block.add_line((0, 0), (10, 10))
|
||||
|
||||
insert = add_blockref_with_attributes(
|
||||
msp, 'TRANSFORM_BLOCK', (300, 300),
|
||||
scale=0.5, rotation=90.0
|
||||
)
|
||||
|
||||
assert insert.dxf.xscale == 0.5
|
||||
assert insert.dxf.yscale == 0.5
|
||||
assert insert.dxf.rotation == 90.0
|
||||
|
||||
|
||||
class TestEntityQuerying:
|
||||
"""Tests for entity querying functions"""
|
||||
|
||||
def test_query_entities_by_layer_single_layer(self, doc, msp):
|
||||
"""Test querying entities on a single layer"""
|
||||
ensure_layer_exists(doc, 'MOTOR')
|
||||
ensure_layer_exists(doc, 'SENSOR')
|
||||
|
||||
# Add entities on different layers
|
||||
msp.add_line((0, 0), (10, 10), dxfattribs={'layer': 'MOTOR'})
|
||||
msp.add_line((0, 0), (20, 20), dxfattribs={'layer': 'SENSOR'})
|
||||
msp.add_line((0, 0), (30, 30), dxfattribs={'layer': 'MOTOR'})
|
||||
|
||||
# Query only MOTOR layer
|
||||
motor_entities = query_entities_by_layer(msp, 'LINE', layers=['MOTOR'])
|
||||
|
||||
assert len(motor_entities) == 2
|
||||
assert all(e.dxf.layer == 'MOTOR' for e in motor_entities)
|
||||
|
||||
def test_query_entities_by_type(self, doc, msp):
|
||||
"""Test querying entities by type"""
|
||||
msp.add_line((0, 0), (10, 10))
|
||||
msp.add_circle((0, 0), 5)
|
||||
msp.add_line((0, 0), (20, 20))
|
||||
|
||||
lines = query_entities_by_layer(msp, 'LINE')
|
||||
|
||||
assert len(lines) == 2
|
||||
assert all(e.dxftype() == 'LINE' for e in lines)
|
||||
|
||||
def test_query_entities_exclude_layers(self, doc, msp):
|
||||
"""Test querying entities excluding certain layers"""
|
||||
msp.add_line((0, 0), (10, 10), dxfattribs={'layer': '0'})
|
||||
msp.add_line((0, 0), (20, 20), dxfattribs={'layer': 'ILS'})
|
||||
msp.add_line((0, 0), (30, 30), dxfattribs={'layer': '0'})
|
||||
|
||||
# Exclude layer '0'
|
||||
entities = query_entities_by_layer(msp, 'LINE', exclude_layers=['0'])
|
||||
|
||||
assert len(entities) == 1
|
||||
assert entities[0].dxf.layer == 'ILS'
|
||||
|
||||
def test_query_entities_multiple_layers(self, doc, msp):
|
||||
"""Test querying entities from multiple layers"""
|
||||
msp.add_line((0, 0), (10, 10), dxfattribs={'layer': 'L1'})
|
||||
msp.add_line((0, 0), (20, 20), dxfattribs={'layer': 'L2'})
|
||||
msp.add_line((0, 0), (30, 30), dxfattribs={'layer': 'L3'})
|
||||
|
||||
entities = query_entities_by_layer(msp, 'LINE', layers=['L1', 'L2'])
|
||||
|
||||
assert len(entities) == 2
|
||||
assert set(e.dxf.layer for e in entities) == {'L1', 'L2'}
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
pytest.main([__file__, '-v'])
|
||||
Reference in New Issue
Block a user