90
90
highlights for example. If you want to simply check for the presence of
91
91
a given node or attribute, use an empty string (`""`) as a `PATTERN`.
92
92
93
- * `@count PATH XPATH COUNT' checks for the occurrence of the given XPath
93
+ * `@count PATH XPATH COUNT` checks for the occurrence of the given XPath
94
94
in the specified file. The number of occurrences must match the given
95
95
count.
96
96
97
+ * `@snapshot NAME PATH XPATH` creates a snapshot test named NAME.
98
+ A snapshot test captures a subtree of the DOM, at the location
99
+ determined by the XPath, and compares it to a pre-recorded value
100
+ in a file. The file's name is the test's name with the `.rs` extension
101
+ replaced with `.NAME.html`, where NAME is the snapshot's name.
102
+
103
+ htmldocck supports the `--bless` option to accept the current subtree
104
+ as expected, saving it to the file determined by the snapshot's name.
105
+ compiletest's `--bless` flag is forwarded to htmldocck.
106
+
97
107
* `@has-dir PATH` checks for the existence of the given directory.
98
108
99
109
All conditions can be negated with `!`. `@!has foo/type.NoSuch.html`
137
147
138
148
channel = os .environ ["DOC_RUST_LANG_ORG_CHANNEL" ]
139
149
150
+ # Initialized in main
151
+ rust_test_path = None
152
+ bless = None
153
+
140
154
class CustomHTMLParser (HTMLParser ):
141
155
"""simplified HTML parser.
142
156
@@ -387,6 +401,32 @@ def get_tree_count(tree, path):
387
401
return len (tree .findall (path ))
388
402
389
403
404
+ def check_snapshot (snapshot_name , tree ):
405
+ assert rust_test_path .endswith ('.rs' )
406
+ snapshot_path = '{}.{}.{}' .format (rust_test_path [:- 3 ], snapshot_name , 'html' )
407
+ try :
408
+ with open (snapshot_path , 'r' ) as snapshot_file :
409
+ expected_str = snapshot_file .read ()
410
+ except FileNotFoundError :
411
+ if bless :
412
+ expected_str = None
413
+ else :
414
+ raise FailedCheck ('No saved snapshot value' )
415
+
416
+ actual_str = ET .tostring (tree ).decode ('utf-8' )
417
+
418
+ if expected_str != actual_str :
419
+ if bless :
420
+ with open (snapshot_path , 'w' ) as snapshot_file :
421
+ snapshot_file .write (actual_str )
422
+ else :
423
+ print ('--- expected ---\n ' )
424
+ print (expected_str )
425
+ print ('\n \n --- actual ---\n ' )
426
+ print (actual_str )
427
+ print ()
428
+ raise FailedCheck ('Actual snapshot value is different than expected' )
429
+
390
430
def stderr (* args ):
391
431
if sys .version_info .major < 3 :
392
432
file = codecs .getwriter ('utf-8' )(sys .stderr )
@@ -448,6 +488,28 @@ def check_command(c, cache):
448
488
ret = expected == found
449
489
else :
450
490
raise InvalidCheck ('Invalid number of @{} arguments' .format (c .cmd ))
491
+
492
+ elif c .cmd == 'snapshot' : # snapshot test
493
+ if len (c .args ) == 3 : # @snapshot <snapshot-name> <html-path> <xpath>
494
+ [snapshot_name , html_path , pattern ] = c .args
495
+ tree = cache .get_tree (html_path )
496
+ xpath = normalize_xpath (pattern )
497
+ subtrees = tree .findall (xpath )
498
+ if len (subtrees ) == 1 :
499
+ [subtree ] = subtrees
500
+ try :
501
+ check_snapshot (snapshot_name , subtree )
502
+ ret = True
503
+ except FailedCheck as err :
504
+ cerr = str (err )
505
+ ret = False
506
+ elif len (subtrees ) == 0 :
507
+ raise FailedCheck ('XPATH did not match' )
508
+ else :
509
+ raise FailedCheck ('Expected 1 match, but found {}' .format (len (subtrees )))
510
+ else :
511
+ raise InvalidCheck ('Invalid number of @{} arguments' .format (c .cmd ))
512
+
451
513
elif c .cmd == 'has-dir' : # has-dir test
452
514
if len (c .args ) == 1 : # @has-dir <path> = has-dir test
453
515
try :
@@ -458,11 +520,13 @@ def check_command(c, cache):
458
520
ret = False
459
521
else :
460
522
raise InvalidCheck ('Invalid number of @{} arguments' .format (c .cmd ))
523
+
461
524
elif c .cmd == 'valid-html' :
462
525
raise InvalidCheck ('Unimplemented @valid-html' )
463
526
464
527
elif c .cmd == 'valid-links' :
465
528
raise InvalidCheck ('Unimplemented @valid-links' )
529
+
466
530
else :
467
531
raise InvalidCheck ('Unrecognized @{}' .format (c .cmd ))
468
532
@@ -483,11 +547,19 @@ def check(target, commands):
483
547
484
548
485
549
if __name__ == '__main__' :
486
- if len (sys .argv ) != 3 :
487
- stderr ('Usage: {} <doc dir> <template>' .format (sys .argv [0 ]))
550
+ if len (sys .argv ) not in [ 3 , 4 ] :
551
+ stderr ('Usage: {} <doc dir> <template> [--bless] ' .format (sys .argv [0 ]))
488
552
raise SystemExit (1 )
489
553
490
- check (sys .argv [1 ], get_commands (sys .argv [2 ]))
554
+ rust_test_path = sys .argv [2 ]
555
+ if len (sys .argv ) > 3 and sys .argv [3 ] == '--bless' :
556
+ bless = True
557
+ else :
558
+ # We only support `--bless` at the end of the arguments.
559
+ # This assert is to prevent silent failures.
560
+ assert '--bless' not in sys .argv
561
+ bless = False
562
+ check (sys .argv [1 ], get_commands (rust_test_path ))
491
563
if ERR_COUNT :
492
564
stderr ("\n Encountered {} errors" .format (ERR_COUNT ))
493
565
raise SystemExit (1 )
0 commit comments