Browse Source

org-table.el: Fix range len bugs for empty ranges

(org-table-make-reference): A range with only empty fields should lead
to length 0.
* testing/lisp/test-org-table.el: Adapt expected for several
ert-deftest.

The range len bugs may lead to wrong calculations for range references
with empty fields when the range len is relevant.  Affects typically
Calc vmean on simple range and without format specifier EN.  Also
Lisp with e. g. `length' on simple range or with L.

It is worth a small compatibility change: For a range with only empty
fields it is now possible and necessary to choose different behaviors
of vmean by adding the format specifiers E and/or N.

This is a follow-up of commit
764315b3fce26de59189b957a8049e299209043a.
Michael Brand 4 years ago
parent
commit
5625a6ed79
2 changed files with 42 additions and 25 deletions
  1. 5 2
      lisp/org-table.el
  2. 37 23
      testing/lisp/test-org-table.el

+ 5 - 2
lisp/org-table.el

@@ -2929,7 +2929,10 @@ list, 'literal is for the format specifier L."
       (if lispp
 	  (if (eq lispp 'literal)
 	      elements
-	    (prin1-to-string (if numbers (string-to-number elements) elements)))
+	    (if (and (eq elements "") (not keep-empty))
+		""
+	      (prin1-to-string
+	       (if numbers (string-to-number elements) elements))))
 	(if (string-match "\\S-" elements)
 	    (progn
 	      (when numbers (setq elements (number-to-string
@@ -2942,7 +2945,7 @@ list, 'literal is for the format specifier L."
 	    (delq nil
 		  (mapcar (lambda (x) (if (string-match "\\S-" x) x nil))
 			  elements))))
-    (setq elements (or elements '("")))
+    (setq elements (or elements '()))  ; if delq returns nil then we need '()
     (if lispp
 	(mapconcat
 	 (lambda (x)

+ 37 - 23
testing/lisp/test-org-table.el

@@ -339,7 +339,7 @@ reference (with row).  No format specifier."
 | 0 | 1 | 0 | #ERROR | #ERROR | #ERROR | 2 | 2 |
 | z | 1 | z | #ERROR | #ERROR | #ERROR | 2 | 2 |
 |   | 1 |   | #ERROR | #ERROR | #ERROR | 1 | 1 |
-|   |   |   | #ERROR | #ERROR | #ERROR | 1 | 1 |
+|   |   |   | #ERROR | 0      | 0      | 0 | 0 |
 "
      1 lisp)
     (org-test-table-target-expect
@@ -348,7 +348,7 @@ reference (with row).  No format specifier."
 | 0 | 1 | 0 |     1 |     1 |     1 | 2 | 2 |
 | z | 1 | z | z + 1 | z + 1 | z + 1 | 2 | 2 |
 |   | 1 | 0 |     1 |     1 |     1 | 1 | 1 |
-|   |   | 0 |     0 |     0 |     0 | 1 | 1 |
+|   |   | 0 |     0 |     0 |     0 | 0 | 0 |
 "
      1 calc)
     (org-test-table-target-expect
@@ -381,7 +381,7 @@ reference (with row).  Format specifier N."
 | 0 | 1 | 0 | 1 | 1 | 1 | 2 | 2 |
 | z | 1 | 0 | 1 | 1 | 1 | 2 | 2 |
 |   | 1 | 0 | 1 | 1 | 1 | 1 | 1 |
-|   |   | 0 | 0 | 0 | 0 | 1 | 1 |
+|   |   | 0 | 0 | 0 | 0 | 0 | 0 |
 "
      1 lisp calc)
     (org-test-table-target-expect
@@ -455,20 +455,34 @@ reference (with row).  Format specifier N."
   ;; Empty fields in simple and complex range reference: Suppress them
   ;; ($5 and $6) or keep them and use 0 ($7 and $8)
 
-  (org-test-table-target-expect
-   "\n|   |   | 5 | 7 | replace | replace | replace | replace |\n"
-   "\n|   |   | 5 | 7 | 6 | 6 | 3 | 3 |\n"
-   1
-   ;; Calc formula
-   (concat "#+TBLFM: "
-	   "$5 = vmean($1..$4)     :: $6 = vmean(@0$1..@0$4) :: "
-	   "$7 = vmean($1..$4); EN :: $8 = vmean(@0$1..@0$4); EN")
-   ;; Lisp formula
-   (concat "#+TBLFM: "
-	   "$5 = '(/ (+   $1..$4  ) (length '(  $1..$4  )));  N :: "
-	   "$6 = '(/ (+ @0$1..@0$4) (length '(@0$1..@0$4)));  N :: "
-	   "$7 = '(/ (+   $1..$4  ) (length '(  $1..$4  ))); EN :: "
-	   "$8 = '(/ (+ @0$1..@0$4) (length '(@0$1..@0$4))); EN"))
+  (let ((calc (concat
+	       "#+TBLFM: "
+	       "$5 = vmean($1..$4)     :: "
+	       "$6 = vmean(@0$1..@0$4) :: "
+	       "$7 = vmean($1..$4); EN :: "
+	       "$8 = vmean(@0$1..@0$4); EN"))
+	(lisp (concat
+	       "#+TBLFM: "
+	       "$5 = '(/ (+   $1..$4  ) (length '(  $1..$4  )));  N :: "
+	       "$6 = '(/ (+ @0$1..@0$4) (length '(@0$1..@0$4)));  N :: "
+	       "$7 = '(/ (+   $1..$4  ) (length '(  $1..$4  ))); EN :: "
+	       "$8 = '(/ (+ @0$1..@0$4) (length '(@0$1..@0$4))); EN")))
+    (org-test-table-target-expect
+     "\n|   |   | 5 | 7 | replace | replace | replace | replace |\n"
+     "\n|   |   | 5 | 7 | 6 | 6 | 3 | 3 |\n"
+     1 calc lisp)
+
+    ;; The mean value of a range with only empty fields is not defined
+    (let ((target
+	   "\n|   |   |   |   | replace | replace | replace | replace |\n"))
+      (org-test-table-target-expect
+       target
+       "\n|   |   |   |   | vmean([]) | vmean([]) | 0 | 0 |\n"
+       1 calc)
+      (org-test-table-target-expect
+       target
+       "\n|   |   |   |   | #ERROR | #ERROR | 0 | 0 |\n"
+       1 lisp)))
 
   ;; Test if one field is empty, else do a calculation
   (org-test-table-target-expect
@@ -667,11 +681,11 @@ reference (with row).  Format specifier N."
   ;; For Lisp formula
   (should (equal "\"0\""       (f   "0"         nil nil t)))
   (should (equal "\"z\""       (f   "z"         nil nil t)))
-  (should (equal  "\"\""       (f   ""          nil nil t)))
+  (should (equal   ""          (f   ""          nil nil t)))
   (should (equal "\"0\" \"1\"" (f '("0"    "1") nil nil t)))
   (should (equal "\"z\" \"1\"" (f '("z"    "1") nil nil t)))
   (should (equal       "\"1\"" (f '(""     "1") nil nil t)))
-  (should (equal    "\"\""     (f '(""     "" ) nil nil t)))
+  (should (equal      ""       (f '(""     "" ) nil nil t)))
   ;; For Calc formula
   (should (equal  "(0)"        (f   "0"         nil nil nil)))
   (should (equal  "(z)"        (f   "z"         nil nil nil)))
@@ -679,7 +693,7 @@ reference (with row).  Format specifier N."
   (should (equal  "[0,1]"      (f '("0"    "1") nil nil nil)))
   (should (equal  "[z,1]"      (f '("z"    "1") nil nil nil)))
   (should (equal    "[1]"      (f '(""     "1") nil nil nil)))
-  (should (equal   "[0]"       (f '(""     "" ) nil nil nil)))
+  (should (equal   "[]"        (f '(""     "" ) nil nil nil)))
   ;; For Calc formula, special numbers
   (should (equal  "(nan)"      (f    "nan"      nil nil nil)))
   (should (equal "(uinf)"      (f   "uinf"      nil nil nil)))
@@ -695,11 +709,11 @@ reference (with row).  Format specifier N."
   ;; For Lisp formula
   (should (equal  "0"    (f   "0"         nil t t)))
   (should (equal  "0"    (f   "z"         nil t t)))
-  (should (equal  "0"    (f   ""          nil t t)))
+  (should (equal  ""     (f   ""          nil t t)))
   (should (equal  "0 1"  (f '("0"    "1") nil t t)))
   (should (equal  "0 1"  (f '("z"    "1") nil t t)))
   (should (equal    "1"  (f '(""     "1") nil t t)))
-  (should (equal   "0"   (f '(""     "" ) nil t t)))
+  (should (equal   ""    (f '(""     "" ) nil t t)))
   ;; For Calc formula
   (should (equal "(0)"   (f   "0"         nil t nil)))
   (should (equal "(0)"   (f   "z"         nil t nil)))
@@ -707,7 +721,7 @@ reference (with row).  Format specifier N."
   (should (equal "[0,1]" (f '("0"    "1") nil t nil)))
   (should (equal "[0,1]" (f '("z"    "1") nil t nil)))
   (should (equal   "[1]" (f '(""     "1") nil t nil)))
-  (should (equal  "[0]"  (f '(""     "" ) nil t nil)))
+  (should (equal  "[]"   (f '(""     "" ) nil t nil)))
   ;; For Calc formula, special numbers
   (should (equal "(0)"   (f    "nan"      nil t nil)))
   (should (equal "(0)"   (f   "uinf"      nil t nil)))