1#![deny(
71 missing_docs,
72 missing_debug_implementations,
73 missing_copy_implementations,
74 trivial_casts,
75 trivial_numeric_casts,
76 unsafe_code,
77 unstable_features,
78 unused_import_braces,
79 unused_qualifications
80)]
81
82mod builder;
83mod elements;
84mod types;
85
86pub use crate::builder::{BarcodeType, Color, DiagonalOrientation, LabelBuilder, Orientation};
87pub use crate::types::ZplError;
88
89#[cfg(test)]
90mod tests {
91 use super::*;
92 use crate::types::{AxisPosition, BoxDimension, GraphicDimension, Thickness, WidthRatio};
93
94 #[test]
97 fn axis_position_valid_bounds() {
98 assert_eq!(AxisPosition::try_from(0), Ok(AxisPosition(0)));
99 assert_eq!(AxisPosition::try_from(32000), Ok(AxisPosition(32000)));
100 assert_eq!(AxisPosition::try_from(1000), Ok(AxisPosition(1000)));
101 }
102
103 #[test]
104 fn axis_position_out_of_range() {
105 assert_eq!(
106 AxisPosition::try_from(32001),
107 Err(ZplError::InvalidPosition(32001))
108 );
109 assert_eq!(
110 AxisPosition::try_from(u16::MAX),
111 Err(ZplError::InvalidPosition(u16::MAX))
112 );
113 }
114
115 #[test]
118 fn width_ratio_valid_values() {
119 assert_eq!(WidthRatio::try_from(2.0).unwrap().to_string(), "2.0");
120 assert_eq!(WidthRatio::try_from(2.5).unwrap().to_string(), "2.5");
121 assert_eq!(WidthRatio::try_from(3.0).unwrap().to_string(), "3.0");
122 }
123
124 #[test]
125 fn width_ratio_out_of_range() {
126 assert_eq!(
127 WidthRatio::try_from(1.9),
128 Err(ZplError::InvalidWidthRatio(1.9))
129 );
130 assert_eq!(
131 WidthRatio::try_from(3.1),
132 Err(ZplError::InvalidWidthRatio(3.1))
133 );
134 }
135
136 #[test]
139 fn graphic_dimension_valid_bounds() {
140 assert_eq!(GraphicDimension::try_from(3), Ok(GraphicDimension(3)));
141 assert_eq!(GraphicDimension::try_from(4095), Ok(GraphicDimension(4095)));
142 }
143
144 #[test]
145 fn graphic_dimension_out_of_range() {
146 assert_eq!(
147 GraphicDimension::try_from(2),
148 Err(ZplError::InvalidGraphicDimension(2))
149 );
150 assert_eq!(
151 GraphicDimension::try_from(4096),
152 Err(ZplError::InvalidGraphicDimension(4096))
153 );
154 }
155
156 #[test]
159 fn box_dimension_equal_to_thickness() {
160 let t = Thickness::try_from(10).unwrap();
161 assert_eq!(BoxDimension::try_new(10, t), Ok(BoxDimension(10)));
162 }
163
164 #[test]
165 fn box_dimension_greater_than_thickness() {
166 let t = Thickness::try_from(10).unwrap();
167 assert_eq!(BoxDimension::try_new(200, t), Ok(BoxDimension(200)));
168 }
169
170 #[test]
171 fn box_dimension_less_than_thickness() {
172 let t = Thickness::try_from(10).unwrap();
173 assert_eq!(
174 BoxDimension::try_new(9, t),
175 Err(ZplError::InvalidBoxDimension {
176 value: 9,
177 thickness: 10
178 })
179 );
180 }
181
182 #[test]
183 fn box_dimension_at_maximum() {
184 let t = Thickness::try_from(1).unwrap();
185 assert_eq!(BoxDimension::try_new(32000, t), Ok(BoxDimension(32000)));
186 assert_eq!(
187 BoxDimension::try_new(32001, t),
188 Err(ZplError::InvalidBoxDimension {
189 value: 32001,
190 thickness: 1
191 })
192 );
193 }
194
195 #[test]
198 fn add_text_normal_orientation() {
199 let label = LabelBuilder::new()
200 .add_text("Text to print.", 10, 10, 'B', 15, Orientation::Normal)
201 .unwrap()
202 .build();
203 assert_eq!(
204 label,
205 "^XA\n^LH0,0\n^AB,15^FO10,10^FDText to print.^FS\n^XZ"
206 );
207 }
208
209 #[test]
210 fn add_text_inverted_orientation() {
211 let label = LabelBuilder::new()
212 .add_text("Text to print.", 10, 10, '1', 15, Orientation::Inverted)
213 .unwrap()
214 .build();
215 assert_eq!(
216 label,
217 "^XA\n^LH0,0\n^A1,15^FWI^FO10,10^FDText to print.^FS\n^XZ"
218 );
219 }
220
221 #[test]
222 fn add_text_rotated_orientation() {
223 let label = LabelBuilder::new()
224 .add_text("Hello", 0, 0, 'A', 10, Orientation::Rotated)
225 .unwrap()
226 .build();
227 assert_eq!(label, "^XA\n^LH0,0\n^AA,10^FWR^FO0,0^FDHello^FS\n^XZ");
228 }
229
230 #[test]
231 fn add_text_bottom_orientation() {
232 let label = LabelBuilder::new()
233 .add_text("Hello", 0, 0, 'A', 10, Orientation::Bottom)
234 .unwrap()
235 .build();
236 assert_eq!(label, "^XA\n^LH0,0\n^AA,10^FWB^FO0,0^FDHello^FS\n^XZ");
237 }
238
239 #[test]
240 fn add_text_invalid_font() {
241 assert_eq!(
242 LabelBuilder::new().add_text("x", 10, 10, '0', 15, Orientation::Normal),
243 Err(ZplError::InvalidFont('0'))
244 );
245 assert_eq!(
246 LabelBuilder::new().add_text("x", 10, 10, 'a', 15, Orientation::Normal),
247 Err(ZplError::InvalidFont('a'))
248 );
249 assert_eq!(
250 LabelBuilder::new().add_text("x", 10, 10, ' ', 15, Orientation::Normal),
251 Err(ZplError::InvalidFont(' '))
252 );
253 }
254
255 #[test]
256 fn add_text_invalid_position() {
257 assert_eq!(
258 LabelBuilder::new().add_text("x", 32001, 0, 'A', 15, Orientation::Normal),
259 Err(ZplError::InvalidPosition(32001))
260 );
261 assert_eq!(
262 LabelBuilder::new().add_text("x", 0, 32001, 'A', 15, Orientation::Normal),
263 Err(ZplError::InvalidPosition(32001))
264 );
265 }
266
267 #[test]
268 fn add_text_invalid_font_size() {
269 assert_eq!(
270 LabelBuilder::new().add_text("x", 0, 0, 'A', 9, Orientation::Normal),
271 Err(ZplError::InvalidFontSize(9))
272 );
273 }
274
275 #[test]
278 fn add_barcode_normal_orientation() {
279 let label = LabelBuilder::new()
280 .add_barcode(
281 BarcodeType::Code128,
282 "Text to encode.",
283 10,
284 10,
285 2,
286 3.0,
287 10,
288 Orientation::Normal,
289 )
290 .unwrap()
291 .build();
292 assert_eq!(
293 label,
294 "^XA\n^LH0,0\n^BY2,3.0,10\n^FO10,10^BC^FDText to encode.^FS\n^XZ"
295 );
296 }
297
298 #[test]
299 fn add_barcode_inverted_orientation() {
300 let label = LabelBuilder::new()
301 .add_barcode(
302 BarcodeType::Code128,
303 "Text to encode.",
304 10,
305 10,
306 2,
307 2.5,
308 10,
309 Orientation::Inverted,
310 )
311 .unwrap()
312 .build();
313 assert_eq!(
314 label,
315 "^XA\n^LH0,0\n^BY2,2.5,10\n^FO10,10^BC,I^FDText to encode.^FS\n^XZ"
316 );
317 }
318
319 #[test]
320 fn add_barcode_invalid_width() {
321 assert_eq!(
322 LabelBuilder::new().add_barcode(
323 BarcodeType::Code128,
324 "x",
325 0,
326 0,
327 0,
328 2.5,
329 10,
330 Orientation::Normal
331 ),
332 Err(ZplError::InvalidBarcodeWidth(0))
333 );
334 assert_eq!(
335 LabelBuilder::new().add_barcode(
336 BarcodeType::Code128,
337 "x",
338 0,
339 0,
340 11,
341 2.5,
342 10,
343 Orientation::Normal
344 ),
345 Err(ZplError::InvalidBarcodeWidth(11))
346 );
347 }
348
349 #[test]
350 fn add_barcode_invalid_width_ratio() {
351 assert_eq!(
352 LabelBuilder::new().add_barcode(
353 BarcodeType::Code128,
354 "x",
355 0,
356 0,
357 2,
358 1.9,
359 10,
360 Orientation::Normal
361 ),
362 Err(ZplError::InvalidWidthRatio(1.9))
363 );
364 assert_eq!(
365 LabelBuilder::new().add_barcode(
366 BarcodeType::Code128,
367 "x",
368 0,
369 0,
370 2,
371 3.1,
372 10,
373 Orientation::Normal
374 ),
375 Err(ZplError::InvalidWidthRatio(3.1))
376 );
377 }
378
379 #[test]
380 fn add_barcode_invalid_height() {
381 assert_eq!(
382 LabelBuilder::new().add_barcode(
383 BarcodeType::Code128,
384 "x",
385 0,
386 0,
387 2,
388 2.5,
389 0,
390 Orientation::Normal
391 ),
392 Err(ZplError::InvalidBarcodeHeight(0))
393 );
394 }
395
396 #[test]
399 fn add_graphical_box_valid() {
400 let label = LabelBuilder::new()
401 .add_graphical_box(10, 10, 100, 200, 3, Color::Black, 0)
402 .unwrap()
403 .build();
404 assert_eq!(label, "^XA\n^LH0,0\n^FO10,10^GB100,200,3,B,0^FS\n^XZ");
405 }
406
407 #[test]
408 fn add_graphical_box_white() {
409 let label = LabelBuilder::new()
410 .add_graphical_box(0, 0, 50, 50, 1, Color::White, 0)
411 .unwrap()
412 .build();
413 assert_eq!(label, "^XA\n^LH0,0\n^FO0,0^GB50,50,1,W,0^FS\n^XZ");
414 }
415
416 #[test]
417 fn add_graphical_box_width_less_than_thickness() {
418 assert_eq!(
419 LabelBuilder::new().add_graphical_box(0, 0, 2, 100, 5, Color::Black, 0),
420 Err(ZplError::InvalidBoxDimension {
421 value: 2,
422 thickness: 5
423 })
424 );
425 }
426
427 #[test]
428 fn add_graphical_box_height_less_than_thickness() {
429 assert_eq!(
430 LabelBuilder::new().add_graphical_box(0, 0, 100, 2, 5, Color::Black, 0),
431 Err(ZplError::InvalidBoxDimension {
432 value: 2,
433 thickness: 5
434 })
435 );
436 }
437
438 #[test]
439 fn add_graphical_box_invalid_rounding() {
440 assert_eq!(
441 LabelBuilder::new().add_graphical_box(0, 0, 100, 100, 1, Color::Black, 9),
442 Err(ZplError::InvalidRounding(9))
443 );
444 }
445
446 #[test]
447 fn add_graphical_box_invalid_thickness() {
448 assert_eq!(
449 LabelBuilder::new().add_graphical_box(0, 0, 100, 100, 0, Color::Black, 0),
450 Err(ZplError::InvalidThickness(0))
451 );
452 }
453
454 #[test]
457 fn add_graphical_circle_valid() {
458 let label = LabelBuilder::new()
459 .add_graphical_circle(10, 10, 100, 2, Color::Black)
460 .unwrap()
461 .build();
462 assert_eq!(label, "^XA\n^LH0,0\n^FO10,10^GC100,2,B^FS\n^XZ");
463 }
464
465 #[test]
466 fn add_graphical_circle_invalid_diameter() {
467 assert_eq!(
468 LabelBuilder::new().add_graphical_circle(0, 0, 2, 1, Color::Black),
469 Err(ZplError::InvalidGraphicDimension(2))
470 );
471 assert_eq!(
472 LabelBuilder::new().add_graphical_circle(0, 0, 4096, 1, Color::Black),
473 Err(ZplError::InvalidGraphicDimension(4096))
474 );
475 }
476
477 #[test]
478 fn add_graphical_circle_invalid_thickness() {
479 assert_eq!(
480 LabelBuilder::new().add_graphical_circle(0, 0, 100, 0, Color::Black),
481 Err(ZplError::InvalidThickness(0))
482 );
483 }
484
485 #[test]
488 fn add_graphical_ellipse_valid() {
489 let label = LabelBuilder::new()
490 .add_graphical_ellipse(10, 10, 100, 150, 2, Color::Black)
491 .unwrap()
492 .build();
493 assert_eq!(label, "^XA\n^LH0,0\n^FO10,10^GE100,150,2,B^FS\n^XZ");
494 }
495
496 #[test]
497 fn add_graphical_ellipse_invalid_width() {
498 assert_eq!(
499 LabelBuilder::new().add_graphical_ellipse(0, 0, 2, 100, 1, Color::Black),
500 Err(ZplError::InvalidGraphicDimension(2))
501 );
502 }
503
504 #[test]
505 fn add_graphical_ellipse_invalid_height() {
506 assert_eq!(
507 LabelBuilder::new().add_graphical_ellipse(0, 0, 100, 4096, 1, Color::Black),
508 Err(ZplError::InvalidGraphicDimension(4096))
509 );
510 }
511
512 #[test]
515 fn add_graphical_diagonal_line_right_leaning() {
516 let label = LabelBuilder::new()
517 .add_graphical_diagonal_line(
518 10,
519 10,
520 100,
521 50,
522 2,
523 Color::Black,
524 DiagonalOrientation::RightLeaning,
525 )
526 .unwrap()
527 .build();
528 assert_eq!(label, "^XA\n^LH0,0\n^FO10,10^GD100,50,2,B,R^FS\n^XZ");
529 }
530
531 #[test]
532 fn add_graphical_diagonal_line_left_leaning() {
533 let label = LabelBuilder::new()
534 .add_graphical_diagonal_line(
535 10,
536 10,
537 100,
538 50,
539 2,
540 Color::Black,
541 DiagonalOrientation::LeftLeaning,
542 )
543 .unwrap()
544 .build();
545 assert_eq!(label, "^XA\n^LH0,0\n^FO10,10^GD100,50,2,B,L^FS\n^XZ");
546 }
547
548 #[test]
549 fn add_graphical_diagonal_line_white() {
550 let label = LabelBuilder::new()
551 .add_graphical_diagonal_line(
552 0,
553 0,
554 200,
555 100,
556 3,
557 Color::White,
558 DiagonalOrientation::RightLeaning,
559 )
560 .unwrap()
561 .build();
562 assert_eq!(label, "^XA\n^LH0,0\n^FO0,0^GD200,100,3,W,R^FS\n^XZ");
563 }
564
565 #[test]
566 fn add_graphical_diagonal_line_square_box() {
567 let label = LabelBuilder::new()
569 .add_graphical_diagonal_line(
570 0,
571 0,
572 100,
573 100,
574 1,
575 Color::Black,
576 DiagonalOrientation::LeftLeaning,
577 )
578 .unwrap()
579 .build();
580 assert_eq!(label, "^XA\n^LH0,0\n^FO0,0^GD100,100,1,B,L^FS\n^XZ");
581 }
582
583 #[test]
584 fn add_graphical_diagonal_line_width_equal_to_thickness() {
585 let label = LabelBuilder::new()
587 .add_graphical_diagonal_line(
588 0,
589 0,
590 5,
591 50,
592 5,
593 Color::Black,
594 DiagonalOrientation::RightLeaning,
595 )
596 .unwrap()
597 .build();
598 assert_eq!(label, "^XA\n^LH0,0\n^FO0,0^GD5,50,5,B,R^FS\n^XZ");
599 }
600
601 #[test]
602 fn add_graphical_diagonal_line_invalid_thickness() {
603 assert_eq!(
604 LabelBuilder::new().add_graphical_diagonal_line(
605 0,
606 0,
607 100,
608 100,
609 0,
610 Color::Black,
611 DiagonalOrientation::RightLeaning
612 ),
613 Err(ZplError::InvalidThickness(0))
614 );
615 }
616
617 #[test]
618 fn add_graphical_diagonal_line_width_less_than_thickness() {
619 assert_eq!(
620 LabelBuilder::new().add_graphical_diagonal_line(
621 0,
622 0,
623 4,
624 100,
625 5,
626 Color::Black,
627 DiagonalOrientation::RightLeaning
628 ),
629 Err(ZplError::InvalidBoxDimension {
630 value: 4,
631 thickness: 5
632 })
633 );
634 }
635
636 #[test]
637 fn add_graphical_diagonal_line_height_less_than_thickness() {
638 assert_eq!(
639 LabelBuilder::new().add_graphical_diagonal_line(
640 0,
641 0,
642 100,
643 4,
644 5,
645 Color::Black,
646 DiagonalOrientation::LeftLeaning
647 ),
648 Err(ZplError::InvalidBoxDimension {
649 value: 4,
650 thickness: 5
651 })
652 );
653 }
654
655 #[test]
656 fn add_graphical_diagonal_line_invalid_position() {
657 assert_eq!(
658 LabelBuilder::new().add_graphical_diagonal_line(
659 32001,
660 0,
661 100,
662 100,
663 1,
664 Color::Black,
665 DiagonalOrientation::RightLeaning
666 ),
667 Err(ZplError::InvalidPosition(32001))
668 );
669 }
670
671 #[test]
674 fn set_home_position_valid() {
675 let label = LabelBuilder::new()
676 .set_home_position(50, 100)
677 .unwrap()
678 .build();
679 assert_eq!(label, "^XA\n^LH50,100\n^XZ");
680 }
681
682 #[test]
683 fn set_home_position_invalid() {
684 assert_eq!(
685 LabelBuilder::new().set_home_position(32001, 0),
686 Err(ZplError::InvalidPosition(32001))
687 );
688 assert_eq!(
689 LabelBuilder::new().set_home_position(0, 32001),
690 Err(ZplError::InvalidPosition(32001))
691 );
692 }
693
694 #[test]
697 fn create_full_label() {
698 let label = LabelBuilder::new()
699 .set_home_position(10, 10)
700 .unwrap()
701 .add_text("Test label", 200, 50, '2', 50, Orientation::Normal)
702 .unwrap()
703 .add_graphical_box(50, 200, 500, 300, 3, Color::Black, 5)
704 .unwrap()
705 .add_barcode(
706 BarcodeType::Code128,
707 "Test barcode",
708 130,
709 270,
710 2,
711 2.5,
712 150,
713 Orientation::Normal,
714 )
715 .unwrap()
716 .add_graphical_ellipse(200, 700, 250, 150, 3, Color::Black)
717 .unwrap()
718 .add_graphical_circle(300, 750, 50, 3, Color::Black)
719 .unwrap()
720 .build();
721 let expected = concat!(
722 "^XA\n",
723 "^LH10,10\n",
724 "^A2,50^FO200,50^FDTest label^FS\n",
725 "^FO50,200^GB500,300,3,B,5^FS\n",
726 "^BY2,2.5,150\n^FO130,270^BC^FDTest barcode^FS\n",
727 "^FO200,700^GE250,150,3,B^FS\n",
728 "^FO300,750^GC50,3,B^FS\n",
729 "^XZ",
730 );
731 assert_eq!(label, expected);
732 }
733
734 #[test]
735 fn empty_label() {
736 let label = LabelBuilder::new().build();
737 assert_eq!(label, "^XA\n^LH0,0\n^XZ");
738 }
739
740 #[test]
741 fn error_stops_chain_early() {
742 let result = LabelBuilder::new()
745 .add_barcode(
746 BarcodeType::Code128,
747 "x",
748 0,
749 0,
750 11,
751 2.5,
752 10,
753 Orientation::Normal,
754 )
755 .and_then(|b| b.add_text("y", 0, 0, 'A', 10, Orientation::Normal));
756 assert_eq!(result, Err(ZplError::InvalidBarcodeWidth(11)));
757 }
758}