/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

// Exercises the opt-in `js:bigint` flag of the compiler. The fixture is
// regenerated by testAll.sh into `gen-nodejs-bigint/` with
// `--gen js:node,es6,bigint`.

const test = require("tape");
const i64types = require("./gen-nodejs-bigint/Int64Test_types.js");

test("js:node,bigint emits native BigInt constants", function (assert) {
  assert.equal(typeof i64types.SMALL_INT64, "bigint", "scalar is bigint");
  assert.equal(i64types.SMALL_INT64, 42n, "SMALL_INT64");
  assert.equal(
    i64types.MAX_JS_SAFE_INT64,
    BigInt(Number.MAX_SAFE_INTEGER),
    "MAX_JS_SAFE_INT64",
  );
  assert.equal(
    i64types.MIN_JS_SAFE_INT64,
    BigInt(Number.MIN_SAFE_INTEGER),
    "MIN_JS_SAFE_INT64",
  );
  assert.equal(
    i64types.MAX_JS_SAFE_PLUS_ONE_INT64,
    BigInt(Number.MAX_SAFE_INTEGER) + 1n,
    "MAX_JS_SAFE_PLUS_ONE_INT64",
  );
  assert.equal(
    i64types.MIN_JS_SAFE_MINUS_ONE_INT64,
    BigInt(Number.MIN_SAFE_INTEGER) - 1n,
    "MIN_JS_SAFE_MINUS_ONE_INT64",
  );
  assert.equal(
    i64types.MAX_SIGNED_INT64,
    (1n << 63n) - 1n,
    "MAX_SIGNED_INT64 — full 64-bit range",
  );
  assert.equal(
    i64types.MIN_SIGNED_INT64,
    -(1n << 63n),
    "MIN_SIGNED_INT64 — full 64-bit range",
  );
  assert.end();
});

test("js:node,bigint emits BigInt list elements", function (assert) {
  const expected = [
    42n,
    BigInt(Number.MAX_SAFE_INTEGER),
    BigInt(Number.MIN_SAFE_INTEGER),
    BigInt(Number.MAX_SAFE_INTEGER) + 1n,
    BigInt(Number.MIN_SAFE_INTEGER) - 1n,
    (1n << 63n) - 1n,
    -(1n << 63n),
  ];
  assert.equal(i64types.INT64_LIST.length, expected.length, "list length");
  for (let i = 0; i < expected.length; ++i) {
    assert.equal(typeof i64types.INT64_LIST[i], "bigint", `INT64_LIST[${i}]`);
    assert.equal(i64types.INT64_LIST[i], expected[i], `INT64_LIST[${i}] value`);
  }
  assert.end();
});

test("js:node,bigint generated map keys are decimal strings, values are BigInt", function (assert) {
  // Map keys cannot be BigInt in JS object literals — the generator stringifies
  // them. Values should be BigInt under js:node,bigint.
  const map = i64types.INT64_2_INT64_MAP;
  assert.equal(typeof map["42"], "bigint", "value at key '42' is bigint");
  assert.equal(map["42"], 42n, "value at key '42' equals 42n");
  assert.equal(
    map[String((1n << 63n) - 1n)],
    (1n << 63n) - 1n,
    "value at MAX_SIGNED_INT64 key round-trips",
  );
  assert.end();
});

test("bigint-mode generated module does not import node-int64", function (assert) {
  const fs = require("fs");
  const path = require("path");
  const src = fs.readFileSync(
    path.join(__dirname, "gen-nodejs-bigint", "Int64Test_types.js"),
    "utf8",
  );
  assert.notOk(
    /require\(['"]node-int64['"]\)/.test(src),
    "no `require('node-int64')` in bigint-mode output",
  );
  assert.notOk(
    /new Int64\(/.test(src),
    "no `new Int64(...)` in bigint-mode output",
  );
  assert.end();
});
