summaryrefslogtreecommitdiff
path: root/gerber/tests
diff options
context:
space:
mode:
Diffstat (limited to 'gerber/tests')
-rw-r--r--gerber/tests/golden/example_two_square_boxes.pngbin0 -> 18247 bytes
-rw-r--r--gerber/tests/resources/example_two_square_boxes.gbr19
-rw-r--r--gerber/tests/test_am_statements.py19
-rw-r--r--gerber/tests/test_cairo_backend.py58
-rw-r--r--gerber/tests/test_cam.py11
-rw-r--r--gerber/tests/test_common.py5
-rw-r--r--gerber/tests/test_excellon.py47
-rw-r--r--gerber/tests/test_layers.py33
-rw-r--r--gerber/tests/test_primitives.py67
9 files changed, 196 insertions, 63 deletions
diff --git a/gerber/tests/golden/example_two_square_boxes.png b/gerber/tests/golden/example_two_square_boxes.png
new file mode 100644
index 0000000..4732995
--- /dev/null
+++ b/gerber/tests/golden/example_two_square_boxes.png
Binary files differ
diff --git a/gerber/tests/resources/example_two_square_boxes.gbr b/gerber/tests/resources/example_two_square_boxes.gbr
new file mode 100644
index 0000000..54a8ac1
--- /dev/null
+++ b/gerber/tests/resources/example_two_square_boxes.gbr
@@ -0,0 +1,19 @@
+G04 Ucamco ex. 1: Two square boxes*
+%FSLAX25Y25*%
+%MOMM*%
+%TF.Part,Other*%
+%LPD*%
+%ADD10C,0.010*%
+D10*
+X0Y0D02*
+G01*
+X500000Y0D01*
+Y500000D01*
+X0D01*
+Y0D01*
+X600000D02*
+X1100000D01*
+Y500000D01*
+X600000D01*
+Y0D01*
+M02* \ No newline at end of file
diff --git a/gerber/tests/test_am_statements.py b/gerber/tests/test_am_statements.py
index 0cee13d..39324e5 100644
--- a/gerber/tests/test_am_statements.py
+++ b/gerber/tests/test_am_statements.py
@@ -146,7 +146,9 @@ def test_AMOutlinePrimitive_factory():
def test_AMOUtlinePrimitive_dump():
o = AMOutlinePrimitive(4, 'on', (0, 0), [(3, 3), (3, 0), (0, 0)], 0)
- assert_equal(o.to_gerber(), '4,1,3,0,0,3,3,3,0,0,0,0*')
+ # New lines don't matter for Gerber, but we insert them to make it easier to remove
+ # For test purposes we can ignore them
+ assert_equal(o.to_gerber().replace('\n', ''), '4,1,3,0,0,3,3,3,0,0,0,0*')
def test_AMOutlinePrimitive_conversion():
o = AMOutlinePrimitive(4, 'on', (0, 0), [(25.4, 25.4), (25.4, 0), (0, 0)], 0)
@@ -229,30 +231,31 @@ def test_AMMoirePrimitive_conversion():
assert_equal(m.crosshair_length, 25.4)
def test_AMThermalPrimitive_validation():
- assert_raises(ValueError, AMThermalPrimitive, 8, (0.0, 0.0), 7, 5, 0.2)
- assert_raises(TypeError, AMThermalPrimitive, 7, (0.0, '0'), 7, 5, 0.2)
+ assert_raises(ValueError, AMThermalPrimitive, 8, (0.0, 0.0), 7, 5, 0.2, 0.0)
+ assert_raises(TypeError, AMThermalPrimitive, 7, (0.0, '0'), 7, 5, 0.2, 0.0)
def test_AMThermalPrimitive_factory():
- t = AMThermalPrimitive.from_gerber('7,0,0,7,6,0.2*')
+ t = AMThermalPrimitive.from_gerber('7,0,0,7,6,0.2,45*')
assert_equal(t.code, 7)
assert_equal(t.position, (0, 0))
assert_equal(t.outer_diameter, 7)
assert_equal(t.inner_diameter, 6)
assert_equal(t.gap, 0.2)
+ assert_equal(t.rotation, 45)
def test_AMThermalPrimitive_dump():
- t = AMThermalPrimitive.from_gerber('7,0,0,7,6,0.2*')
- assert_equal(t.to_gerber(), '7,0,0,7.0,6.0,0.2*')
+ t = AMThermalPrimitive.from_gerber('7,0,0,7,6,0.2,30*')
+ assert_equal(t.to_gerber(), '7,0,0,7.0,6.0,0.2,30.0*')
def test_AMThermalPrimitive_conversion():
- t = AMThermalPrimitive(7, (25.4, 25.4), 25.4, 25.4, 25.4)
+ t = AMThermalPrimitive(7, (25.4, 25.4), 25.4, 25.4, 25.4, 0.0)
t.to_inch()
assert_equal(t.position, (1., 1.))
assert_equal(t.outer_diameter, 1.)
assert_equal(t.inner_diameter, 1.)
assert_equal(t.gap, 1.)
- t = AMThermalPrimitive(7, (1, 1), 1, 1, 1)
+ t = AMThermalPrimitive(7, (1, 1), 1, 1, 1, 0)
t.to_metric()
assert_equal(t.position, (25.4, 25.4))
assert_equal(t.outer_diameter, 25.4)
diff --git a/gerber/tests/test_cairo_backend.py b/gerber/tests/test_cairo_backend.py
new file mode 100644
index 0000000..e298439
--- /dev/null
+++ b/gerber/tests/test_cairo_backend.py
@@ -0,0 +1,58 @@
+#! /usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# Author: Garret Fick <garret@ficksworkshop.com>
+import io
+import os
+
+from ..render.cairo_backend import GerberCairoContext
+from ..rs274x import read, GerberFile
+from .tests import *
+
+
+TWO_BOXES_FILE = os.path.join(os.path.dirname(__file__),
+ 'resources/example_two_square_boxes.gbr')
+TWO_BOXES_EXPECTED = os.path.join(os.path.dirname(__file__),
+ 'golden/example_two_square_boxes.png')
+
+def test_render_polygon():
+
+ _test_render(TWO_BOXES_FILE, TWO_BOXES_EXPECTED)
+
+def _test_render(gerber_path, png_expected_path, create_output_path = None):
+ """Render the gerber file and compare to the expected PNG output.
+
+ Parameters
+ ----------
+ gerber_path : string
+ Path to Gerber file to open
+ png_expected_path : string
+ Path to the PNG file to compare to
+ create_output : string|None
+ If not None, write the generated PNG to the specified path.
+ This is primarily to help with
+ """
+
+ gerber = read(gerber_path)
+
+ # Create PNG image to the memory stream
+ ctx = GerberCairoContext()
+ gerber.render(ctx)
+
+ actual_bytes = ctx.dump(None)
+
+ # If we want to write the file bytes, do it now. This happens
+ if create_output_path:
+ with open(create_output_path, 'wb') as out_file:
+ out_file.write(actual_bytes)
+ # Creating the output is dangerous - it could overwrite the expected result.
+ # So if we are creating the output, we make the test fail on purpose so you
+ # won't forget to disable this
+ assert_false(True, 'Test created the output %s. This needs to be disabled to make sure the test behaves correctly' % (create_output_path,))
+
+ # Read the expected PNG file
+
+ with open(png_expected_path, 'rb') as expected_file:
+ expected_bytes = expected_file.read()
+
+ assert_equal(expected_bytes, actual_bytes)
diff --git a/gerber/tests/test_cam.py b/gerber/tests/test_cam.py
index 00a8285..3ae0a24 100644
--- a/gerber/tests/test_cam.py
+++ b/gerber/tests/test_cam.py
@@ -113,10 +113,19 @@ def test_zeros():
def test_filesettings_validation():
""" Test FileSettings constructor argument validation
"""
+
+ # absolute-ish is not a valid notation
assert_raises(ValueError, FileSettings, 'absolute-ish', 'inch', None, (2, 5), None)
+
+ # degrees kelvin isn't a valid unit for a CAM file
assert_raises(ValueError, FileSettings, 'absolute', 'degrees kelvin', None, (2, 5), None)
+
assert_raises(ValueError, FileSettings, 'absolute', 'inch', 'leading', (2, 5), 'leading')
- assert_raises(ValueError, FileSettings, 'absolute', 'inch', 'following', (2, 5), None)
+
+ # Technnically this should be an error, but Eangle files often do this incorrectly so we
+ # allow it
+ # assert_raises(ValueError, FileSettings, 'absolute', 'inch', 'following', (2, 5), None)
+
assert_raises(ValueError, FileSettings, 'absolute', 'inch', None, (2, 5), 'following')
assert_raises(ValueError, FileSettings, 'absolute', 'inch', None, (2, 5, 6), None)
diff --git a/gerber/tests/test_common.py b/gerber/tests/test_common.py
index 7c66c0f..5991e5e 100644
--- a/gerber/tests/test_common.py
+++ b/gerber/tests/test_common.py
@@ -2,6 +2,7 @@
# -*- coding: utf-8 -*-
# Author: Hamilton Kibbe <ham@hamiltonkib.be>
+from ..exceptions import ParseError
from ..common import read, loads
from ..excellon import ExcellonFile
from ..rs274x import GerberFile
@@ -31,12 +32,12 @@ def test_load_from_string():
top_copper = loads(f.read())
assert_true(isinstance(ncdrill, ExcellonFile))
assert_true(isinstance(top_copper, GerberFile))
-
+
def test_file_type_validation():
""" Test file format validation
"""
- assert_raises(TypeError, read, 'LICENSE')
+ assert_raises(ParseError, read, 'LICENSE')
diff --git a/gerber/tests/test_excellon.py b/gerber/tests/test_excellon.py
index 705adc3..cd94b0f 100644
--- a/gerber/tests/test_excellon.py
+++ b/gerber/tests/test_excellon.py
@@ -78,8 +78,9 @@ def test_conversion():
for m_tool, i_tool in zip(iter(ncdrill.tools.values()), iter(ncdrill_inch.tools.values())):
assert_equal(i_tool, m_tool)
- for m, i in zip(ncdrill.primitives,inch_primitives):
- assert_equal(m, i)
+ for m, i in zip(ncdrill.primitives, inch_primitives):
+ assert_equal(m.position, i.position, '%s not equal to %s' % (m, i))
+ assert_equal(m.diameter, i.diameter, '%s not equal to %s' % (m, i))
def test_parser_hole_count():
@@ -98,60 +99,60 @@ def test_parser_hole_sizes():
def test_parse_whitespace():
p = ExcellonParser(FileSettings())
- assert_equal(p._parse(' '), None)
+ assert_equal(p._parse_line(' '), None)
def test_parse_comment():
p = ExcellonParser(FileSettings())
- p._parse(';A comment')
+ p._parse_line(';A comment')
assert_equal(p.statements[0].comment, 'A comment')
def test_parse_format_comment():
p = ExcellonParser(FileSettings())
- p._parse('; FILE_FORMAT=9:9 ')
+ p._parse_line('; FILE_FORMAT=9:9 ')
assert_equal(p.format, (9, 9))
def test_parse_header():
p = ExcellonParser(FileSettings())
- p._parse('M48 ')
+ p._parse_line('M48 ')
assert_equal(p.state, 'HEADER')
- p._parse('M95 ')
+ p._parse_line('M95 ')
assert_equal(p.state, 'DRILL')
def test_parse_rout():
p = ExcellonParser(FileSettings())
- p._parse('G00 ')
+ p._parse_line('G00 ')
assert_equal(p.state, 'ROUT')
- p._parse('G05 ')
+ p._parse_line('G05 ')
assert_equal(p.state, 'DRILL')
def test_parse_version():
p = ExcellonParser(FileSettings())
- p._parse('VER,1 ')
+ p._parse_line('VER,1 ')
assert_equal(p.statements[0].version, 1)
- p._parse('VER,2 ')
+ p._parse_line('VER,2 ')
assert_equal(p.statements[1].version, 2)
def test_parse_format():
p = ExcellonParser(FileSettings())
- p._parse('FMAT,1 ')
+ p._parse_line('FMAT,1 ')
assert_equal(p.statements[0].format, 1)
- p._parse('FMAT,2 ')
+ p._parse_line('FMAT,2 ')
assert_equal(p.statements[1].format, 2)
def test_parse_units():
settings = FileSettings(units='inch', zeros='trailing')
p = ExcellonParser(settings)
- p._parse(';METRIC,LZ')
+ p._parse_line(';METRIC,LZ')
assert_equal(p.units, 'inch')
assert_equal(p.zeros, 'trailing')
- p._parse('METRIC,LZ')
+ p._parse_line('METRIC,LZ')
assert_equal(p.units, 'metric')
assert_equal(p.zeros, 'leading')
@@ -160,9 +161,9 @@ def test_parse_incremental_mode():
settings = FileSettings(units='inch', zeros='trailing')
p = ExcellonParser(settings)
assert_equal(p.notation, 'absolute')
- p._parse('ICI,ON ')
+ p._parse_line('ICI,ON ')
assert_equal(p.notation, 'incremental')
- p._parse('ICI,OFF ')
+ p._parse_line('ICI,OFF ')
assert_equal(p.notation, 'absolute')
@@ -170,29 +171,29 @@ def test_parse_absolute_mode():
settings = FileSettings(units='inch', zeros='trailing')
p = ExcellonParser(settings)
assert_equal(p.notation, 'absolute')
- p._parse('ICI,ON ')
+ p._parse_line('ICI,ON ')
assert_equal(p.notation, 'incremental')
- p._parse('G90 ')
+ p._parse_line('G90 ')
assert_equal(p.notation, 'absolute')
def test_parse_repeat_hole():
p = ExcellonParser(FileSettings())
p.active_tool = ExcellonTool(FileSettings(), number=8)
- p._parse('R03X1.5Y1.5')
+ p._parse_line('R03X1.5Y1.5')
assert_equal(p.statements[0].count, 3)
def test_parse_incremental_position():
p = ExcellonParser(FileSettings(notation='incremental'))
- p._parse('X01Y01')
- p._parse('X01Y01')
+ p._parse_line('X01Y01')
+ p._parse_line('X01Y01')
assert_equal(p.pos, [2.,2.])
def test_parse_unknown():
p = ExcellonParser(FileSettings())
- p._parse('Not A Valid Statement')
+ p._parse_line('Not A Valid Statement')
assert_equal(p.statements[0].stmt, 'Not A Valid Statement')
diff --git a/gerber/tests/test_layers.py b/gerber/tests/test_layers.py
new file mode 100644
index 0000000..c77084d
--- /dev/null
+++ b/gerber/tests/test_layers.py
@@ -0,0 +1,33 @@
+#! /usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# Author: Hamilton Kibbe <ham@hamiltonkib.be>
+
+from .tests import *
+from ..layers import guess_layer_class, hints
+
+
+def test_guess_layer_class():
+ """ Test layer type inferred correctly from filename
+ """
+
+ # Add any specific test cases here (filename, layer_class)
+ test_vectors = [(None, 'unknown'), ('NCDRILL.TXT', 'unknown'),
+ ('example_board.gtl', 'top'),
+ ('exampmle_board.sst', 'topsilk'),
+ ('ipc-d-356.ipc', 'ipc_netlist'),]
+
+ for hint in hints:
+ for ext in hint.ext:
+ assert_equal(hint.layer, guess_layer_class('board.{}'.format(ext)))
+ for name in hint.name:
+ assert_equal(hint.layer, guess_layer_class('{}.pho'.format(name)))
+
+ for filename, layer_class in test_vectors:
+ assert_equal(layer_class, guess_layer_class(filename))
+
+
+def test_sort_layers():
+ """ Test layer ordering
+ """
+ pass
diff --git a/gerber/tests/test_primitives.py b/gerber/tests/test_primitives.py
index f8a32da..a88497c 100644
--- a/gerber/tests/test_primitives.py
+++ b/gerber/tests/test_primitives.py
@@ -9,10 +9,18 @@ from operator import add
def test_primitive_smoketest():
p = Primitive()
- assert_raises(NotImplementedError, p.bounding_box)
+ try:
+ p.bounding_box
+ assert_false(True, 'should have thrown the exception')
+ except NotImplementedError:
+ pass
p.to_metric()
p.to_inch()
- p.offset(1, 1)
+ try:
+ p.offset(1, 1)
+ assert_false(True, 'should have thrown the exception')
+ except NotImplementedError:
+ pass
def test_line_angle():
""" Test Line primitive angle calculation
@@ -150,7 +158,7 @@ def test_arc_radius():
((0, 1), (1, 0), (0, 0), 1),]
for start, end, center, radius in cases:
- a = Arc(start, end, center, 'clockwise', 0)
+ a = Arc(start, end, center, 'clockwise', 0, 'single-quadrant')
assert_equal(a.radius, radius)
def test_arc_sweep_angle():
@@ -163,7 +171,7 @@ def test_arc_sweep_angle():
for start, end, center, direction, sweep in cases:
c = Circle((0,0), 1)
- a = Arc(start, end, center, direction, c)
+ a = Arc(start, end, center, direction, c, 'single-quadrant')
assert_equal(a.sweep_angle, sweep)
def test_arc_bounds():
@@ -175,12 +183,12 @@ def test_arc_bounds():
]
for start, end, center, direction, bounds in cases:
c = Circle((0,0), 1)
- a = Arc(start, end, center, direction, c)
+ a = Arc(start, end, center, direction, c, 'single-quadrant')
assert_equal(a.bounding_box, bounds)
def test_arc_conversion():
c = Circle((0, 0), 25.4, units='metric')
- a = Arc((2.54, 25.4), (254.0, 2540.0), (25400.0, 254000.0),'clockwise', c, units='metric')
+ a = Arc((2.54, 25.4), (254.0, 2540.0), (25400.0, 254000.0),'clockwise', c, 'single-quadrant', units='metric')
#No effect
a.to_metric()
@@ -203,7 +211,7 @@ def test_arc_conversion():
assert_equal(a.aperture.diameter, 1.0)
c = Circle((0, 0), 1.0, units='inch')
- a = Arc((0.1, 1.0), (10.0, 100.0), (1000.0, 10000.0),'clockwise', c, units='inch')
+ a = Arc((0.1, 1.0), (10.0, 100.0), (1000.0, 10000.0),'clockwise', c, 'single-quadrant', units='inch')
a.to_metric()
assert_equal(a.start, (2.54, 25.4))
assert_equal(a.end, (254.0, 2540.0))
@@ -212,7 +220,7 @@ def test_arc_conversion():
def test_arc_offset():
c = Circle((0, 0), 1)
- a = Arc((0, 0), (1, 1), (2, 2), 'clockwise', c)
+ a = Arc((0, 0), (1, 1), (2, 2), 'clockwise', c, 'single-quadrant')
a.offset(1, 0)
assert_equal(a.start,(1., 0.))
assert_equal(a.end, (2., 1.))
@@ -703,29 +711,30 @@ def test_obround_offset():
def test_polygon_ctor():
""" Test polygon creation
"""
- test_cases = (((0,0), 3, 5),
- ((0, 0), 5, 6),
- ((1,1), 7, 7))
- for pos, sides, radius in test_cases:
- p = Polygon(pos, sides, radius)
+ test_cases = (((0,0), 3, 5, 0),
+ ((0, 0), 5, 6, 0),
+ ((1,1), 7, 7, 45))
+ for pos, sides, radius, hole_radius in test_cases:
+ p = Polygon(pos, sides, radius, hole_radius)
assert_equal(p.position, pos)
assert_equal(p.sides, sides)
assert_equal(p.radius, radius)
+ assert_equal(p.hole_radius, hole_radius)
def test_polygon_bounds():
""" Test polygon bounding box calculation
"""
- p = Polygon((2,2), 3, 2)
+ p = Polygon((2,2), 3, 2, 0)
xbounds, ybounds = p.bounding_box
assert_array_almost_equal(xbounds, (0, 4))
assert_array_almost_equal(ybounds, (0, 4))
- p = Polygon((2,2),3, 4)
+ p = Polygon((2,2), 3, 4, 0)
xbounds, ybounds = p.bounding_box
assert_array_almost_equal(xbounds, (-2, 6))
assert_array_almost_equal(ybounds, (-2, 6))
def test_polygon_conversion():
- p = Polygon((2.54, 25.4), 3, 254.0, units='metric')
+ p = Polygon((2.54, 25.4), 3, 254.0, 0, units='metric')
#No effect
p.to_metric()
@@ -741,7 +750,7 @@ def test_polygon_conversion():
assert_equal(p.position, (0.1, 1.0))
assert_equal(p.radius, 10.0)
- p = Polygon((0.1, 1.0), 3, 10.0, units='inch')
+ p = Polygon((0.1, 1.0), 3, 10.0, 0, units='inch')
#No effect
p.to_inch()
@@ -758,7 +767,7 @@ def test_polygon_conversion():
assert_equal(p.radius, 254.0)
def test_polygon_offset():
- p = Polygon((0, 0), 5, 10)
+ p = Polygon((0, 0), 5, 10, 0)
p.offset(1, 0)
assert_equal(p.position,(1., 0.))
p.offset(0, 1)
@@ -997,7 +1006,7 @@ def test_drill_ctor():
"""
test_cases = (((0, 0), 2), ((1, 1), 3), ((2, 2), 5))
for position, diameter in test_cases:
- d = Drill(position, diameter)
+ d = Drill(position, diameter, None)
assert_equal(d.position, position)
assert_equal(d.diameter, diameter)
assert_equal(d.radius, diameter/2.)
@@ -1005,21 +1014,21 @@ def test_drill_ctor():
def test_drill_ctor_validation():
""" Test drill argument validation
"""
- assert_raises(TypeError, Drill, 3, 5)
- assert_raises(TypeError, Drill, (3,4,5), 5)
+ assert_raises(TypeError, Drill, 3, 5, None)
+ assert_raises(TypeError, Drill, (3,4,5), 5, None)
def test_drill_bounds():
- d = Drill((0, 0), 2)
+ d = Drill((0, 0), 2, None)
xbounds, ybounds = d.bounding_box
assert_array_almost_equal(xbounds, (-1, 1))
assert_array_almost_equal(ybounds, (-1, 1))
- d = Drill((1, 2), 2)
+ d = Drill((1, 2), 2, None)
xbounds, ybounds = d.bounding_box
assert_array_almost_equal(xbounds, (0, 2))
assert_array_almost_equal(ybounds, (1, 3))
def test_drill_conversion():
- d = Drill((2.54, 25.4), 254., units='metric')
+ d = Drill((2.54, 25.4), 254., None, units='metric')
#No effect
d.to_metric()
@@ -1036,7 +1045,7 @@ def test_drill_conversion():
assert_equal(d.diameter, 10.0)
- d = Drill((0.1, 1.0), 10., units='inch')
+ d = Drill((0.1, 1.0), 10., None, units='inch')
#No effect
d.to_inch()
@@ -1053,15 +1062,15 @@ def test_drill_conversion():
assert_equal(d.diameter, 254.0)
def test_drill_offset():
- d = Drill((0, 0), 1.)
+ d = Drill((0, 0), 1., None)
d.offset(1, 0)
assert_equal(d.position,(1., 0.))
d.offset(0, 1)
assert_equal(d.position,(1., 1.))
def test_drill_equality():
- d = Drill((2.54, 25.4), 254.)
- d1 = Drill((2.54, 25.4), 254.)
+ d = Drill((2.54, 25.4), 254., None)
+ d1 = Drill((2.54, 25.4), 254., None)
assert_equal(d, d1)
- d1 = Drill((2.54, 25.4), 254.2)
+ d1 = Drill((2.54, 25.4), 254.2, None)
assert_not_equal(d, d1)