2
# ***************************************************************************
3
# * Copyright (c) 2022 sliptonic <shopinthewoods@gmail.com> *
5
# * This program is free software; you can redistribute it and/or modify *
6
# * it under the terms of the GNU Lesser General Public License (LGPL) *
7
# * as published by the Free Software Foundation; either version 2 of *
8
# * the License, or (at your option) any later version. *
9
# * for detail see the LICENCE text file. *
11
# * This program is distributed in the hope that it will be useful, *
12
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14
# * GNU Library General Public License for more details. *
16
# * You should have received a copy of the GNU Library General Public *
17
# * License along with this program; if not, write to the Free Software *
18
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
21
# ***************************************************************************
26
import Tests.PathTestUtils as PathTestUtils
27
from importlib import reload
28
from Path.Post.scripts import grbl_post as postprocessor
31
Path.Log.setLevel(Path.Log.Level.DEBUG, Path.Log.thisModule())
32
Path.Log.trackModule(Path.Log.thisModule())
35
class TestGrblPost(PathTestUtils.PathTestBase):
39
This method is called upon instantiation of this test class. Add code
40
and objects here that are needed for the duration of the test() methods
41
in this class. In other words, set up the 'global' test environment
42
here; use the `setUp()` method to set up a 'local' test environment.
43
This method does not have access to the class `self` reference, but it
44
is able to call static methods within this same class.
47
# Open existing FreeCAD document with test geometry
48
FreeCAD.newDocument("Unnamed")
51
def tearDownClass(cls):
53
This method is called prior to destruction of this test class. Add
54
code and objects here that cleanup the test environment after the
55
test() methods in this class have been executed. This method does
56
not have access to the class `self` reference. This method is able
57
to call static methods within this same class.
59
# Close geometry document without saving
60
FreeCAD.closeDocument(FreeCAD.ActiveDocument.Name)
62
# Setup and tear down methods called before and after each unit test
65
This method is called prior to each `test()` method. Add code and
66
objects here that are needed for multiple `test()` methods.
68
self.doc = FreeCAD.ActiveDocument
69
self.con = FreeCAD.Console
70
self.docobj = FreeCAD.ActiveDocument.addObject("Path::Feature", "testpath")
73
) # technical debt. This shouldn't be necessary but here to bypass a bug
77
This method is called after each test() method. Add cleanup instructions here.
78
Such cleanup instructions will likely undo those in the setUp() method.
80
FreeCAD.ActiveDocument.removeObject("testpath")
83
"""Test Output Generation.
84
Empty path. Produces only the preamble and postable.
87
self.docobj.Path = Path.Path([])
88
postables = [self.docobj]
90
# Test generating with header
91
# Header contains a time stamp that messes up unit testing. Only test
93
args = "--no-show-editor"
94
gcode = postprocessor.export(postables, "-", args)
95
self.assertTrue(len(gcode.splitlines()) == 13)
98
expected = """(Begin preamble)
101
(Begin operation: testpath)
103
(Finish operation: testpath)
110
self.docobj.Path = Path.Path([])
111
postables = [self.docobj]
113
args = "--no-header --no-show-editor"
114
# args = ("--no-header --no-comments --no-show-editor --precision=2")
115
gcode = postprocessor.export(postables, "-", args)
116
self.assertEqual(gcode, expected)
118
# test without comments
119
expected = """G17 G90
126
args = "--no-header --no-comments --no-show-editor"
127
# args = ("--no-header --no-comments --no-show-editor --precision=2")
128
gcode = postprocessor.export(postables, "-", args)
129
self.assertEqual(gcode, expected)
132
"""Test command Generation.
134
Test imperial / inches
136
c = Path.Command("G0 X10 Y20 Z30")
138
self.docobj.Path = Path.Path([c])
139
postables = [self.docobj]
141
args = "--no-header --no-show-editor"
142
gcode = postprocessor.export(postables, "-", args)
143
result = gcode.splitlines()[5]
144
expected = "G0 X10.000 Y20.000 Z30.000"
145
self.assertEqual(result, expected)
147
args = "--no-header --precision=2 --no-show-editor"
148
gcode = postprocessor.export(postables, "-", args)
149
result = gcode.splitlines()[5]
150
expected = "G0 X10.00 Y20.00 Z30.00"
151
self.assertEqual(result, expected)
157
c = Path.Command("G0 X10 Y20 Z30")
159
self.docobj.Path = Path.Path([c])
160
postables = [self.docobj]
162
args = "--no-header --line-numbers --no-show-editor"
163
gcode = postprocessor.export(postables, "-", args)
164
result = gcode.splitlines()[5]
165
expected = "N150 G0 X10.000 Y20.000 Z30.000"
166
self.assertEqual(result, expected)
173
self.docobj.Path = Path.Path([])
174
postables = [self.docobj]
176
args = "--no-header --no-comments --preamble='G18 G55\n' --no-show-editor"
177
gcode = postprocessor.export(postables, "-", args)
178
result = gcode.splitlines()[0]
179
self.assertEqual(result, "G18 G55")
185
self.docobj.Path = Path.Path([])
186
postables = [self.docobj]
187
args = "--no-header --no-comments --postamble='G0 Z50\nM2' --no-show-editor"
188
gcode = postprocessor.export(postables, "-", args)
189
result = gcode.splitlines()[-2]
190
self.assertEqual(result, "G0 Z50")
191
self.assertEqual(gcode.splitlines()[-1], "M2")
198
c = Path.Command("G0 X10 Y20 Z30")
199
self.docobj.Path = Path.Path([c])
200
postables = [self.docobj]
202
args = "--no-header --inches --no-show-editor"
203
gcode = postprocessor.export(postables, "-", args)
204
self.assertEqual(gcode.splitlines()[2], "G20")
206
result = gcode.splitlines()[5]
207
expected = "G0 X0.3937 Y0.7874 Z1.1811"
208
self.assertEqual(result, expected)
210
# Technical debt. The following test fails. Precision not working
211
# with imperial units.
213
# args = ("--no-header --inches --precision=2")
214
# gcode = postprocessor.export(postables, "-", args)
215
# result = gcode.splitlines()[5]
216
# expected = "G0 X0.39 Y0.78 Z1.18 "
217
# self.assertEqual(result, expected)
222
Suppress the command name if the same as previous
224
c = Path.Command("G0 X10 Y20 Z30")
225
c1 = Path.Command("G0 X10 Y30 Z30")
227
self.docobj.Path = Path.Path([c, c1])
228
postables = [self.docobj]
231
# The grbl postprocessor does not have a --modal option.
233
# args = "--no-header --modal --no-show-editor"
234
# gcode = postprocessor.export(postables, "-", args)
235
# result = gcode.splitlines()[6]
236
# expected = "X10.000 Y30.000 Z30.000 "
237
# self.assertEqual(result, expected)
242
Suppress the axis coordinate if the same as previous
244
c = Path.Command("G0 X10 Y20 Z30")
245
c1 = Path.Command("G0 X10 Y30 Z30")
247
self.docobj.Path = Path.Path([c, c1])
248
postables = [self.docobj]
251
# The grbl postprocessor does not have a --axis-modal option.
253
# args = "--no-header --axis-modal --no-show-editor"
254
# gcode = postprocessor.export(postables, "-", args)
255
# result = gcode.splitlines()[6]
256
# expected = "G0 Y30.000 "
257
# self.assertEqual(result, expected)
263
c = Path.Command("M6 T2")
264
c2 = Path.Command("M3 S3000")
265
self.docobj.Path = Path.Path([c, c2])
266
postables = [self.docobj]
268
args = "--no-header --no-show-editor"
269
gcode = postprocessor.export(postables, "-", args)
270
self.assertEqual(gcode.splitlines()[6], "( M6 T2 )")
271
self.assertEqual(gcode.splitlines()[7], "M3 S3000")
275
# The grbl postprocessor does not have a --no-tlo option.
277
# args = "--no-header --no-tlo --no-show-editor"
278
# gcode = postprocessor.export(postables, "-", args)
279
# self.assertEqual(gcode.splitlines()[7], "M3 S3000 ")
286
c = Path.Command("(comment)")
288
self.docobj.Path = Path.Path([c])
289
postables = [self.docobj]
291
args = "--no-header --no-show-editor"
292
gcode = postprocessor.export(postables, "-", args)
293
result = gcode.splitlines()[5]
294
expected = "(comment)"
295
self.assertEqual(result, expected)