summaryrefslogtreecommitdiff
path: root/gerbonara/gerber/tests
diff options
context:
space:
mode:
authorjaseg <git@jaseg.de>2021-11-08 13:06:23 +0100
committerjaseg <git@jaseg.de>2021-11-08 13:06:23 +0100
commit125eb821b9f5d4c58b17d43e318e9a6829120d03 (patch)
tree6564a0c275e8ddb256e1198a2af00c7c4b348182 /gerbonara/gerber/tests
parent5aa184757e4fb5c2fc141c41aed2fccc0c96ce7e (diff)
downloadgerbonara-125eb821b9f5d4c58b17d43e318e9a6829120d03.tar.gz
gerbonara-125eb821b9f5d4c58b17d43e318e9a6829120d03.tar.bz2
gerbonara-125eb821b9f5d4c58b17d43e318e9a6829120d03.zip
Parser half-refactored
Diffstat (limited to 'gerbonara/gerber/tests')
-rw-r--r--gerbonara/gerber/tests/panelize/data/ref_gerber_inch.gtl1
-rw-r--r--gerbonara/gerber/tests/panelize/data/ref_gerber_metric.gtl1
-rw-r--r--gerbonara/gerber/tests/panelize/data/ref_gerber_single_quadrant.gtl40
-rw-r--r--gerbonara/gerber/tests/panelize/expects/RS2724x_offset.gtl1
-rw-r--r--gerbonara/gerber/tests/panelize/expects/RS2724x_rotate.gtl1
-rw-r--r--gerbonara/gerber/tests/panelize/expects/RS2724x_save.gtl1
-rw-r--r--gerbonara/gerber/tests/panelize/expects/RS2724x_single_quadrant.gtl35
-rw-r--r--gerbonara/gerber/tests/panelize/expects/RS2724x_to_inch.gtl1
-rw-r--r--gerbonara/gerber/tests/panelize/expects/RS2724x_to_metric.gtl1
-rw-r--r--gerbonara/gerber/tests/panelize/test_am_expression.py13
-rw-r--r--gerbonara/gerber/tests/panelize/test_rs274x.py5
-rw-r--r--gerbonara/gerber/tests/test_am_statements.py395
-rw-r--r--gerbonara/gerber/tests/test_cairo_backend.py382
-rw-r--r--gerbonara/gerber/tests/test_gerber_statements.py64
14 files changed, 4 insertions, 937 deletions
diff --git a/gerbonara/gerber/tests/panelize/data/ref_gerber_inch.gtl b/gerbonara/gerber/tests/panelize/data/ref_gerber_inch.gtl
index 3ec60d8..f71c948 100644
--- a/gerbonara/gerber/tests/panelize/data/ref_gerber_inch.gtl
+++ b/gerbonara/gerber/tests/panelize/data/ref_gerber_inch.gtl
@@ -8,7 +8,6 @@
1,1,0.015748,-0.0472441,0,$1*
4,1,4,0.0472441,0,0.0551181,-0.00787402,0.0472441,-0.015748,0.0393701,-0.00787402,0.0472441,0,$1*
5,1,6,0.0472441,0.00787402,0.015748,$1*
-6,-0.0275591,0,0.019685,0.0019685,0.00590551,2,0.0019685,0.023622,$1*
7,0.0275591,0,0.023622,0.019685,0.00590551,$1*%
%ADD10C,0.0003937*%
%ADD11C,0.03937X0.01575*%
diff --git a/gerbonara/gerber/tests/panelize/data/ref_gerber_metric.gtl b/gerbonara/gerber/tests/panelize/data/ref_gerber_metric.gtl
index 8dfbdd4..98833de 100644
--- a/gerbonara/gerber/tests/panelize/data/ref_gerber_metric.gtl
+++ b/gerbonara/gerber/tests/panelize/data/ref_gerber_metric.gtl
@@ -8,7 +8,6 @@
1,1,0.4,-1.2,0,$1*
4,1,4,1.2,0,1.4,-0.2,1.2,-0.4,1,-0.2,1.2,0,$1*
5,1,6,1.2,0.2,0.4,$1*
-6,-0.7,0,0.5,0.05,0.15,2,0.05,0.6,$1*
7,0.7,0,0.6,0.5,0.15,$1*%
%ADD10C,0.01*%
%ADD11C,1X0.4*%
diff --git a/gerbonara/gerber/tests/panelize/data/ref_gerber_single_quadrant.gtl b/gerbonara/gerber/tests/panelize/data/ref_gerber_single_quadrant.gtl
deleted file mode 100644
index f31f1e7..0000000
--- a/gerbonara/gerber/tests/panelize/data/ref_gerber_single_quadrant.gtl
+++ /dev/null
@@ -1,40 +0,0 @@
-%MOMM*%
-%FSLAX34Y34*%
-%IPPOS*%
-%ADD10C,0.1*%
-G74*
-%LPD*%
-
-D10*
-
-G36*
-G01*
-X0Y10000D02*
-Y90000D01*
-G02*
-X10000Y100000I10000*
-X20000Y90000J10000*
-G01*
-Y20000*
-X40000*
-G02*
-X50000Y10000J10000*
-X40000Y0I10000*
-G01*
-X10000*
-G02*
-X0Y10000J10000*
-G37*
-
-G03*
-X70000Y50000D02*
-X60000Y60000I10000D01*
-X50000Y50000J10000*
-X60000Y40000I10000*
-X70000Y50000J10000*
-
-G02*
-X60000Y90000D02*
-X60000Y90000I10000D01*
-
-M02*
diff --git a/gerbonara/gerber/tests/panelize/expects/RS2724x_offset.gtl b/gerbonara/gerber/tests/panelize/expects/RS2724x_offset.gtl
index 3dc3e6a..0bebd07 100644
--- a/gerbonara/gerber/tests/panelize/expects/RS2724x_offset.gtl
+++ b/gerbonara/gerber/tests/panelize/expects/RS2724x_offset.gtl
@@ -7,7 +7,6 @@
1,1,0.4,-1.2,0,$1*
4,1,4,1.2,0,1.4,-0.2,1.2,-0.4,1,-0.2,1.2,0,$1*
5,1,6,1.2,0.2,0.4,$1*
-6,-0.7,0,0.5,0.05,0.15,2,0.05,0.6,$1*
7,0.7,0,0.6,0.5,0.15,$1*%
%ADD10C,0.01*%
%ADD11C,1X0.4*%
diff --git a/gerbonara/gerber/tests/panelize/expects/RS2724x_rotate.gtl b/gerbonara/gerber/tests/panelize/expects/RS2724x_rotate.gtl
index f7c82cd..00335b8 100644
--- a/gerbonara/gerber/tests/panelize/expects/RS2724x_rotate.gtl
+++ b/gerbonara/gerber/tests/panelize/expects/RS2724x_rotate.gtl
@@ -7,7 +7,6 @@
1,1,0.4,-1.2,0,($1)+(20)*
4,1,4,1.2,0,1.4,-0.2,1.2,-0.4,1,-0.2,1.2,0,($1)+(20)*
5,1,6,1.2,0.2,0.4,($1)+(20)*
-6,-0.7,0,0.5,0.05,0.15,2,0.05,0.6,($1)+(20)*
7,0.7,0,0.6,0.5,0.15,($1)+(20)*%
%AMMACR*
21,1,$1,$2,0,0,20*
diff --git a/gerbonara/gerber/tests/panelize/expects/RS2724x_save.gtl b/gerbonara/gerber/tests/panelize/expects/RS2724x_save.gtl
index 5053d99..b4fe9e1 100644
--- a/gerbonara/gerber/tests/panelize/expects/RS2724x_save.gtl
+++ b/gerbonara/gerber/tests/panelize/expects/RS2724x_save.gtl
@@ -7,7 +7,6 @@
1,1,0.4,-1.2,0,$1*
4,1,4,1.2,0,1.4,-0.2,1.2,-0.4,1,-0.2,1.2,0,$1*
5,1,6,1.2,0.2,0.4,$1*
-6,-0.7,0,0.5,0.05,0.15,2,0.05,0.6,$1*
7,0.7,0,0.6,0.5,0.15,$1*%
%ADD10C,0.01*%
%ADD11C,1X0.4*%
diff --git a/gerbonara/gerber/tests/panelize/expects/RS2724x_single_quadrant.gtl b/gerbonara/gerber/tests/panelize/expects/RS2724x_single_quadrant.gtl
deleted file mode 100644
index dbec705..0000000
--- a/gerbonara/gerber/tests/panelize/expects/RS2724x_single_quadrant.gtl
+++ /dev/null
@@ -1,35 +0,0 @@
-%MOMM*%
-%FSLAX34Y34*%
-%IPPOS*%
-%ADD10C,0.1*%
-G75*
-%LPD*%
-D10*
-G36*
-G01*
-X0Y10000D02*
-X0Y90000D01*
-G02*
-X10000Y100000I10000J0D01*
-X20000Y90000I0J-10000D01*
-G01*
-X20000Y20000D01*
-X40000Y20000D01*
-G02*
-X50000Y10000I0J-10000D01*
-X40000Y0I-10000J0D01*
-G01*
-X10000Y0D01*
-G02*
-X0Y10000I0J10000D01*
-G37*
-G03*
-X70000Y50000D02*
-X60000Y60000I-10000J0D01*
-X50000Y50000I0J-10000D01*
-X60000Y40000I10000J0D01*
-X70000Y50000I0J10000D01*
-G02*
-X60000Y90000D02*
-X60000Y90000I0J0D01*
-M02*
diff --git a/gerbonara/gerber/tests/panelize/expects/RS2724x_to_inch.gtl b/gerbonara/gerber/tests/panelize/expects/RS2724x_to_inch.gtl
index cb9234e..ed23a58 100644
--- a/gerbonara/gerber/tests/panelize/expects/RS2724x_to_inch.gtl
+++ b/gerbonara/gerber/tests/panelize/expects/RS2724x_to_inch.gtl
@@ -7,7 +7,6 @@
1,1,0.015748,-0.0472441,0,$1*
4,1,4,0.0472441,0,0.0551181,-0.00787402,0.0472441,-0.015748,0.0393701,-0.00787402,0.0472441,0,$1*
5,1,6,0.0472441,0.00787402,0.015748,$1*
-6,-0.0275591,0,0.019685,0.0019685,0.00590551,2,0.0019685,0.023622,$1*
7,0.0275591,0,0.023622,0.019685,0.00590551,$1*%
%ADD10C,0.0003937*%
%ADD11C,0.03937X0.01575*%
diff --git a/gerbonara/gerber/tests/panelize/expects/RS2724x_to_metric.gtl b/gerbonara/gerber/tests/panelize/expects/RS2724x_to_metric.gtl
index a8efda8..2a4df41 100644
--- a/gerbonara/gerber/tests/panelize/expects/RS2724x_to_metric.gtl
+++ b/gerbonara/gerber/tests/panelize/expects/RS2724x_to_metric.gtl
@@ -7,7 +7,6 @@
1,1,0.399999,-1.2,0,$1*
4,1,4,1.2,0,1.4,-0.2,1.2,-0.399999,1,-0.2,1.2,0,$1*
5,1,6,1.2,0.2,0.399999,$1*
-6,-0.700001,0,0.499999,0.0499999,0.15,2,0.0499999,0.599999,$1*
7,0.700001,0,0.599999,0.499999,0.15,$1*%
%ADD10C,0.01*%
%ADD11C,1X0.4*%
diff --git a/gerbonara/gerber/tests/panelize/test_am_expression.py b/gerbonara/gerber/tests/panelize/test_am_expression.py
index 45758b7..576be88 100644
--- a/gerbonara/gerber/tests/panelize/test_am_expression.py
+++ b/gerbonara/gerber/tests/panelize/test_am_expression.py
@@ -30,10 +30,6 @@ class TestAMConstantExpression(unittest.TestCase):
self.assertEqual(self.const_int.to_gerber(), '7')
self.assertEqual(self.const_float.to_gerber(), '1.2345')
- def test_to_instructions(self):
- self.const_int.to_instructions()
- self.const_float.to_instructions()
-
class TestAMVariableExpression(unittest.TestCase):
def setUp(self):
self.var1_num = 1
@@ -57,10 +53,6 @@ class TestAMVariableExpression(unittest.TestCase):
self.assertEqual(self.var1.to_gerber(), '$1')
self.assertEqual(self.var2.to_gerber(), '$512')
- def test_to_instructions(self):
- self.var1.to_instructions()
- self.var2.to_instructions()
-
class TestAMOperatorExpression(unittest.TestCase):
def setUp(self):
self.c1 = 10
@@ -132,11 +124,6 @@ class TestAMOperatorExpression(unittest.TestCase):
self.c1, self.c2, self.c1, self.c2
))
- def test_to_instructions(self):
- for of, expression in self.vc_exps + self.cv_exps + self.cc_exps:
- expression.to_instructions()
- self.composition.to_instructions()
-
class TestAMExpression(unittest.TestCase):
def setUp(self):
self.c1 = 10
diff --git a/gerbonara/gerber/tests/panelize/test_rs274x.py b/gerbonara/gerber/tests/panelize/test_rs274x.py
index 067717d..73f3172 100644
--- a/gerbonara/gerber/tests/panelize/test_rs274x.py
+++ b/gerbonara/gerber/tests/panelize/test_rs274x.py
@@ -68,8 +68,3 @@ class TestRs274x(unittest.TestCase):
gerber.rotate(20, (10,10))
gerber.write(outfile)
- def test_single_quadrant(self):
- with self._check_result('RS2724x_single_quadrant.gtl') as outfile:
- gerber = read(self.SQ_FILE)
- gerber.write(outfile)
-
diff --git a/gerbonara/gerber/tests/test_am_statements.py b/gerbonara/gerber/tests/test_am_statements.py
deleted file mode 100644
index 0d100b5..0000000
--- a/gerbonara/gerber/tests/test_am_statements.py
+++ /dev/null
@@ -1,395 +0,0 @@
-#! /usr/bin/env python
-# -*- coding: utf-8 -*-
-
-# Author: Hamilton Kibbe <ham@hamiltonkib.be>
-
-import pytest
-
-from ..am_statements import *
-from ..am_statements import inch, metric
-
-
-def test_AMPrimitive_ctor():
- for exposure in ("on", "off", "ON", "OFF"):
- for code in (0, 1, 2, 4, 5, 6, 7, 20, 21, 22):
- p = AMPrimitive(code, exposure)
- assert p.code == code
- assert p.exposure == exposure.lower()
-
-
-def test_AMPrimitive_validation():
- pytest.raises(TypeError, AMPrimitive, "1", "off")
- pytest.raises(ValueError, AMPrimitive, 0, "exposed")
- pytest.raises(ValueError, AMPrimitive, 3, "off")
-
-
-def test_AMPrimitive_conversion():
- p = AMPrimitive(4, "on")
- pytest.raises(NotImplementedError, p.to_inch)
- pytest.raises(NotImplementedError, p.to_metric)
-
-
-def test_AMCommentPrimitive_ctor():
- c = AMCommentPrimitive(0, " This is a comment *")
- assert c.code == 0
- assert c.comment == "This is a comment"
-
-
-def test_AMCommentPrimitive_validation():
- pytest.raises(ValueError, AMCommentPrimitive, 1, "This is a comment")
-
-
-def test_AMCommentPrimitive_factory():
- c = AMCommentPrimitive.from_gerber("0 Rectangle with rounded corners. *")
- assert c.code == 0
- assert c.comment == "Rectangle with rounded corners."
-
-
-def test_AMCommentPrimitive_dump():
- c = AMCommentPrimitive(0, "Rectangle with rounded corners.")
- assert c.to_gerber() == "0 Rectangle with rounded corners. *"
-
-
-def test_AMCommentPrimitive_conversion():
- c = AMCommentPrimitive(0, "Rectangle with rounded corners.")
- ci = c
- cm = c
- ci.to_inch()
- cm.to_metric()
- assert c == ci
- assert c == cm
-
-
-def test_AMCommentPrimitive_string():
- c = AMCommentPrimitive(0, "Test Comment")
- assert str(c) == "<Aperture Macro Comment: Test Comment>"
-
-
-def test_AMCirclePrimitive_ctor():
- test_cases = (
- (1, "on", 0, (0, 0)),
- (1, "off", 1, (0, 1)),
- (1, "on", 2.5, (0, 2)),
- (1, "off", 5.0, (3, 3)),
- )
- for code, exposure, diameter, position in test_cases:
- c = AMCirclePrimitive(code, exposure, diameter, position)
- assert c.code == code
- assert c.exposure == exposure
- assert c.diameter == diameter
- assert c.position == position
-
-
-def test_AMCirclePrimitive_validation():
- pytest.raises(ValueError, AMCirclePrimitive, 2, "on", 0, (0, 0))
-
-
-def test_AMCirclePrimitive_factory():
- c = AMCirclePrimitive.from_gerber("1,0,5,0,0*")
- assert c.code == 1
- assert c.exposure == "off"
- assert c.diameter == 5
- assert c.position == (0, 0)
-
-
-def test_AMCirclePrimitive_dump():
- c = AMCirclePrimitive(1, "off", 5, (0, 0))
- assert c.to_gerber() == "1,0,5,0,0*"
- c = AMCirclePrimitive(1, "on", 5, (0, 0))
- assert c.to_gerber() == "1,1,5,0,0*"
-
-
-def test_AMCirclePrimitive_conversion():
- c = AMCirclePrimitive(1, "off", 25.4, (25.4, 0))
- c.to_inch()
- assert c.diameter == 1
- assert c.position == (1, 0)
-
- c = AMCirclePrimitive(1, "off", 1, (1, 0))
- c.to_metric()
- assert c.diameter == 25.4
- assert c.position == (25.4, 0)
-
-
-def test_AMVectorLinePrimitive_validation():
- pytest.raises(
- ValueError, AMVectorLinePrimitive, 3, "on", 0.1, (0, 0), (3.3, 5.4), 0
- )
-
-
-def test_AMVectorLinePrimitive_factory():
- l = AMVectorLinePrimitive.from_gerber("20,1,0.9,0,0.45,12,0.45,0*")
- assert l.code == 20
- assert l.exposure == "on"
- assert l.width == 0.9
- assert l.start == (0, 0.45)
- assert l.end == (12, 0.45)
- assert l.rotation == 0
-
-
-def test_AMVectorLinePrimitive_dump():
- l = AMVectorLinePrimitive.from_gerber("20,1,0.9,0,0.45,12,0.45,0*")
- assert l.to_gerber() == "20,1,0.9,0.0,0.45,12.0,0.45,0.0*"
-
-
-def test_AMVectorLinePrimtive_conversion():
- l = AMVectorLinePrimitive(20, "on", 25.4, (0, 0), (25.4, 25.4), 0)
- l.to_inch()
- assert l.width == 1
- assert l.start == (0, 0)
- assert l.end == (1, 1)
-
- l = AMVectorLinePrimitive(20, "on", 1, (0, 0), (1, 1), 0)
- l.to_metric()
- assert l.width == 25.4
- assert l.start == (0, 0)
- assert l.end == (25.4, 25.4)
-
-
-def test_AMOutlinePrimitive_validation():
- pytest.raises(
- ValueError,
- AMOutlinePrimitive,
- 7,
- "on",
- (0, 0),
- [(3.3, 5.4), (4.0, 5.4), (0, 0)],
- 0,
- )
- pytest.raises(
- ValueError,
- AMOutlinePrimitive,
- 4,
- "on",
- (0, 0),
- [(3.3, 5.4), (4.0, 5.4), (0, 1)],
- 0,
- )
-
-
-def test_AMOutlinePrimitive_factory():
- o = AMOutlinePrimitive.from_gerber("4,1,3,0,0,3,3,3,0,0,0,0*")
- assert o.code == 4
- assert o.exposure == "on"
- assert o.start_point == (0, 0)
- assert o.points == [(3, 3), (3, 0), (0, 0)]
- assert o.rotation == 0
-
-
-def test_AMOUtlinePrimitive_dump():
- o = AMOutlinePrimitive(4, "on", (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 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)
- o.to_inch()
- assert o.start_point == (0, 0)
- assert o.points == ((1.0, 1.0), (1.0, 0.0), (0.0, 0.0))
-
- o = AMOutlinePrimitive(4, "on", (0, 0), [(1, 1), (1, 0), (0, 0)], 0)
- o.to_metric()
- assert o.start_point == (0, 0)
- assert o.points == ((25.4, 25.4), (25.4, 0), (0, 0))
-
-
-def test_AMPolygonPrimitive_validation():
- pytest.raises(ValueError, AMPolygonPrimitive, 6, "on", 3, (3.3, 5.4), 3, 0)
- pytest.raises(ValueError, AMPolygonPrimitive, 5, "on", 2, (3.3, 5.4), 3, 0)
- pytest.raises(ValueError, AMPolygonPrimitive, 5, "on", 13, (3.3, 5.4), 3, 0)
-
-
-def test_AMPolygonPrimitive_factory():
- p = AMPolygonPrimitive.from_gerber("5,1,3,3.3,5.4,3,0")
- assert p.code == 5
- assert p.exposure == "on"
- assert p.vertices == 3
- assert p.position == (3.3, 5.4)
- assert p.diameter == 3
- assert p.rotation == 0
-
-
-def test_AMPolygonPrimitive_dump():
- p = AMPolygonPrimitive(5, "on", 3, (3.3, 5.4), 3, 0)
- assert p.to_gerber() == "5,1,3,3.3,5.4,3,0*"
-
-
-def test_AMPolygonPrimitive_conversion():
- p = AMPolygonPrimitive(5, "off", 3, (25.4, 0), 25.4, 0)
- p.to_inch()
- assert p.diameter == 1
- assert p.position == (1, 0)
-
- p = AMPolygonPrimitive(5, "off", 3, (1, 0), 1, 0)
- p.to_metric()
- assert p.diameter == 25.4
- assert p.position == (25.4, 0)
-
-
-def test_AMMoirePrimitive_validation():
- pytest.raises(
- ValueError, AMMoirePrimitive, 7, (0, 0), 5.1, 0.2, 0.4, 6, 0.1, 6.1, 0
- )
-
-
-def test_AMMoirePrimitive_factory():
- m = AMMoirePrimitive.from_gerber("6,0,0,5,0.5,0.5,2,0.1,6,0*")
- assert m.code == 6
- assert m.position == (0, 0)
- assert m.diameter == 5
- assert m.ring_thickness == 0.5
- assert m.gap == 0.5
- assert m.max_rings == 2
- assert m.crosshair_thickness == 0.1
- assert m.crosshair_length == 6
- assert m.rotation == 0
-
-
-def test_AMMoirePrimitive_dump():
- m = AMMoirePrimitive.from_gerber("6,0,0,5,0.5,0.5,2,0.1,6,0*")
- assert m.to_gerber() == "6,0,0,5.0,0.5,0.5,2,0.1,6.0,0.0*"
-
-
-def test_AMMoirePrimitive_conversion():
- m = AMMoirePrimitive(6, (25.4, 25.4), 25.4, 25.4, 25.4, 6, 25.4, 25.4, 0)
- m.to_inch()
- assert m.position == (1.0, 1.0)
- assert m.diameter == 1.0
- assert m.ring_thickness == 1.0
- assert m.gap == 1.0
- assert m.crosshair_thickness == 1.0
- assert m.crosshair_length == 1.0
-
- m = AMMoirePrimitive(6, (1, 1), 1, 1, 1, 6, 1, 1, 0)
- m.to_metric()
- assert m.position == (25.4, 25.4)
- assert m.diameter == 25.4
- assert m.ring_thickness == 25.4
- assert m.gap == 25.4
- assert m.crosshair_thickness == 25.4
- assert m.crosshair_length == 25.4
-
-
-def test_AMThermalPrimitive_validation():
- pytest.raises(ValueError, AMThermalPrimitive, 8, (0.0, 0.0), 7, 5, 0.2, 0.0)
- pytest.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,45*")
- assert t.code == 7
- assert t.position == (0, 0)
- assert t.outer_diameter == 7
- assert t.inner_diameter == 6
- assert t.gap == 0.2
- assert t.rotation == 45
-
-
-def test_AMThermalPrimitive_dump():
- t = AMThermalPrimitive.from_gerber("7,0,0,7,6,0.2,30*")
- assert 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, 0.0)
- t.to_inch()
- assert t.position == (1.0, 1.0)
- assert t.outer_diameter == 1.0
- assert t.inner_diameter == 1.0
- assert t.gap == 1.0
-
- t = AMThermalPrimitive(7, (1, 1), 1, 1, 1, 0)
- t.to_metric()
- assert t.position == (25.4, 25.4)
- assert t.outer_diameter == 25.4
- assert t.inner_diameter == 25.4
- assert t.gap == 25.4
-
-
-def test_AMCenterLinePrimitive_validation():
- pytest.raises(ValueError, AMCenterLinePrimitive, 22, 1, 0.2, 0.5, (0, 0), 0)
-
-
-def test_AMCenterLinePrimtive_factory():
- l = AMCenterLinePrimitive.from_gerber("21,1,6.8,1.2,3.4,0.6,0*")
- assert l.code == 21
- assert l.exposure == "on"
- assert l.width == 6.8
- assert l.height == 1.2
- assert l.center == (3.4, 0.6)
- assert l.rotation == 0
-
-
-def test_AMCenterLinePrimitive_dump():
- l = AMCenterLinePrimitive.from_gerber("21,1,6.8,1.2,3.4,0.6,0*")
- assert l.to_gerber() == "21,1,6.8,1.2,3.4,0.6,0.0*"
-
-
-def test_AMCenterLinePrimitive_conversion():
- l = AMCenterLinePrimitive(21, "on", 25.4, 25.4, (25.4, 25.4), 0)
- l.to_inch()
- assert l.width == 1.0
- assert l.height == 1.0
- assert l.center == (1.0, 1.0)
-
- l = AMCenterLinePrimitive(21, "on", 1, 1, (1, 1), 0)
- l.to_metric()
- assert l.width == 25.4
- assert l.height == 25.4
- assert l.center == (25.4, 25.4)
-
-
-def test_AMLowerLeftLinePrimitive_validation():
- pytest.raises(ValueError, AMLowerLeftLinePrimitive, 23, 1, 0.2, 0.5, (0, 0), 0)
-
-
-def test_AMLowerLeftLinePrimtive_factory():
- l = AMLowerLeftLinePrimitive.from_gerber("22,1,6.8,1.2,3.4,0.6,0*")
- assert l.code == 22
- assert l.exposure == "on"
- assert l.width == 6.8
- assert l.height == 1.2
- assert l.lower_left == (3.4, 0.6)
- assert l.rotation == 0
-
-
-def test_AMLowerLeftLinePrimitive_dump():
- l = AMLowerLeftLinePrimitive.from_gerber("22,1,6.8,1.2,3.4,0.6,0*")
- assert l.to_gerber() == "22,1,6.8,1.2,3.4,0.6,0.0*"
-
-
-def test_AMLowerLeftLinePrimitive_conversion():
- l = AMLowerLeftLinePrimitive(22, "on", 25.4, 25.4, (25.4, 25.4), 0)
- l.to_inch()
- assert l.width == 1.0
- assert l.height == 1.0
- assert l.lower_left == (1.0, 1.0)
-
- l = AMLowerLeftLinePrimitive(22, "on", 1, 1, (1, 1), 0)
- l.to_metric()
- assert l.width == 25.4
- assert l.height == 25.4
- assert l.lower_left == (25.4, 25.4)
-
-
-def test_AMUnsupportPrimitive():
- u = AMUnsupportPrimitive.from_gerber("Test")
- assert u.primitive == "Test"
- u = AMUnsupportPrimitive("Test")
- assert u.to_gerber() == "Test"
-
-
-def test_AMUnsupportPrimitive_smoketest():
- u = AMUnsupportPrimitive.from_gerber("Test")
- u.to_inch()
- u.to_metric()
-
-
-def test_inch():
- assert inch(25.4) == 1
-
-
-def test_metric():
- assert metric(1) == 25.4
diff --git a/gerbonara/gerber/tests/test_cairo_backend.py b/gerbonara/gerber/tests/test_cairo_backend.py
deleted file mode 100644
index b8c9676..0000000
--- a/gerbonara/gerber/tests/test_cairo_backend.py
+++ /dev/null
@@ -1,382 +0,0 @@
-#! /usr/bin/env python
-# -*- coding: utf-8 -*-
-
-# Author: Garret Fick <garret@ficksworkshop.com>
-import os
-import shutil
-import io
-import tempfile
-import uuid
-import cv2
-from pathlib import Path
-
-import pytest
-from PIL import Image
-import numpy as np
-
-from ..render.cairo_backend import GerberCairoContext
-from ..rs274x import read
-
-class Tempdir:
- def __init__(self):
- self.path = tempfile.mkdtemp(prefix='gerbonara-test-')
- self.delete = True
-
- def cleanup(self):
- if self.delete:
- shutil.rmtree(self.path)
-
- def create(self, prefix='fail-', suffix=''):
- return Path(self.path) / f'{prefix}{uuid.uuid4()}{suffix}'
-
- def keep(self):
- self.delete = False
-
-output_dir = Tempdir()
-@pytest.fixture(scope='session', autouse=True)
-def cleanup(request):
- global output_dir
- request.addfinalizer(output_dir.cleanup)
-
-def test_render_two_boxes():
- """Umaco exapmle of two boxes"""
- _test_render("resources/example_two_square_boxes.gbr", "golden/example_two_square_boxes.png")
-
-
-def test_render_simple_contour():
- """Umaco exapmle of a simple arrow-shaped contour"""
- gerber = _test_render("resources/example_simple_contour.gbr", "golden/example_simple_contour.png")
-
- # Check the resulting dimensions
- assert ((2.0, 11.0), (1.0, 9.0)) == gerber.bounding_box
-
-
-def test_render_single_contour_1():
- """Umaco example of a single contour
-
- The resulting image for this test is used by other tests because they must generate the same output."""
- _test_render(
- "resources/example_single_contour_1.gbr", "golden/example_single_contour.png",
- 0.001 # TODO: It looks like we have some aliasing artifacts here. Make sure this is not caused by an actual error.
- )
-
-
-def test_render_single_contour_2():
- """Umaco exapmle of a single contour, alternate contour end order
-
- The resulting image for this test is used by other tests because they must generate the same output."""
- _test_render(
- "resources/example_single_contour_2.gbr", "golden/example_single_contour.png",
- 0.001 # TODO: It looks like we have some aliasing artifacts here. Make sure this is not caused by an actual error.
- )
-
-
-def test_render_single_contour_3():
- """Umaco exapmle of a single contour with extra line"""
- _test_render(
- "resources/example_single_contour_3.gbr", "golden/example_single_contour_3.png",
- 0.001 # TODO: It looks like we have some aliasing artifacts here. Make sure this is not caused by an actual error.
- )
-
-
-def test_render_not_overlapping_contour():
- """Umaco example of D02 staring a second contour"""
- _test_render(
- "resources/example_not_overlapping_contour.gbr",
- "golden/example_not_overlapping_contour.png",
- )
-
-
-def test_render_not_overlapping_touching():
- """Umaco example of D02 staring a second contour"""
- _test_render(
- "resources/example_not_overlapping_touching.gbr",
- "golden/example_not_overlapping_touching.png",
- )
-
-
-def test_render_overlapping_touching():
- """Umaco example of D02 staring a second contour"""
- _test_render(
- "resources/example_overlapping_touching.gbr",
- "golden/example_overlapping_touching.png",
- )
-
-
-def test_render_overlapping_contour():
- """Umaco example of D02 staring a second contour"""
- _test_render("resources/example_overlapping_contour.gbr", "golden/example_overlapping_contour.png")
-
-
-def test_render_level_holes():
- """Umaco example of using multiple levels to create multiple holes"""
- _test_render("resources/example_level_holes.gbr", "golden/example_level_holes.png",
- autocrop_golden=True, auto_contrast=True, scale=50, max_delta=0.005)
-
-
-def test_render_cutin():
- """Umaco example of using a cutin"""
- _test_render("resources/example_cutin.gbr", "golden/example_cutin.png",
- autocrop_golden=True, auto_contrast=True, max_delta=0.005)
-
-
-def test_render_fully_coincident():
- """Umaco example of coincident lines rendering two contours"""
-
- _test_render(
- "resources/example_fully_coincident.gbr", "golden/example_fully_coincident.png"
- )
-
-
-def test_render_coincident_hole():
- """Umaco example of coincident lines rendering a hole in the contour"""
-
- _test_render(
- "resources/example_coincident_hole.gbr", "golden/example_coincident_hole.png"
- )
-
-
-def test_render_cutin_multiple():
- """Umaco example of a region with multiple cutins"""
-
- _test_render(
- "resources/example_cutin_multiple.gbr", "golden/example_cutin_multiple.png"
- )
-
-
-def test_flash_circle():
- """Umaco example a simple circular flash with and without a hole"""
-
- _test_render(
- "resources/example_flash_circle.gbr",
- "golden/example_flash_circle.png",
- )
-
-
-def test_flash_rectangle():
- """Umaco example a simple rectangular flash with and without a hole"""
-
- _test_render(
- "resources/example_flash_rectangle.gbr", "golden/example_flash_rectangle.png"
- )
-
-
-def test_flash_obround():
- """Umaco example a simple obround flash with and without a hole"""
-
- _test_render(
- "resources/example_flash_obround.gbr", "golden/example_flash_obround.png"
- )
-
-
-def test_flash_polygon():
- """Umaco example a simple polygon flash with and without a hole"""
-
- _test_render(
- "resources/example_flash_polygon.gbr", "golden/example_flash_polygon.png"
- )
-
-
-def test_holes_dont_clear():
- """Umaco example that an aperture with a hole does not clear the area"""
-
- _test_render(
- "resources/example_holes_dont_clear.gbr", "golden/example_holes_dont_clear.png"
- )
-
-
-def test_render_am_exposure_modifier():
- """Umaco example that an aperture macro with a hole does not clear the area"""
-
- _test_render(
- "resources/example_am_exposure_modifier.gbr",
- "golden/example_am_exposure_modifier.png",
- scale = 50,
- autocrop_golden = True,
- auto_contrast = True,
- max_delta = 0.005 # Take artifacts due to differences in anti-aliasing and thresholding into account
- )
-
-
-def test_render_svg_simple_contour():
- """Example of rendering to an SVG file"""
- _test_simple_render_svg("resources/example_simple_contour.gbr")
-
-
-def test_fine_lines_x():
- """ Regression test for pcb-tools upstream PR #199 """
- for fn, axis in [
- ('resources/test_fine_lines_x.gbr', 1),
- ('resources/test_fine_lines_y.gbr', 0) ]:
- gerber_path = _resolve_path(fn)
-
- gerber = read(gerber_path)
-
- # Create PNG image to the memory stream
- ctx = GerberCairoContext(scale=51)
- gerber.render(ctx)
-
- global output_dir
- with output_dir.create(suffix='.png') as outfile:
- actual_bytes = ctx.dump(outfile)
-
- out = Image.open(outfile)
- out = np.array(out)
- out = out.astype(float).mean(axis=2) / 255
-
- means = out[10:-10,10:-10].mean(axis=axis)
-
- print(means.mean(), means.max(), means.min(), means.std())
- #print(means_y.mean(), means_y.max(), means_y.min(), means_y.std())
- # means_x broken: 0.3240598567858516 0.3443678513071895 0.2778033088235294 0.017457710324088545
- # means_x fixed: 0.33338519639882097 0.3443678513071895 0.3183159722222221 0.006792500045785638
- # means_y broken: 0.3240598567858518 0.3247468922209409 0.1660387030629246 0.009953477851147686
- # means_y fixed: 0.33338519639882114 0.3340766371908242 0.17388184031782652 0.010043400730860096
-
- assert means.std() < 0.01
-
-# TODO add scale tests: Export with different scale=... params and compare against bitmap-scaled reference image
-
-def _resolve_path(path):
- return os.path.join(os.path.dirname(__file__), path)
-
-def images_match(reference, output, max_delta, autocrop_golden=False, auto_contrast=False):
- global output_dir
-
- ref, out = Image.open(reference), Image.open(output)
- if ref.mode == 'P': # palette mode
- ref = ref.convert('RGB')
-
- ref, out = np.array(ref), np.array(out)
- # convert to grayscale
- ref, out = ref.astype(float).mean(axis=2), out.astype(float).mean(axis=2)
-
- if autocrop_golden:
- rows = ref.sum(axis=1)
- cols = ref.sum(axis=0)
-
- x0 = np.argmax(cols > 0)
- y0 = np.argmax(rows > 0)
- x1 = len(cols) - np.argmax(cols[::-1] > 0)
- y1 = len(rows) - np.argmax(rows[::-1] > 0)
- print(f'{x0=} {y0=} {x1=} {y1=}')
-
- ref = ref[y0:y1, x0:x1]
- ref = cv2.resize(ref, dsize=out.shape[::-1], interpolation=cv2.INTER_LINEAR)
-
- def print_stats(name, ref):
- print(name, 'stats:', ref.min(), ref.mean(), ref.max(), 'std:', ref.std())
-
- if auto_contrast:
- print_stats('ref pre proc', ref)
- print_stats('out pre proc', out)
-
- ref -= ref.min()
- ref /= ref.max() + 1e-9
- ref *= 255
-
- out -= out.min()
- out /= out.max() + 1e-9
- out *= 255
-
- def write_refout():
- nonlocal autocrop_golden, ref
- if autocrop_golden:
- global output_dir
- with output_dir.create(suffix='.png') as ref_out:
- cv2.imwrite(str(ref_out), ref)
- print('Processed reference image:', ref_out)
-
- if ref.shape != out.shape:
- print(f'Rendering image size mismatch: {ref.shape} != {out.shape}')
- print(f'Reference image: {Path(reference).absolute()}')
- print(f'Actual output: {output}')
-
- write_refout()
- output_dir.keep()
-
- return False
-
- delta = np.abs(out - ref).astype(float) / 255
-
- if delta.mean() > max_delta:
- print(f'Renderings mismatch: {delta.mean()=}, {max_delta=}')
- print(f'Reference image: {Path(reference).absolute()}')
- print(f'Actual output: {output}')
- with output_dir.create(suffix='.png') as proc_out:
- cv2.imwrite(str(proc_out), out)
- print('Processed output image:', proc_out)
- print_stats('reference', ref)
- print_stats('actual', out)
-
- write_refout()
- output_dir.keep()
-
- return False
-
- return True
-
-
-def _test_render(gerber_path, png_expected_path, max_delta=1e-6, scale=300, autocrop_golden=False, auto_contrast=False):
- """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_path = _resolve_path(gerber_path)
- png_expected_path = _resolve_path(png_expected_path)
-
- gerber = read(gerber_path)
-
- # Create PNG image to the memory stream
- ctx = GerberCairoContext(scale=scale)
- gerber.render(ctx)
-
- global output_dir
- with output_dir.create(suffix='.png') as outfile:
- actual_bytes = ctx.dump(outfile)
-
- assert images_match(png_expected_path, outfile, max_delta, autocrop_golden, auto_contrast)
-
- return gerber
-
-
-def _test_simple_render_svg(gerber_path):
- """Render the gerber file as SVG
-
- Note: verifies only the header, not the full content.
-
- Parameters
- ----------
- gerber_path : string
- Path to Gerber file to open
- """
-
- gerber_path = _resolve_path(gerber_path)
- gerber = read(gerber_path)
-
- # Create SVG image to the memory stream
- ctx = GerberCairoContext()
- gerber.render(ctx)
-
- temp_dir = tempfile.mkdtemp()
- svg_temp_path = os.path.join(temp_dir, "output.svg")
-
- assert not os.path.exists(svg_temp_path)
- ctx.dump(svg_temp_path)
- assert os.path.exists(svg_temp_path)
-
- with open(svg_temp_path, "r") as expected_file:
- expected_bytes = expected_file.read()
- assert expected_bytes[:38] == '<?xml version="1.0" encoding="UTF-8"?>'
-
- shutil.rmtree(temp_dir)
-
diff --git a/gerbonara/gerber/tests/test_gerber_statements.py b/gerbonara/gerber/tests/test_gerber_statements.py
index 140cbd1..17e2591 100644
--- a/gerbonara/gerber/tests/test_gerber_statements.py
+++ b/gerbonara/gerber/tests/test_gerber_statements.py
@@ -413,84 +413,29 @@ def test_AMParamStmt_factory():
1,1,1.5,0,0*
20,1,0.9,0,0.45,12,0.45,0*
21,1,6.8,1.2,3.4,0.6,0*
-22,1,6.8,1.2,0,0,0*
4,1,4,0.1,0.1,0.5,0.1,0.5,0.5,0.1,0.5,0.1,0.1,0*
5,1,8,0,0,8,0*
-6,0,0,5,0.5,0.5,2,0.1,6,0*
7,0,0,7,6,0.2,0*
-8,THIS IS AN UNSUPPORTED PRIMITIVE*
"""
- s = AMParamStmt.from_dict({"param": "AM", "name": name, "macro": macro})
- s.build()
+ s = AMParamStmt.from_dict({"param": "AM", "name": name, "macro": macro}, units='mm')
assert len(s.primitives) == 10
assert isinstance(s.primitives[0], AMCommentPrimitive)
assert isinstance(s.primitives[1], AMCirclePrimitive)
assert isinstance(s.primitives[2], AMVectorLinePrimitive)
assert isinstance(s.primitives[3], AMCenterLinePrimitive)
- assert isinstance(s.primitives[4], AMLowerLeftLinePrimitive)
assert isinstance(s.primitives[5], AMOutlinePrimitive)
assert isinstance(s.primitives[6], AMPolygonPrimitive)
- assert isinstance(s.primitives[7], AMMoirePrimitive)
assert isinstance(s.primitives[8], AMThermalPrimitive)
- assert isinstance(s.primitives[9], AMUnsupportPrimitive)
-
-
-def testAMParamStmt_conversion():
- name = "POLYGON"
- macro = "5,1,8,25.4,25.4,25.4,0*"
- s = AMParamStmt.from_dict({"param": "AM", "name": name, "macro": macro})
-
- s.build()
- s.units = "metric"
-
- # No effect
- s.to_metric()
- assert s.primitives[0].position == (25.4, 25.4)
- assert s.primitives[0].diameter == 25.4
-
- s.to_inch()
- assert s.units == "inch"
- assert s.primitives[0].position == (1.0, 1.0)
- assert s.primitives[0].diameter == 1.0
-
- # No effect
- s.to_inch()
- assert s.primitives[0].position == (1.0, 1.0)
- assert s.primitives[0].diameter == 1.0
-
- macro = "5,1,8,1,1,1,0*"
- s = AMParamStmt.from_dict({"param": "AM", "name": name, "macro": macro})
- s.build()
- s.units = "inch"
-
- # No effect
- s.to_inch()
- assert s.primitives[0].position == (1.0, 1.0)
- assert s.primitives[0].diameter == 1.0
-
- s.to_metric()
- assert s.units == "metric"
- assert s.primitives[0].position == (25.4, 25.4)
- assert s.primitives[0].diameter == 25.4
-
- # No effect
- s.to_metric()
- assert s.primitives[0].position == (25.4, 25.4)
- assert s.primitives[0].diameter == 25.4
def test_AMParamStmt_dump():
name = "POLYGON"
macro = "5,1,8,25.4,25.4,25.4,0.0"
- s = AMParamStmt.from_dict({"param": "AM", "name": name, "macro": macro})
- s.build()
+ s = AMParamStmt.from_dict({"param": "AM", "name": name, "macro": macro}, units='mm')
assert s.to_gerber() == "%AMPOLYGON*5,1,8,25.4,25.4,25.4,0.0*%"
# TODO - Store Equations and update on unit change...
- s = AMParamStmt.from_dict(
- {"param": "AM", "name": "OC8", "macro": "5,1,8,0,0,1.08239X$1,22.5"}
- )
- s.build()
+ s = AMParamStmt.from_dict({"param": "AM", "name": "OC8", "macro": "5,1,8,0,0,1.08239X$1,22.5"}, units='mm')
# assert_equal(s.to_gerber(), '%AMOC8*5,1,8,0,0,1.08239X$1,22.5*%')
assert s.to_gerber() == "%AMOC8*5,1,8,0,0,0,22.5*%"
@@ -498,8 +443,7 @@ def test_AMParamStmt_dump():
def test_AMParamStmt_string():
name = "POLYGON"
macro = "5,1,8,25.4,25.4,25.4,0*"
- s = AMParamStmt.from_dict({"param": "AM", "name": name, "macro": macro})
- s.build()
+ s = AMParamStmt.from_dict({"param": "AM", "name": name, "macro": macro}, units='mm')
assert str(s) == "<Aperture Macro POLYGON: 5,1,8,25.4,25.4,25.4,0*>"