templater: make pad() evaluate boolean argument (BC)
authorYuya Nishihara <yuya@tcha.org>
Fri, 22 Apr 2016 21:29:13 +0900
changeset 29817 cc11079644fc
parent 29816 034412ca28c3
child 29818 407879b0893b
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.
mercurial/templater.py
tests/test-command-template.t
--- 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'