"use strict";

var _interpreter = _interopRequireDefault(require("../interpreter"));

var _compiler = _interopRequireDefault(require("../compiler"));

var _parser = _interopRequireDefault(require("../parsers/parser"));

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

var tests = [{
  sourceCode: "null",
  output: null
}, {
  sourceCode: "true",
  output: true
}, {
  sourceCode: "$",
  input: true,
  output: true
}, {
  sourceCode: "$",
  input: 98,
  output: 98
}, {
  sourceCode: ".bar",
  input: {
    bar: 4,
    baz: 'hello'
  },
  output: 4
}, {
  sourceCode: ".$shit",
  input: {
    $shit: null,
    baz: 'hello'
  },
  output: null
}, {
  sourceCode: "[0.14, true, \"true 2\"]",
  output: [0.14, true, 'true 2']
}, {
  sourceCode: "[[false], [true, null]]",
  output: [[false], [true, null]]
}, {
  sourceCode: "false | true",
  output: true
}, {
  sourceCode: ".foo | .bar",
  input: {
    foo: {
      bar: 'hello'
    }
  },
  output: 'hello'
}, {
  sourceCode: ".foo | .bar | .baz",
  input: {
    foo: {
      bar: {
        baz: 'world'
      }
    }
  },
  output: 'world'
}, {
  sourceCode: ".apple.pear",
  input: {
    apple: {
      pear: 42
    }
  },
  output: 42
}, {
  sourceCode: ".apple.pear.bar",
  input: {
    apple: {
      pear: {
        bar: false
      }
    }
  },
  output: false
}, {
  sourceCode: "null: true",
  output: [null, true]
}, {
  sourceCode: "{\n      \"foo\": [-42, $],\n      \"bar\": {\n        \"message\": \"Hello World\"\n      }\n    }",
  input: 42,
  output: {
    foo: [-42, 42],
    bar: {
      message: 'Hello World'
    }
  }
}, {
  sourceCode: "{\"foo\": (\"bar\" | \"baz\")}",
  output: {
    foo: 'baz'
  }
}, {
  sourceCode: "{\"foo\": (\"bar\" | \"baz\")}[\"foo\"]",
  output: 'baz'
}, {
  sourceCode: "[3, 2][0]",
  output: 3
}, {
  sourceCode: "[3, 2][0] : [3, 2][1]",
  output: [3, 2]
}, {
  sourceCode: "[3, 2][0] | [3, 2][1]",
  output: 2
}, {
  sourceCode: "join \" \"",
  input: ['Hello', 'World'],
  output: 'Hello World'
}, {
  sourceCode: "map \\\" \"",
  input: ['Hello', 'World'],
  output: [' ', ' ']
}, {
  sourceCode: "{\"original\": $.foo} | {\"new\": $}",
  input: {
    foo: 42
  },
  output: {
    new: {
      original: 42
    }
  }
}, {
  sourceCode: "map $ => {\"original\": $.foo} | map $=> {\"new\": $}",
  input: [{
    foo: 42
  }, {
    foo: 'hello'
  }],
  output: [{
    new: {
      original: 42
    }
  }, {
    new: {
      original: 'hello'
    }
  }]
}, {
  sourceCode: "map $ => {\"original\": $.foo} | \"foo\"",
  input: [{
    foo: 42
  }, {
    foo: 'hello'
  }],
  output: 'foo'
}, {
  sourceCode: "[0,1,2][1,2][1,1][0]",
  output: 2
}, {
  sourceCode: "[0,1,\"foo\"][1,2][1,1][0]",
  output: 'foo'
}, {
  sourceCode: "{\"foo\": [{\"bar\": \"baz\"}]} | $.foo[0].bar",
  output: 'baz'
}, {
  sourceCode: "sortBy \\.age | map \\.name",
  output: ['John', 'Mary'],
  input: [{
    name: 'John',
    age: 11
  }, {
    name: 'Mary',
    age: 33
  }]
}, {
  sourceCode: "8 * 3.14 / 2",
  output: 8 * 3.14 / 2
}, {
  sourceCode: "8 + 3.14 * 2",
  output: 8 + 3.14 * 2
}, {
  sourceCode: "(8 + 3.14) * 2",
  output: (8 + 3.14) * 2
}, {
  sourceCode: "8 - (3.14 * 2)",
  output: 8 - 3.14 * 2
}, {
  sourceCode: "8314 % 34 -3",
  output: 8314 % 34 - 3
}, {
  sourceCode: "3 * 2 -1 <= -1.34 * 3",
  output: 3 * 2 - 1 <= -1.34 * 3
}, {
  sourceCode: "3 * 2 -1 < -1.34 * 3",
  output: 3 * 2 - 1 < -1.34 * 3
}, {
  sourceCode: "3 * 2 -1 >= -1.34 * 3",
  output: 3 * 2 - 1 >= -1.34 * 3
}, {
  sourceCode: "3 * 2 -1 > -1.34 * 3",
  output: 3 * 2 - 1 > -1.34 * 3
}, {
  sourceCode: "3 * 2 -1 == -1.34 * 3",
  output: 3 * 2 - 1 === -1.34 * 3
}, {
  sourceCode: "3 * 2 -1 != -1.34 * 3",
  output: 3 * 2 - 1 !== -1.34 * 3
}, {
  sourceCode: "\"1\" == 1",
  output: '1' === 1
}, {
  sourceCode: "3 * 2 -1 > -1.34 * 3 || true",
  output: 3 * 2 - 1 > -1.34 * 3 || true
}, {
  sourceCode: "3 * 2 -1 > -1.34 * 3 || false",
  output: 3 * 2 - 1 > -1.34 * 3 || false
}, {
  sourceCode: "3 * 2 -1 > -1.34 * 3 && false",
  output: 3 * 2 - 1 > -1.34 * 3 && false
}, {
  sourceCode: "3 * 2 -1 > -1.34 * 3 && true",
  output: 3 * 2 - 1 > -1.34 * 3 && true
}, {
  sourceCode: "-(3 * 2) -1 > -1.34 * 3 && true",
  output: -(3 * 2) - 1 > -1.34 * 3 && true
}, {
  sourceCode: "+(3 * 2) -1 > -1.34 * 3 && true",
  output: +(3 * 2) - 1 > -1.34 * 3 && true
}, {
  sourceCode: "!(3 * 2 -1 > -1.34 * 3) && true",
  output: !(3 * 2 - 1 > -1.34 * 3) && true
}, {
  sourceCode: "!(3 * .foo -1 > -1.34 * .bar) && true",
  input: {
    foo: 2,
    bar: 3
  },
  output: !(3 * 2 - 1 > -1.34 * 3) && true
}, {
  sourceCode: "filter $ => .age >= 18 | map $ => .name",
  input: [{
    name: 'John',
    age: 17
  }, {
    name: 'Mary',
    age: 18
  }, {
    name: 'Gabe',
    age: 19
  }, {
    name: 'Franz',
    age: 8
  }],
  output: ['Mary', 'Gabe']
}, {
  sourceCode: "3 * 2 -1 > -1.34 * 3 or true",
  output: 3 * 2 - 1 > -1.34 * 3 || true
}, {
  sourceCode: "!(3 * 2 -1 > -1.34 * 3) and true",
  output: !(3 * 2 - 1 > -1.34 * 3) && true
}, {
  sourceCode: "3 + $foobar where $foobar = 4",
  output: 7
}, {
  sourceCode: "(3 + $foobar | [$, $foobar]) where $foobar = $",
  input: 4,
  output: [7, 4]
}, {
  sourceCode: "($x + $foobar | [$, $foobar]) where $x = 3 $foobar = ($x + 1)",
  input: 4,
  output: [7, 4]
}, {
  sourceCode: "([1] | map $foo | $[0]) where $foo = ($ => 4)",
  output: 4
}, {
  sourceCode: "([1] | foo 4) where $foo = ($ => $ => 4)",
  output: 4
}, {
  sourceCode: "([1, 2] | foo) where $foo = $reverse",
  output: [2, 1]
}, {
  sourceCode: "map $foo => [$foo]",
  input: [1, 2],
  output: [[1], [2]]
}, {
  sourceCode: "reduce ($a => $b => $a + $b): 0",
  input: [1, 2, -1, 3],
  output: 5
}, {
  sourceCode: "[1, ...$, 3, ...$]",
  input: [1, 2],
  output: [1, 1, 2, 3, 1, 2]
}, {
  sourceCode: "{\"foo\": 3} | {\"bar\": \"baz\", ...$}",
  output: {
    foo: 3,
    bar: 'baz'
  }
}, {
  sourceCode: "$.uno?.dos?.tres",
  input: {
    uno: {}
  },
  output: null
}, {
  sourceCode: "$?[3]",
  input: undefined,
  output: null
}, {
  sourceCode: "$?[3]",
  input: [1, 2, 3],
  output: null
}, {
  sourceCode: "3 + 4 if 2 <= 3 else -12",
  output: 7
}, {
  sourceCode: "3 : 4 if null else [-12] | [$[0]]",
  output: [-12]
}, {
  sourceCode: "[each .author.name in .articles sortBy $ => .author.age]",
  input: {
    articles: [{
      author: {
        age: 3,
        name: 'Jonas'
      }
    }, {
      author: {
        age: 34,
        name: 'Johnny'
      }
    }, {
      author: {
        age: 33,
        name: 'Mary'
      }
    }]
  },
  output: ['Jonas', 'Mary', 'Johnny']
}, {
  sourceCode: "[each .author.age in .articles reverse]",
  input: {
    articles: [{
      author: {
        age: 3,
        name: 'Jonas'
      }
    }, {
      author: {
        age: 34,
        name: 'John'
      }
    }, {
      author: {
        age: 33,
        name: 'Mary'
      }
    }]
  },
  output: [33, 34, 3]
}, {
  sourceCode: "[each .author.age in .articles]",
  input: {
    articles: [{
      author: {
        age: 3,
        name: 'Jonas'
      }
    }, {
      author: {
        age: 34,
        name: 'Johnny'
      }
    }, {
      author: {
        age: 33,
        name: 'Maria'
      }
    }]
  },
  output: [3, 34, 33]
}, {
  sourceCode: "[each .author.name in .articles if .author.age >= 30 sortBy $ => .author.age]",
  input: {
    articles: [{
      author: {
        age: 3,
        name: 'Jones'
      }
    }, {
      author: {
        age: 34,
        name: 'John'
      }
    }, {
      author: {
        age: 33,
        name: 'Mary'
      }
    }]
  },
  output: ['Mary', 'John']
}, {
  sourceCode: "{each $: (length) in $}",
  input: ['bo', 'boo'],
  output: {
    bo: 2,
    boo: 3
  }
}, {
  sourceCode: "$[1:3]",
  input: [1, 2, 3, 4],
  output: [2, 3]
}, {
  sourceCode: "[0, ...\"Hello\"]",
  output: [0, 'H', 'e', 'l', 'l', 'o']
}, {
  sourceCode: "[...$foo] where $foo = \"Hello\"",
  output: ['H', 'e', 'l', 'l', 'o']
}, {
  sourceCode: "error \"Hello\" if false else \"asdfgb\"",
  output: 'asdfgb'
}, {
  sourceCode: "[($ => error \"asd\" | \"f\")]",
  output: ['f']
}, {
  sourceCode: "((3))",
  output: 3
}, {
  sourceCode: "( ((3)))",
  output: 3
}, {
  sourceCode: "[[]]",
  output: [[]]
}, {
  sourceCode: "[[[]]]",
  output: [[[]]]
}, {
  sourceCode: "[ [  [ [  [ ] ]]]  ]",
  output: [[[[[]]]]]
}, {
  sourceCode: "{\"a\": [2], \"b\": \"b\"} {\n        b\n    }",
  output: {
    b: 'b'
  }
}, {
  sourceCode: "$ {\n            user {\n                name {\n                    firstName\n                }\n                city\n                email\n            }\n\n            post {\n                content{ long }\n            }\n        }",
  input: {
    user: {
      name: {
        firstName: 'John',
        lastName: 'Doe'
      },
      city: 'London',
      gender: 'male'
    },
    post: {
      title: 'foo bar',
      content: {
        short: 'baz',
        long: 'bazzzz'
      }
    }
  },
  output: {
    user: {
      name: {
        firstName: 'John'
      },
      city: 'London',
      email: null
    },
    post: {
      content: {
        long: 'bazzzz'
      }
    }
  }
}, {
  sourceCode: "$ {\n            Person: user {\n                name {\n                    first_name: firstName\n                }\n                city\n                email\n            }\n\n            Post: post {\n                content{ long }\n            }\n        }",
  input: {
    user: {
      name: {
        firstName: 'John',
        lastName: 'Doe'
      },
      city: 'London',
      gender: 'male'
    },
    post: {
      title: 'foo bar',
      content: {
        short: 'baz',
        long: 'bazzzz'
      }
    }
  },
  output: {
    Person: {
      name: {
        first_name: 'John'
      },
      city: 'London',
      email: null
    },
    Post: {
      content: {
        long: 'bazzzz'
      }
    }
  }
}, {
  sourceCode: "$ {...x} where $x = ($ => {\"y\": 0})",
  input: null,
  output: {
    y: 0
  }
}, {
  sourceCode: "\n            $ {\n                ...Stuff\n                hello\n            }\n\n            where\n                $Stuff = (\n                    $ => $ {\n                      foo\n                      bar\n                    }\n                )\n        ",
  input: {
    foo: 4,
    bar: 'baz',
    baz: 'thing',
    hello: 'world',
    more: {
      foo: 5
    }
  },
  output: {
    foo: 4,
    bar: 'baz',
    hello: 'world'
  }
}, {
  sourceCode: "\n            $ {\n                ...Stuff\n                hello\n                more {\n                  ...Stuff\n                }\n            }\n\n            where\n                $Stuff = (\n                    $ => $ {\n                      foo\n                      bar\n                    }\n                )\n        ",
  input: {
    foo: 4,
    bar: 'baz',
    baz: 'thing',
    hello: 'world',
    more: {
      foo: 5
    }
  },
  output: {
    foo: 4,
    bar: 'baz',
    hello: 'world',
    more: {
      foo: 5,
      bar: null
    }
  }
}];
describe('interpreter', function () {
  it('handles errors correctly', function () {
    expect(function () {
      return (0, _interpreter.default)("error \"x\"")();
    }).toThrow('x');
  });
  tests.forEach(function (_ref) {
    var sourceCode = _ref.sourceCode,
        output = _ref.output,
        input = _ref.input;
    it("executes ".concat(sourceCode), function () {
      expect((0, _interpreter.default)(sourceCode)(input)).toEqual(output);
    });
    it("correct target code ".concat(sourceCode), function () {
      expect((0, _compiler.default)(sourceCode)).toMatchSnapshot();
    });
    it("correct target tree ".concat(sourceCode), function () {
      expect((0, _parser.default)(sourceCode)).toMatchSnapshot();
    });
  });
  it("allow passing single variable", function () {
    expect((0, _interpreter.default)('$foo')(null, {
      foo: 3
    })).toEqual(3);
  });
  it("allow passing multiple variables", function () {
    expect((0, _interpreter.default)('$foo + $bar')(null, {
      foo: 4,
      bar: -2
    })).toEqual(2);
  });
  it("doesn't allow passing functions", function () {
    expect(function () {
      return (0, _interpreter.default)('foo 4')(null, {
        foo: function foo(x) {
          return 3;
        }
      });
    }).toThrow();
  });
  it('throws syntax error on invalid source code', function () {
    expect(function () {
      (0, _interpreter.default)('¡');
    }).toThrow(SyntaxError);
  });
});