3 import static org.testng.AssertJUnit.assertEquals;
4 import static org.testng.AssertJUnit.assertFalse;
5 import static org.testng.AssertJUnit.assertNull;
6 import static org.testng.AssertJUnit.assertTrue;
7 import static org.testng.AssertJUnit.fail;
9 import jalview.datamodel.AlignmentI;
10 import jalview.datamodel.Sequence;
11 import jalview.datamodel.SequenceFeature;
12 import jalview.datamodel.SequenceI;
14 import java.io.IOException;
15 import java.util.Vector;
17 import org.testng.annotations.Test;
20 * Unit tests for MegaFile - read and write in MEGA format(s).
22 public class MegaFileTest
24 private static final String TWENTY_CHARS = "9876543210abcdefghij";
26 private static final String THIRTY_CHARS = "0123456789klmnopqrstABCDEFGHIJ";
29 private static final String INTERLEAVED =
31 "TITLE: Interleaved sequence data\n\n" +
33 "#CPZANT MNOPQR\n\n" +
37 private static final String INTERLEAVED_NOHEADERS =
39 + "#CPZANT MNOPQR\n\n"
43 // interleaved sequences, with 50 residues
44 private static final String INTERLEAVED_50RESIDUES =
46 + "!TITLE Interleaved sequence data\n\n"
47 + "#U455 " + THIRTY_CHARS + TWENTY_CHARS + "\n"
48 + "#CPZANT " + TWENTY_CHARS + THIRTY_CHARS + "\n";
50 private static final String NONINTERLEAVED =
52 + "!TITLE Noninterleaved sequence data\n\n"
60 // this one starts interleaved then switches to non-interleaved
61 private static final String MIXED =
63 + "!TITLE This is a mess\n\n"
64 + "#CPZANT KLMNOPWXYZCGATC\n\n"
68 // interleaved with a new sequence appearing in the second block :-O
69 private static final String INTERLEAVED_SEQUENCE_ERROR =
71 + "!TITLE Interleaved sequence data\n\n"
73 + "#CPZANT MNOPQR\n\n"
76 // interleaved with description, bases/gaps in triplet groups
77 private static final String INTERLEAVED_WITH_DESCRIPTION =
79 + "!Title Data with description;\n"
80 + "!Format DataType=DNA indel=-\tCodeTable=Standard Missing=? MatchChar=.;\n\n"
82 + " Line one of description\n"
83 + " Line two of description;\n\n"
85 + "#CPZANT ATC -G-\n\n"
87 + "#CPZANT CA- -GC\n";
92 * Test parse of interleaved mega format data.
96 @Test(groups = { "Functional" })
97 public void testParse_interleaved() throws IOException
99 MegaFile testee = new MegaFile(INTERLEAVED, AppletFormatAdapter.PASTE);
100 assertEquals("Title not as expected", "Interleaved sequence data",
101 testee.getAlignmentProperty(MegaFile.PROP_TITLE));
102 Vector<SequenceI> seqs = testee.getSeqs();
103 // should be 2 sequences
104 assertEquals("Expected two sequences", 2, seqs.size());
105 // check sequence names correct and order preserved
106 assertEquals("First sequence id wrong", "U455", seqs.get(0).getName());
107 assertEquals("Second sequence id wrong", "CPZANT", seqs.get(1)
109 // check sequence data
110 assertEquals("First sequence data wrong", "ABCDEFKLMNOP", seqs.get(0)
111 .getSequenceAsString());
112 assertEquals("Second sequence data wrong", "MNOPQRWXYZGC", seqs.get(1)
113 .getSequenceAsString());
114 assertTrue("File format is not flagged as interleaved",
115 testee.isInterleaved());
119 * Test parse of noninterleaved mega format data.
121 * @throws IOException
123 @Test(groups = { "Functional" })
124 public void testParse_nonInterleaved() throws IOException
126 MegaFile testee = new MegaFile(NONINTERLEAVED,
127 AppletFormatAdapter.PASTE);
128 assertEquals("Title not as expected", "Noninterleaved sequence data",
129 testee.getAlignmentProperty(MegaFile.PROP_TITLE));
130 Vector<SequenceI> seqs = testee.getSeqs();
131 // should be 2 sequences
132 assertEquals("Expected two sequences", 2, seqs.size());
133 // check sequence names correct and order preserved
134 assertEquals("First sequence id wrong", "U455", seqs.get(0).getName());
135 assertEquals("Second sequence id wrong", "CPZANT", seqs.get(1)
137 // check sequence data
138 assertEquals("First sequence data wrong", "ABCFEDHIJMNOPQR", seqs
139 .get(0).getSequenceAsString());
140 assertEquals("Second sequence data wrong", "KLMNOPWXYZCGATC",
141 seqs.get(1).getSequenceAsString());
142 assertFalse("File format is not flagged as noninterleaved",
143 testee.isInterleaved());
147 * Test parsing an interleaved file with an extra sequence appearing after the
148 * first block - should fail.
150 @Test(groups = { "Functional" })
151 public void testParse_interleavedExtraSequenceError()
155 new MegaFile(INTERLEAVED_SEQUENCE_ERROR, AppletFormatAdapter.PASTE);
156 fail("Expected extra sequence IOException");
157 } catch (IOException e)
160 "Unexpected exception message",
161 "Parse error: misplaced new sequence starting at #U456 KLMNOP",
167 * Test a mixed up file.
169 @Test(groups = { "Functional" })
170 public void testParse_mixedInterleavedNonInterleaved()
174 new MegaFile(MIXED, AppletFormatAdapter.PASTE);
175 fail("Expected mixed content exception");
176 } catch (IOException e)
179 "Unexpected exception message",
180 "Parse error: interleaved was true but now seems to be false, at line: ABCFEDHIJ",
186 @Test(groups = { "Functional" })
187 public void testGetSequenceId()
189 assertEquals("AB123", MegaFile.getSequenceId("#AB123 CGATC"));
190 assertEquals("AB123", MegaFile.getSequenceId("#AB123 CGATC"));
191 assertEquals("AB123", MegaFile.getSequenceId("#AB123 CGC TAC"));
192 assertEquals("AB123", MegaFile.getSequenceId("#AB123"));
193 assertNull(MegaFile.getSequenceId("AB123 CTAG"));
194 assertNull(MegaFile.getSequenceId("AB123"));
195 assertNull(MegaFile.getSequenceId(""));
196 assertNull(MegaFile.getSequenceId(null));
199 @Test(groups = { "Functional" })
200 public void testGetMaxIdLength()
202 SequenceI[] seqs = new Sequence[2];
203 seqs[0] = new Sequence("Something", "GCATAC");
204 seqs[1] = new Sequence("SomethingElse", "GCATAC");
205 assertEquals(13, MegaFile.getMaxIdLength(seqs));
206 seqs[1] = new Sequence("DNA", "GCATAC");
207 assertEquals(9, MegaFile.getMaxIdLength(seqs));
210 @Test(groups = { "Functional" })
211 public void testGetMaxSequenceLength()
213 SequenceI[] seqs = new Sequence[2];
214 seqs[0] = new Sequence("Seq1", "GCATAC");
215 seqs[1] = new Sequence("Seq2", "GCATACTAG");
216 assertEquals(9, MegaFile.getMaxSequenceLength(seqs));
217 seqs[1] = new Sequence("Seq2", "GCA");
218 assertEquals(6, MegaFile.getMaxSequenceLength(seqs));
222 * Test (parse and) print of interleaved mega format data.
224 * @throws IOException
226 @Test(groups = { "Functional" })
227 public void testPrint_interleaved() throws IOException
229 MegaFile testee = new MegaFile(INTERLEAVED, AppletFormatAdapter.PASTE);
230 String printed = testee.print();
231 System.out.println(printed);
232 // normally output should match input
233 // we cheated here with a number of short input lines
234 // nb don't get Title in output if not calling print(AlignmentI)
235 String expected = "#MEGA\n\n" + "#U455 ABCDEF [6]\n"
236 + "#CPZANT MNOPQR [6]\n\n" + "#U455 KLMNOP [12]\n"
237 + "#CPZANT WXYZGC [12]"
239 assertEquals("Print format wrong", expected, printed);
243 * Test (parse and) print of interleaved data with no headers (acceptable).
245 * @throws IOException
247 @Test(groups = { "Functional" })
248 public void testPrint_interleavedNoHeaders() throws IOException
250 MegaFile testee = new MegaFile(INTERLEAVED_NOHEADERS,
251 AppletFormatAdapter.PASTE);
252 String printed = testee.print();
253 System.out.println(printed);
256 assertEquals("Print format wrong",
257 "#MEGA\n\n" + "#U455 ABCDEF [6]\n"
258 + "#CPZANT MNOPQR [6]\n\n"
259 + "#U455 KLMNOP [12]\n"
260 + "#CPZANT WXYZGC [12]\n",
266 * Test (parse and) print of noninterleaved mega format data.
268 * @throws IOException
270 @Test(groups = { "Functional" })
271 public void testPrint_noninterleaved() throws IOException
273 MegaFile testee = new MegaFile(NONINTERLEAVED,
274 AppletFormatAdapter.PASTE);
275 assertEquals(10, testee.getPositionsPerLine());
276 String printed = testee.print();
277 System.out.println(printed);
278 // normally output should match input
279 // we cheated here with a number of short input lines
280 String expected = "#MEGA\n\n"
281 + "#U455\n" + "ABCFEDHIJM\nNOPQR\n\n"
282 + "#CPZANT\n" + "KLMNOPWXYZ\nCGATC\n";
283 assertEquals("Print format wrong", expected, printed);
287 * Test (parse and) print of interleaved mega format data extending to more
288 * than one line of output.
290 * @throws IOException
292 @Test(groups = { "Functional" })
293 public void testPrint_interleavedMultiLine() throws IOException
295 MegaFile testee = new MegaFile(INTERLEAVED_50RESIDUES,
296 AppletFormatAdapter.PASTE);
297 assertEquals(50, testee.getPositionsPerLine());
299 * now simulate choosing 20 residues per line on output
301 testee.setPositionsPerLine(20);
302 String printed = testee.print();
303 System.out.println(printed);
305 //0123456789klmnopqrstABCDEFGHIJ9876543210abcdefghij
308 "#U455 0123456789 klmnopqrst [20]\n" + // first 20
309 "#CPZANT 9876543210 abcdefghij [20]\n\n" +
310 "#U455 ABCDEFGHIJ 9876543210 [40]\n" + // next 20
311 "#CPZANT 0123456789 klmnopqrst [40]\n\n" +
312 "#U455 abcdefghij [50]\n" + // last 10
313 "#CPZANT ABCDEFGHIJ [50]\n";
315 assertEquals("Print format wrong", expected, printed);
319 * Test (parse and) print of noninterleaved mega format data extending to more
320 * than one line of output.
322 * @throws IOException
324 @Test(groups = { "Functional" })
325 public void testPrint_noninterleavedMultiLine() throws IOException
327 final String NONINTERLEAVED_LONGERTHAN50 = "#SIXTY\n" + THIRTY_CHARS
328 + "\n" + TWENTY_CHARS + "9993332221\n";
329 MegaFile testee = new MegaFile(NONINTERLEAVED_LONGERTHAN50,
330 AppletFormatAdapter.PASTE);
331 assertEquals(30, testee.getPositionsPerLine());
332 testee.setPositionsPerLine(25);
333 String printed = testee.print();
334 // 60 character sequence should be output as 50 on first line then 10 more
335 String expected = "#MEGA\n\n" + "#SIXTY\n"
336 + "0123456789klmnopqrstABCDE\n" + "FGHIJ9876543210abcdefghij\n"
338 assertEquals("Print format wrong", expected, printed);
342 * Test parse of data including description
344 * @throws IOException
346 @Test(groups = { "Functional" })
347 public void testParse_withDescription() throws IOException
349 MegaFile testee = new MegaFile(INTERLEAVED_WITH_DESCRIPTION,
350 AppletFormatAdapter.PASTE);
351 assertEquals("Title not as expected", "Data with description",
352 testee.getAlignmentProperty(MegaFile.PROP_TITLE));
354 Vector<SequenceI> seqs = testee.getSeqs();
355 // should be 2 sequences
356 assertEquals("Expected two sequences", 2, seqs.size());
357 // check sequence names correct and order preserved
358 assertEquals("First sequence id wrong", "U455", seqs.get(0).getName());
359 assertEquals("Second sequence id wrong", "CPZANT", seqs.get(1)
361 // check sequence data
362 assertEquals("First sequence data wrong", "C--GTACGA--T", seqs.get(0)
363 .getSequenceAsString());
364 assertEquals("Second sequence data wrong", "ATC-G-CA--GC", seqs.get(1)
365 .getSequenceAsString());
366 assertTrue("File format is not flagged as interleaved",
367 testee.isInterleaved());
370 "Description property not parsed",
371 " Line one of description\n" + " Line two of description",
372 testee.getAlignmentProperty(MegaFile.PROP_DESCRIPTION));
375 @Test(groups = { "Functional" })
376 public void testGetNonCommentContent() throws FileFormatException
378 assertEquals("abcde", MegaFile.getNonCommentContent("abcde", 0));
379 assertEquals("CGT ACG GAC ",
380 MegaFile.getNonCommentContent("CGT ACG GAC [9]", 0));
381 assertEquals("", MegaFile.getNonCommentContent("abcde", 1));
382 assertEquals(" abcde",
383 MegaFile.getNonCommentContent("and others ] abcde", 1));
384 assertEquals(" abcde", MegaFile.getNonCommentContent(
385 "and others [including refs] ] abcde", 1));
386 assertEquals(" x ] abcde",
387 MegaFile.getNonCommentContent("and others ] x ] abcde", 1));
390 @Test(groups = { "Functional" })
391 public void testCommentDepth() throws FileFormatException
393 assertEquals(0, MegaFile.commentDepth("abcde", 0));
394 assertEquals(1, MegaFile.commentDepth("abc[de", 0));
395 assertEquals(3, MegaFile.commentDepth("ab[c[de", 1));
396 assertEquals(1, MegaFile.commentDepth("ab]c[d]e[f", 1));
397 assertEquals(0, MegaFile.commentDepth("a]b[c]d]e", 1));
400 @Test(groups = { "Functional" })
401 public void testGetValue()
403 assertEquals("Mega", MegaFile.getValue("Name=Mega"));
404 assertEquals("Mega", MegaFile.getValue("Name =Mega"));
405 assertEquals("Mega", MegaFile.getValue(" Name = Mega "));
406 assertEquals("Mega", MegaFile.getValue("Name = Mega; "));
407 assertEquals("Mega", MegaFile.getValue(" Name = Mega ; "));
408 assertEquals("Mega", MegaFile.getValue("\t!Name \t= \tMega ; "));
409 assertEquals("Mega", MegaFile.getValue("!Name \t\t Mega; "));
410 assertEquals("", MegaFile.getValue("Name"));
414 * Test reading a MEGA file to an alignment then writing it out in MEGA
415 * format. Verify the output is (functionally) the same as the input.
417 * @throws IOException
419 @Test(groups = "Functional")
420 public void testRoundTrip_Interleaved() throws IOException
422 AppletFormatAdapter fa = new AppletFormatAdapter();
423 AlignmentI al = fa.readFile(INTERLEAVED_WITH_DESCRIPTION,
424 AppletFormatAdapter.PASTE, "MEGA");
425 MegaFile output = new MegaFile();
426 String formatted = output.print(al);
429 "#MEGA\n!Title Data with description;\n" +
431 " Line one of description\n" +
432 " Line two of description;\n" +
434 " DataType=DNA CodeTable=Standard\n" +
435 " NSeqs=2 NSites=12\n" + // NSites includes gaps
436 " Indel=- Identical=. Missing=?;\n\n" +
437 "#U455 C-- GTA [6]\n" +
438 "#CPZANT ATC -G- [6]\n\n" +
439 "#U455 CGA --T [12]\n" +
440 "#CPZANT CA- -GC [12]\n";
442 assertEquals("Roundtrip didn't match", expected,
447 * Test reading a MEGA file to an alignment then writing it out in MEGA
448 * format. Verify the output is (functionally) the same as the input.
450 * @throws IOException
452 @Test(groups = "Functional")
453 public void testRoundTrip_multilineFormatWithComments()
456 AppletFormatAdapter fa = new AppletFormatAdapter();
458 AlignmentI al = fa.readFile("#MEGA\n"
459 + "!Title Data with description;\n"
460 + "[ this comment should be ignored\n"
461 + "including [this nested comment]\n"
464 + "DataType=DNA CodeTable=Standard\n"
465 + "indel=- Missing=? MatchChar=.;\n\n"
467 + " Line one of description\n"
468 + " Line two of description;\n\n"
470 + "#CPZANT ATC GGG\n\n"
472 + "#CPZANT CAA TGC\n",
473 AppletFormatAdapter.PASTE, "MEGA");
475 MegaFile output = new MegaFile();
476 String formatted = output.print(al);
479 "#MEGA\n!Title Data with description;\n" +
481 " Line one of description\n" +
482 " Line two of description;\n" +
484 " DataType=DNA CodeTable=Standard\n" +
485 " NSeqs=2 NSites=12\n" +
486 " Indel=- Identical=. Missing=?;\n\n" +
487 "#U455 CGC GTA [6]\n" +
488 "#CPZANT ATC GGG [6]\n\n" +
489 "#U455 CGA TTT [12]\n" +
490 "#CPZANT CAA TGC [12]\n";
492 assertEquals("Roundtrip didn't match", expected,
499 * Test parse of interleaved mega format data where the identity character is
500 * used in sequences after the first
502 * @throws IOException
504 @Test(groups = { "Functional" })
505 public void testParse_interleavedWithIdentity() throws IOException
508 MegaFile testee = new MegaFile("#MEGA\n"+
509 "!TITLE Interleaved sequence data;\n" +
510 "!Format Identical=.;\n\n" +
512 "#CPZANT M..P.R\n\n" +
514 "#CPZANT ..YZ..", AppletFormatAdapter.PASTE);
516 assertEquals("Title not as expected", "Interleaved sequence data",
517 testee.getAlignmentProperty(MegaFile.PROP_TITLE));
518 Vector<SequenceI> seqs = testee.getSeqs();
519 // should be 2 sequences
520 assertEquals("Expected two sequences", 2, seqs.size());
521 // check sequence names correct and order preserved
522 assertEquals("First sequence id wrong", "U455", seqs.get(0).getName());
523 assertEquals("Second sequence id wrong", "CPZANT", seqs.get(1)
525 // check sequence data
526 assertEquals("First sequence data wrong", "ABCDEFKLMNOP", seqs.get(0)
527 .getSequenceAsString());
528 assertEquals("Second sequence data wrong", "MBCPERKLYZOP", seqs.get(1)
529 .getSequenceAsString());
530 assertTrue("File format is not flagged as interleaved",
531 testee.isInterleaved());
535 * Test parse of noninterleaved format data including identity symbol
537 * @throws IOException
539 @Test(groups = { "Functional" })
540 public void testParse_nonInterleavedWithIdentity() throws IOException
543 MegaFile testee = new MegaFile("#MEGA\n"
544 + "!TITLE Noninterleaved sequence data;\n"
545 + "!Format MatchChar=.;\n"
552 AppletFormatAdapter.PASTE);
554 assertEquals("Title not as expected", "Noninterleaved sequence data",
555 testee.getAlignmentProperty(MegaFile.PROP_TITLE));
556 Vector<SequenceI> seqs = testee.getSeqs();
557 // should be 2 sequences
558 assertEquals("Expected two sequences", 2, seqs.size());
559 // check sequence names correct and order preserved
560 assertEquals("First sequence id wrong", "U455", seqs.get(0).getName());
561 assertEquals("Second sequence id wrong", "CPZANT", seqs.get(1)
563 // check sequence data
564 assertEquals("First sequence data wrong", "ABCFEDHIJMNOPQR", seqs
565 .get(0).getSequenceAsString());
566 assertEquals("Second sequence data wrong", "KLCFODHXYZCGPQC",
567 seqs.get(1).getSequenceAsString());
568 assertFalse("File format is not flagged as noninterleaved",
569 testee.isInterleaved());
575 * Test parse of interleaved format data including position number comments.
577 * @throws IOException
579 @Test(groups = { "Functional" })
580 public void testParse_interleavedWithPositionNumber() throws IOException
583 MegaFile testee = new MegaFile("#MEGA\n"+
584 "TITLE: Interleaved sequence data\n\n" +
585 "#U455 ABCDEF [6]\n" +
586 "#CPZANT MNOPQR [6]\n\n" +
587 "#U455 KLMNOP [12]\n" +
588 "#CPZANT WXYZGC [12]\n", AppletFormatAdapter.PASTE);
590 assertEquals("Title not as expected", "Interleaved sequence data",
591 testee.getAlignmentProperty(MegaFile.PROP_TITLE));
592 Vector<SequenceI> seqs = testee.getSeqs();
593 // should be 2 sequences
594 assertEquals("Expected two sequences", 2, seqs.size());
595 // check sequence names correct and order preserved
596 assertEquals("First sequence id wrong", "U455", seqs.get(0).getName());
597 assertEquals("Second sequence id wrong", "CPZANT", seqs.get(1)
599 // check sequence data
600 assertEquals("First sequence data wrong", "ABCDEFKLMNOP", seqs.get(0)
601 .getSequenceAsString());
602 assertEquals("Second sequence data wrong", "MNOPQRWXYZGC", seqs.get(1)
603 .getSequenceAsString());
604 assertTrue("File format is not flagged as interleaved",
605 testee.isInterleaved());
611 * Test parse of data with !Gene and !Domain statements.
613 * @throws IOException
615 @Test(groups = { "Functional" })
616 public void testParse_geneDomains() throws IOException
619 String data = "#MEGA\n"+
620 "TITLE: Interleaved sequence data\n\n" +
622 "#CPZANT TTTTTT\n\n" +
623 "!Domain=Exon1 Gene=Adh Property=Coding CodonStart=1;\n" +
625 "#CPZANT AAAAAA\n\n" +
626 "!Domain=Intron1 Property=Intron Gene=Adh;\n" +
628 "#CPZANT cccccc\n\n" +
629 "!Domain=Exon2 Gene=Adh Property=Exon CodonStart=1;\n" +
631 "#CPZANT gggggg\n\n" +
632 // explicit end of Exon2, implicit end of Adh:
633 "!Domain=Exon2 Property=domainend;\n" +
634 "!Domain=Intron1 Gene=Opsin Property=Noncoding;\n" +
636 "#CPZANT AAAAAA\n\n" +
637 // end Opsin, start MEF2A
638 "!Domain=Exon1 Gene=MEF2A Property=Coding CodonStart=1;\n" +
640 "#CPZANT cccccc\n\n" +
642 "!Domain=BindingSite;\n" +
644 "#CPZANT TTTTTT\n\n";
646 MegaFile testee = new MegaFile(data, AppletFormatAdapter.PASTE);
648 Vector<SequenceI> seqs = testee.getSeqs();
649 // should be 2 sequences
650 assertEquals("Expected two sequences", 2, seqs.size());
651 // check sequence data
652 assertEquals("First sequence data wrong",
653 "CCCCCCGGGGGGttttttaaaaaaGGGGGGttttttCCCCCC", seqs.get(0)
654 .getSequenceAsString());
655 assertEquals("Second sequence data wrong",
656 "TTTTTTAAAAAAccccccggggggAAAAAAccccccTTTTTT", seqs.get(1)
657 .getSequenceAsString());
660 * sequences should have features for Gene=Adh 7-24, Exon1 7-12, Intron1
661 * 13-18, Exon2 19-24, BindingSite 25-30
663 for (SequenceI seq : seqs) {
664 SequenceFeature[] sfs = seq.getSequenceFeatures();
665 // features are added in the order in which their end is found
666 // (Domain before Gene when they end together)
667 assertEquals(9, sfs.length);
668 // TODO settle which way round type/description go!
669 verifySequenceFeature(sfs[0], "Exon1 (Adh Coding)", "Domain", 7, 12);
670 verifySequenceFeature(sfs[1], "Intron1 (Adh Noncoding)", "Domain",
672 verifySequenceFeature(sfs[2], "Exon2 (Adh Coding)", "Domain", 19, 24);
673 verifySequenceFeature(sfs[3], "Adh", "Gene", 7, 24);
674 verifySequenceFeature(sfs[4], "Intron1 (Opsin Noncoding)", "Domain",
676 verifySequenceFeature(sfs[5], "Opsin", "Gene", 25, 30);
677 verifySequenceFeature(sfs[6], "Exon1 (MEF2A Coding)", "Domain", 31,
679 verifySequenceFeature(sfs[7], "MEF2A", "Gene", 31, 36);
680 verifySequenceFeature(sfs[8], "BindingSite", "Domain", 37, 42);
685 * Helper method to assert properties of a SequenceFeature
693 protected void verifySequenceFeature(SequenceFeature sf,
694 String description, String type, int begin, int end)
696 assertEquals(description, sf.type);
697 assertEquals(type, sf.description);
698 assertEquals(begin, sf.begin);
699 assertEquals(end, sf.end);