@@ -238,6 +238,49 @@ public static void TestProteinGroupPopulateSampleGroupsReflectsPostSilacState()
238238 Assert . That ( headerFields . Length , Is . EqualTo ( row . Split ( '\t ' ) . Length ) ) ;
239239 }
240240
241+ // Guards #2: the protein-group TSV header is emitted once from proteinGroups.First()
242+ // (see PostSearchAnalysisTask / PostGlycoSearchAnalysisTask), while each row re-derives its
243+ // own dynamic columns. When groups are populated through the normal pipeline path
244+ // (IntensitiesByFile always assigned, with zeros where a protein had no measured intensity),
245+ // every row's column count must equal the single header's column count.
246+ [ Test ]
247+ public static void TestMultipleProteinGroupsHeaderAndRowsHaveSameColumnCount ( )
248+ {
249+ Protein protA = new Protein ( "MEDEEK" , "protA" ) ;
250+ Protein protB = new Protein ( "MENEEK" , "protB" ) ;
251+ PeptideWithSetModifications pwsmA = new PeptideWithSetModifications ( protA , new DigestionParams ( ) , 1 , 3 , CleavageSpecificity . Full , "" , 0 , new Dictionary < int , Modification > ( ) , 0 ) ;
252+ PeptideWithSetModifications pwsmB = new PeptideWithSetModifications ( protB , new DigestionParams ( ) , 1 , 3 , CleavageSpecificity . Full , "" , 0 , new Dictionary < int , Modification > ( ) , 0 ) ;
253+
254+ ProteinGroup pgA = new ProteinGroup ( new HashSet < IBioPolymer > { protA } ,
255+ new HashSet < IBioPolymerWithSetMods > { pwsmA } , new HashSet < IBioPolymerWithSetMods > { pwsmA } ) ;
256+ ProteinGroup pgB = new ProteinGroup ( new HashSet < IBioPolymer > { protB } ,
257+ new HashSet < IBioPolymerWithSetMods > { pwsmB } , new HashSet < IBioPolymerWithSetMods > { pwsmB } ) ;
258+
259+ var fileA = new SpectraFileInfo ( @"X:\fakeA.mzML" , condition : "" , biorep : 0 , fraction : 0 , techrep : 0 ) ;
260+ var fileB = new SpectraFileInfo ( @"X:\fakeB.mzML" , condition : "" , biorep : 1 , fraction : 0 , techrep : 0 ) ;
261+ var files = new List < SpectraFileInfo > { fileA , fileB } ;
262+
263+ // pgA has measured intensity in both samples; pgB has none (zeros) -- mirrors how
264+ // QuantificationAnalysis always assigns IntensitiesByFile, even for unmeasured proteins.
265+ pgA . FilesForQuantification = files ;
266+ pgA . IntensitiesByFile = new Dictionary < SpectraFileInfo , double > { { fileA , 100.0 } , { fileB , 200.0 } } ;
267+ pgA . PopulateSampleGroupResults ( ) ;
268+
269+ pgB . FilesForQuantification = files ;
270+ pgB . IntensitiesByFile = new Dictionary < SpectraFileInfo , double > { { fileA , 0.0 } , { fileB , 0.0 } } ;
271+ pgB . PopulateSampleGroupResults ( ) ;
272+
273+ var proteinGroups = new List < ProteinGroup > { pgA , pgB } ;
274+
275+ // Header is generated once from the first group, exactly as the writers do.
276+ int headerColumnCount = proteinGroups . First ( ) . GetTabSeparatedHeader ( ) . Split ( '\t ' ) . Length ;
277+ foreach ( var pg in proteinGroups )
278+ {
279+ Assert . That ( pg . ToString ( ) . Split ( '\t ' ) . Length , Is . EqualTo ( headerColumnCount ) ,
280+ $ "Row column count for '{ pg . ProteinGroupName } ' does not match the header column count.") ;
281+ }
282+ }
283+
241284 [ Test ]
242285 public static void ProteinGroupMergeTest ( )
243286 {
0 commit comments