@@ -17,7 +17,7 @@ use std::collections::HashMap;
1717use strum:: VariantArray ;
1818mod util;
1919use gerber_parser:: util:: {
20- coordinates_from_gerber, gerber_to_reader, partial_coordinates_from_gerber,
20+ coordinates_from_gerber, gerber_doc_as_str , gerber_to_reader, partial_coordinates_from_gerber,
2121 partial_coordinates_offset_from_gerber,
2222} ;
2323use util:: testing:: logging_init;
@@ -2025,6 +2025,84 @@ fn TF_file_attributes() {
20252025 assert_eq ! ( filtered_commands, expected_commands, )
20262026}
20272027
2028+ /// Guards against silent drift between the parser and the gerber-types serializer
2029+ /// for every `FileAttribute` variant. Each TF line is written in the exact form the
2030+ /// serializer produces, so any divergence surfaces as a textual diff.
2031+ #[ test]
2032+ #[ allow( non_snake_case) ]
2033+ fn TF_file_attributes_serialize_roundtrip ( ) {
2034+ logging_init ( ) ;
2035+
2036+ const GERBER : & str = "%FSLAX23Y23*%
2037+ %MOMM*%
2038+ %TF.Part,Single*%
2039+ %TF.Part,Array*%
2040+ %TF.Part,FabricationPanel*%
2041+ %TF.Part,Coupon*%
2042+ %TF.Part,Other,Value 1*%
2043+ %TF.FileFunction,Copper,L1,Top*%
2044+ %TF.FileFunction,Copper,L2,Inr,Plane*%
2045+ %TF.FileFunction,Copper,L3,Inr,Signal*%
2046+ %TF.FileFunction,Copper,L4,Bot,Mixed*%
2047+ %TF.FileFunction,Copper,L5,Bot,Hatched*%
2048+ %TF.FileFunction,Plated,1,2,PTH*%
2049+ %TF.FileFunction,Plated,1,6,Blind,Drill*%
2050+ %TF.FileFunction,Plated,3,4,Buried,Rout*%
2051+ %TF.FileFunction,NonPlated,1,2,NPTH*%
2052+ %TF.FileFunction,NonPlated,1,6,Blind,Mixed*%
2053+ %TF.FileFunction,NonPlated,3,4,Buried,Drill*%
2054+ %TF.FileFunction,Profile*%
2055+ %TF.FileFunction,Profile,P*%
2056+ %TF.FileFunction,Profile,NP*%
2057+ %TF.FileFunction,Keepout,Top*%
2058+ %TF.FileFunction,Keepout,Bot*%
2059+ %TF.FileFunction,Soldermask,Top*%
2060+ %TF.FileFunction,Soldermask,Bot,1*%
2061+ %TF.FileFunction,Legend,Top*%
2062+ %TF.FileFunction,Legend,Bot,2*%
2063+ %TF.FileFunction,Component,L1,Top*%
2064+ %TF.FileFunction,Paste,Top*%
2065+ %TF.FileFunction,Paste,Bot*%
2066+ %TF.FileFunction,Glue,Top*%
2067+ %TF.FileFunction,Carbonmask,Top*%
2068+ %TF.FileFunction,Goldmask,Top,1*%
2069+ %TF.FileFunction,Heatsinkmask,Bot*%
2070+ %TF.FileFunction,Peelablemask,Top*%
2071+ %TF.FileFunction,Silvermask,Bot,2*%
2072+ %TF.FileFunction,Tinmask,Top*%
2073+ %TF.FileFunction,Depthrout,Top*%
2074+ %TF.FileFunction,Vcut*%
2075+ %TF.FileFunction,Vcut,Top*%
2076+ %TF.FileFunction,Viafill*%
2077+ %TF.FileFunction,Pads,Top*%
2078+ %TF.FileFunction,Other,Value 1*%
2079+ %TF.FileFunction,Drillmap*%
2080+ %TF.FileFunction,FabricationDrawing*%
2081+ %TF.FileFunction,Vcutmap*%
2082+ %TF.FileFunction,AssemblyDrawing,Top*%
2083+ %TF.FileFunction,AssemblyDrawing,Bot*%
2084+ %TF.FileFunction,ArrayDrawing*%
2085+ %TF.FileFunction,OtherDrawing,Value 1*%
2086+ %TF.FilePolarity,Positive*%
2087+ %TF.FilePolarity,Negative*%
2088+ %TF.SameCoordinates*%
2089+ %TF.SameCoordinates,ident*%
2090+ %TF.SameCoordinates,ffffffff-ffff-ffff-ffff-ffffffffffff*%
2091+ %TF.CreationDate,2015-02-23T15:59:51+01:00*%
2092+ %TF.GenerationSoftware,MakerPnP,gerber-types*%
2093+ %TF.GenerationSoftware,MakerPnP,gerber-types,0.4.0*%
2094+ %TF.ProjectId,My PCB,ffffffff-ffff-ffff-ffff-ffffffffffff,2.0*%
2095+ %TF.MD5,6ab9e892830469cdff7e3e346331d404*%
2096+ %TFNonStandardAttribute,Value 1,Value 2*%
2097+ M02*
2098+ " ;
2099+
2100+ let doc = parse ( gerber_to_reader ( GERBER ) ) . unwrap ( ) ;
2101+ let errors = doc. errors ( ) ;
2102+ assert ! ( errors. is_empty( ) , "parse produced errors: {:?}" , errors) ;
2103+ assert_eq ! ( gerber_doc_as_str( & doc) , GERBER ) ;
2104+ }
2105+
20282106#[ test]
20292107#[ should_panic]
20302108fn conflicting_aperture_codes ( ) {
0 commit comments