commit 6f0e697e4155ca567ddfd46a7f4e7c013287c42a Author: Nick Mathewson nickm@torproject.org Date: Thu Sep 26 10:03:28 2019 -0400
Use Doctests to test the behavior of annotate_ifdef_directives. --- scripts/maint/annotate_ifdef_directives | 115 ++++++++++++++++++++++++++------ 1 file changed, 94 insertions(+), 21 deletions(-)
diff --git a/scripts/maint/annotate_ifdef_directives b/scripts/maint/annotate_ifdef_directives index f88dd4fdf..514b5e58b 100755 --- a/scripts/maint/annotate_ifdef_directives +++ b/scripts/maint/annotate_ifdef_directives @@ -2,24 +2,60 @@ # Copyright (c) 2017-2019, The Tor Project, Inc. # See LICENSE for licensing information
-# This script iterates over a list of C files. For each file, it looks at the -# #if/#else C macros, and annotates them with comments explaining what they -# match. -# -# For example, it replaces this: -# -# #ifdef HAVE_OCELOT -# // 500 lines of ocelot code -# #endif -# -# with this: -# -# #ifdef HAVE_OCELOT -# // 500 lines of ocelot code -# #endif /* defined(HAVE_OCELOT) */ -# -# Note that only #else and #endif lines are annotated. Existing comments -# on those lines are removed. +r""" +This script iterates over a list of C files. For each file, it looks at the +#if/#else C macros, and annotates them with comments explaining what they +match. + +For example, it replaces this kind of input... + +>>> INPUT = ''' +... #ifdef HAVE_OCELOT +... C code here +... #if MIMSY == BOROGROVE +... block 1 +... block 1 +... block 1 +... block 1 +... #else +... block 2 +... block 2 +... block 2 +... block 2 +... #endif +... #endif +... ''' + +With this kind of output: +>>> EXPECTED_OUTPUT = ''' +... #ifdef HAVE_OCELOT +... C code here +... #if MIMSY == BOROGROVE +... block 1 +... block 1 +... block 1 +... block 1 +... #else /* !(MIMSY == BOROGROVE) */ +... block 2 +... block 2 +... block 2 +... block 2 +... #endif /* MIMSY == BOROGROVE */ +... #endif /* defined(HAVE_OCELOT) */ +... ''' + +Here's how to use it: +>>> import sys +>>> if sys.version_info.major < 3: from cStringIO import StringIO +>>> if sys.version_info.major >= 3: from io import StringIO + +>>> OUTPUT = StringIO() +>>> translate(StringIO(INPUT), OUTPUT) +>>> assert OUTPUT.getvalue() == EXPECTED_OUTPUT + +Note that only #else and #endif lines are annotated. Existing comments +on those lines are removed. +"""
import re
@@ -38,6 +74,17 @@ class Problem(Exception): def close_parens_needed(expr): """Return the number of left-parentheses needed to make 'expr' balanced. + + >>> close_parens_needed("1+2") + 0 + >>> close_parens_needed("(1 + 2)") + 0 + >>> close_parens_needed("(1 + 2") + 1 + >>> close_parens_needed("(1 + (2 *") + 2 + >>> close_parens_needed("(1 + (2 * 3) + (4") + 2 """ return expr.count("(") - expr.count(")")
@@ -47,6 +94,17 @@ def truncate_expression(expr, new_width): characters long.
Try to return an expression with balanced parentheses. + + >>> truncate_expression("1+2+3", 8) + '1+2+3' + >>> truncate_expression("1+2+3+4+5", 8) + '1+2+3...' + >>> truncate_expression("(1+2+3+4)", 8) + '(1+2...)' + >>> truncate_expression("(1+(2+3+4))", 8) + '(1+...)' + >>> truncate_expression("(((((((((", 8) + '((...))' """ if len(expr) <= new_width: # The expression is already short enough. @@ -69,14 +127,23 @@ def truncate_expression(expr, new_width): return ellipsis
def commented_line(fmt, argument, maxwidth=LINE_WIDTH): - - """ + # (This is a raw docstring so that our doctests can use .) + r""" Return fmt%argument, for use as a commented line. If the line would - be longer than maxwidth, truncate argument. + be longer than maxwidth, truncate argument but try to keep its + parentheses balanced.
Requires that fmt%"..." will fit into maxwidth characters.
Requires that fmt ends with a newline. + + >>> commented_line("/* %s */\n", "hello world", 32) + '/* hello world */\n' + >>> commented_line("/* %s */\n", "hello world", 15) + '/* hello... */\n' + >>> commented_line("#endif /* %s */\n", "((1+2) && defined(FOO))", 32) + '#endif /* ((1+2) && defi...) */\n' + """ assert fmt.endswith("\n") result = fmt % argument @@ -208,6 +275,12 @@ def translate(f_in, f_out): raise Problem("Missing #endif")
import sys,os + +if sys.argv[1] == "--self-test": + import doctest + doctest.testmod() + sys.exit(0) + for fn in sys.argv[1:]: with open(fn+"_OUT", 'w') as output_file: translate(open(fn, 'r'), output_file)