import selftest from '../tool-testing/selftest.js';
import { findAssignedGlobals } from '../isobuild/js-analyze.js';

selftest.define('findAssignedGlobals', () => {
  function run(source, expected) {
    selftest.expectEqual(findAssignedGlobals(source), expected);
  };

  run('x', {});
  run('x + y', {});
  run('x = y', {x: true});
  run('var x; x = y', {});
  run('var y; x = y', {x: true});
  run('var x,y; x = y', {});
  run('for (x in y);', {x: true});
  run('for (var x in y);', {});
  // Update operators cause ReferenceError if the left-hand is not defined.
  run('x++', {});
  run('x += 5', {x: true});
  run('var x = y', {});
  run('a.b[c.d]', {});
  run('foo.bar[baz][c.d].z = 3', {});
  run('foo.bar(baz)[c.d].z = 3', {});
  run('var x = y.z; x.a = y; z.b;', {});
  run('Foo.Bar', {});
  run('Foo.Bar = 3', {});
  run(
    '(function (a, d) { var b = a, c; return f(a.z, b.z, c.z, d.z, e.z); })()',
    {});
  // catch clause declares a name
  run('try { Foo } catch (e) { e = 5 }', {});
  run('try { Foo } catch (e) { Foo }', {});
  run('try { Foo } catch (Foo) { Foo }', {});
  run('try { e } catch (Foo) { Foo }', {});
  run('var x = function y () { return String(y); }', {});
  run('a[b=c] = d', {b: true});
  run('a.a.a[b.b.b=c.c.c] = d.d.d', {});
  // esprima ignores parentheses
  run('((((x)))) = 5', {x: true});
  // esprima ignores comments
  run('x /* foo */ = 5', {x: true});

  // Without ignoreEval, this thinks J is global.
  run('function x(){var J;J=3;eval("foo");}', {});

  let threw = true;
  try {
    findAssignedGlobals("x = ");
    threw = false;
  } catch (e) {
    selftest.expectTrue(e.$ParseError);
  }
  selftest.expectTrue(threw);
});
