Repository: jsonata-js/jsonata (js)

Issue:
Boolean operators return inconsistent results with undefined inputs
This issue was first raised in a [Slack post](https://jsonata.slack.com/messages/C2L3MR5EH/p1531168044000184). I'm reposting here (with some additional info) so it doesn't get lost.

The original poster was using the `or` operator with one falsy value and one undefined value (a non-existent path expression). They noticed that the `or` operator sometimes returned `false` and sometimes returned `undefined` depending on the order of the operands.

I tried various combinations of the `or` and `and` operators with one or more undefined values (named `foo` and `bar`) and got the following results.

#### Or

```
true or foo    // true
foo or true    // true

false or foo   // undefined
foo or false   // false

foo or bar     // undefined
```

#### And

```
true and foo    // undefined
foo and true    // undefined

false and foo   // false
foo and false   // undefined

foo and bar     // undefined
```

Note that:

1. Combining a falsy value with an undefined value does indeed give different results depending on the order of the operands.

2. There's a mix of boolean and undefined results, e.g. `true or foo` returns `true` but `true and foo` returns `undefined`.

These are the only binary operations that produce such inconsistent results. Numeric operators (like `+` and `-`) return `undefined` if either operand is undefined. Comparison operators (like `=` and  `<`) return `false` if either operand is undefined. And the concatenation operator (`&`) treats undefined operands as empty strings.

Boolean operators should have a similarly well-defined approach to undefined inputs. I suggest one of the following:

1. Treat undefined operands as `false` (this would turn all of the `undefined` results above to `false`).

2. Return `undefined` if either operand is undefined (all of the above expressions would then evaluate to `undefined`).

Any thoughts on this, @andrew-coleman?


Pull request description:
operands of and/or operators should be treated as false if undefined
operands of Boolean operators (and/or) should be treated as false if undefined

resolves #246 

Patch:
diff --git a/src/jsonata.js b/src/jsonata.js
index 6eaffb5..77f8a60 100644
--- a/src/jsonata.js
+++ b/src/jsonata.js
@@ -2201,12 +2201,23 @@ var jsonata = (function() {
     function evaluateBooleanExpression(lhs, rhs, op) {
         var result;
 
+        var lBool = functionBoolean(lhs);
+        var rBool = functionBoolean(rhs);
+
+        if (typeof  lBool === 'undefined') {
+            lBool = false;
+        }
+
+        if (typeof  rBool === 'undefined') {
+            rBool = false;
+        }
+
         switch (op) {
             case 'and':
-                result = functionBoolean(lhs) && functionBoolean(rhs);
+                result = lBool && rBool;
                 break;
             case 'or':
-                result = functionBoolean(lhs) || functionBoolean(rhs);
+                result = lBool || rBool;
                 break;
         }
         return result;


Test patch:
diff --git a/test/test-suite/groups/boolean-expresssions/case017.json b/test/test-suite/groups/boolean-expresssions/case017.json
new file mode 100644
index 0000000..b67be28
--- /dev/null
+++ b/test/test-suite/groups/boolean-expresssions/case017.json
@@ -0,0 +1,5 @@
+{
+    "expr": "true or foo",
+    "data": "null",
+    "result": true
+}
diff --git a/test/test-suite/groups/boolean-expresssions/case018.json b/test/test-suite/groups/boolean-expresssions/case018.json
new file mode 100644
index 0000000..f580911
--- /dev/null
+++ b/test/test-suite/groups/boolean-expresssions/case018.json
@@ -0,0 +1,5 @@
+{
+    "expr": "foo or true",
+    "data": "null",
+    "result": true
+}
diff --git a/test/test-suite/groups/boolean-expresssions/case019.json b/test/test-suite/groups/boolean-expresssions/case019.json
new file mode 100644
index 0000000..8e17bce
--- /dev/null
+++ b/test/test-suite/groups/boolean-expresssions/case019.json
@@ -0,0 +1,5 @@
+{
+    "expr": "false or foo",
+    "data": "null",
+    "result": false
+}
diff --git a/test/test-suite/groups/boolean-expresssions/case020.json b/test/test-suite/groups/boolean-expresssions/case020.json
new file mode 100644
index 0000000..57ae2d1
--- /dev/null
+++ b/test/test-suite/groups/boolean-expresssions/case020.json
@@ -0,0 +1,5 @@
+{
+    "expr": "foo or false",
+    "data": "null",
+    "result": false
+}
diff --git a/test/test-suite/groups/boolean-expresssions/case021.json b/test/test-suite/groups/boolean-expresssions/case021.json
new file mode 100644
index 0000000..85e3ec8
--- /dev/null
+++ b/test/test-suite/groups/boolean-expresssions/case021.json
@@ -0,0 +1,5 @@
+{
+    "expr": "foo or bar",
+    "data": "null",
+    "result": false
+}
diff --git a/test/test-suite/groups/boolean-expresssions/case022.json b/test/test-suite/groups/boolean-expresssions/case022.json
new file mode 100644
index 0000000..3657c3b
--- /dev/null
+++ b/test/test-suite/groups/boolean-expresssions/case022.json
@@ -0,0 +1,5 @@
+{
+    "expr": "true and foo",
+    "data": "null",
+    "result": false
+}
diff --git a/test/test-suite/groups/boolean-expresssions/case023.json b/test/test-suite/groups/boolean-expresssions/case023.json
new file mode 100644
index 0000000..2cea93f
--- /dev/null
+++ b/test/test-suite/groups/boolean-expresssions/case023.json
@@ -0,0 +1,5 @@
+{
+    "expr": "foo and true",
+    "data": "null",
+    "result": false
+}
diff --git a/test/test-suite/groups/boolean-expresssions/case024.json b/test/test-suite/groups/boolean-expresssions/case024.json
new file mode 100644
index 0000000..3ff77d2
--- /dev/null
+++ b/test/test-suite/groups/boolean-expresssions/case024.json
@@ -0,0 +1,5 @@
+{
+    "expr": "false and foo",
+    "data": "null",
+    "result": false
+}
diff --git a/test/test-suite/groups/boolean-expresssions/case025.json b/test/test-suite/groups/boolean-expresssions/case025.json
new file mode 100644
index 0000000..7f745d3
--- /dev/null
+++ b/test/test-suite/groups/boolean-expresssions/case025.json
@@ -0,0 +1,5 @@
+{
+    "expr": "foo and false",
+    "data": "null",
+    "result": false
+}
diff --git a/test/test-suite/groups/boolean-expresssions/case026.json b/test/test-suite/groups/boolean-expresssions/case026.json
new file mode 100644
index 0000000..f5b7cd0
--- /dev/null
+++ b/test/test-suite/groups/boolean-expresssions/case026.json
@@ -0,0 +1,5 @@
+{
+    "expr": "foo and bar",
+    "data": "null",
+    "result": false
+}