changeset 29817:cc11079644fc

templater: make pad() evaluate boolean argument (BC) Otherwise it would crash if template expression was passed. This patch unifies the way how boolean expression is evaluated, which involves BC. Before "if(true)" and "pad(..., 'false')" were False, which are now True since they are boolean literal and non-empty string respectively. "func is runsymbol" is the same hack as evalstringliteral(), which is needed for label() to take color literals.
author Yuya Nishihara <yuya@tcha.org>
date Fri, 22 Apr 2016 21:29:13 +0900
parents 034412ca28c3
children 407879b0893b
files mercurial/templater.py tests/test-command-template.t
diffstat 2 files changed, 47 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/templater.py	Thu Aug 18 16:29:22 2016 +0900
+++ b/mercurial/templater.py	Fri Apr 22 21:29:13 2016 +0900
@@ -290,8 +290,15 @@
     return thing
 
 def evalboolean(context, mapping, arg):
+    """Evaluate given argument as boolean, but also takes boolean literals"""
     func, data = arg
-    thing = func(context, mapping, data)
+    if func is runsymbol:
+        thing = func(context, mapping, data, default=None)
+        if thing is None:
+            # not a template keyword, takes as a boolean literal
+            thing = util.parsebool(data)
+    else:
+        thing = func(context, mapping, data)
     if isinstance(thing, bool):
         return thing
     # other objects are evaluated as strings, which means 0 is True, but
@@ -516,7 +523,7 @@
     if len(args) > 2:
         fillchar = evalstring(context, mapping, args[2])
     if len(args) > 3:
-        right = util.parsebool(args[3][1])
+        right = evalboolean(context, mapping, args[3])
 
     if right:
         return text.rjust(width, fillchar)
--- a/tests/test-command-template.t	Thu Aug 18 16:29:22 2016 +0900
+++ b/tests/test-command-template.t	Fri Apr 22 21:29:13 2016 +0900
@@ -3323,6 +3323,27 @@
   hg: parse error: pad() expects an integer width
   [255]
 
+Test boolean argument passed to pad function
+
+ no crash
+
+  $ hg log -r 0 -T '{pad(rev, 10, "-", "f{"oo"}")}\n'
+  ---------0
+
+ string/literal
+
+  $ hg log -r 0 -T '{pad(rev, 10, "-", "false")}\n'
+  ---------0
+  $ hg log -r 0 -T '{pad(rev, 10, "-", false)}\n'
+  0---------
+  $ hg log -r 0 -T '{pad(rev, 10, "-", "")}\n'
+  0---------
+
+ unknown keyword is evaluated to ''
+
+  $ hg log -r 0 -T '{pad(rev, 10, "-", unknownkeyword)}\n'
+  0---------
+
 Test separate function
 
   $ hg log -r 0 -T '{separate("-", "", "a", "b", "", "", "c", "")}\n'
@@ -3332,6 +3353,23 @@
   $ hg log -r 0 --color=always -T '{separate(" ", "a", label(red, "b"), "c", label(red, ""), "d")}\n'
   a \x1b[0;31mb\x1b[0m c d (esc)
 
+Test boolean expression/literal passed to if function
+
+  $ hg log -r 0 -T '{if(rev, "rev 0 is True")}\n'
+  rev 0 is True
+  $ hg log -r 0 -T '{if(0, "literal 0 is True as well")}\n'
+  literal 0 is True as well
+  $ hg log -r 0 -T '{if("", "", "empty string is False")}\n'
+  empty string is False
+  $ hg log -r 0 -T '{if(revset(r"0 - 0"), "", "empty list is False")}\n'
+  empty list is False
+  $ hg log -r 0 -T '{if(true, "true is True")}\n'
+  true is True
+  $ hg log -r 0 -T '{if(false, "", "false is False")}\n'
+  false is False
+  $ hg log -r 0 -T '{if("false", "non-empty string is True")}\n'
+  non-empty string is True
+
 Test ifcontains function
 
   $ hg log --template '{rev} {ifcontains(rev, "2 two 0", "is in the string", "is not")}\n'