1#![allow(clippy::new_without_default)]
20
21#[cfg(test)]
22#[macro_use]
23mod test_macros;
24
25mod attributes;
26mod codegen;
27mod coordinates;
28mod errors;
29mod extended_codes;
30mod function_codes;
31mod macros;
32mod traits;
33mod types;
34
35pub use crate::attributes::*;
36pub use crate::codegen::*;
37pub use crate::coordinates::*;
38pub use crate::errors::*;
39pub use crate::extended_codes::*;
40pub use crate::function_codes::*;
41pub use crate::macros::*;
42pub use crate::traits::GerberCode;
43pub use crate::types::*;
44
45#[cfg(test)]
46mod test {
47 use std::io::BufWriter;
48
49 use super::traits::PartialGerberCode;
50 use super::*;
51
52 #[test]
53 fn test_serialize() {
54 let comment = GCode::Comment("testcomment".to_string());
56 assert_code!(comment, "G04 testcomment*\n");
57 }
58
59 #[test]
60 fn test_vec_serialize() {
61 let mut v = Vec::new();
63 v.push(GCode::Comment("comment 1".to_string()));
64 v.push(GCode::Comment("another one".to_string()));
65 assert_code!(v, "G04 comment 1*\nG04 another one*\n");
66 }
67
68 #[test]
69 fn test_command_serialize() {
70 let c = Command::FunctionCode(FunctionCode::GCode(GCode::Comment("comment".to_string())));
72 assert_code!(c, "G04 comment*\n");
73 }
74
75 #[test]
76 fn test_interpolation_mode() {
77 let mut commands = Vec::new();
78 let c1 = GCode::InterpolationMode(InterpolationMode::Linear);
79 let c2 = GCode::InterpolationMode(InterpolationMode::ClockwiseCircular);
80 let c3 = GCode::InterpolationMode(InterpolationMode::CounterclockwiseCircular);
81 commands.push(c1);
82 commands.push(c2);
83 commands.push(c3);
84 assert_code!(commands, "G01*\nG02*\nG03*\n");
85 }
86
87 #[test]
88 fn test_region_mode() {
89 let mut commands = Vec::new();
90 commands.push(GCode::RegionMode(true));
91 commands.push(GCode::RegionMode(false));
92 assert_code!(commands, "G36*\nG37*\n");
93 }
94
95 #[test]
96 fn test_quadrant_mode() {
97 let mut commands = Vec::new();
98 commands.push(GCode::QuadrantMode(QuadrantMode::Single));
99 commands.push(GCode::QuadrantMode(QuadrantMode::Multi));
100 assert_code!(commands, "G74*\nG75*\n");
101 }
102
103 #[test]
104 fn test_end_of_file() {
105 let c = MCode::EndOfFile;
106 assert_code!(c, "M02*\n");
107 }
108
109 #[test]
110 fn test_operation_interpolate() {
111 let cf = CoordinateFormat::new(2, 5);
112 let c1 = Operation::Interpolate(
113 Coordinates::new(1, 2, cf),
114 Some(CoordinateOffset::new(5, 10, cf)),
115 );
116 assert_code!(c1, "X100000Y200000I500000J1000000D01*\n");
117 let c2 = Operation::Interpolate(Coordinates::at_y(-2, CoordinateFormat::new(4, 4)), None);
118 assert_code!(c2, "Y-20000D01*\n");
119 let cf = CoordinateFormat::new(4, 4);
120 let c3 = Operation::Interpolate(
121 Coordinates::at_x(1, cf),
122 Some(CoordinateOffset::at_y(2, cf)),
123 );
124 assert_code!(c3, "X10000J20000D01*\n");
125 }
126
127 #[test]
128 fn test_operation_move() {
129 let c = Operation::Move(Coordinates::new(23, 42, CoordinateFormat::new(6, 4)));
130 assert_code!(c, "X230000Y420000D02*\n");
131 }
132
133 #[test]
134 fn test_operation_flash() {
135 let c = Operation::Flash(Coordinates::new(23, 42, CoordinateFormat::new(4, 4)));
136 assert_code!(c, "X230000Y420000D03*\n");
137 }
138
139 #[test]
140 fn test_select_aperture() {
141 let c1 = DCode::SelectAperture(10);
142 assert_code!(c1, "D10*\n");
143 let c2 = DCode::SelectAperture(2147483647);
144 assert_code!(c2, "D2147483647*\n");
145 }
146
147 #[test]
148 fn test_coordinate_format() {
149 let c = ExtendedCode::CoordinateFormat(CoordinateFormat::new(2, 5));
150 assert_code!(c, "%FSLAX25Y25*%\n");
151 }
152
153 #[test]
154 fn test_unit() {
155 let c1 = ExtendedCode::Unit(Unit::Millimeters);
156 let c2 = ExtendedCode::Unit(Unit::Inches);
157 assert_code!(c1, "%MOMM*%\n");
158 assert_code!(c2, "%MOIN*%\n");
159 }
160
161 #[test]
162 fn test_aperture_circle_definition() {
163 let ad1 = ApertureDefinition {
164 code: 10,
165 aperture: Aperture::Circle(Circle {
166 diameter: 4.0,
167 hole_diameter: Some(2.0),
168 }),
169 };
170 let ad2 = ApertureDefinition {
171 code: 11,
172 aperture: Aperture::Circle(Circle {
173 diameter: 4.5,
174 hole_diameter: None,
175 }),
176 };
177 assert_partial_code!(ad1, "10C,4X2");
178 assert_partial_code!(ad2, "11C,4.5");
179 }
180
181 #[test]
182 fn test_aperture_rectangular_definition() {
183 let ad1 = ApertureDefinition {
184 code: 12,
185 aperture: Aperture::Rectangle(Rectangular {
186 x: 1.5,
187 y: 2.25,
188 hole_diameter: Some(3.8),
189 }),
190 };
191 let ad2 = ApertureDefinition {
192 code: 13,
193 aperture: Aperture::Rectangle(Rectangular {
194 x: 1.0,
195 y: 1.0,
196 hole_diameter: None,
197 }),
198 };
199 let ad3 = ApertureDefinition {
200 code: 14,
201 aperture: Aperture::Obround(Rectangular {
202 x: 2.0,
203 y: 4.5,
204 hole_diameter: None,
205 }),
206 };
207 assert_partial_code!(ad1, "12R,1.5X2.25X3.8");
208 assert_partial_code!(ad2, "13R,1X1");
209 assert_partial_code!(ad3, "14O,2X4.5");
210 }
211
212 #[test]
213 fn test_aperture_polygon_definition() {
214 let ad1 = ApertureDefinition {
215 code: 15,
216 aperture: Aperture::Polygon(Polygon {
217 diameter: 4.5,
218 vertices: 3,
219 rotation: None,
220 hole_diameter: None,
221 }),
222 };
223 let ad2 = ApertureDefinition {
224 code: 16,
225 aperture: Aperture::Polygon(Polygon {
226 diameter: 5.0,
227 vertices: 4,
228 rotation: Some(30.6),
229 hole_diameter: None,
230 }),
231 };
232 let ad3 = ApertureDefinition {
233 code: 17,
234 aperture: Aperture::Polygon(Polygon {
235 diameter: 5.5,
236 vertices: 5,
237 rotation: None,
238 hole_diameter: Some(1.8),
239 }),
240 };
241 assert_partial_code!(ad1, "15P,4.5X3");
242 assert_partial_code!(ad2, "16P,5X4X30.6");
243 assert_partial_code!(ad3, "17P,5.5X5X0X1.8");
244 }
245
246 #[test]
247 fn test_polarity_serialize() {
248 let d = ExtendedCode::LoadPolarity(Polarity::Dark);
249 let c = ExtendedCode::LoadPolarity(Polarity::Clear);
250 assert_code!(d, "%LPD*%\n");
251 assert_code!(c, "%LPC*%\n");
252 }
253
254 #[test]
255 fn test_step_and_repeat_serialize() {
256 let o = ExtendedCode::StepAndRepeat(StepAndRepeat::Open {
257 repeat_x: 2,
258 repeat_y: 3,
259 distance_x: 2.0,
260 distance_y: 3.0,
261 });
262 let c = ExtendedCode::StepAndRepeat(StepAndRepeat::Close);
263 assert_code!(o, "%SRX2Y3I2J3*%\n");
264 assert_code!(c, "%SR*%\n");
265 }
266
267 #[test]
268 fn test_delete_attribute_serialize() {
269 let d = ExtendedCode::DeleteAttribute("foo".into());
270 assert_code!(d, "%TDfoo*%\n");
271 }
272
273 #[test]
274 fn test_file_attribute_serialize() {
275 let part = ExtendedCode::FileAttribute(FileAttribute::Part(Part::Other("foo".into())));
276 assert_code!(part, "%TF.Part,Other,foo*%\n");
277
278 let gensw1 = ExtendedCode::FileAttribute(FileAttribute::GenerationSoftware(
279 GenerationSoftware::new("Vend0r", "superpcb", None),
280 ));
281 assert_code!(gensw1, "%TF.GenerationSoftware,Vend0r,superpcb*%\n");
282
283 let gensw2 = ExtendedCode::FileAttribute(FileAttribute::GenerationSoftware(
284 GenerationSoftware::new("Vend0r", "superpcb", Some("1.2.3")),
285 ));
286 assert_code!(gensw2, "%TF.GenerationSoftware,Vend0r,superpcb,1.2.3*%\n");
287 }
288}