/*
 * Copyright (C) Igor Sysoev
 * Copyright (C) NGINX, Inc.
 */


#include <njs.h>
#include <njs_unix.h>
#include <njs_utils.h>
#include <njs_queue.h>
#include <njs_string.h>

#include <time.h>

#ifndef NJS_HAVE_PCRE2
#include <pcre.h>
#endif

#include "njs_externals_test.h"


#define NJS_HAVE_LARGE_STACK (!NJS_HAVE_ADDRESS_SANITIZER && !NJS_HAVE_MEMORY_SANITIZER)

#ifdef NJS_HAVE_LITTLE_ENDIAN
#define njs_evar(little, big) little
#else
#define njs_evar(little, big) big
#endif

#ifdef NJS_HAVE_PCRE2
#define njs_pcre_var(pcre2, pcre) pcre2
#else
#define njs_pcre_var(pcre2, pcre) pcre
#endif


#define njs_declare_sparse_array(nm, sz)                                      \
    "var " nm " = Array(" njs_stringify(sz) "); "                             \
    "Object.defineProperty(" nm ", '0',"                                      \
    "{writable:true, enumerable:false, configurable:true});"                  \
    "delete " nm "[0];"


#define njs_buffer_byte_map(func, sign, divisor)                              \
    "var buf = Buffer.alloc(6);"                                              \
    "[1,2,3,4,5,6].map(byte => {"                                             \
    "    buf." func "(" sign "(2 ** (byte * 7)) / "                           \
                                     njs_stringify(divisor) ", 0, byte);"     \
    "    return njs.dump(buf);"                                               \
    "})"


typedef struct {
    njs_str_t  script;
    njs_str_t  ret;
} njs_unit_test_t;


static njs_unit_test_t  njs_test[] =
{
    { njs_str("@"),
      njs_str("SyntaxError: Unexpected token \"@\"") },

    { njs_str("}"),
      njs_str("SyntaxError: Unexpected token \"}\"") },

    { njs_str("1}"),
      njs_str("SyntaxError: Unexpected token \"}\"") },

    { njs_str("/***/1/*\n**/"),
      njs_str("1") },

    { njs_str("/***/1//  "),
      njs_str("1") },

    { njs_str(">"),
      njs_str("SyntaxError: Unexpected token \">\"") },

    { njs_str(">>"),
      njs_str("SyntaxError: Unexpected token \">>\"") },

    { njs_str(">>>"),
      njs_str("SyntaxError: Unexpected token \">>>\"") },

    { njs_str("=="),
      njs_str("SyntaxError: Unexpected token \"==\"") },

    { njs_str("?"),
      njs_str("SyntaxError: Unexpected token \"?\"") },

    /* Variable declarations. */

    { njs_str("var x"),
      njs_str("undefined") },

    { njs_str("var x;"),
      njs_str("undefined") },

    { njs_str("var x;;"),
      njs_str("undefined") },

    { njs_str("var x = 0"),
      njs_str("undefined") },

    { njs_str("var x = 0;"),
      njs_str("undefined") },

    { njs_str("var x = 0;;"),
      njs_str("undefined") },

    { njs_str("var; a"),
      njs_str("SyntaxError: Unexpected token \";\"") },

    { njs_str("var + a"),
      njs_str("SyntaxError: Unexpected token \"+\"") },

    { njs_str("//\r\n; var + a"),
      njs_str("SyntaxError: Unexpected token \"+\"") },

    { njs_str("/*\n*/; var + a"),
      njs_str("SyntaxError: Unexpected token \"+\"") },

    { njs_str("var \n a \n = 1; a"),
      njs_str("1") },

    { njs_str("var \n a, \n b; b"),
      njs_str("undefined") },

    { njs_str("var from = 2; from + 2"),
      njs_str("4") },

    { njs_str("var a / ="),
      njs_str("SyntaxError: Unexpected token \"/\"") },

    { njs_str("var a = 1; var b; a"),
      njs_str("1") },

    { njs_str("a = 1;for(;a;a--)var a; a"),
      njs_str("0") },

    { njs_str("if(1)if(0){0?0:0}else\nvar a\nelse\nvar b"),
      njs_str("undefined") },

    { njs_str("var a = 1; var a; a"),
      njs_str("1") },

    { njs_str("(function (x) {if (x) { var a = 3; return a} else { var a = 4; return a}})(1)"),
      njs_str("3") },

    { njs_str("(function (x) {if (x) { var a = 3; return a} else { var a = 4; return a}})(0)"),
      njs_str("4") },

    { njs_str("function f(){return 2}; var f; f()"),
      njs_str("2") },

    { njs_str("function f(){return 2}; var f = 1; f()"),
      njs_str("TypeError: number is not a function") },

    { njs_str("function f(){return 1}; function f(){return 2}; f()"),
      njs_str("2") },

    { njs_str("var f = 1; function f() {}; f"),
      njs_str("1") },

    { njs_str("var f = 1; function f() {}; f"),
      njs_str("1") },

    { njs_str("function f(a) {return function (x) {return a(x)}} f(1)(0)"),
      njs_str("TypeError: number is not a function") },

    { njs_str("var fooCalled = false;"
              "function foo(){ fooCalled = true; }"
              "var o = {}, r;"
              "try { o.bar(foo()) } catch (e) { r = e.name + ':' + fooCalled }"
              "r"),
      njs_str("TypeError:true") },

    { njs_str("var o = {}, r;"
              "Object.defineProperty(o, 'bar', {"
              "    get: function() { this.barGetter = true; return 42; }"
              "});"
              "try { o.foo(o.bar) } catch (e) { r = e.name + ':' + o.barGetter }"
              "r"),
      njs_str("TypeError:true") },

    { njs_str("var o = {}, r;"
              "Object.defineProperty(o, 'bar', {"
              "    get: function() { this.barGetter = true; return 42; }"
              "});"
              "try { o.foo(o['bar']) } catch (e) {"
              "    r = e.name + ':' + o.barGetter"
              "}"
              "r"),
      njs_str("TypeError:true") },

    { njs_str("var fooCalled = false;"
              "function foo(){ fooCalled = true; }"
              "var o = {}, r;"
              "try { o.bar.gar(foo()) } catch (e) {"
              "    r = e.name + ':' + fooCalled"
              "}"
              "r"),
      njs_str("TypeError:false") },

    { njs_str("var x = function() { this.foo = 42; };"
              "var result = new x(x = 1);"
              "[x, result.foo]"),
      njs_str("1,42") },

    { njs_str("function fn() {"
              "    var x = function() { this.foo = 42; };"
              "    var result = new x(x = 1);"
              "    return [x, result.foo];"
              "}"
              "fn()"),
      njs_str("1,42") },

    { njs_str("var C = {}; var ran = false, r;"
              "try { new C((ran = true, 1)) } catch (e) {"
              "    r = e.name + ':' + ran"
              "}"
              "r"),
      njs_str("TypeError:true") },

    { njs_str("var o = {"
              "    get f() { this.hit = (this.hit || 0) + 1; return 1; }"
              "};"
              "var ran = false, r;"
              "try { o.f((ran = true, 1)) } catch (e) {"
              "    r = ran + ':' + o.hit"
              "}"
              "r"),
      njs_str("true:1") },

    { njs_str("var o = {"
              "    get f() { return function(v) { return this.x + v } },"
              "    x: 7"
              "};"
              "o.f(5)"),
      njs_str("12") },

    { njs_str("var x = 0;"
              ""
              "function f1() {"
              "    function f2() {"
              "        return x;"
              "    };"
              ""
              "    return f2();"
              ""
              "    var x = 1;"
              "}"
              ""
              "f1() === undefined"),
      njs_str("true") },

    { njs_str("var fn = function fn() {return fn.test}; fn.test = 'test'; fn()"),
      njs_str("test") },

    { njs_str("var body;"
              "var n = 'outside';"
              "var before = function() {return n};"
              ""
              "var func = function n() {"
              "    var n;"
              "    body = function() {return n};"
              "};"
              ""
              "func();"
              ""
              "[before(), body()]"),
      njs_str("outside,") },

    { njs_str("var func = function x(x) {return x}; func()"),
      njs_str("undefined") },

    { njs_str("var func = function f() {f = null; return f;}; func()"),
      njs_str("TypeError: assignment to constant variable") },

    { njs_str("var func = function f() {let f = null; return f;}; func()"),
      njs_str("null") },

    { njs_str("var a; Object.getOwnPropertyDescriptor(this, 'a').value"),
      njs_str("undefined") },

    { njs_str("f() = 1"),
      njs_str("ReferenceError: Invalid left-hand side in assignment") },

    { njs_str("f.a() = 1"),
      njs_str("ReferenceError: Invalid left-hand side in assignment") },

    { njs_str("++f()"),
      njs_str("ReferenceError: Invalid left-hand side in prefix operation") },

    { njs_str("f()++"),
      njs_str("ReferenceError: Invalid left-hand side in postfix operation") },

    /* Numbers. */

    { njs_str("0"),
      njs_str("0") },

    { njs_str("-0"),
      njs_str("-0") },

    { njs_str(".0"),
      njs_str("0") },

    { njs_str("0.1"),
      njs_str("0.1") },

    { njs_str(".9"),
      njs_str("0.9") },

    { njs_str("-.0_1"),
      njs_str("-0.01") },

    { njs_str("0.000_001"),
      njs_str("0.000001") },

    { njs_str("0.00000_123456"),
      njs_str("0.00000123456") },

    { njs_str("0.0000001"),
      njs_str("1e-7") },

    { njs_str("1.1000000"),
      njs_str("1.1") },

    { njs_str("1_0"),
      njs_str("10") },

    { njs_str("99_999_999_999_999_999_999"),
      njs_str("100000000000000000000") },

    { njs_str("9999999999999999999_9.1_1_1"),
      njs_str("100000000000000000000") },

    { njs_str("999999999999999999999"),
      njs_str("1e+21") },

    { njs_str("9223372036854775808"),
      njs_str("9223372036854776000") },

    { njs_str("18446744073709551616"),
      njs_str("18446744073709552000") },

    { njs_str("1.79769313_48623157E+3_0_8"),
      njs_str("1.7976931348623157e+308") },

    { njs_str("+1"),
      njs_str("1") },

    { njs_str("+1\n"),
      njs_str("1") },

    { njs_str("."),
      njs_str("SyntaxError: Unexpected token \".\"") },

    { njs_str("0_1"),
      njs_str("SyntaxError: Unexpected token \"0_1\"") },

    { njs_str("1_"),
      njs_str("SyntaxError: Unexpected token \"1_\"") },

    { njs_str("1__0"),
      njs_str("SyntaxError: Unexpected token \"1__0\"") },

    { njs_str("._1"),
      njs_str("SyntaxError: Unexpected token \".\"") },

    { njs_str(".1_"),
      njs_str("SyntaxError: Unexpected token \".1_\"") },

    { njs_str("1_.1"),
      njs_str("SyntaxError: Unexpected token \"1_\"") },

    { njs_str(".0__1"),
      njs_str("SyntaxError: Unexpected token \".0__1\"") },

    { njs_str("1e_1"),
      njs_str("SyntaxError: Unexpected token \"1e_1\"") },

    { njs_str("1e-_1"),
      njs_str("SyntaxError: Unexpected token \"1e\"") },

    { njs_str("1E1__0"),
      njs_str("SyntaxError: Unexpected token \"1E1__0\"") },

    { njs_str("1_e1"),
      njs_str("SyntaxError: Unexpected token \"1_e1\"") },

    { njs_str("1e1_"),
      njs_str("SyntaxError: Unexpected token \"1e1_\"") },

    { njs_str("-_1"),
      njs_str("ReferenceError: \"_1\" is not defined") },

    { njs_str("_1"),
      njs_str("ReferenceError: \"_1\" is not defined") },

    /* Octal Numbers. */

    { njs_str("0o0"),
      njs_str("0") },

    { njs_str("0O10"),
      njs_str("8") },

    { njs_str("0o011"),
      njs_str("9") },

    { njs_str("-0O7_7_7"),
      njs_str("-511") },

    { njs_str("0o7777777777777777777777777777777777700000000000000000000000000000000"),
      njs_str("3.2138760885179806e+60") },

    { njs_str("0o"),
      njs_str("SyntaxError: Unexpected token \"0o\"") },

    { njs_str("0O778"),
      njs_str("SyntaxError: Unexpected token \"0O778\"") },

    { njs_str("0O_7"),
      njs_str("SyntaxError: Unexpected token \"0O_7\"") },

    { njs_str("0O + 1"),
      njs_str("SyntaxError: Unexpected token \"0O\"") },

    { njs_str("0o7_"),
      njs_str("SyntaxError: Unexpected token \"0o7_\"") },

    { njs_str("0o7__7"),
      njs_str("SyntaxError: Unexpected token \"0o7__7\"") },

    { njs_str("0o7.1"),
      njs_str("SyntaxError: Unexpected token \".1\"") },

    /* Legacy Octal Numbers are deprecated. */

    { njs_str("00"),
      njs_str("SyntaxError: Unexpected token \"00\"") },

    { njs_str("08"),
      njs_str("SyntaxError: Unexpected token \"08\"") },

    { njs_str("09"),
      njs_str("SyntaxError: Unexpected token \"09\"") },

    { njs_str("0011"),
      njs_str("SyntaxError: Unexpected token \"0011\"") },

    { njs_str("0_"),
      njs_str("SyntaxError: Unexpected token \"0_\"") },

    { njs_str("0_1"),
      njs_str("SyntaxError: Unexpected token \"0_1\"") },

    { njs_str("00_1"),
      njs_str("SyntaxError: Unexpected token \"00_1\"") },

    /* Binary Numbers. */

    { njs_str("0b0"),
      njs_str("0") },

    { njs_str("0B10"),
      njs_str("2") },

    { njs_str("0b0_1_0_1"),
      njs_str("5") },

    { njs_str("-0B1111_1111"),
      njs_str("-255") },

    { njs_str("0b111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000"),
      njs_str("1.2379400392853803e+27") },

    { njs_str("0b"),
      njs_str("SyntaxError: Unexpected token \"0b\"") },

    { njs_str("0B12"),
      njs_str("SyntaxError: Unexpected token \"0B12\"") },

    { njs_str("0b_11"),
      njs_str("SyntaxError: Unexpected token \"0b_11\"") },

    { njs_str("0b + 1"),
      njs_str("SyntaxError: Unexpected token \"0b\"") },

    { njs_str("0B1__1"),
      njs_str("SyntaxError: Unexpected token \"0B1__1\"") },

    { njs_str("0b11_"),
      njs_str("SyntaxError: Unexpected token \"0b11_\"") },

    { njs_str("0b1.1"),
      njs_str("SyntaxError: Unexpected token \".1\"") },

    /* Hex Numbers. */

    { njs_str("0x0"),
      njs_str("0") },

    { njs_str("-0x1"),
      njs_str("-1") },

    { njs_str("0xffFF"),
      njs_str("65535") },

    { njs_str("0X00_00_BE_EF"),
      njs_str("48879") },

    { njs_str("0x21bc2b266d3a3600000000000000000000000000000000000000000000000000000"),
      njs_str("6.25e+79") },

    { njs_str("0x21bc2b266d3a36000000000000000000000000000000000000000000000000000000"),
      njs_str("1e+81") },

    { njs_str("0x"),
      njs_str("SyntaxError: Unexpected token \"0x\"") },

    { njs_str("0xffff."),
      njs_str("SyntaxError: Unexpected end of input") },

    { njs_str("0x12g"),
      njs_str("SyntaxError: Unexpected token \"0x12g\"") },

    { njs_str("0X_ff"),
      njs_str("SyntaxError: Unexpected token \"0X_ff\"") },

    { njs_str("0X + 1"),
      njs_str("SyntaxError: Unexpected token \"0X\"") },

    { njs_str("0xff_"),
      njs_str("SyntaxError: Unexpected token \"0xff_\"") },

    { njs_str("0Xf__f"),
      njs_str("SyntaxError: Unexpected token \"0Xf__f\"") },

    { njs_str(""),
      njs_str("undefined") },

    { njs_str("\n"),
      njs_str("undefined") },

    { njs_str(";"),
      njs_str("undefined") },

    { njs_str("\n +1"),
      njs_str("1") },

    /* Scientific notation. */

    { njs_str("0e0"),
      njs_str("0") },

    { njs_str("0.0e0"),
      njs_str("0") },

    { njs_str("1e0"),
      njs_str("1") },

    { njs_str("1e1"),
      njs_str("10") },

    { njs_str("1.e01"),
      njs_str("10") },

    { njs_str("5.7e1"),
      njs_str("57") },

    { njs_str("5.7e-1"),
      njs_str("0.57") },

    { njs_str("-5.7e-1"),
      njs_str("-0.57") },

    { njs_str("1.1e-01"),
      njs_str("0.11") },

    { njs_str("5.7e-2"),
      njs_str("0.057") },

    { njs_str("1.1e+01"),
      njs_str("11") },

    { njs_str("-.01e-01"),
      njs_str("-0.001") },

    { njs_str("1e9"),
      njs_str("1000000000") },

    { njs_str("1.0e308"),
      njs_str("1e+308") },

    { njs_str("0e309"),
      njs_str("0") },

    { njs_str("0e-309"),
      njs_str("0") },

    { njs_str("1e309"),
      njs_str("Infinity") },

    { njs_str("-1e309"),
      njs_str("-Infinity") },

    { njs_str("1e"),
      njs_str("SyntaxError: Unexpected token \"1e\"") },

    { njs_str("1.e"),
      njs_str("SyntaxError: Unexpected token \"1.e\"") },

    { njs_str("1e+"),
      njs_str("SyntaxError: Unexpected token \"1e\"") },

    { njs_str("1.e-"),
      njs_str("SyntaxError: Unexpected token \"1.e\"") },

    { njs_str("1eZ"),
      njs_str("SyntaxError: Unexpected token \"1eZ\"") },

    { njs_str(".e1"),
      njs_str("SyntaxError: Unexpected token \".\"") },

    { njs_str("Number.prototype.X = function(){return 123;};"
                 "(1).X()"),
      njs_str("123") },

    /* Indices. */

    { njs_str("var a = []; a[-1] = 2; a[-1] == a['-1']"),
      njs_str("true") },

    { njs_str("var a = []; a[Infinity] = 2; a[Infinity] == a['Infinity']"),
      njs_str("true") },

    { njs_str("var a = []; a[NaN] = 2; a[NaN] == a['NaN']"),
      njs_str("true") },

#define NJS_NOT_CANONICAL_INDICES "['+0', '-0', '1.', '0.', '0.0', '4294967295', " \
                                  " '4294967296', '-1', '1.1', '9223372036854775808']"

    { njs_str("var a = [1,2]; "
              NJS_NOT_CANONICAL_INDICES
               ".every(v=>(a[v] === undefined))"),
      njs_str("true") },

    { njs_str("var a = [1,2]; "
              NJS_NOT_CANONICAL_INDICES
               ".every(v=>{a[v] = 'a'; return a[v] === 'a'})"),
      njs_str("true") },

    /* Number.toString(radix) method. */

    { njs_str("0..toString(2)"),
      njs_str("0") },

    { njs_str("(1234.567).toString(3)"),
      njs_str("1200201.120022100021001021021002202") },

    { njs_str("(1234.567).toString(5)"),
      njs_str("14414.240414141414141414") },

    { njs_str("(1234.567).toString(17)"),
      njs_str("44a.9aeb6faa0da") },

    { njs_str("(1234.567).toString(36)"),
      njs_str("ya.kety9sifl") },

    { njs_str("Number(-1.1).toString(36)"),
      njs_str("-1.3llllllllm") },

    { njs_str("Math.pow(-2, 1023).toString(2).length"),
      njs_str("1025") },

    { njs_str("8.0625.toString(2)"),
      njs_str("1000.0001") },

    { njs_str("(1/3).toString(2)"),
      njs_str("0.010101010101010101010101010101010101010101010101010101") },

    { njs_str("9999..toString(3)"),
      njs_str("111201100") },

    { njs_str("-9999..toString(3)"),
      njs_str("-111201100") },

    { njs_str("81985529216486895..toString(16)"),
      njs_str("123456789abcdf0") },

    { njs_str("0xffff.toString(16)"),
      njs_str("ffff") },

    { njs_str("30520..toString(36)"),
      njs_str("njs") },

    { njs_str("Infinity.toString()"),
      njs_str("Infinity") },

    { njs_str("Infinity.toString(2)"),
      njs_str("Infinity") },

    { njs_str("Infinity.toString(10)"),
      njs_str("Infinity") },

    { njs_str("Infinity.toString(NaN)"),
      njs_str("RangeError: radix argument must be between 2 and 36") },

    { njs_str("Infinity.toString({})"),
      njs_str("RangeError: radix argument must be between 2 and 36") },

    { njs_str("Infinity.toString(Infinity)"),
      njs_str("RangeError: radix argument must be between 2 and 36") },

    { njs_str("NaN.toString()"),
      njs_str("NaN") },

    { njs_str("NaN.toString(2)"),
      njs_str("NaN") },

    { njs_str("NaN.toString(10)"),
      njs_str("NaN") },

    { njs_str("NaN.toString(Infinity)"),
      njs_str("RangeError: radix argument must be between 2 and 36") },

    { njs_str("NaN.toString({})"),
      njs_str("RangeError: radix argument must be between 2 and 36") },

    { njs_str("NaN.toString(NaN)"),
      njs_str("RangeError: radix argument must be between 2 and 36") },

    { njs_str("1.2312313132.toString(14)"),
      njs_str("1.3346da6d5d455c") },

    { njs_str("7.799999999999999.toString(14)"),
      njs_str("7.b2b2b2b2b2b2a5") },

#ifndef NJS_SUNC
    { njs_str("1e20.toString(14)"),
      njs_str("33cb3bb449c2a90000") },

    { njs_str("1.7976931348623157E+308.toString(36) == ('1a1e4vngail' + '0'.repeat(188))"),
      njs_str("true") },

    /* Largest positive double (prev_double(INFINITY)). */
    { njs_str("1.7976931348623157E+308.toString(2) == ('1'.repeat(53) + '0'.repeat(971))"),
      njs_str("true") },

    { njs_str("Array(5).fill().map((n, i) => i + 10).map((v)=>(1.2312313132).toString(v))"),
      njs_str("1.2312313132,1.25a850416057383,1.293699002749414,1.3010274cab0288,1.3346da6d5d455c") },

    { njs_str("Array(5).fill().map((n, i) => 36 - i).map((v)=>(1e23).toString(v))"),
      njs_str("ga894a06ac00000,o5hlsorok5a0000,128fpsprqldf0000,1m1s0ajv6cn00000,2kmg5hv19br00000") },
#endif

    /* Number.prototype.toFixed(frac) method. */

    { njs_str("(900.1).toFixed(1)"),
      njs_str("900.1") },

    { njs_str("(0).toFixed(0)"),
      njs_str("0") },

    { njs_str("(0).toFixed(3)"),
      njs_str("0.000") },

    { njs_str("(7).toFixed()"),
      njs_str("7") },

    { njs_str("(7).toFixed(0)"),
      njs_str("7") },

    { njs_str("(7).toFixed(2)"),
      njs_str("7.00") },

    { njs_str("(-900.1).toFixed(3.3)"),
      njs_str("-900.100") },

    { njs_str("(900.123).toFixed(5)"),
      njs_str("900.12300") },

    { njs_str("(1/3).toFixed(5)"),
      njs_str("0.33333") },

    { njs_str("(new Number(1/3)).toFixed(5)"),
      njs_str("0.33333") },

    { njs_str("(new Number(1/3)).toFixed(5)"),
      njs_str("0.33333") },

    { njs_str("(1/3).toFixed({toString(){return '5'}})"),
      njs_str("0.33333") },

    { njs_str("(1/3).toFixed(100)"),
      njs_str("0.3333333333333333148296162562473909929394721984863281250000000000000000000000000000000000000000000000") },

    { njs_str("(1.23e+20).toFixed(2)"),
      njs_str("123000000000000000000.00") },

    { njs_str("(1.23e-10).toFixed(2)"),
      njs_str("0.00") },

    { njs_str("(1.23e-10).toFixed(15)"),
      njs_str("0.000000000123000") },

    { njs_str("(1.23e-10).toFixed(100)"),
      njs_str("0.0000000001229999999999999888422768137255427361997917046210204716771841049194335937500000000000000000") },

    { njs_str("NaN.toFixed(1)"),
      njs_str("NaN") },

    { njs_str("(2 ** -100).toFixed(100)"),
      njs_str("0.0000000000000000000000000000007888609052210118054117285652827862296732064351090230047702789306640625") },

    /* Number.prototype.toPrecision(prec) method. */

    { njs_str("Array(4).fill().map((n, i) => i+1).map((v)=>(1/7).toPrecision(v))"),
      njs_str("0.1,0.14,0.143,0.1429") },

    { njs_str("Array(4).fill().map((n, i) => i+1).map((v)=>(0).toPrecision(v))"),
      njs_str("0,0.0,0.00,0.000") },

    { njs_str("Array(4).fill().map((n, i) => i+1).map((v)=>(1/2).toPrecision(v))"),
      njs_str("0.5,0.50,0.500,0.5000") },

    { njs_str("Array(6).fill().map((n, i) => i+2).map((v)=>(1/v).toPrecision(5))"),
      njs_str("0.50000,0.33333,0.25000,0.20000,0.16667,0.14286") },

    { njs_str("Array(6).fill().map((n, i) => i+2).map((v)=>(1/(v*100)).toPrecision(5))"),
      njs_str("0.0050000,0.0033333,0.0025000,0.0020000,0.0016667,0.0014286") },

    { njs_str("Array(6).fill().map((n, i) => i+1).map((v)=>(10*v/7).toPrecision(5))"),
      njs_str("1.4286,2.8571,4.2857,5.7143,7.1429,8.5714") },

    { njs_str("Array(6).fill().map((n, i) => i+1).map((v)=>(v/3).toPrecision(5))"),
      njs_str("0.33333,0.66667,1.0000,1.3333,1.6667,2.0000") },

    { njs_str("Array(6).fill().map((n, i) => i+1).map((v)=>((Math.pow(-1,v))*(2*v)/3).toPrecision(5))"),
      njs_str("-0.66667,1.3333,-2.0000,2.6667,-3.3333,4.0000") },

    { njs_str("Array(12).fill().map((n, i) => i-3).map((v)=>(2**v).toPrecision(6))"),
      njs_str("0.125000,0.250000,0.500000,1.00000,2.00000,4.00000,8.00000,16.0000,32.0000,64.0000,128.000,256.000") },

    { njs_str("Array(5).fill().map((n, i) => i+16).map((v)=>(4.1).toPrecision(v))"),
      njs_str("4.100000000000000,4.0999999999999996,4.09999999999999964,4.099999999999999645,4.0999999999999996447") },

    { njs_str("Array(3).fill().map((n, i) => i + 19).map((v)=>(2**(-v)).toPrecision(20))"),
      njs_str("0.0000019073486328125000000,9.5367431640625000000e-7,4.7683715820312500000e-7") },

    { njs_str("Array(3).fill().map((n, i) => i + 32).map((v)=>(2**(v)+0.1).toPrecision(10))"),
      njs_str("4294967296,8589934592,1.717986918e+10") },

    { njs_str("(1/7).toPrecision(100)"),
      njs_str("0.1428571428571428492126926812488818541169166564941406250000000000000000000000000000000000000000000000") },

    { njs_str("(2**128).toPrecision(40)"),
      njs_str("340282366920938463463374607431768211456.0") },

    { njs_str("(2**128).toPrecision(1)"),
      njs_str("3e+38") },

    { njs_str("(2**128).toPrecision(2)"),
      njs_str("3.4e+38") },

    { njs_str("(2**128).toPrecision(40)"),
      njs_str("340282366920938463463374607431768211456.0") },

    { njs_str("(123).toPrecision(0)"),
      njs_str("RangeError: precision argument must be between 1 and 100") },

    { njs_str("(123).toPrecision(2.4)"),
      njs_str("1.2e+2") },

    { njs_str("(123).toPrecision(101)"),
      njs_str("RangeError: precision argument must be between 1 and 100") },

    { njs_str("(2**10000).toPrecision()"),
      njs_str("Infinity") },

    { njs_str("(-(2**10000)).toPrecision()"),
      njs_str("-Infinity") },

    { njs_str("var v = parseFloat('9'.repeat(98));"
              "[98,100].map(p=>v.toPrecision(p).length)"),
      njs_str("98,101") },

    { njs_str("(-0).toPrecision(2)"),
      njs_str("0.0") },

    { njs_str("NaN.toPrecision()"),
      njs_str("NaN") },

    { njs_str("NaN.toPrecision(0)"),
      njs_str("NaN") },

    { njs_str("(10**22).toPrecision()"),
      njs_str("1e+22") },

    { njs_str("Number.prototype.toPrecision.call('12')"),
      njs_str("TypeError: unexpected value type:string") },

    { njs_str("(1000000000000000128).toString()"),
      njs_str("1000000000000000100") },

    { njs_str("(1000000000000000128).toFixed(0)"),
      njs_str("1000000000000000128") },

    { njs_str("(1e21).toFixed(1)"),
      njs_str("1e+21") },

    { njs_str("Number.prototype.toFixed.call({})"),
      njs_str("TypeError: unexpected value type:object") },

    { njs_str("(0).toFixed(-1)"),
      njs_str("RangeError: digits argument must be between 0 and 100") },

    { njs_str("(0).toFixed(101)"),
      njs_str("RangeError: digits argument must be between 0 and 100") },

    /* Number.prototype.toExponential(frac) method. */

    { njs_str("Array(3).fill().map((n, i) => i + 1).map((v)=>(0).toExponential(v))"),
      njs_str("0.0e+0,0.00e+0,0.000e+0") },

    { njs_str("Array(6).fill().map((n, i) => i + 1).map((v)=>((Math.pow(-1,v))*(2*v)/3).toExponential(5))"),
      njs_str("-6.66667e-1,1.33333e+0,-2.00000e+0,2.66667e+0,-3.33333e+0,4.00000e+0") },

    { njs_str("Array(5).fill().map((n, i) => i + 1).map((v)=>((Math.pow(-1,v))*(2*v)/3).toExponential())"),
      njs_str("-6.666666666666666e-1,1.3333333333333333e+0,-2e+0,2.6666666666666665e+0,-3.3333333333333335e+0") },

    { njs_str("1.7976931348623157e+308.toExponential()"),
      njs_str("1.7976931348623157e+308") },

    { njs_str("(1/7).toExponential(100)"),
      njs_str("1.4285714285714284921269268124888185411691665649414062500000000000000000000000000000000000000000000000e-1") },

    { njs_str("var v = 1.7976931348623157e+308; Number(v.toExponential()) == v"),
      njs_str("true") },

    { njs_str("(123).toExponential(-1)"),
      njs_str("RangeError: digits argument must be between 0 and 100") },

    { njs_str("(123).toExponential(2.4)"),
      njs_str("1.23e+2") },

    { njs_str("(123).toExponential(101)"),
      njs_str("RangeError: digits argument must be between 0 and 100") },

    { njs_str("[2**10000,-(2**10000),NaN].map((v)=>v.toExponential())"),
      njs_str("Infinity,-Infinity,NaN") },

    { njs_str("[2**10000,-(2**10000),NaN].map((v)=>v.toExponential(1000))"),
      njs_str("Infinity,-Infinity,NaN") },

    { njs_str("Number.prototype.toExponential.call('12')"),
      njs_str("TypeError: unexpected value type:string") },

    /* An object "valueOf/toString" methods. */

    { njs_str("var a = { valueOf: function() { return 1 } };    +a"),
      njs_str("1") },

    { njs_str("var a = { valueOf: function() { return '1' } };  +a"),
      njs_str("1") },

    { njs_str("var a = { valueOf: 2,"
                 "          toString: function() { return '1' } }; +a"),
      njs_str("1") },

    { njs_str("var a = { valueOf: function() { return 1 } }; ''+a"),
      njs_str("1") },

    { njs_str("var a = { valueOf: function() { return [] },"
                 "          toString: function() { return '1' } }; +a"),
      njs_str("1") },

    { njs_str("var a = { toString: function() { return 'a' } };"
                 "var b = { toString: function() { return a+'b' } }; '0'+b"),
      njs_str("0ab") },

    { njs_str("({valueOf:()=>'4'}) / ({valueOf:()=>2})"),
      njs_str("2") },

    { njs_str("({valueOf:()=>{throw 'x'}}) / ({valueOf:()=>{throw 'y'}});"
                 "var e; try { x/y } catch(ex) {e = ex}; ex"),
      njs_str("x") },

    { njs_str("({valueOf:()=>{ try {throw 'x'} catch (ex) {return 6} } }) / 2"),
      njs_str("3") },

    { njs_str("({valueOf:()=>2}) / ({valueOf:()=>{throw 'y'}});"
                 "var e; try { x/y } catch(ex) {e = ex}; ex"),
      njs_str("y") },

    { njs_str("({valueOf:()=>'4'}) % ({valueOf:()=>3})"),
      njs_str("1") },

    { njs_str("({valueOf:()=>9}) >>> ({valueOf:()=>2})"),
      njs_str("2") },

    { njs_str("({valueOf:()=>0x1f}) & ({valueOf:()=>0xf})"),
      njs_str("15") },

    { njs_str("({valueOf:()=>0x1f}) ^ ({valueOf:()=>0xf})"),
      njs_str("16") },

    { njs_str("({valueOf:()=>0xf}) == ({valueOf:()=>0xf})"),
      njs_str("false") },

    { njs_str("var e; try {({valueOf: String.prototype.valueOf}) == 1} "
                 "catch (ex) { e = ex}; e"),
      njs_str("TypeError: unexpected value type:object") },

    { njs_str("({valueOf:()=>0xf}) == 0xf"),
      njs_str("true") },

    { njs_str("0xf == ({valueOf:()=>0xf})"),
      njs_str("true") },

    { njs_str("({valueOf:()=>'0xf'}) == 0xf"),
      njs_str("true") },

    { njs_str("0xf == ({valueOf:()=>'0xf'})"),
      njs_str("true") },

    { njs_str("({valueOf:()=>0xf}) == '0xf'"),
      njs_str("true") },

    { njs_str("'0xf' == ({valueOf:()=>0xf})"),
      njs_str("true") },
    /**/

    { njs_str("1 + undefined"),
      njs_str("NaN") },

    { njs_str("1 + ''"),
      njs_str("1") },

    { njs_str("0xA + ''"),
      njs_str("10") },

    { njs_str("undefined + undefined"),
      njs_str("NaN") },

    { njs_str("var undefined"),
      njs_str("undefined") },

    { njs_str("1.2 + 5.7"),
      njs_str("6.9") },

    { njs_str("0xf + 1"),
      njs_str("16") },

    { njs_str("1 + 1 + '2' + 1 + 1"),
      njs_str("2211") },

    { njs_str("'gg' + -0"),
      njs_str("gg0") },

    { njs_str("1.2 - '5.7'"),
      njs_str("-4.5") },

    { njs_str("1.2 + -'5.7'"),
      njs_str("-4.5") },

    { njs_str("1.2 - '-5.7'"),
      njs_str("6.9") },

    { njs_str("5 - ' \t 12  \t'"),
      njs_str("-7") },

    { njs_str("5 - '12zz'"),
      njs_str("NaN") },

    { njs_str("5 - '0x2'"),
      njs_str("3") },

    { njs_str("5 - '-0x2'"),
      njs_str("NaN") },

    { njs_str("5 - '\t 0x2 \t'"),
      njs_str("3") },

    { njs_str("5 - '\t\\u000c0x2 \t'"),
      njs_str("3") },

    { njs_str("5 - '0x2 z'"),
      njs_str("NaN") },

    { njs_str("12 - '5.7e1'"),
      njs_str("-45") },

    { njs_str("12 - '5.e1'"),
      njs_str("-38") },

    { njs_str("12 - '5.7e+01'"),
      njs_str("-45") },

    { njs_str("12 - '5.7e-01'"),
      njs_str("11.43") },

    { njs_str("12 - ' 5.7e1 '"),
      njs_str("-45") },

    { njs_str("12 - '5.7e'"),
      njs_str("NaN") },

    { njs_str("12 - '5.7e+'"),
      njs_str("NaN") },

    { njs_str("12 - '5.7e-'"),
      njs_str("NaN") },

    { njs_str("12 - ' 5.7e1 z'"),
      njs_str("NaN") },

    { njs_str("5 - '0x'"),
      njs_str("NaN") },

    { njs_str("1 + +'3'"),
      njs_str("4") },

    { njs_str("1 - undefined"),
      njs_str("NaN") },

    { njs_str("1 - ''"),
      njs_str("1") },

    { njs_str("undefined - undefined"),
      njs_str("NaN") },

    { njs_str("'A'.toString()"),
      njs_str("A") },

    /* Assignment. */

    { njs_str("var a, b = (a = [2]) * (3 * 4); a +' '+ b"),
      njs_str("2 24") },

    { njs_str("var a = 1; var b = a += 1; b"),
      njs_str("2") },

    { njs_str("var a = 1; var b = a -= 1; b"),
      njs_str("0") },

    { njs_str("var a = 1; var b = a <<= 1; b"),
      njs_str("2") },

    /* 3 address operation and side effect. */

    { njs_str("var a = 1; function f(x) { a = x; return 2 }; a+f(5)+' '+a"),
      njs_str("3 5") },

    { njs_str("var a = 1; function f(x) { a = x; return 2 }; a += f(5)"),
      njs_str("3") },

    { njs_str("var x; x in (x = 1, [1, 2, 3])"),
      njs_str("false") },

    /* ToInt32(). */

    { njs_str("-1.0 | 0"),
      njs_str("-1") },

    { njs_str("0.0 | 0"),
      njs_str("0") },

    { njs_str("0.001 | 0"),
      njs_str("0") },

    { njs_str("1.0 | 0"),
      njs_str("1") },

    { njs_str("2147483647.0 | 0"),
      njs_str("2147483647") },

    { njs_str("2147483648.0 | 0"),
      njs_str("-2147483648") },

    { njs_str("2147483649.0 | 0"),
      njs_str("-2147483647") },

    { njs_str("-1844674406941458432.0 | 0"),
      njs_str("-2147483648") },

    { njs_str("4.835703278458518e+24 /* 2**(53+29) + 2**30 */ | 0"),
      njs_str("1073741824") },

    { njs_str("9.671406556917036e+24 /* 2**(53+30) + 2**31 */ | 0"),
      njs_str("-2147483648") },

    /* Exponentiation. */

    { njs_str("2 ** 3 ** 2"),
      njs_str("512") },

    { njs_str("2 ** (3 ** 2)"),
      njs_str("512") },

    { njs_str("(2 ** 3) ** 2"),
      njs_str("64") },

    { njs_str("3 ** 2 - 9"),
      njs_str("0") },

    { njs_str("-9 + 3 ** 2"),
      njs_str("0") },

    { njs_str("-3 ** 2"),
      njs_str("SyntaxError: Either left-hand side or entire exponentiation "
                 "must be parenthesized") },

    { njs_str("-(3) ** 2"),
      njs_str("SyntaxError: Either left-hand side or entire exponentiation "
                 "must be parenthesized") },

    { njs_str("-(3 ** 2)"),
      njs_str("-9") },

    { njs_str("(-3) ** 2"),
      njs_str("9") },

    { njs_str("1 ** NaN"),
      njs_str("NaN") },

    { njs_str("'a' ** -0"),
      njs_str("1") },

    { njs_str("1.1 ** Infinity"),
      njs_str("Infinity") },

    { njs_str("(-1.1) ** -Infinity"),
      njs_str("0") },

    { njs_str("(-1) ** Infinity"),
      njs_str("NaN") },

    { njs_str("1 ** -Infinity"),
      njs_str("NaN") },

    { njs_str("(-0.9) ** Infinity"),
      njs_str("0") },

    { njs_str("0.9 ** -Infinity"),
      njs_str("Infinity") },

    { njs_str("'Infinity' ** 0.1"),
      njs_str("Infinity") },

    { njs_str("Infinity ** '-0.1'"),
      njs_str("0") },

    { njs_str("(-Infinity) ** 3"),
      njs_str("-Infinity") },

    { njs_str("'-Infinity' ** '3.1'"),
      njs_str("Infinity") },

    { njs_str("(-Infinity) ** '-3'"),
      njs_str("-0") },

    { njs_str("'-Infinity' ** -2"),
      njs_str("0") },

    { njs_str("'0' ** 0.1"),
      njs_str("0") },

#ifndef __NetBSD__  /* NetBSD 7: pow(0, negative) == -Infinity. */
    { njs_str("0 ** '-0.1'"),
      njs_str("Infinity") },
#endif

    { njs_str("(-0) ** 3"),
      njs_str("-0") },

    { njs_str("'-0' ** '3.1'"),
      njs_str("0") },

    { njs_str("(-0) ** '-3'"),
      njs_str("-Infinity") },

#ifndef __NetBSD__  /* NetBSD 7: pow(0, negative) == -Infinity. */
    { njs_str("'-0' ** -2"),
      njs_str("Infinity") },
#endif

    { njs_str("(-3) ** 0.1"),
      njs_str("NaN") },

    { njs_str("var a = 0.1; a **= -2"),
      njs_str("99.99999999999999") },

    { njs_str("var a = 1; a **= NaN"),
      njs_str("NaN") },

    { njs_str("var a = 'a'; a **= -0"),
      njs_str("1") },

    { njs_str("var a = 1.1; a **= Infinity"),
      njs_str("Infinity") },

    { njs_str("var a = -1.1; a **= -Infinity"),
      njs_str("0") },

    { njs_str("var a = -1; a **= Infinity"),
      njs_str("NaN") },

    { njs_str("var a = 1; a **= -Infinity"),
      njs_str("NaN") },

    { njs_str("var a = -0.9; a **= Infinity"),
      njs_str("0") },

    { njs_str("var a = 0.9; a **= -Infinity"),
      njs_str("Infinity") },

    { njs_str("var a = 'Infinity'; a **= 0.1"),
      njs_str("Infinity") },

    { njs_str("var a = Infinity; a **= '-0.1'"),
      njs_str("0") },

    { njs_str("var a = -Infinity; a **= 3"),
      njs_str("-Infinity") },

    { njs_str("var a = '-Infinity'; a **= '3.1'"),
      njs_str("Infinity") },

    { njs_str("var a = -Infinity; a **= '-3'"),
      njs_str("-0") },

    { njs_str("var a = '-Infinity'; a **= -2"),
      njs_str("0") },

    { njs_str("var a = '0'; a **= 0.1"),
      njs_str("0") },

#ifndef __NetBSD__  /* NetBSD 7: pow(0, negative) == -Infinity. */
    { njs_str("var a = 0; a **= '-0.1'"),
      njs_str("Infinity") },
#endif

    { njs_str("var a = -0; a **= 3"),
      njs_str("-0") },

    { njs_str("var a = '-0'; a **= '3.1'"),
      njs_str("0") },

    { njs_str("var a = -0; a **= '-3'"),
      njs_str("-Infinity") },

#ifndef __NetBSD__  /* NetBSD 7: pow(0, negative) == -Infinity. */
    { njs_str("var a = '-0'; a **= -2"),
      njs_str("Infinity") },
#endif

    { njs_str("var a = -3; a **= 0.1"),
      njs_str("NaN") },

    /**/

    { njs_str("12 | 6"),
      njs_str("14") },

    { njs_str("12 | 'abc'"),
      njs_str("12") },

    { njs_str("-1 | 0"),
      njs_str("-1") },

    { njs_str("-2147483648 | 0"),
      njs_str("-2147483648") },

    { njs_str("1024.9 | 0"),
      njs_str("1024") },

    { njs_str("-1024.9 | 0"),
      njs_str("-1024") },

    { njs_str("9007199254740991 | 0"),
      njs_str("-1") },

    { njs_str("9007199254740992 | 0"),
      njs_str("0") },

    { njs_str("9007199254740993 | 0"),
      njs_str("0") },

    { njs_str("9223372036854775808 | 0"),
      njs_str("0") },

    { njs_str("9223372036854777856 | 0"),
      njs_str("2048") },

    { njs_str("-9223372036854777856 | 0"),
      njs_str("-2048") },

    { njs_str("NaN | 0"),
      njs_str("0") },

    { njs_str("-NaN | 0"),
      njs_str("0") },

    { njs_str("Infinity | 0"),
      njs_str("0") },

    { njs_str("-Infinity | 0"),
      njs_str("0") },

    { njs_str("+0 | 0"),
      njs_str("0") },

    { njs_str("-0 | 0"),
      njs_str("0") },

    { njs_str("32.5 << 2.4"),
      njs_str("128") },

    { njs_str("32.5 << 'abc'"),
      njs_str("32") },

    { njs_str("'abc' << 2"),
      njs_str("0") },

    { njs_str("-1 << 0"),
      njs_str("-1") },

    { njs_str("-1 << -1"),
      njs_str("-2147483648") },

    { njs_str("-2147483648 << 0"),
      njs_str("-2147483648") },

    { njs_str("9223372036854775808 << 0"),
      njs_str("0") },

    { njs_str("9223372036854777856 << 0"),
      njs_str("2048") },

    { njs_str("-9223372036854777856 << 0"),
      njs_str("-2048") },

    { njs_str("NaN << 0"),
      njs_str("0") },

    { njs_str("32.5 >> 2.4"),
      njs_str("8") },

    { njs_str("-1 >> 30"),
      njs_str("-1") },

    { njs_str("'abc' >> 2"),
      njs_str("0") },

    { njs_str("-1 >> 0"),
      njs_str("-1") },

    { njs_str("-1 >> -1"),
      njs_str("-1") },

    { njs_str("-2147483648 >> 0"),
      njs_str("-2147483648") },

    { njs_str("-2147483648 >> -1"),
      njs_str("-1") },

    { njs_str("9223372036854775808 >> 0"),
      njs_str("0") },

    { njs_str("9223372036854777856 >> 0"),
      njs_str("2048") },

    { njs_str("-9223372036854777856 >> 0"),
      njs_str("-2048") },

    { njs_str("NaN >> 0"),
      njs_str("0") },

    { njs_str("-1 >>> 30"),
      njs_str("3") },

    { njs_str("NaN >>> 1"),
      njs_str("0") },

    { njs_str("9223372036854775808 >>> 1"),
      njs_str("0") },

    { njs_str("-1 >>> 0"),
      njs_str("4294967295") },

    { njs_str("-1 >>> -1"),
      njs_str("1") },

    { njs_str("-2147483648 >>> 0"),
      njs_str("2147483648") },

    { njs_str("-2147483648 >>> -1"),
      njs_str("1") },

    { njs_str("9223372036854775808 >>> 0"),
      njs_str("0") },

    { njs_str("9223372036854777856 >>> 0"),
      njs_str("2048") },

    { njs_str("-9223372036854777856 >>> 0"),
      njs_str("4294965248") },

    { njs_str("NaN >>> 0"),
      njs_str("0") },

    { njs_str("!2"),
      njs_str("false") },

    /**/

    { njs_str("var a = { valueOf: function() { return 1 } };   ~a"),
      njs_str("-2") },

    { njs_str("var a = { valueOf: function() { return '1' } }; ~a"),
      njs_str("-2") },

    /**/

    { njs_str("1 || 2"),
      njs_str("1") },

    { njs_str("var a = 1; 1 || (a = 2); a"),
      njs_str("1") },

    { njs_str("var x; x = 0 || x; x"),
      njs_str("undefined") },

    { njs_str("var x; x = 1 && x; x"),
      njs_str("undefined") },

    { njs_str("1 || 2 || 3"),
      njs_str("1") },

    { njs_str("1 || (2 + 2) || 3"),
      njs_str("1") },

    { njs_str("1 && 2"),
      njs_str("2") },

    { njs_str("1 && 2 && 3"),
      njs_str("3") },

    { njs_str("var a = 1; 0 && (a = 2); a"),
      njs_str("1") },

    { njs_str("false && true || true"),
      njs_str("true") },

    { njs_str("false && (true || true)"),
      njs_str("false") },

    { njs_str("true && (null ?? true)"),
      njs_str("true") },

    { njs_str("(null || undefined) ?? (true && true)"),
      njs_str("true") },

    { njs_str("undefined ?? null ?? false ?? true"),
      njs_str("false") },

    { njs_str("1 && 1 ?? true"),
      njs_str("SyntaxError: Unexpected token \"??\"") },

    { njs_str("null ?? 0 || 1"),
      njs_str("SyntaxError: Unexpected token \"||\"") },

    /* Logical assignment: ||= */

    { njs_str("var a = 0; a ||= 5; a"),
      njs_str("5") },
    { njs_str("var a = 1; a ||= 5; a"),
      njs_str("1") },
    { njs_str("var a = ''; a ||= 'x'; a"),
      njs_str("x") },
    { njs_str("var a = 'y'; a ||= 'x'; a"),
      njs_str("y") },
    { njs_str("var a = null; a ||= 42; a"),
      njs_str("42") },
    { njs_str("var a = undefined; a ||= 1"),
      njs_str("1") },

    /* ||= short-circuit: RHS not evaluated */

    { njs_str("var a = 1; var b = 0; a ||= (b = 2); b"),
      njs_str("0") },
    { njs_str("var a = 0; var b = 0; a ||= (b = 2); b"),
      njs_str("2") },

    /* Logical assignment: &&= */

    { njs_str("var a = 1; a &&= 5; a"),
      njs_str("5") },
    { njs_str("var a = 0; a &&= 5; a"),
      njs_str("0") },
    { njs_str("var a = 'y'; a &&= 'x'; a"),
      njs_str("x") },
    { njs_str("var a = ''; a &&= 'x'; a"),
      njs_str("") },

    /* &&= short-circuit: RHS not evaluated */

    { njs_str("var a = 0; var b = 0; a &&= (b = 2); b"),
      njs_str("0") },
    { njs_str("var a = 1; var b = 0; a &&= (b = 2); b"),
      njs_str("2") },

    /* Logical assignment: property targets */

    { njs_str("var o = {a: 0}; o.a ||= 5; o.a"),
      njs_str("5") },
    { njs_str("var o = {a: 1}; o.a ||= 5; o.a"),
      njs_str("1") },
    { njs_str("var o = {a: 1}; o.a &&= 5; o.a"),
      njs_str("5") },
    { njs_str("var o = {a: 0}; o.a &&= 5; o.a"),
      njs_str("0") },

    /* Logical assignment: bracket property targets */

    { njs_str("var o = {a: 0}; o['a'] ||= 5; o.a"),
      njs_str("5") },
    { njs_str("var o = {a: 1}; o['a'] &&= 5; o.a"),
      njs_str("5") },

    /* Logical assignment: expression result value */

    { njs_str("var a = 1; (a ||= 5)"),
      njs_str("1") },
    { njs_str("var a = 0; (a ||= 5)"),
      njs_str("5") },
    { njs_str("var a = 1; (a &&= 5)"),
      njs_str("5") },
    { njs_str("var a = 0; (a &&= 5)"),
      njs_str("0") },

    /* Logical assignment: const error */

    { njs_str("const a = 1; a ||= 2"),
      njs_str("1") },
    { njs_str("const a = 0; a ||= 2"),
      njs_str("TypeError: assignment to constant variable") },
    { njs_str("const a = 1; a &&= 2"),
      njs_str("TypeError: assignment to constant variable") },
    { njs_str("const a = 0; a &&= 2"),
      njs_str("0") },

    /* Logical assignment: getter/setter short-circuit. */

    { njs_str("var log = '';"
              "var o = {"
              "    get x() {log += 'g'; return 1},"
              "    set x(v) {log += 's'}"
              "};"
              "o.x ||= 2;"
              "log"),
      njs_str("g") },
    { njs_str("var log = '';"
              "var o = {"
              "    get x() {log += 'g'; return 0},"
              "    set x(v) {log += 's'}"
              "};"
              "o.x ||= 2;"
              "log"),
      njs_str("gs") },
    { njs_str("var log = '';"
              "var o = {"
              "    get x() {log += 'g'; return 0},"
              "    set x(v) {log += 's'}"
              "};"
              "o.x &&= 2;"
              "log"),
      njs_str("g") },
    { njs_str("var log = '';"
              "var o = {"
              "    get x() {log += 'g'; return 1},"
              "    set x(v) {log += 's'}"
              "};"
              "o.x &&= 2;"
              "log"),
      njs_str("gs") },

    /* Logical assignment: short-circuit with non-writable property. */

    { njs_str("var o = {};"
              "Object.defineProperty(o, 'x', {value: 0, writable: false});"
              "o.x &&= 1"),
      njs_str("0") },
    { njs_str("var o = {};"
              "Object.defineProperty(o, 'x', {value: 2, writable: false});"
              "o.x ||= 1"),
      njs_str("2") },

    /* Logical assignment: short-circuit with getter-only property. */

    { njs_str("var o = {};"
              "Object.defineProperty(o, 'x',"
              "    {get: function() {return 0}, set: undefined});"
              "o.x &&= 1"),
      njs_str("0") },
    { njs_str("var o = {};"
              "Object.defineProperty(o, 'x',"
              "    {get: function() {return 2}, set: undefined});"
              "o.x ||= 1"),
      njs_str("2") },

    /* Logical assignment: short-circuit with non-extensible object. */

    { njs_str("var o = {};"
              "Object.preventExtensions(o);"
              "o.prop &&= 1;"
              "o.prop"),
      njs_str("undefined") },

    /* Logical assignment: non-lvalue error */

    { njs_str("1 ||= 2"),
      njs_str("ReferenceError: Invalid left-hand side in assignment") },
    { njs_str("1 &&= 2"),
      njs_str("ReferenceError: Invalid left-hand side in assignment") },

    /* Logical assignment: ??= */

    { njs_str("var a = null; a ?\?= 5; a"),
      njs_str("5") },
    { njs_str("var a = undefined; a ?\?= 5; a"),
      njs_str("5") },
    { njs_str("var a = 0; a ?\?= 5; a"),
      njs_str("0") },
    { njs_str("var a = ''; a ?\?= 'x'; a"),
      njs_str("") },
    { njs_str("var a = false; a ?\?= true; a"),
      njs_str("false") },
    { njs_str("var a = 1; a ?\?= 5; a"),
      njs_str("1") },

    /* ??= short-circuit: RHS not evaluated */

    { njs_str("var a = 1; var b = 0; a ?\?= (b = 2); b"),
      njs_str("0") },
    { njs_str("var a = null; var b = 0; a ?\?= (b = 2); b"),
      njs_str("2") },

    /* ??= property targets */

    { njs_str("var o = {a: null}; o.a ?\?= 5; o.a"),
      njs_str("5") },
    { njs_str("var o = {a: 0}; o.a ?\?= 5; o.a"),
      njs_str("0") },
    { njs_str("var o = {a: null}; o['a'] ?\?= 5; o.a"),
      njs_str("5") },

    /* ??= expression result value */

    { njs_str("var a = 1; (a ?\?= 5)"),
      njs_str("1") },
    { njs_str("var a = null; (a ?\?= 5)"),
      njs_str("5") },

    /* ??= const error */

    { njs_str("const a = 1; a ?\?= 2"),
      njs_str("1") },
    { njs_str("const a = null; a ?\?= 2"),
      njs_str("TypeError: assignment to constant variable") },

    /* ??= getter/setter short-circuit */

    { njs_str("var log = '';"
              "var o = {"
              "    get x() {log += 'g'; return 1},"
              "    set x(v) {log += 's'}"
              "};"
              "o.x ?\?= 2;"
              "log"),
      njs_str("g") },
    { njs_str("var log = '';"
              "var o = {"
              "    get x() {log += 'g'; return null},"
              "    set x(v) {log += 's'}"
              "};"
              "o.x ?\?= 2;"
              "log"),
      njs_str("gs") },

    /* ??= short-circuit with non-writable property. */

    { njs_str("var o = {};"
              "Object.defineProperty(o, 'x', {value: 0, writable: false});"
              "o.x ?\?= 1"),
      njs_str("0") },

    /* ??= short-circuit with getter-only property. */

    { njs_str("var o = {};"
              "Object.defineProperty(o, 'x',"
              "    {get: function() {return 0}, set: undefined});"
              "o.x ?\?= 1"),
      njs_str("0") },

    /* ??= non-lvalue error */

    { njs_str("1 ?\?= 2"),
      njs_str("ReferenceError: Invalid left-hand side in assignment") },

    /* Optional chaining: property access. */

    { njs_str("var o = {a: 1}; o?.a"),
      njs_str("1") },

    { njs_str("var o = null; o?.a"),
      njs_str("undefined") },

    { njs_str("undefined?.a"),
      njs_str("undefined") },

    { njs_str("var o = {a: {b: 2}}; o?.a.b"),
      njs_str("2") },

    { njs_str("var o = null; o?.a.b"),
      njs_str("undefined") },

    /* Optional chaining: bracket access. */

    { njs_str("var o = {a: 1}; o?.['a']"),
      njs_str("1") },

    { njs_str("var o = null; o?.['a']"),
      njs_str("undefined") },

    /* Optional chaining: method call. */

    { njs_str("var o = {f: function() {return 42}}; o?.f()"),
      njs_str("42") },

    { njs_str("var o = null; o?.f()"),
      njs_str("undefined") },

    { njs_str("var o = { b() { return this._b; }, _b: { c: 42 }};"
              "o?.b().c"),
      njs_str("42") },

    { njs_str("var o = null;"
              "o?.b().c"),
      njs_str("undefined") },

    /* Optional chaining: optional call. */

    { njs_str("var f = function() {return 42}; f?.()"),
      njs_str("42") },

    { njs_str("var f = null; f?.()"),
      njs_str("undefined") },

    /* Optional chaining: nested. */

    { njs_str("var o = {a: {b: 3}}; o?.a?.b"),
      njs_str("3") },

    { njs_str("var o = {a: null}; o?.a?.b"),
      njs_str("undefined") },

    { njs_str("var o = null; o?.a?.b"),
      njs_str("undefined") },

    /* Optional chaining: short-circuit side effects. */

    { njs_str("var c = 0; var o = null; o?.a; c"),
      njs_str("0") },

    /* Optional chaining: delete semantics. */

    { njs_str("var o = null; delete o?.a"),
      njs_str("true") },

    { njs_str("var o = null; delete o?.['a']"),
      njs_str("true") },

    { njs_str("var o = {a: 1}; delete o?.a; o.a"),
      njs_str("undefined") },

    { njs_str("var o = {a: 1}; delete o?.['a']; o.a"),
      njs_str("undefined") },

    /* Optional chaining with ??. */

    { njs_str("var o = null; o?.a ?? 'default'"),
      njs_str("default") },

    { njs_str("var o = {a: 0}; o?.a ?? 'default'"),
      njs_str("0") },

    /* Optional chaining: advanced and corner cases. */

    { njs_str("var i = 0; var o = null; o?.[i++]; i"),
      njs_str("0") },

    { njs_str("var i = 0; var o = null; o?.f(i++); i"),
      njs_str("0") },

    { njs_str("var o = {x: 7, m: function() {return this.x}}; o.m?.()"),
      njs_str("7") },

    { njs_str("var o = {x: 9, m: function() {return this.x}}; o?.m?.()"),
      njs_str("9") },

    { njs_str("var i = 0; var o = {m: null}; o.m?.(i++); i"),
      njs_str("0") },

    { njs_str("var o = null; (o?.a).b"),
      njs_str("TypeError: cannot get property \"b\" of undefined") },

    { njs_str("var o = {a: null}; o?.a.b"),
      njs_str("TypeError: cannot get property \"b\" of null") },

    { njs_str("var o = null; o?.().a"),
      njs_str("undefined") },

    { njs_str("var o = function() {return {a: 1}}; o?.().a"),
      njs_str("1") },

    { njs_str("var o = {}; o?.()"),
      njs_str("TypeError: object is not a function") },

    { njs_str("var o = {x: 2, m: function() {return this.x}}; (o.m)?.()"),
      njs_str("2") },

    { njs_str("var o = {m: function() {return 42}}; (o?.m)()"),
      njs_str("42") },

    { njs_str("var o = {x: 5, m: function() {return this.x}}; (o?.m)()"),
      njs_str("5") },

    { njs_str("var o = {x: 3, m: function() {return {c: this.x}}};"
              "o.m?.().c"),
      njs_str("3") },

    { njs_str("var o = {x: 4, m: function() {return {c: this.x}}};"
              "(o.m)?.().c"),
      njs_str("4") },

    { njs_str("var o = {x: 6, m: function() {return {c: this.x}}};"
              "o?.m?.().c"),
      njs_str("6") },

    { njs_str("var o = {x: 8, m: function() {return {c: this.x}}};"
              "(o?.m)?.().c"),
      njs_str("8") },

    { njs_str("var k = 'm';"
              "var o = {x: 9, m: function() {return this.x}};"
              "(o?.[k])()"),
      njs_str("9") },

    { njs_str("var o = null; (o?.m)()"),
      njs_str("TypeError: undefined is not a function") },

    { njs_str("var o = {x: 7, t: function(s) {return this.x + s[0]}};"
              "o.t`!`"),
      njs_str("7!") },

    { njs_str("var o = {a: {b: 1}}; delete o?.a?.b; o.a.b"),
      njs_str("undefined") },

    { njs_str("var o = null; delete o?.a?.b"),
      njs_str("true") },

    /* Optional chaining: nested property + optional call. */

    { njs_str("var o = {a: {m: function() {return 42}}};"
              "o.a.m?.()"),
      njs_str("42") },

    { njs_str("var o = {a: {x: 7, m: function() {return this.x}}};"
              "o.a.m?.()"),
      njs_str("7") },

    { njs_str("var o = {a: {m: null}}; o.a.m?.()"),
      njs_str("undefined") },

    { njs_str("var o = {a: {m: function() {return 42}}};"
              "var k = 'a'; o[k].m?.()"),
      njs_str("42") },

    { njs_str("var o = {a: {m: function() {return 42}}};"
              "var e = 'a'; o?.[e].m?.()"),
      njs_str("42") },

    { njs_str("var o = null; o?.[0].m?.()"),
      njs_str("undefined") },

    { njs_str("var o = {a: {b: {m: function() {return 99}}}};"
              "o.a.b.m?.()"),
      njs_str("99") },

    /* Optional chaining: chained call with continuation. */

    { njs_str("var o = {a: function() { return {b: 42}; }};"
              "o?.a().b"),
      njs_str("42") },

    { njs_str("var o = null; o?.a().b"),
      njs_str("undefined") },

    { njs_str("var o = {a: function() { return {b: 42}; }};"
              "o?.a?.().b"),
      njs_str("42") },

    { njs_str("var o = null; o?.a?.().b"),
      njs_str("undefined") },

    /* Optional chaining: ternary disambiguation. */

    { njs_str("var r = 1 ? .5 : 2; r"),
      njs_str("0.5") },

    { njs_str("var r = 0 ? .5 : 2; r"),
      njs_str("2") },

    { njs_str("var a = {b: 1}; a?.b : 2"),
      njs_str("SyntaxError: Unexpected token \":\"") },

    { njs_str("var o = {c: 3}; var r = o ? o?.c : 0; r"),
      njs_str("3") },

    /* Optional chaining: not a valid assignment target. */

    { njs_str("var o = {a: 1}; o?.a = 2"),
      njs_str("ReferenceError: Invalid left-hand side in assignment") },

    { njs_str("var o = {a: 1}; o?.a++"),
      njs_str("ReferenceError: Invalid left-hand side in postfix operation") },

    { njs_str("var o = {a: 1}; ++o?.a"),
      njs_str("ReferenceError: Invalid left-hand side in prefix operation") },

    { njs_str("function F(){}; new F?.()"),
      njs_str("SyntaxError: Optional chaining cannot be used with new") },

    { njs_str("var o = {m: function() {}}; new o?.m()"),
      njs_str("SyntaxError: Optional chaining cannot be used with new") },

    { njs_str("var o = {m: function() {}}; new o.m?.()"),
      njs_str("SyntaxError: Optional chaining cannot be used with new") },

    { njs_str("var a = true; a = -~!a"),
      njs_str("1") },

    { njs_str("12 & 6"),
      njs_str("4") },

    { njs_str("-1 & 65536"),
      njs_str("65536") },

    { njs_str("-2147483648 & 65536"),
      njs_str("0") },

    { njs_str("9223372036854775808 & 65536"),
      njs_str("0") },

    { njs_str("NaN & 65536"),
      njs_str("0") },

    { njs_str("12 ^ 6"),
      njs_str("10") },

    { njs_str("-1 ^ 65536"),
      njs_str("-65537") },

    { njs_str("-2147483648 ^ 65536"),
      njs_str("-2147418112") },

    { njs_str("9223372036854775808 ^ 65536"),
      njs_str("65536") },

    { njs_str("NaN ^ 65536"),
      njs_str("65536") },

    { njs_str("var x = '1'; +x + 2"),
      njs_str("3") },

    /* Weird things. */

    { njs_str("'3' -+-+-+ '1' + '1' / '3' * '6' + '2'"),
      njs_str("42") },

    { njs_str("((+!![])+(+!![])+(+!![])+(+!![])+[])+((+!![])+(+!![])+[])"),
      njs_str("42") },

    { njs_str("1+[[]+[]]-[]+[[]-[]]-1"),
      njs_str("9") },

    { njs_str("[[]+[]]-[]+[[]-[]]"),
      njs_str("00") },

    { njs_str("!--[][1]"),
      njs_str("true") },

    { njs_str("[].concat[1,2,3]"),
      njs_str("undefined") },

    /**/

    { njs_str("'true' == true"),
      njs_str("false") },

    { njs_str("null == false"),
      njs_str("false") },

    { njs_str("0 == null"),
      njs_str("false") },

    { njs_str("!null"),
      njs_str("true") },

    { njs_str("0 === -0"),
      njs_str("true") },

    { njs_str("1/-0"),
      njs_str("-Infinity") },

    { njs_str("1/0 === 1/-0"),
      njs_str("false") },

    { njs_str("1 == true"),
      njs_str("true") },

    { njs_str("NaN === NaN"),
      njs_str("false") },

    { njs_str("NaN !== NaN"),
      njs_str("true") },

    { njs_str("NaN == NaN"),
      njs_str("false") },

    { njs_str("NaN != NaN"),
      njs_str("true") },

    { njs_str("NaN == false"),
      njs_str("false") },

    { njs_str("Infinity == Infinity"),
      njs_str("true") },

    { njs_str("-Infinity == -Infinity"),
      njs_str("true") },

    { njs_str("-Infinity < Infinity"),
      njs_str("true") },

    { njs_str("Infinity - Infinity"),
      njs_str("NaN") },

    { njs_str("Infinity - -Infinity"),
      njs_str("Infinity") },

    { njs_str("undefined == 0"),
      njs_str("false") },

    { njs_str("undefined == null"),
      njs_str("true") },

    { njs_str("'1' == 1"),
      njs_str("true") },

    { njs_str("'1a' == '1'"),
      njs_str("false") },

    { njs_str("'abc' == 'abc'"),
      njs_str("true") },

    { njs_str("'abc' < 'abcde'"),
      njs_str("true") },

    { njs_str("0 == ''"),
      njs_str("true") },

    { njs_str("0 == ' '"),
      njs_str("true") },

    { njs_str("0 == '  '"),
      njs_str("true") },

    { njs_str("0 == '0'"),
      njs_str("true") },

    { njs_str("0 == ' 0 '"),
      njs_str("true") },

    { njs_str("0 == '000'"),
      njs_str("true") },

    { njs_str("'0' == ''"),
      njs_str("false") },

    { njs_str("1 < 2"),
      njs_str("true") },

    { njs_str("NaN < NaN"),
      njs_str("false") },

    { njs_str("NaN > NaN"),
      njs_str("false") },

    { njs_str("undefined < 1"),
      njs_str("false") },

    { njs_str("[] == false"),
      njs_str("true") },

    { njs_str("[0] == false"),
      njs_str("true") },

    { njs_str("[0,0] == false"),
      njs_str("false") },

    { njs_str("({}) == false"),
      njs_str("false") },

    { njs_str("new Number(1) == new String('1')"),
      njs_str("false") },

    { njs_str("var a = Object; a == Object"),
      njs_str("true") },

    { njs_str("'1' == new Number(1)"),
      njs_str("true") },

    { njs_str("new Number(null) + ''"),
      njs_str("0") },

    { njs_str("new String('abc') == 'abc'"),
      njs_str("true") },

    { njs_str("false == new String('0')"),
      njs_str("true") },

    { njs_str("var a = { valueOf: function() { return 5 } };   a == 5"),
      njs_str("true") },

    { njs_str("var a = { valueOf: function() { return '5' } }; a == 5"),
      njs_str("true") },

    { njs_str("var a = { valueOf: function() { return '5' } }; a == '5'"),
      njs_str("true") },

    { njs_str("var a = { valueOf: function() { return 5 } }; a == '5'"),
      njs_str("true") },

    { njs_str("var a = { toString: function() { return true } }; '1' == a"),
      njs_str("true") },

    { njs_str("var a = { valueOf: function() { return 'b' },"
                 "          toString: function() { return 'a' } }; a == 'a'"),
      njs_str("false") },

    /* Comparisions. */

    { njs_str("1 < 2"),
      njs_str("true") },

    { njs_str("1 < 1"),
      njs_str("false") },

    { njs_str("1 <= 1"),
      njs_str("true") },

    { njs_str("1 <= 2"),
      njs_str("true") },

    { njs_str("2 > 1"),
      njs_str("true") },

    { njs_str("1 > 2"),
      njs_str("false") },

    { njs_str("1 > 1"),
      njs_str("false") },

    { njs_str("1 >= 1"),
      njs_str("true") },

    { njs_str("2 >= 1"),
      njs_str("true") },

    { njs_str("1 >= 2"),
      njs_str("false") },

    /**/

    { njs_str("null === null"),
      njs_str("true") },

    { njs_str("null !== null"),
      njs_str("false") },

    { njs_str("null == null"),
      njs_str("true") },

    { njs_str("null != null"),
      njs_str("false") },

    { njs_str("null < null"),
      njs_str("false") },

    { njs_str("null > null"),
      njs_str("false") },

    { njs_str("null <= null"),
      njs_str("true") },

    { njs_str("null >= null"),
      njs_str("true") },

    /**/

    { njs_str("null === undefined"),
      njs_str("false") },

    { njs_str("null !== undefined"),
      njs_str("true") },

    { njs_str("null == undefined"),
      njs_str("true") },

    { njs_str("null != undefined"),
      njs_str("false") },

    { njs_str("null < undefined"),
      njs_str("false") },

    { njs_str("null > undefined"),
      njs_str("false") },

    { njs_str("null <= undefined"),
      njs_str("false") },

    { njs_str("null >= undefined"),
      njs_str("false") },

    /**/

    { njs_str("null === false"),
      njs_str("false") },

    { njs_str("null !== false"),
      njs_str("true") },

    { njs_str("null == false"),
      njs_str("false") },

    { njs_str("null != false"),
      njs_str("true") },

    { njs_str("null < false"),
      njs_str("false") },

    { njs_str("null > false"),
      njs_str("false") },

    { njs_str("null <= false"),
      njs_str("true") },

    { njs_str("null >= false"),
      njs_str("true") },

    /**/

    { njs_str("null === true"),
      njs_str("false") },

    { njs_str("null !== true"),
      njs_str("true") },

    { njs_str("null == true"),
      njs_str("false") },

    { njs_str("null != true"),
      njs_str("true") },

    { njs_str("null < true"),
      njs_str("true") },

    { njs_str("null > true"),
      njs_str("false") },

    { njs_str("null <= true"),
      njs_str("true") },

    { njs_str("null >= true"),
      njs_str("false") },

    /**/

    { njs_str("Infinity === Infinity"),
      njs_str("true") },

    { njs_str("Infinity !== Infinity"),
      njs_str("false") },

    { njs_str("Infinity == Infinity"),
      njs_str("true") },

    { njs_str("Infinity != Infinity"),
      njs_str("false") },

    { njs_str("Infinity < Infinity"),
      njs_str("false") },

    { njs_str("Infinity > Infinity"),
      njs_str("false") },

    { njs_str("Infinity <= Infinity"),
      njs_str("true") },

    { njs_str("Infinity >= Infinity"),
      njs_str("true") },

    /**/

    { njs_str("-Infinity === Infinity"),
      njs_str("false") },

    { njs_str("-Infinity !== Infinity"),
      njs_str("true") },

    { njs_str("-Infinity == Infinity"),
      njs_str("false") },

    { njs_str("-Infinity != Infinity"),
      njs_str("true") },

    { njs_str("-Infinity < Infinity"),
      njs_str("true") },

    { njs_str("-Infinity > Infinity"),
      njs_str("false") },

    { njs_str("-Infinity <= Infinity"),
      njs_str("true") },

    { njs_str("-Infinity >= Infinity"),
      njs_str("false") },

    { njs_str("Boolean(Infinity)"),
      njs_str("true") },

    { njs_str("!Infinity === false"),
      njs_str("true") },

    { njs_str("var Infinity"),
      njs_str("undefined") },

    { njs_str("Infinity = 1"),
      njs_str("TypeError: Cannot assign to read-only property \"Infinity\" of object") },

    /**/

    { njs_str("NaN === NaN"),
      njs_str("false") },

    { njs_str("NaN !== NaN"),
      njs_str("true") },

    { njs_str("NaN == NaN"),
      njs_str("false") },

    { njs_str("NaN != NaN"),
      njs_str("true") },

    { njs_str("NaN < NaN"),
      njs_str("false") },

    { njs_str("NaN > NaN"),
      njs_str("false") },

    { njs_str("NaN >= NaN"),
      njs_str("false") },

    { njs_str("NaN <= NaN"),
      njs_str("false") },

    { njs_str("var NaN"),
      njs_str("undefined") },

    { njs_str("NaN = 1"),
      njs_str("TypeError: Cannot assign to read-only property \"NaN\" of object") },

    /**/

    { njs_str("null < 0"),
      njs_str("false") },

    { njs_str("null < 1"),
      njs_str("true") },

    { njs_str("null < NaN"),
      njs_str("false") },

    { njs_str("null < -Infinity"),
      njs_str("false") },

    { njs_str("null < Infinity"),
      njs_str("true") },

    { njs_str("null < 'null'"),
      njs_str("false") },

    { njs_str("null < '1'"),
      njs_str("true") },

    { njs_str("null < [1]"),
      njs_str("true") },

    { njs_str("null < ({})"),
      njs_str("false") },

    { njs_str("var a = { valueOf: function() { return 1 } };     null < a"),
      njs_str("true") },

    { njs_str("var a = { valueOf: function() { return 'null' } };null < a"),
      njs_str("false") },

    { njs_str("var a = { valueOf: function() { return '1' } };   null < a"),
      njs_str("true") },

    { njs_str("1 < {valueOf: ()=>{throw 'x'}}"),
      njs_str("x") },

    { njs_str("({valueOf: ()=>{throw 'x'}}) <= ({valueOf:()=>{throw 'y'}})"),
      njs_str("x") },

    { njs_str("({valueOf:()=>{throw 'x'}}) > ({valueOf:()=>{throw 'y'}})"),
      njs_str("x") },

    /**/

    { njs_str("undefined == undefined"),
      njs_str("true") },

    { njs_str("undefined != undefined"),
      njs_str("false") },

    { njs_str("undefined === undefined"),
      njs_str("true") },

    { njs_str("undefined !== undefined"),
      njs_str("false") },

    { njs_str("undefined < undefined"),
      njs_str("false") },

    { njs_str("undefined < null"),
      njs_str("false") },

    { njs_str("undefined < false"),
      njs_str("false") },

    { njs_str("undefined < true"),
      njs_str("false") },

    { njs_str("undefined < 0"),
      njs_str("false") },

    { njs_str("undefined < 1"),
      njs_str("false") },

    { njs_str("undefined < NaN"),
      njs_str("false") },

    { njs_str("undefined < -Infinity"),
      njs_str("false") },

    { njs_str("undefined < Infinity"),
      njs_str("false") },

    { njs_str("undefined < 'undefined'"),
      njs_str("false") },

    { njs_str("undefined < '1'"),
      njs_str("false") },

    { njs_str("undefined < [1]"),
      njs_str("false") },

    { njs_str("undefined < ({})"),
      njs_str("false") },

    { njs_str("var a = { valueOf: function() { return 1 } }; undefined < a"),
      njs_str("false") },

    { njs_str("var a = { valueOf: function() { return 'undefined' } };"
                 "undefined < a"),
      njs_str("false") },

    { njs_str("var a = { valueOf: function() { return '1' } };"
                 "undefined < a"),
      njs_str("false") },

    /**/

    { njs_str("false < 1"),
      njs_str("true") },

    { njs_str("true < 1"),
      njs_str("false") },

    { njs_str("-1 < 1"),
      njs_str("true") },

    { njs_str("-1 < '1'"),
      njs_str("true") },

    { njs_str("NaN < NaN"),
      njs_str("false") },

    { njs_str("-Infinity < Infinity"),
      njs_str("true") },

    { njs_str("Infinity < -Infinity"),
      njs_str("false") },

    { njs_str("1 < 'abc'"),
      njs_str("false") },

    /**/

    { njs_str("[] === []"),
      njs_str("false") },

    { njs_str("[] !== []"),
      njs_str("true") },

    { njs_str("[] == []"),
      njs_str("false") },

    { njs_str("[] != []"),
      njs_str("true") },

    { njs_str("[] < []"),
      njs_str("false") },

    { njs_str("[] > []"),
      njs_str("false") },

    { njs_str("[] >= []"),
      njs_str("true") },

    { njs_str("[] <= []"),
      njs_str("true") },

    /**/

    { njs_str("({}) === ({})"),
      njs_str("false") },

    { njs_str("({}) !== ({})"),
      njs_str("true") },

    { njs_str("({}) == ({})"),
      njs_str("false") },

    { njs_str("({}) != ({})"),
      njs_str("true") },

    { njs_str("({}) > ({})"),
      njs_str("false") },

    { njs_str("({}) <= ({})"),
      njs_str("true") },

    { njs_str("({}) >= ({})"),
      njs_str("true") },

    /**/

    { njs_str("[0] == ({})"),
      njs_str("false") },

    { njs_str("[0] != ({})"),
      njs_str("true") },

    { njs_str("[0] <= ({})"),
      njs_str("true") },

    { njs_str("[0] >= ({})"),
      njs_str("false") },

    /**/
    { njs_str("new String('1') > new Number(1)"),
      njs_str("false") },

    { njs_str("new Boolean(true) > '1'"),
      njs_str("false") },

    { njs_str("'0' >= new Number(1)"),
      njs_str("false") },

    { njs_str("'1' >= new Number(1)"),
      njs_str("true") },

    { njs_str("new String('1') < new Number(1)"),
      njs_str("false") },

    { njs_str("new Boolean(true) < '1'"),
      njs_str("false") },

    { njs_str("new String('1') <= new Number(1)"),
      njs_str("true") },

    { njs_str("new Boolean(true) <= '1'"),
      njs_str("true") },

    { njs_str("'-1' < {valueOf: function() {return -2}}"),
      njs_str("false") },

    { njs_str("new 0[isNaN]"),
      njs_str("TypeError: undefined is not a function") },

    { njs_str("new 0[undefined]"),
      njs_str("TypeError: undefined is not a function") },

    /**/

    { njs_str("var a; a = 1 ? 2 : 3"),
      njs_str("2") },

    { njs_str("var a; a = 1 ? 2 : 3 ? 4 : 5"),
      njs_str("2") },

    { njs_str("var a; a = 0 ? 2 : 3 ? 4 : 5"),
      njs_str("4") },

    { njs_str("0 ? 2 ? 3 : 4 : 5"),
      njs_str("5") },

    { njs_str("1 ? 2 ? 3 : 4 : 5"),
      njs_str("3") },

    { njs_str("1 ? 0 ? 3 : 4 : 5"),
      njs_str("4") },

    { njs_str("(1 ? 0 : 3) ? 4 : 5"),
      njs_str("5") },

    { njs_str("var a; a = (1 + 2) ? 2 ? 3 + 4 : 5 : 6"),
      njs_str("7") },

    { njs_str("var a; a = (1 ? 2 : 3) + 4"),
      njs_str("6") },

    { njs_str("var a, b; a = 1 ? b = 2 + 4 : b = 3"),
      njs_str("6") },

    { njs_str("var a; a = 1 ? [1,2] : []"),
      njs_str("1,2") },

    /**/

    { njs_str("var a = { valueOf: function() { return 1 } };   +a"),
      njs_str("1") },

    { njs_str("var a = { valueOf: function() { return '1' } }; +a"),
      njs_str("1") },

    { njs_str("var a = { valueOf: function() { return 1 } };   -a"),
      njs_str("-1") },

    { njs_str("var a = { valueOf: function() { return '1' } }; -a"),
      njs_str("-1") },

    /* Increment. */

    { njs_str("var a = 1;   ++a"),
      njs_str("2") },

    { njs_str("var a = '1'; ++a"),
      njs_str("2") },

    { njs_str("var a = [1]; ++a"),
      njs_str("2") },

    { njs_str("var a = {};  ++a"),
      njs_str("NaN") },

    { njs_str("var a = [1,2,3]; var b = 1; b = ++a[b]; b + ' '+ a"),
      njs_str("3 1,3,3") },

    { njs_str("var a = { valueOf: function() { return 1 } };"
                 "++a +' '+ a +' '+ typeof a"),
      njs_str("2 2 number") },

    { njs_str("var a = { valueOf: function() { return '1' } };"
                 "++a +' '+ a +' '+ typeof a"),
      njs_str("2 2 number") },

    { njs_str("var a = { valueOf: function() { return [1] } };"
                 "++a +' '+ a +' '+ typeof a"),
      njs_str("NaN NaN number") },

    { njs_str("var a = { valueOf: function() { return {} } };"
                 "++a +' '+ a +' '+ typeof a"),
      njs_str("NaN NaN number") },

    /**/

    { njs_str("var a = 1;   a = ++a"),
      njs_str("2") },

    { njs_str("var a = '1'; a = ++a"),
      njs_str("2") },

    { njs_str("var a = [1]; a = ++a"),
      njs_str("2") },

    { njs_str("var a = {};  a = ++a"),
      njs_str("NaN") },

    { njs_str("var a = { valueOf: function() { return 1 } };   a = ++a"),
      njs_str("2") },

    { njs_str("var a = { valueOf: function() { return '1' } }; a = ++a"),
      njs_str("2") },

    { njs_str("var a = { valueOf: function() { return [1] } }; a = ++a"),
      njs_str("NaN") },

    { njs_str("var a = { valueOf: function() { return {} } };  a = ++a"),
      njs_str("NaN") },

    /**/

    { njs_str("var a = 1;   var b = ++a; a +' '+ b"),
      njs_str("2 2") },

    { njs_str("var a = '1'; var b = ++a; a +' '+ b"),
      njs_str("2 2") },

    { njs_str("var a = [1]; var b = ++a; a +' '+ b"),
      njs_str("2 2") },

    { njs_str("var a = {};  var b = ++a; a +' '+ b"),
      njs_str("NaN NaN") },

    { njs_str("var a = { valueOf: function() { return 1 } };"
                 "var b = ++a; a +' '+ b"),
      njs_str("2 2") },

    { njs_str("var a = { valueOf: function() { return '1' } };"
                 "var b = ++a; a +' '+ b"),
      njs_str("2 2") },

    { njs_str("var a = { valueOf: function() { return [1] } };"
                 "var b = ++a; a +' '+ b"),
      njs_str("NaN NaN") },

    { njs_str("var a = { valueOf: function() { return {} } };"
                 "var b = ++a; a +' '+ b"),
      njs_str("NaN NaN") },

    { njs_str("var a = 0; a = a + ++a; a"),
      njs_str("1") },

    { njs_str("var a = 0; a += a + ++a; a"),
      njs_str("1") },

    { njs_str("var i = 0, arr = ['a', 'b'];"
              "arr[i] = arr[i] + arr[++i]; arr"),
      njs_str("ab,b") },

    { njs_str("var i = 0, arr = ['a', 'b'];"
              "arr[i] += arr[i] + arr[++i]; arr"),
      njs_str("aab,b") },

    /* Post increment. */

    { njs_str("var a = 1;   a++"),
      njs_str("1") },

    { njs_str("var a = '1'; a++"),
      njs_str("1") },

    { njs_str("var a = [1]; a++"),
      njs_str("1") },

    { njs_str("var a = {};  a++"),
      njs_str("NaN") },

    { njs_str("var a = { valueOf: function() { return 1 } };   a++"),
      njs_str("1") },

    { njs_str("var a = { valueOf: function() { return '1' } }; a++"),
      njs_str("1") },

    { njs_str("var a = { valueOf: function() { return [1] } }; a++"),
      njs_str("NaN") },

    { njs_str("var a = { valueOf: function() { return {} } };  a++"),
      njs_str("NaN") },

    /**/

    { njs_str("var a = 1;   a = a++"),
      njs_str("1") },

    { njs_str("var a = '1'; a = a++"),
      njs_str("1") },

    { njs_str("var a = [1]; a = a++"),
      njs_str("1") },

    { njs_str("var a = {};  a = a++"),
      njs_str("NaN") },

    { njs_str("var a = { valueOf: function() { return 1 } };   a = a++"),
      njs_str("1") },

    { njs_str("var a = { valueOf: function() { return '1' } }; a = a++"),
      njs_str("1") },

    { njs_str("var a = { valueOf: function() { return [1] } }; a = a++"),
      njs_str("NaN") },

    { njs_str("var a = { valueOf: function() { return {} } };  a = a++"),
      njs_str("NaN") },

    /**/

    { njs_str("var a = 1;   var b = a++; a +' '+ b"),
      njs_str("2 1") },

    { njs_str("var a = '1'; var b = a++; a +' '+ b"),
      njs_str("2 1") },

    { njs_str("var a = [1]; var b = a++; a +' '+ b"),
      njs_str("2 1") },

    { njs_str("var a = {};  var b = a++; a +' '+ b"),
      njs_str("NaN NaN") },

    { njs_str("var a = { valueOf: function() { return 1 } };"
                 "var b = a++; a +' '+ b"),
      njs_str("2 1") },

    { njs_str("var a = { valueOf: function() { return '1' } };"
                 "var b = a++; a +' '+ b"),
      njs_str("2 1") },

    { njs_str("var a = { valueOf: function() { return [1] } };"
                 "var b = a++; a +' '+ b"),
      njs_str("NaN NaN") },

    { njs_str("var a = { valueOf: function() { return {} } };"
                 "var b = a++; a +' '+ b"),
      njs_str("NaN NaN") },

    { njs_str("var a = 0; a = a + a++; a"),
      njs_str("0") },

    { njs_str("var a = 0; a += a + a++; a"),
      njs_str("0") },

    { njs_str("var i = 1, arr = ['a', 'b'];"
              "arr[i] = arr[i] + arr[i++]; arr"),
      njs_str("a,bb") },

    { njs_str("var i = 1, arr = ['a', 'b'];"
              "arr[i] += arr[i] + arr[i++]; arr"),
      njs_str("a,bbb") },

    /* Decrement. */

    { njs_str("var a = 1;   --a"),
      njs_str("0") },

    { njs_str("var a = '1'; --a"),
      njs_str("0") },

    { njs_str("var a = [1]; --a"),
      njs_str("0") },

    { njs_str("var a = {};  --a"),
      njs_str("NaN") },

    { njs_str("var a = { valueOf: function() { return 1} };   --a"),
      njs_str("0") },

    { njs_str("var a = { valueOf: function() { return '1'} }; --a"),
      njs_str("0") },

    { njs_str("var a = { valueOf: function() { return [1]} }; --a"),
      njs_str("NaN") },

    { njs_str("var a = { valueOf: function() { return {} } }; --a"),
      njs_str("NaN") },

    /**/

    { njs_str("var a = 1;   a = --a"),
      njs_str("0") },

    { njs_str("var a = '1'; a = --a"),
      njs_str("0") },

    { njs_str("var a = [1]; a = --a"),
      njs_str("0") },

    { njs_str("var a = {};  a = --a"),
      njs_str("NaN") },

    { njs_str("var a = { valueOf: function() { return 1} };   a = --a"),
      njs_str("0") },

    { njs_str("var a = { valueOf: function() { return '1'} }; a = --a"),
      njs_str("0") },

    { njs_str("var a = { valueOf: function() { return [1]} }; a = --a"),
      njs_str("NaN") },

    { njs_str("var a = { valueOf: function() { return {} } }; a = --a"),
      njs_str("NaN") },

    /**/

    { njs_str("var a = 1;   var b = --a; a +' '+ b"),
      njs_str("0 0") },

    { njs_str("var a = '1'; var b = --a; a +' '+ b"),
      njs_str("0 0") },

    { njs_str("var a = [1]; var b = --a; a +' '+ b"),
      njs_str("0 0") },

    { njs_str("var a = {};  var b = --a; a +' '+ b"),
      njs_str("NaN NaN") },

    { njs_str("var a = { valueOf: function() { return 1 } };"
                 "var b = --a; a +' '+ b"),
      njs_str("0 0") },

    { njs_str("var a = { valueOf: function() { return '1' } };"
                 "var b = --a; a +' '+ b"),
      njs_str("0 0") },

    { njs_str("var a = { valueOf: function() { return [1] } };"
                 "var b = --a; a +' '+ b"),
      njs_str("NaN NaN") },

    { njs_str("var a = { valueOf: function() { return {} } };"
                 "var b = --a; a +' '+ b"),
      njs_str("NaN NaN") },

    { njs_str("var a = 0; a = a + --a; a"),
      njs_str("-1") },

    { njs_str("var a = 0; a -= a + --a; a"),
      njs_str("1") },

    { njs_str("var i = 1, arr = ['a', 'b'];"
              "arr[i] = arr[i] + arr[--i]; arr"),
      njs_str("a,ba") },

    { njs_str("var i = 1, arr = ['a', 'b'];"
              "arr[i] += arr[i] + arr[--i]; arr"),
      njs_str("a,bba") },

    /* Post decrement. */

    { njs_str("var a = 1;   a--"),
      njs_str("1") },

    { njs_str("var a = '1'; a--"),
      njs_str("1") },

    { njs_str("var a = [1]; a--"),
      njs_str("1") },

    { njs_str("var a = {};  a--"),
      njs_str("NaN") },

    { njs_str("var a = { valueOf: function() { return 1 } };   a--"),
      njs_str("1") },

    { njs_str("var a = { valueOf: function() { return '1' } }; a--"),
      njs_str("1") },

    { njs_str("var a = { valueOf: function() { return [1] } }; a--"),
      njs_str("NaN") },

    { njs_str("var a = { valueOf: function() { return {} } };  a--"),
      njs_str("NaN") },

    /**/

    { njs_str("var a = 1;   a = a--"),
      njs_str("1") },

    { njs_str("var a = '1'; a = a--"),
      njs_str("1") },

    { njs_str("var a = [1]; a = a--"),
      njs_str("1") },

    { njs_str("var a = {};  a = a--"),
      njs_str("NaN") },

    { njs_str("var a = { valueOf: function() { return 1 } };   a = a--"),
      njs_str("1") },

    { njs_str("var a = { valueOf: function() { return '1' } }; a = a--"),
      njs_str("1") },

    { njs_str("var a = { valueOf: function() { return [1] } }; a = a--"),
      njs_str("NaN") },

    { njs_str("var a = { valueOf: function() { return {} } };  a = a--"),
      njs_str("NaN") },

    /**/

    { njs_str("var a = 1;   var b = a--; a +' '+ b"),
      njs_str("0 1") },

    { njs_str("var a = '1'; var b = a--; a +' '+ b"),
      njs_str("0 1") },

    { njs_str("var a = [1]; var b = a--; a +' '+ b"),
      njs_str("0 1") },

    { njs_str("var a = {};  var b = a--; a +' '+ b"),
      njs_str("NaN NaN") },

    { njs_str("var a = { valueOf: function() { return 1 } };"
                 "var b = a--; a +' '+ b"),
      njs_str("0 1") },

    { njs_str("var a = { valueOf: function() { return '1' } };"
                 "var b = a--; a +' '+ b"),
      njs_str("0 1") },

    { njs_str("var a = { valueOf: function() { return [1] } };"
                 "var b = a--; a +' '+ b"),
      njs_str("NaN NaN") },

    { njs_str("var a = { valueOf: function() { return {} } };"
                 "var b = a--; a +' '+ b"),
      njs_str("NaN NaN") },

    { njs_str("var a = 0; a = a + a--; a"),
      njs_str("0") },

    { njs_str("var a = 0; a += a + a--; a"),
      njs_str("0") },

    { njs_str("var i = 1, arr = ['a', 'b'];"
              "arr[i] = arr[i] + arr[i--]; arr"),
      njs_str("a,bb") },

    { njs_str("var i = 1, arr = ['a', 'b'];"
              "arr[i] += arr[i] + arr[i--]; arr"),
      njs_str("a,bbb") },

    /**/

    { njs_str("var a, b; a = 2; b = ++a + ++a; a + ' ' + b"),
      njs_str("4 7") },

    { njs_str("var a, b; a = 2; b = a++ + a++; a + ' ' + b"),
      njs_str("4 5") },

    { njs_str("var a, b; a = b = 7; a +' '+ b"),
      njs_str("7 7") },

    { njs_str("var a, b, c; a = b = c = 5; a +' '+ b +' '+ c"),
      njs_str("5 5 5") },

    { njs_str("var a, b, c; a = b = (c = 5) + 2; a +' '+ b +' '+ c"),
      njs_str("7 7 5") },

    { njs_str("1, 2 + 5, 3"),
      njs_str("3") },

    { njs_str("var a, b; a = 1 /* YES */\n b = a + 2 \n \n + 1 \n + 3"),
      njs_str("7") },

    { njs_str("var a, b; a = 1 // YES \n b = a + 2 \n \n + 1 \n + 3"),
      njs_str("7") },

    { njs_str("var a; a = 0; ++ \n a"),
      njs_str("1") },

    { njs_str("var a; a = 0\n ++a"),
      njs_str("1") },

    { njs_str("a = 0; a \n ++"),
      njs_str("SyntaxError: Unexpected end of input") },

    { njs_str("a = 0; a \n --"),
      njs_str("SyntaxError: Unexpected end of input") },

    { njs_str("var a = 0; a \n + 1"),
      njs_str("1") },

    { njs_str("var a = 0; a \n +\n 1"),
      njs_str("1") },

    { njs_str("var a; a = 1 ? 2 \n : 3"),
      njs_str("2") },

    { njs_str("var a, b, c;"
                 "a = 0 / 0; b = 1 / 0; c = -1 / 0; a +' '+ b +' '+ c"),
      njs_str("NaN Infinity -Infinity") },

    { njs_str("var a, b; a = (b = 7) + 5; var c; a +' '+ b +' '+ c"),
      njs_str("12 7 undefined") },

    { njs_str("var a, b = 1, c; a +' '+ b +' '+ c"),
      njs_str("undefined 1 undefined") },

    { njs_str("var a = 1, b = a + 1; a +' '+ b"),
      njs_str("1 2") },

    { njs_str("var a; a = a = 1"),
      njs_str("1") },

    { njs_str("var a = 1, \n b; a +' '+ b"),
      njs_str("1 undefined") },

    { njs_str("var a; a = b + 1; var b; a +' '+ b"),
      njs_str("NaN undefined") },

    { njs_str("var a += 1"),
      njs_str("SyntaxError: Unexpected token \"+=\"") },

    { njs_str("var a = a + 1"),
      njs_str("undefined") },

    { njs_str("var a; a = b + 1; var b = 1; a +' '+ b"),
      njs_str("NaN 1") },

    { njs_str("var a; (a) = 1"),
      njs_str("1") },

    { njs_str("a"),
      njs_str("ReferenceError: \"a\" is not defined") },

    { njs_str("\na"),
      njs_str("ReferenceError: \"a\" is not defined") },

    { njs_str("\n\na"),
      njs_str("ReferenceError: \"a\" is not defined") },

    { njs_str("a + a"),
      njs_str("ReferenceError: \"a\" is not defined") },

    { njs_str("a = b + 1"),
      njs_str("ReferenceError: \"a\" is not defined") },

    { njs_str("a = a + 1"),
      njs_str("ReferenceError: \"a\" is not defined") },

    { njs_str("a += 1"),
      njs_str("ReferenceError: \"a\" is not defined") },

    { njs_str("a += 1; var a = 2"),
      njs_str("undefined") },

    { njs_str("var a = 1"),
      njs_str("undefined") },

    { njs_str("var a = 1; a = (a = 2) + a"),
      njs_str("4") },

    { njs_str("var a = 1; a = a + (a = 2)"),
      njs_str("3") },

    { njs_str("var a = 1; a += (a = 2)"),
      njs_str("3") },

    { njs_str("var a = b = 1; var b; a +' '+ b"),
      njs_str("1 1") },

    { njs_str("var a \n if (!a) a = 3; a"),
      njs_str("3") },

    /* automatic semicolon insertion. */

    { njs_str("(a\n--"),
      njs_str("SyntaxError: Unexpected token \"--\"") },

    { njs_str("(a\n++"),
      njs_str("SyntaxError: Unexpected token \"++\"") },

    { njs_str("var x = 0, y = 2; x\n--\ny; [x,y]"),
      njs_str("0,1") },

    { njs_str("function f() {return\n}"),
      njs_str("undefined") },

    /* if. */

    { njs_str("if (0);"),
      njs_str("undefined") },

    { njs_str("if (0) {}"),
      njs_str("undefined") },

    { njs_str("if (0);else;"),
      njs_str("undefined") },

    { njs_str("var a = 1; if (true); else a = 2; a"),
      njs_str("1") },

    { njs_str("var a = 1; if (false); else a = 2; a"),
      njs_str("2") },

    { njs_str("var a = 1; if (true) a = 2; else a = 3; a"),
      njs_str("2") },

    { njs_str("var a = 3; if (true) if (false); else a = 2; a"),
      njs_str("2") },

    { njs_str("var a = 3; if (true) if (false); else; a = 2; a"),
      njs_str("2") },

    { njs_str("var a = [3], b; if (1==1||2==2) { b = '1'+'2'+a[0] }; b"),
      njs_str("123") },

    { njs_str("(function(){ if(true) return 1 else return 0; })()"),
      njs_str("SyntaxError: Unexpected token \"else\"") },

    { njs_str("(function(){ if(true) return 1; else return 0; })()"),
      njs_str("1") },

    { njs_str("(function(){ if(true) return 1;; else return 0; })()"),
      njs_str("SyntaxError: Unexpected token \"else\"") },

    { njs_str("(function(){ if(true) return 1\n else return 0; })()"),
      njs_str("1") },

    { njs_str("(function(){ if(true) return 1\n;\n else return 0; })()"),
      njs_str("1") },

    { njs_str("function f(n) {if (n) throw 'foo' else return 1}; f(0)"),
      njs_str("SyntaxError: Unexpected token \"else\"") },

    { njs_str("function f(n) {if (n)\n throw 'foo'\nelse return 1}; f(0)"),
      njs_str("1") },

    { njs_str("function f(n) {if (n)\n throw 'foo'\nelse return 1}; f(1)"),
      njs_str("foo") },

    { njs_str("function f(n) {if (n == 1) throw 'foo'\nelse if (n == 2) return 1}; f(2)"),
      njs_str("1") },

    { njs_str("(function(){ for (var p in [1] ){ if (1) break else return 0; }})()"),
      njs_str("SyntaxError: Unexpected token \"else\"") },

    { njs_str("(function(){ for (var p in [1] ){ if (1) break\n else return 0; }})()"),
      njs_str("undefined") },

    { njs_str("(function(){ for (var p in [1] ){ if (1) break; else return 0; }})()"),
      njs_str("undefined") },

    { njs_str("(function(){ for (var p in [1] ){ if (1) continue else return 0; }})()"),
      njs_str("SyntaxError: Unexpected token \"else\"") },

    { njs_str("(function(){ for (var p in [1] ){ if (1) continue\n else return 0; }})()"),
      njs_str("undefined") },

    { njs_str("(function(){ for (var p in [1] ){ if (1) continue; else return 0; }})()"),
      njs_str("undefined") },

    { njs_str("(function(x){ if\n(x) return -1; else return 0; })(0)"),
      njs_str("0") },

    { njs_str("(function(x){ if\n(\nx) return -1; else return 0; })(0)"),
      njs_str("0") },

    { njs_str("(function(x){ if\n(\nx)\nreturn -1; else return 0; })(0)"),
      njs_str("0") },

    { njs_str("(function(x){ if\n(\nx)\nreturn -1\n else return 0; })(0)"),
      njs_str("0") },

    { njs_str("(function(x){ if\n(\nx)\nreturn -1\n else\nreturn 0; })(0)"),
      njs_str("0") },

    /* do while. */

    { njs_str("do { break } if (false)"),
      njs_str("SyntaxError: Unexpected token \"if\"") },

    /* for in. */

    { njs_str("for (null in undefined);"),
      njs_str("ReferenceError: Invalid left-hand side \"null\" in for-in statement") },

    { njs_str("for (var a, b in []);"),
      njs_str("SyntaxError: Unexpected token \"in\"") },

    { njs_str("var s = ''; for (var p in [1,2]) {s += p}; s"),
      njs_str("01") },

    { njs_str("var s; for (var p in [1]) {s = typeof(p)}; s"),
      njs_str("string") },

    { njs_str("var s = ''; for (var p in {a:1, b:2}) {s += p}; s"),
      njs_str("ab") },

    { njs_str("var s = '';"
                 "var o = Object.defineProperty({}, 'x', {value:1});"
                 "Object.defineProperty(o, 'y', {value:2, enumerable:true});"
                 "for (var p in o) {s += p}; s"),
      njs_str("y") },

    { njs_str("var o = {a:1, b:2}; var arr = []; "
                 "for (var a in o) {arr.push(a)}; arr"),
      njs_str("a,b") },

    { njs_str("var o = {a:1, b:2}; var arr = []; delete o.a; "
                 "for (var a in o) {arr.push(a)}; arr"),
      njs_str("b") },

    { njs_str("var a = []; for (var k in new Uint8Array([1,2,3])) { a.push(k); }; a"),
      njs_str("0,1,2") },

    { njs_str("var dst = {}; for (dst.a in {x: 1}) {} dst.a"),
      njs_str("x") },

    { njs_str("var dst = {}; for ((dst.a) in {x: 1}) {} dst.a"),
      njs_str("x") },

    { njs_str("var i=0, a=[], r=[], d=[3,5];"
              "function ret_a() {r.push('ret_a'); return a};"
              "function ret_d() {r.push('ret_d'); return d};"
              "for (ret_a()[i++] in 0 || ret_d()) {d[2]=22; r.push(a)}; r"),
      njs_str("ret_d,ret_a,0,1,ret_a,0,1") },

    { njs_str("this.a = 0; for (a in {b:1}) {}; a;"),
      njs_str("b") },

    { njs_str("for (var x = x in [1,2]; ; ) {break};"),
      njs_str("SyntaxError: Invalid left-hand side in for-loop") },

    { njs_str("for (x = x in [1,2]; ; ) {break};"),
      njs_str("SyntaxError: Invalid left-hand side in for-loop") },

    { njs_str("for (var x = (x in [1,2]); ; ) {break}; x;"),
      njs_str("false") },

    { njs_str("var x; for (x = (x in [1,2]); ; ) {break}; x;"),
      njs_str("false") },

    { njs_str("for (++a in {}; ; ) {break}"),
      njs_str("SyntaxError: Invalid left-hand side in for-loop") },

    { njs_str("var a, b, c, d = 1; for (a + b, c = d; ; ){break}; c"),
      njs_str("1") },

    { njs_str("var x = 1, y, z = 'a', u = {a:1};"
              "for (var a = x, y = z in u; ; ) {break}; y"),
      njs_str("SyntaxError: Invalid left-hand side in for-loop") },

    { njs_str("var x = 1, y, z = 'a', u = {a:1};"
              "for (var a = x, y= (z in u) ; ; ) {break}; y"),
      njs_str("true") },

    { njs_str("var a = 0; for (++a; ; ) {break}; a"),
      njs_str("1") },

    { njs_str("var a = 0; for (a++; ; ) {break}; a"),
      njs_str("1") },

    { njs_str("var a = 0; for (+a; ; ) {break}; a"),
      njs_str("0") },

    { njs_str("for (in + j;;) {}"),
      njs_str("SyntaxError: Unexpected token \"in\"") },

    { njs_str("for (true ? 0 in {}: 0; false; ) ;"),
      njs_str("undefined") },

    { njs_str("for (true ? 0 : 0 in {}; false; ) ;"),
      njs_str("SyntaxError: Invalid left-hand side in for-loop") },

    { njs_str("for ((a in b)) {}"),
      njs_str("SyntaxError: Unexpected token \")\"") },

    { njs_str("var a='a', b={b:1}; for ((a in b); ; ) {break}; a"),
      njs_str("a") },

    { njs_str("for ((a,b,c) => {};;) {break}"),
      njs_str("undefined") },

    { njs_str("for(I in``[)8"),
      njs_str("SyntaxError: Unexpected token \")\"") },

    { njs_str("for(9A=>>"),
      njs_str("SyntaxError: Unexpected token \"9A\"") },

    { njs_str("for(A?{,"),
      njs_str("SyntaxError: Unexpected token \",\"") },

    { njs_str("for(Symbol(A=>A+       in 'A') P/$"),
      njs_str("SyntaxError: Unexpected token \"in\"") },

    { njs_str("for (a(b * in d) ;"),
      njs_str("SyntaxError: Unexpected token \"in\"") },

    { njs_str("for(c=let c"),
      njs_str("SyntaxError: Unexpected token \"let\"") },

    { njs_str("for(var``>0; 0 ;) ;"),
      njs_str("SyntaxError: Unexpected token \"`\"") },

    { njs_str("for(1;;)for(-x;;)fr({-x;;)f"),
      njs_str("SyntaxError: Unexpected token \"-\"") },

    { njs_str("for(i;;)for(-new+3;;)break;"),
      njs_str("SyntaxError: Unexpected token \"+\"") },

    /* switch. */

    { njs_str("switch"),
      njs_str("SyntaxError: Unexpected end of input") },

    { njs_str("switch (1);"),
      njs_str("SyntaxError: Unexpected token \";\"") },

    { njs_str("switch (1) { do { } while (1) }"),
      njs_str("SyntaxError: Unexpected token \"do\"") },

    { njs_str("switch (1) {}"),
      njs_str("undefined") },

    { njs_str("switch (1) {default:}"),
      njs_str("undefined") },

    { njs_str("switch (1) {case 0:}"),
      njs_str("undefined") },

    { njs_str("switch (1) {default:;}"),
      njs_str("undefined") },

    { njs_str("switch (1) {default:; default:}"),
      njs_str("SyntaxError: More than one default clause in switch statement") },

    { njs_str("switch (1) {case 0:;}"),
      njs_str("undefined") },

    { njs_str("var a = 'A'; switch (a) {"
                 "case 0: a += '0';"
                 "case 1: a += '1';"
                 "}; a"),
      njs_str("A") },

    { njs_str("var a = 'A'; switch (0) {"
                 "case 0: a += '0';"
                 "case 1: a += '1';"
                 "}; a"),
      njs_str("A01") },

    { njs_str("var a = 'A'; switch (0) {"
                 "case 0: a += '0'; break;"
                 "case 1: a += '1';"
                 "}; a"),
      njs_str("A0") },

    { njs_str("var a = 'A'; switch (1) {"
                 "case 0: a += '0';"
                 "case 1: a += '1';"
                 "}; a"),
      njs_str("A1") },

    { njs_str("var a = 'A'; switch (2) {"
                 "case 0: a += '0';"
                 "case 1: a += '1';"
                 "default: a += 'D';"
                 "}; a"),
      njs_str("AD") },

    { njs_str("var a = 'A'; switch (2) {"
                 "case 0: a += '0';"
                 "default: a += 'D';"
                 "case 1: a += '1';"
                 "}; a"),
      njs_str("AD1") },

    { njs_str("var a = 'A'; function f(x) { a += x; return 0 }"
                 "switch (a) {"
                 "case f(1):"
                 "default:"
                 "case f(2): a += 'D';"
                 "case f(3): a += 'T';"
                 "} a"),
      njs_str("A123DT") },

    { njs_str("[isNaN, undefined, isFinite]."
              "map((v)=>{switch(v) { case isNaN: return 1; default: return 0;}})"),
      njs_str("1,0,0") },

    { njs_str("switch (1) {case 1: ii > 1; ii => default:}"),
      njs_str("SyntaxError: Unexpected token \"default\"") },

    { njs_str("switch (1) {case 1: ii > 1; var a = functin () {default:}"),
      njs_str("SyntaxError: Unexpected token \"{\"") },

    { njs_str("switch (1) {default: ii > 1; ii => case 2:}"),
      njs_str("SyntaxError: Unexpected token \"case\"") },

    { njs_str("switch (1) {default: ii > 1; var a = functin () {case 2:}"),
      njs_str("SyntaxError: Unexpected token \"{\"") },

    { njs_str("switch (1) {case 1: ii > 1; ii => case 2:}"),
      njs_str("SyntaxError: Unexpected token \"case\"") },

    { njs_str("switch (1) {case 1: ii > 1; var a = functin () {case 2:}"),
      njs_str("SyntaxError: Unexpected token \"{\"") },

    /* continue. */

    { njs_str("continue"),
      njs_str("SyntaxError: Illegal continue statement") },

    { njs_str("\n{\ncontinue;\n}"),
      njs_str("SyntaxError: Illegal continue statement") },

    { njs_str("do continue while (false)"),
      njs_str("SyntaxError: Unexpected token \"while\"") },

    { njs_str("do continue; while (false)"),
      njs_str("undefined") },

    { njs_str("do { continue } while (false)"),
      njs_str("undefined") },

    { njs_str("var i = 0; do if (i++ > 9) continue; while (i < 100); i"),
      njs_str("100") },

    { njs_str("while (false) continue"),
      njs_str("undefined") },

    { njs_str("while (false) continue;"),
      njs_str("undefined") },

    { njs_str("while (false) { continue }"),
      njs_str("undefined") },

    { njs_str("var i = 0; while (i < 100) if (i++ > 9) continue; i"),
      njs_str("100") },

    { njs_str("for ( ;null; ) continue"),
      njs_str("undefined") },

    { njs_str("for ( ;null; ) continue;"),
      njs_str("undefined") },

    { njs_str("for ( ;null; ) { continue }"),
      njs_str("undefined") },

    { njs_str("var i; for (i = 0; i < 100; i++) if (i > 9) continue; i"),
      njs_str("100") },

    { njs_str("var a = [], i; for (i in a) continue"),
      njs_str("undefined") },

    { njs_str("var a = [], i; for (i in a) continue;"),
      njs_str("undefined") },

    { njs_str("var a = [], i; for (i in a) { continue }"),
      njs_str("undefined") },

    { njs_str("var a = [1,2,3,4,5]; var s = 0, i;"
                 "for (i in a) { if (a[i] > 4) continue; else s += a[i] } s"),
      njs_str("10") },

    { njs_str("var a = [1,2,3,4,5]; var s = 0, i;"
                 "for (i in a) { if (a[i] > 4) continue; s += a[i] } s"),
      njs_str("10") },

    { njs_str("var a; for (a = 1; a; a--) switch (a) { case 0: continue }"),
      njs_str("undefined") },

    { njs_str("var a = [1,2,3], i; for (i in a) {Object.seal({})}"),
      njs_str("undefined") },

    { njs_str("var i; for (i in [1,2,3]) {Object.seal({});}"),
      njs_str("undefined") },

    { njs_str("while (0) {continue\n}"),
      njs_str("undefined") },

    /* break. */

    { njs_str("break"),
      njs_str("SyntaxError: Illegal break statement") },

    { njs_str("{break}"),
      njs_str("SyntaxError: Illegal break statement") },

    { njs_str("\nbreak"),
      njs_str("SyntaxError: Illegal break statement") },

    { njs_str("do break while (true)"),
      njs_str("SyntaxError: Unexpected token \"while\"") },

    { njs_str("do break; while (true)"),
      njs_str("undefined") },

    { njs_str("do { break } while (true)"),
      njs_str("undefined") },

    { njs_str("var i = 0; do if (i++ > 9) break; while (i < 100); i"),
      njs_str("11") },

    { njs_str("while (true) break"),
      njs_str("undefined") },

    { njs_str("while (true) break;"),
      njs_str("undefined") },

    { njs_str("while (true) { break }"),
      njs_str("undefined") },

    { njs_str("var i = 0; while (i < 100) if (i++ > 9) break; i"),
      njs_str("11") },

    { njs_str("for ( ;; ) break"),
      njs_str("undefined") },

    { njs_str("for ( ;; ) break;"),
      njs_str("undefined") },

    { njs_str("for ( ;; ) { break }"),
      njs_str("undefined") },

    { njs_str("var i; for (i = 0; i < 100; i++) if (i > 9) break; i"),
      njs_str("10") },

    { njs_str("var a = [], i; for (i in a) break"),
      njs_str("undefined") },

    { njs_str("var a = [], i; for (i in a) break;"),
      njs_str("undefined") },

    { njs_str("var a = [], i; for (i in a) { break }"),
      njs_str("undefined") },

    { njs_str("var a = [1,2,3,4,5]; var s = 0, i;"
                 "for (i in a) { if (a[i] > 4) break; else s += a[i] } s"),
      njs_str("10") },

    { njs_str("var a = [1,2,3,4,5]; var s = 0, i;"
                 "for (i in a) { if (a[i] > 4) break; s += a[i] } s"),
      njs_str("10") },

    { njs_str("var a = [1,2,3,4,5]; var s = 0, i;"
                 "for (i in a) if (a[i] > 4) break; s += a[i]; s"),
      njs_str("5") },

    { njs_str("while (0) {break\n}"),
      njs_str("undefined") },

    /* Labels. */

    { njs_str("var n = 0; a:{n++}; a:{n++}; n"),
      njs_str("2") },

    { njs_str("a: throw 'a'"),
      njs_str("a") },

    { njs_str("a\n:\n1"),
      njs_str("1") },

    { njs_str("a\n\n:1"),
      njs_str("1") },

    { njs_str("a:\n\n1"),
      njs_str("1") },

    { njs_str("a:;"),
      njs_str("undefined") },

    { njs_str("a:\n\n"),
      njs_str("SyntaxError: Unexpected end of input") },

    { njs_str("a : var n = 0; b :++n"),
      njs_str("1") },

    { njs_str("a:{a:1}"),
      njs_str("SyntaxError: Label \"a\" has already been declared") },

    { njs_str("for (var i in [1]) {break b}"),
      njs_str("SyntaxError: Undefined label \"b\"") },

    { njs_str("for (var i in [1]) {continue b}"),
      njs_str("SyntaxError: Undefined label \"b\"") },

    { njs_str("a:{break b}"),
      njs_str("SyntaxError: Undefined label \"b\"") },

    { njs_str("a:{continue b}"),
      njs_str("SyntaxError: Undefined label \"b\"") },

    { njs_str("a:function name() {}"),
      njs_str("SyntaxError: In strict mode code, functions can only be declared at top level or inside a block.") },

#if 0 /* TODO */
    { njs_str("a:{1; break a}"),
      njs_str("1") },
#endif

    { njs_str("var r='ok'; a:if(1){break a; r='!ok'}; r"),
      njs_str("ok") },

    { njs_str("var r='ok'; a:if(0){break a; r='!ok1'} else {break a; r='!ok2'}; r"),
      njs_str("ok") },

    { njs_str("var a = 0; a:{a++}; a"),
      njs_str("1") },

    { njs_str("var a = 0; a:{break a; a++}; a"),
      njs_str("0") },

    { njs_str("var r = 0; "
                 "out: for (var i in [1,2,3]) { if (i == 2) {break out;}; r++}; r"),
      njs_str("2") },

    { njs_str("var r = 0; "
                 "out: for (var i = 0; i < 5; i++) { if (i == 2) {break out;}; r++}; r"),
      njs_str("2") },

    { njs_str("var l1 = 0, l2 = 0; "
                 "out: "
                 "for (var i in [1,2,3]) { "
                 "  for (var j in [1,2,3]) { "
                 "    if (i == 1 && j == 1) {break;}"
                 "    l2++;"
                 "  }"
                 "  l1++;"
                 "}; [l1, l2]"),
      njs_str("3,7") },

    { njs_str("var l1 = 0, l2 = 0; "
                 "out: "
                 "for (var i in [1,2,3]) { "
                 "  for (var j in [1,2,3]) { "
                 "    if (i == 1 && j == 1) {break out;}"
                 "    l2++;"
                 "  }"
                 "  l1++;"
                 "}; [l1, l2]"),
      njs_str("1,4") },

    { njs_str("var l1 = 0, l2 = 0; "
                 "out: "
                 "for (var i in [1,2,3]) { "
                 "  for (var j in [1,2,3]) { "
                 "    if (i == 1 && j == 1) {continue out;}"
                 "    l2++;"
                 "  }"
                 "  l1++;"
                 "}; [l1, l2]"),
      njs_str("2,7") },

    { njs_str("var l1 = 0, l2 = 0; "
                 "out: "
                 "for (var i in [1,2,3]) { "
                 "  l1++;"
                 "  switch (i) { "
                 "    case '1':"
                 "      break out;"
                 "    default:"
                 "  }"
                 "  l2++;"
                 "}; [l1, l2]"),
      njs_str("2,1") },

    { njs_str("var l1 = 0, l2 = 0; "
                 "out: "
                 "for (var i in [1,2,3]) { "
                 "  l1++;"
                 "  switch (i) { "
                 "    case '1':"
                 "      continue out;"
                 "    default:"
                 "  }"
                 "  l2++;"
                 "}; [l1, l2]"),
      njs_str("3,2") },

    { njs_str("var l1 = 0, l2 = 0, i = 0, j; "
                 "out: "
                 "while (i < 3) { "
                 "  j = 0;"
                 "  while (j < 3) { "
                 "    if (i == 1 && j == 1) {break out;}"
                 "    l2++;"
                 "    j++;"
                 "  }"
                 "  l1++;"
                 "  i++;"
                 "}; [l1, l2]"),
      njs_str("1,4") },

    { njs_str("var l1 = 0, l2 = 0, i = 0, j; "
                 "out: "
                 "while (i < 3) { "
                 "  j = 0;"
                 "  while (j < 3) { "
                 "    if (i == 1 && j == 1) {i++; continue out;}"
                 "    l2++;"
                 "    j++;"
                 "  }"
                 "  l1++;"
                 "  i++;"
                 "}; [l1, l2]"),
      njs_str("2,7") },

    { njs_str("var l1 = 0, l2 = 0, i = 0, j; "
                 "out: "
                 "do { "
                 "  j = 0;"
                 "  do { "
                 "    if (i == 1 && j == 1) {break out;}"
                 "    l2++;"
                 "    j++;"
                 "  } while (j < 3)"
                 "  l1++;"
                 "  i++;"
                 "} while (i < 3); [l1, l2]"),
      njs_str("1,4") },

    { njs_str("var l1 = 0, l2 = 0, i = 0, j; "
                 "out: "
                 "do { "
                 "  j = 0;"
                 "  do { "
                 "    if (i == 1 && j == 1) {i++; continue out;}"
                 "    l2++;"
                 "    j++;"
                 "  } while (j < 3)"
                 "  l1++;"
                 "  i++;"
                 "} while (i < 3); [l1, l2]"),
      njs_str("2,7") },

    { njs_str("out1: while (1) { out2: while (1) { "
                 "  try { break out1; break out2; } catch (e) {}"
                 "}}"),
      njs_str("InternalError: break/return instructions with different labels "
                 "(\"out1\" vs \"out2\") from try-catch block are not supported") },

    { njs_str("out1: while (1) { out2: while (1) { "
                 "  try { } catch (e) {break out1; break out2;} finally {}"
                 "}}"),
      njs_str("InternalError: break/return instructions with different labels "
                 "(\"out1\" vs \"out2\") from try-catch block are not supported") },

    { njs_str("out1: while (1) { out2: while (1) { "
                 "  try { break out1; } catch (e) {break out2;} finally {}"
                 "}}"),
      njs_str("InternalError: try break/return instructions with different labels "
                 "(\"out1\" vs \"out2\") from try-catch block are not supported") },

    { njs_str("out1: while (1) { out2: while (1) { "
                 "  try { break out1; break out2; } finally {}"
                 "}}"),
      njs_str("InternalError: break/return instructions with different labels "
                 "(\"out1\" vs \"out2\") from try-catch block are not supported") },

    { njs_str("out1: while (1) { out2: while (1) { "
                 "  try { continue out1; continue out2; } catch (e) {}"
                 "}}"),
      njs_str("InternalError: continue instructions with different labels "
                 "(\"out1\" vs \"out2\") from try-catch block are not supported") },

    { njs_str("out1: while (1) { out2: while (1) { "
                 "  try { continue out1; } catch (e) {continue out2;} finally {}"
                 "}}"),
      njs_str("InternalError: try continue instructions with different labels "
                 "(\"out1\" vs \"out2\") from try-catch block are not supported") },

    { njs_str("function f() {"
                 "  a:{ try { try { return 'a'; } catch (e) {break a;} finally {} } "
                 "      catch (e) {} finally {}; }"
                 "}"),
      njs_str("InternalError: try break/return instructions with different labels "
                 "(\"@return\" vs \"a\") from try-catch block are not supported") },

    { njs_str("a:{ try { try { continue a; } catch (e) {} finally {} } "
                 "    catch (e) {} finally {}; "
                 "}"),
      njs_str("SyntaxError: Illegal continue statement") },

    { njs_str("var i = 0, j = 0, r = 0;"
                 "out1: while (i < 3) "
                 "{ "
                 "  i++;"
                 "  out2: while (j < 3) { "
                 "      j++; try { break out1; } catch (e) {} finally {r++}"
                 "  }"
                 "}; [i, j, r]"),
      njs_str("1,1,1") },

    { njs_str("var i = 0, j = 0, r = 0;"
                 "out1: while (i < 3) "
                 "{ "
                 "  i++;"
                 "  out2: while (j < 3) { "
                 "      j++; try { continue out1; } catch (e) {} finally {r++}"
                 "  }"
                 "}; [i, j, r]"),
      njs_str("3,3,3") },

    { njs_str("var c=0,fin=0;"
                 "try {"
                 " while (c < 2) {"
                 "    try { c += 1; throw 'e';}"
                 "    finally { fin = 1; break;}"
                 "    fin = -1;"
                 "    c += 2;"
                 " }"
                 "} catch(e) {c = 10;}; [c, fin]"),
      njs_str("1,1") },

    { njs_str("function v1() {"
                 "function v2 () {}"
                 "v3:;"
                 "1;"
              "} v1();"),
      njs_str("undefined") },

    { njs_str("function v1() {"
                 "function v2 () {}"
                 "v3:;"
              "} v1();"),
      njs_str("undefined") },

    { njs_str("{v1:;}"),
      njs_str("undefined") },

    /* jumping out of a nested try-catch block. */

    { njs_str("var r = 0; "
                 "function f () { try { try {return 'a';} finally { r++; }} "
                 "                finally { r++; } }; "
                 "[f(), r]"),
      njs_str("a,2") },

    { njs_str("function f(n) { "
              "  var r1 = 0, r2 = 0, r3 = 0;"
              "  a:{ try { try { "
              "              if (n == 0) { break a; } "
              "              if (n == 1) { throw 'a'; } "
              "            } "
              "            catch (e) { break a; } finally { r1++; } } "
              "      catch (e) {} "
              "      finally { r2++; } "
              "      r3++;  "
              "  }; "
              "return [r1, r2, r3]"
              "}; njs.dump([f(0), f(1), f(3)])"),
      njs_str("[[1,1,0],[1,1,0],[1,1,1]]") },


    { njs_str("function f(n) {"
              "    while (1)"
              "           try {"
              "              if (n == 0) { break; }"
              "              if (n == 1) { throw 'a'; }"
              ""
              "              try { return 42; }"
              "              catch (a) {}"
              ""
              "            } catch (b) { return b; }"
              "};"
              "njs.dump([f(0), f(1), f(2)])"),
      njs_str("[undefined,'a',42]") },

    { njs_str("function f(n, r) {"
              "    while (1)"
              "           try {"
              "              if (n == 0) { break; }"
              "              if (n == 1) { throw 'a'; }"
              ""
              "              try { return 42; }"
              "              catch (a) {}"
              "              finally { r.push('in');}"
              ""
              "            } catch (b) { return b; }"
              "            finally { r.push('out'); }"
              "};"
              "function g(n) { var r = []; return [f(n, r), r]}"
              "njs.dump([g(0), g(1), g(2)])"),
      njs_str("[[undefined,['out']],['a',['out']],[42,['in','out']]]") },

    /**/

    { njs_str("function f() { Object.prototype.toString = 1; };"
              "Object.prototype.toString = f;"
              "(function () { try { 's'[{}](); } catch (e) { throw e; } })()"),
      njs_str("TypeError: undefined is not a function") },

    { njs_str("var i; for (i = 0; i < 10; i++) { i += 1 } i"),
      njs_str("10") },

    /* Factorial. */

    { njs_str("var n = 5, f = 1; while (n--) f *= n + 1; f"),
      njs_str("120") },

    { njs_str("var n = 5, f = 1; while (n) { f *= n; n-- } f"),
      njs_str("120") },

    /* Fibonacci. */

    { njs_str("var n = 50, x, i, j, k;"
                 "for(i=0,j=1,k=0; k<n; i=j,j=x,k++ ){ x=i+j } x"),
      njs_str("20365011074") },

    { njs_str("3 + 'abc' + 'def' + null + true + false + undefined"),
      njs_str("3abcdefnulltruefalseundefined") },

    { njs_str("var a = 0; do a++; while (a < 5) if (a == 5) a = 7.33 \n"
                 "else a = 8; while (a < 10) a++; a"),
      njs_str("10.33") },

    /* typeof. */

    { njs_str("typeof null"),
      njs_str("object") },

    { njs_str("typeof undefined"),
      njs_str("undefined") },

    { njs_str("typeof false"),
      njs_str("boolean") },

    { njs_str("typeof true"),
      njs_str("boolean") },

    { njs_str("typeof 0"),
      njs_str("number") },

    { njs_str("typeof -1"),
      njs_str("number") },

    { njs_str("typeof Infinity"),
      njs_str("number") },

    { njs_str("typeof NaN"),
      njs_str("number") },

    { njs_str("typeof 'a'"),
      njs_str("string") },

    { njs_str("typeof {}"),
      njs_str("object") },

    { njs_str("typeof Object()"),
      njs_str("object") },

    { njs_str("typeof []"),
      njs_str("object") },

    { njs_str("typeof function(){}"),
      njs_str("function") },

    { njs_str("typeof Object"),
      njs_str("function") },

    { njs_str("typeof /./i"),
      njs_str("object") },

    { njs_str("typeof Date.prototype"),
      njs_str("object") },

    { njs_str("typeof a"),
      njs_str("undefined") },

    { njs_str("typeof a; var a"),
      njs_str("undefined") },

    { njs_str("typeof a; var a; a"),
      njs_str("undefined") },

    { njs_str("var a = 5; typeof a"),
      njs_str("number") },

    { njs_str("function f() { return typeof a } ; f()"),
      njs_str("undefined") },

    { njs_str("typeof a; a"),
      njs_str("ReferenceError: \"a\" is not defined") },

    { njs_str("typeof a; a = 1"),
      njs_str("ReferenceError: \"a\" is not defined") },

    /**/

    { njs_str("void 0"),
      njs_str("undefined") },

    { njs_str("null = 1"),
      njs_str("ReferenceError: Invalid left-hand side in assignment") },

    { njs_str("undefined = 1"),
      njs_str("TypeError: Cannot assign to read-only property \"undefined\" of object") },

    { njs_str("null++"),
      njs_str("ReferenceError: Invalid left-hand side in postfix operation") },

    { njs_str("++null"),
      njs_str("ReferenceError: Invalid left-hand side in prefix operation") },

    { njs_str("var a, b; b = a; a = 1; a +' '+ b"),
      njs_str("1 undefined") },

    { njs_str("a = 1"),
      njs_str("ReferenceError: \"a\" is not defined") },

    { njs_str("var a; a = 1; a"),
      njs_str("1") },

    { njs_str("var a = {}; typeof a +' '+ a"),
      njs_str("object [object Object]") },

    { njs_str("var a = {}; a.b"),
      njs_str("undefined") },

    { njs_str("var a = {}; a.b = 1 + 2; a.b"),
      njs_str("3") },

    { njs_str("var a = {}; a['b']"),
      njs_str("undefined") },

    { njs_str("var a = {}; a.b.c"),
      njs_str("TypeError: cannot get property \"c\" of undefined") },

    { njs_str("'a'[0]"),
      njs_str("a") },

    { njs_str("'a'[undefined]"),
      njs_str("undefined") },

    { njs_str("'a'[null]"),
      njs_str("undefined") },

    { njs_str("'a'[false]"),
      njs_str("undefined") },

    { njs_str("'a'.b = 1"),
      njs_str("TypeError: property set on primitive string type") },

    { njs_str("'a'[2] = 1"),
      njs_str("TypeError: property set on primitive string type") },

    { njs_str("var a = {}; a.b = 1; a.b"),
      njs_str("1") },

    { njs_str("var a = {}; a.b = 1; a.b += 2"),
      njs_str("3") },

    { njs_str("var a = {}; a.b = 1; a.b += a.b"),
      njs_str("2") },

    { njs_str("var a = {}; a.b = 1; var x = {}; x.b = 3; a.b += (x.b = 2)"),
      njs_str("3") },

    { njs_str("var a = {}; a.b = 1; a.b += (a.b = 2)"),
      njs_str("3") },

    { njs_str("var a = {}; a.b += 1"),
      njs_str("NaN") },

    { njs_str("var a = 1; var b = 2; a = b += 1"),
      njs_str("3") },

    { njs_str("var a = 1; var b = { x:2 }; a = b.x += 1"),
      njs_str("3") },

    { njs_str("var a = 1; var b = { x:2 }; a = b.x += (a = 1)"),
      njs_str("3") },

    { njs_str("var o = {true:1}; o[true] += 1; o.true"),
      njs_str("2") },

    { njs_str("var o = {false:1}; o[false] += 1; o.false"),
      njs_str("2") },

    { njs_str("var o = {undefined:1}; o[undefined] += 1; o.undefined"),
      njs_str("2") },

    { njs_str("var o = {'5':1}; o[5] += 1; o[5]"),
      njs_str("2") },

    { njs_str("var o = {a:1}; o[{toString:()=>'a'}] += 1; o.a"),
      njs_str("2") },

    { njs_str("var o = {true:1}; o[true]++; o.true"),
      njs_str("2") },

    { njs_str("var o = {false:1}; o[false]++; o.false"),
      njs_str("2") },

    { njs_str("var o = {undefined:1}; o[undefined]++; o.undefined"),
      njs_str("2") },

    { njs_str("var o = {'5':1}; o[5]++; o[5]"),
      njs_str("2") },

    { njs_str("var o = {a:1}; o[{toString:()=>'a'}]++; o.a"),
      njs_str("2") },

    { njs_str("var a = undefined; a.b++; a.b"),
      njs_str("TypeError: cannot get property \"b\" of undefined") },

    { njs_str("var a = null; a.b++; a.b"),
      njs_str("TypeError: cannot get property \"b\" of null") },

    { njs_str("var a = true; a.b++; a.b"),
      njs_str("TypeError: property set on primitive boolean type") },

    { njs_str("var a = 1; a.b++; a.b"),
      njs_str("TypeError: property set on primitive number type") },

    { njs_str("var n = 1, o = { p: n += 1 }; o.p"),
      njs_str("2") },

    { njs_str("var a = {}; a.b = {}; a.b.c = 1; a.b['c']"),
      njs_str("1") },

    { njs_str("var a = {}; a.b = {}; a.b.c = 1; a['b']['c']"),
      njs_str("1") },

    { njs_str("var a = {}; a.b = {}; var c = 'd'; a.b.d = 1; a['b'][c]"),
      njs_str("1") },

    { njs_str("var a = {}; a.b = 1; var c = a.b++; a.b +' '+ c"),
      njs_str("2 1") },

    { njs_str("var a = 2; a.b = 1; var c = a.b++; a +' '+ a.b +' '+ c"),
      njs_str("TypeError: property set on primitive number type") },

    { njs_str("var x = { a: 1 }; x.a"),
      njs_str("1") },

    { njs_str("var a = { x:1 }; var b = { y:2 }; a.x = b.y; a.x"),
      njs_str("2") },

    { njs_str("var a = { x:1 }; var b = { y:2 }; var c; c = a.x = b.y"),
      njs_str("2") },

    { njs_str("var a = { x:1 }; var b = { y:2 }; var c = a.x = b.y; c"),
      njs_str("2") },

    { njs_str("var a = { x:1 }; var b = { y:2 }; a.x = b.y"),
      njs_str("2") },

    { njs_str("var a = { x:1 }; var b = a.x = 1 + 2; a.x +' '+ b"),
      njs_str("3 3") },

    { njs_str("var a = { x:1 }; var b = { y:2 }; var c = {};"
                 "c.x = a.x = b.y; c.x"),
      njs_str("2") },

    { njs_str("var y = 2, x = { a:1, b: y + 5, c:3 };"
                 "x.a +' '+ x.b +' '+ x.c"),
      njs_str("1 7 3") },

    { njs_str("var x = { a: 1, b: { a:2, c:5 } };"
                 "x.a +' '+ x.b.a +' '+ x.b.c"),
      njs_str("1 2 5") },

    { njs_str("var y = 5, x = { a:y }; x.a"),
      njs_str("5") },

    { njs_str("var x = { a: 1; b: 2 }"),
      njs_str("SyntaxError: Unexpected token \";\"") },

    { njs_str("var x = { a: 1, b: x.a }"),
      njs_str("TypeError: cannot get property \"a\" of undefined") },

    { njs_str("var a = { b: 2 }; a.b += 1"),
      njs_str("3") },

    { njs_str("var o = {a:1}, c = o; o.a = o = {b:5};"
                 "o.a +' '+ o.b +' '+ c.a.b"),
      njs_str("undefined 5 5") },

    { njs_str("var y = { a: 2 }, x = { a: 1, b: y.a }; x.a +' '+ x.b"),
      njs_str("1 2") },

    { njs_str("var y = { a: 1 }, x = { a: y.a++, b: y.a++ }\n"
                 "x.a +' '+ x.b +' '+ y.a"),
      njs_str("1 2 3") },

    { njs_str("var a='', o = {a:1, b:2}, p;"
                 "for (p in o) { a += p +':'+ o[p] +',' } a"),
      njs_str("a:1,b:2,") },

    { njs_str("var x = { a: 1 }, b = delete x.a; x.a +' '+ b"),
      njs_str("undefined true") },

    /* Object shorthand property. */

    { njs_str("var a = 1; njs.dump({a})"),
      njs_str("{a:1}") },

    { njs_str("var a = 1, b; njs.dump({a,b})"),
      njs_str("{a:1,b:undefined}") },

    { njs_str("var a = 1, b = 2; ({a,b,c})"),
      njs_str("ReferenceError: \"c\" is not defined") },

    { njs_str("var a = 1, b = 2; njs.dump({a,b,c:3})"),
      njs_str("{a:1,b:2,c:3}") },

    { njs_str("var b = 2, c = 3; njs.dump({a:1,b,c})"),
      njs_str("{a:1,b:2,c:3}") },

    { njs_str("({1})"),
      njs_str("SyntaxError: Unexpected token \"}\"") },

    { njs_str("({default})"),
      njs_str("SyntaxError: Unexpected token \"}\"") },

    { njs_str("({var})"),
      njs_str("SyntaxError: Unexpected token \"}\"") },

    { njs_str("({this})"),
        njs_str("SyntaxError: Unexpected token \"}\"") },

    { njs_str("typeof ({Number}).Number"),
      njs_str("function") },

    { njs_str("typeof ({eval}).eval"),
      njs_str("function") },

    { njs_str("typeof ({Math}).Math.sin"),
      njs_str("function") },

    { njs_str("delete null"),
      njs_str("true") },

    { njs_str("var a; delete a"),
      njs_str("SyntaxError: Delete of an unqualified identifier") },

    { njs_str("delete undefined"),
      njs_str("SyntaxError: Delete of an unqualified identifier") },

    { njs_str("delete this !== true"),
      njs_str("false") },

    { njs_str("undefined[Symbol()]"),
      njs_str("TypeError: cannot get property \"Symbol()\" of undefined") },

    /* Object shorthand methods. */

    { njs_str("var o = {m(){}}; new o.m();"),
      njs_str("TypeError: function is not a constructor") },

    { njs_str("var o = {sum(a, b){return a + b;}}; o.sum(1, 2)"),
      njs_str("3") },

    /* Object computed property. */

    { njs_str("var o = { [0]: 1, [-0]: 2 }; o[0];"),
      njs_str("2") },

    { njs_str("var k = 'abc'.split('');var o = {[k[0]]: 'baz'}; o.a"),
      njs_str("baz") },

    { njs_str("var k = {}; var o = {[k]() {return 'baz'}}; o[k]()"),
      njs_str("baz") },

    { njs_str("njs.dump({[{toString(){return 'xx'}}]:1})"),
      njs_str("{xx:1}") },

    { njs_str("var o = {}; Object.defineProperty(o, 'toString', {value:()=>'xx'});"
                 "njs.dump({[o]:1})"),
      njs_str("{xx:1}") },

    { njs_str("({[{toString(){return {}}}]:1})"),
      njs_str("TypeError: Cannot convert object to primitive value") },

    { njs_str("({['a' + 'v'](){}}).av.name"),
      njs_str("av") },

    { njs_str("({[Symbol.toStringTag](){}})[Symbol.toStringTag].name"),
      njs_str("[Symbol.toStringTag]") },

    { njs_str("var anonSym = Symbol(); ({[anonSym]: () => {}})[anonSym].name"),
      njs_str("") },

    { njs_str("var named = Symbol('xxx'); ({[named]: () => {}})[named].name"),
      njs_str("[xxx]") },

    { njs_str("var obj = {}; ({[obj](){}}); typeof obj"),
      njs_str("object") },

    { njs_str("[function(){}][0].name"),
      njs_str("") },

    { njs_str("var called = false;"
             "({"
             "   [{toString(){ if (called) throw 'OOps'; called = true; return 'a'}}](){}"
             "}).a.name"),
      njs_str("a") },

    { njs_str("var o = { [new Number(12345)]: 1000 }; o[12345]"),
      njs_str("1000") },

    { njs_str("delete NaN"),
      njs_str("SyntaxError: Delete of an unqualified identifier") },

    { njs_str("delete Infinity"),
      njs_str("SyntaxError: Delete of an unqualified identifier") },

    { njs_str("delete -Infinity"),
      njs_str("true") },

    { njs_str("delete (1/0)"),
      njs_str("true") },

    { njs_str("delete 1"),
      njs_str("true") },

    { njs_str("var a = []; delete a[1]"),
      njs_str("true") },

    { njs_str("var o = {}; [delete o.m, delete o.m]"),
      njs_str("true,true") },

    { njs_str("[delete Array.nonexistent, delete Array.Array]"),
      njs_str("true,true") },

    { njs_str("var a; delete (a = 1); a"),
      njs_str("1") },

    { njs_str("delete a"),
      njs_str("SyntaxError: Delete of an unqualified identifier") },

    { njs_str("var a = 1; delete a"),
      njs_str("SyntaxError: Delete of an unqualified identifier") },

    { njs_str("function f(){} delete f"),
      njs_str("SyntaxError: Delete of an unqualified identifier") },

    { njs_str("var a = { x:1 }; ('x' in a) +' '+ (1 in a)"),
      njs_str("true false") },

    { njs_str("delete --[][1]"),
      njs_str("true") },

    { njs_str("var a = [1,2]; delete a.length"),
      njs_str("TypeError: Cannot delete property \"length\" of array") },

    { njs_str("var a = [1,2,3]; a.x = 10;  delete a[1]"),
      njs_str("true") },

    { njs_str("var o = Object.create({a:1}); o.a = 2; delete o.a; o.a"),
      njs_str("1") },

    { njs_str("delete Array.name"),
      njs_str("true") },

    { njs_str("delete Math.max"),
      njs_str("true") },

    { njs_str("delete Math.max.length"),
      njs_str("true") },

    { njs_str("function f(a,b) {} "
                 "[f.length, delete f.length, f.length, delete f.length]"),
      njs_str("2,true,0,true") },

    { njs_str("njs.dump({break:1,3:2,'a':4,\"b\":2,true:1,null:0,async:2})"),
      njs_str("{3:2,break:1,a:4,b:2,true:1,null:0,async:2}") },

    { njs_str("var o1 = {a:1,b:2}, o2 = {c:3}; o1.a + o2.c"),
      njs_str("4") },

    { njs_str("({[]:1})"),
      njs_str("SyntaxError: Unexpected token \"]\"") },

    { njs_str("({'AB\\ncd':1})['AB\\ncd']"),
      njs_str("1") },

    /* Inheritance. */

    { njs_str("function Foo() {this.bar = 10;}; Foo.prototype.bar = 42; "
                 "var v = new Foo(); delete v.bar; v.bar"),
      njs_str("42") },

    { njs_str("function Cl(x,y) {this.x = x; this.y = y}; "
                 "var c = new Cl('a', 'b'); Cl.prototype.z = 1; c.z"),
      njs_str("1") },

    /**/

    { njs_str("delete Math.E"),
      njs_str("TypeError: Cannot delete property \"E\" of object") },

    { njs_str("Math.E = 1"),
      njs_str("TypeError: Cannot assign to read-only property \"E\" of object") },

    /* "in" operation. */

    { njs_str("var o = { 'a': 1, 'b': 2 }; var i; "
                 "for (i in o) { delete o.a; delete o.b; }; njs.dump(o)"),
      njs_str("{}") },

    { njs_str("var o  = {}; Object.defineProperty(o, 'a', {value:1, configurable:1}); "
                 "delete o.a; o.a=2; o.a"),
      njs_str("2") },

    { njs_str("var a = {}; 1 in a"),
      njs_str("false") },

    { njs_str("'a' in {a:1}"),
      njs_str("true") },

    { njs_str("Symbol.unscopables in { [Symbol.unscopables]: 1 }"),
      njs_str("true") },

    { njs_str("Object(Symbol.toStringTag) in Math"),
      njs_str("true") },

    { njs_str("'1' in [0,,2]"),
      njs_str("false") },

    { njs_str("var o = {}; Object.defineProperty(o, 'a', {get:()=>und}); 'a' in o"),
      njs_str("true") },

    { njs_str("var o = {}; Object.defineProperty(o, 'a', {value:1}); ({toString(){return 'a'}}) in o"),
      njs_str("true") },

    { njs_str("'a' in Object.create({a:1})"),
      njs_str("true") },

    { njs_str("[false, NaN, '', Symbol()]"
              ".map((x) => { "
              "    try { 'toString' in x; } "
              "    catch (e) { return e instanceof TypeError ? e.message : ''; } "
              "})"
              ".every((x) => x.startsWith('property \"in\" on primitive'))"),
      njs_str("true") },

    { njs_str("var p = new String('test');"
              "p.toString = () => { throw new Error('failed') };"
              "p in 1"),
      njs_str("TypeError: property \"in\" on primitive number type") },

    { njs_str("var n = { toString: function() { return 'a' } };"
                 "var o = { a: 5 }; o[n]"),
      njs_str("5") },

    { njs_str("var n = { valueOf: function() { return 'a' } };"
                 "var o = { a: 5, '[object Object]': 7 }; o[n]"),
      njs_str("7") },

    { njs_str("var o = {}; o.new = 'OK'; o.new"),
      njs_str("OK") },

    { njs_str("var o = { new: 'OK'}; o.new"),
      njs_str("OK") },

    /* Arrays */

    /* Empty array to primitive. */

    { njs_str("3 + []"),
      njs_str("3") },

    { njs_str("3 * []"),
      njs_str("0") },

    /* Single element array to primitive. */

    { njs_str("3 + [5]"),
      njs_str("35") },

    { njs_str("3 * [5]"),
      njs_str("15") },

    /* Array to primitive. */

    { njs_str("3 + [5,7]"),
      njs_str("35,7") },

    { njs_str("3 * [5,7]"),
      njs_str("NaN") },

    { njs_str("var a = [ 1, 2, 3 ]; a[0] + a[1] + a[2]"),
      njs_str("6") },

    { njs_str("var a = [ 1, 2, 3 ]; a[-1] = 4; a + a[-1]"),
      njs_str("1,2,34") },

    { njs_str("var a = [ 1, 2, 3 ]; a[4294967295] = 4; a + a[4294967295]"),
      njs_str("1,2,34") },

    { njs_str("var a = [ 1, 2, 3 ]; a[4294967296] = 4; a + a[4294967296]"),
      njs_str("1,2,34") },

    { njs_str("var x = []; var k = 1;"
              "for (var i = 0; i < 32; i++) { k = k * 2; x[k - 2] = k; };"
              "k = 1; for (i = 0; i < 32; i++) { k = k * 2; if (x[k - 2] != k) { throw 'error'; } }"),
      njs_str("undefined") },

    { njs_str("delete[]['4e9']"),
      njs_str("true") },

    { njs_str("var n = 1, a = [ n += 1 ]; a"),
      njs_str("2") },

    { njs_str("var a = [ 1, 2; 3 ]; a[0] + a[1] + a[2]"),
      njs_str("SyntaxError: Unexpected token \";\"") },

    { njs_str("var a = [ 1, 2, 3 ]; a[0] +' '+ a[1] +' '+ a[2] +' '+ a[3]"),
      njs_str("1 2 3 undefined") },

    { njs_str("var a = [ 5, 6, 7 ]; a['1']"),
      njs_str("6") },

    { njs_str("var a = [ 5, 6, 7 ]; a['01']"),
      njs_str("undefined") },

    { njs_str("var a = [ 5, 6, 7 ]; a[0x1]"),
      njs_str("6") },

    { njs_str("var a = [ 5, 6, 7 ]; a['0x1']"),
      njs_str("undefined") },

    { njs_str("[] - 2"),
      njs_str("-2") },

    { njs_str("[1] - 2"),
      njs_str("-1") },

    { njs_str("[[1]] - 2"),
      njs_str("-1") },

    { njs_str("[[[1]]] - 2"),
      njs_str("-1") },

    { njs_str("var a = []; a - 2"),
      njs_str("-2") },

    { njs_str("var a = [1]; a - 2"),
      njs_str("-1") },

    { njs_str("var a = []; a[0] = 1; a - 2"),
      njs_str("-1") },

    { njs_str("[] + 2 + 3"),
      njs_str("23") },

    { njs_str("[1] + 2 + 3"),
      njs_str("123") },

    { njs_str("var a = []; a + 2 + 3"),
      njs_str("23") },

    { njs_str("var a = [1]; a + 2 + 3"),
      njs_str("123") },

    { njs_str("var a = [1,2], i = 0; a[i++] += a[0] = 5 + i;"
                 "a[0] +' '+ a[1]"),
      njs_str("7 2") },

    { njs_str("var a = []; a[0] = 1; a + 2 + 3"),
      njs_str("123") },

    { njs_str("var a = []; a['0'] = 1; a + 2 + 3"),
      njs_str("123") },

    { njs_str("var a = []; a[2] = 1; a[2]"),
      njs_str("1") },

    { njs_str("var a = [1, 2]; 1 in a"),
      njs_str("true") },

    { njs_str("var a = [1, 2]; 2 in a"),
      njs_str("false") },

    { njs_str("var a = [1, 2]; delete a[0]; 0 in a"),
      njs_str("false") },

    { njs_str("var a = [ function(a) {return a + 1} ]; a[0](5)"),
      njs_str("6") },

    { njs_str("var s = '', a = [5,1,2], i;"
                 "a[null] = null;"
                 "a[undefined] = 'defined';"
                 "a[false] = false;"
                 "a[true] = true;"
                 "a[-0] = 0;"
                 "a[Infinity] = Infinity;"
                 "a[-Infinity] = -Infinity;"
                 "a[NaN] = NaN;"
                 "a[-NaN] = -NaN;"
                 "for (i in a) { s += i +':'+ a[i] +',' } s"),
      njs_str("0:0,1:1,2:2,null:null,undefined:defined,false:false,"
                 "true:true,Infinity:Infinity,-Infinity:-Infinity,NaN:NaN,") },

    { njs_str("--[][3e9]"),
      njs_str("NaN") },

    { njs_str("[].length"),
      njs_str("0") },

    { njs_str("[1,2].length"),
      njs_str("2") },

    { njs_str("var a = [1,2]; a.length"),
      njs_str("2") },

    { njs_str("[\n1]"),
      njs_str("1") },

    { njs_str("\n[\n1\n]"),
      njs_str("1") },

    { njs_str("\n[\n1\n,\n2]\n[\n0]"),
      njs_str("1") },

    { njs_str("Object.create([1,2]).length"),
      njs_str("2") },

    { njs_str("Object.create(['α','β'])[1]"),
      njs_str("β") },

    { njs_str("Object.create(['α','β'])[false]"),
      njs_str("undefined") },

    { njs_str("var a = ['abc']; var o = Object.create(a); o[0] = 32;"
                 "[a,o[0]]"),
      njs_str("abc,32") },

    /* Array.length setter */

    { njs_str("[].length = {}"),
      njs_str("RangeError: Invalid array length") },

    { njs_str("[].length = 2**32 - 1"),
      njs_str("4294967295") },

    { njs_str("var a = []; a.length = 2**32 - 1; a.length"),
      njs_str("4294967295") },

    { njs_str("[].length = 3e9"),
      njs_str("3000000000") },

    { njs_str("var a = []; Object.defineProperty(a, 'length',{value: 2**32 - 1}); a.length"),
      njs_str("4294967295") },

    { njs_str("[].length = 2**32"),
      njs_str("RangeError: Invalid array length") },

    { njs_str("[].length = 2**32 + 1"),
      njs_str("RangeError: Invalid array length") },

    { njs_str("[].length = -1"),
      njs_str("RangeError: Invalid array length") },

    { njs_str("var a = [1];"
                 "typeof (a.length = '') == 'string' && a.length == 0"),
      njs_str("true") },

    { njs_str("var a = [1]; "
                 "typeof (a.length = Object(2)) == 'object' && a.length == 2"),
      njs_str("true") },

    { njs_str("var a = [1]; "
                 "typeof (a.length = Object('2')) == 'object'"),
      njs_str("true") },

    { njs_str("var a = [1]; "
                 "a.length = { valueOf: () => 2 }; a.length == 2"),
      njs_str("true") },

    { njs_str("var a = [1]; "
                 "a.length = { toString: () => '2' }; a.length == 2"),
      njs_str("true") },

    { njs_str("var a = []; a.length = 0; JSON.stringify(a)"),
      njs_str("[]") },

    { njs_str("var a = []; a.length = 1; JSON.stringify(a)"),
      njs_str("[null]") },

    { njs_str("var a = [1]; a.length = 1; JSON.stringify(a)"),
      njs_str("[1]") },

    { njs_str("var a = [1]; a.length = 2; JSON.stringify(a)"),
      njs_str("[1,null]") },

    { njs_str("var a = [1]; a.length = 4; a.length = 0; JSON.stringify(a)"),
      njs_str("[]") },

    { njs_str("var a = [1,2,3]; a.length = 2; JSON.stringify(a)"),
      njs_str("[1,2]") },

    { njs_str("var a = [1,2,3]; a.length = 3; a"),
      njs_str("1,2,3") },

    { njs_str("var a = [1,2,3]; a.length = 16; a"),
      njs_str("1,2,3,,,,,,,,,,,,,") },

    { njs_str("var a = [1,2,3]; a.join()"),
      njs_str("1,2,3") },

    { njs_str("var a = [1,2,3]; a.join(':')"),
      njs_str("1:2:3") },

    { njs_str("["
              "  [],"
              "  ['β', 'γ'],"
              "]"
              ".map(v=>{v.length = 2**14+1; var out = v.join('α'); return [out[0], out[out.length - 1],out.length]})"
              ".map(v=>njs.dump(v))"),
      njs_str("['α','α',16384],['β','α',16386]") },

    { njs_str("["
              "  'α'.repeat(33),"
              "]"
              ".map(v=>{var out = ['β', 'γ'].join(v); return out.length})"),
      njs_str("35") },

    { njs_str("["
              "  [],"
              "  ['β', 'γ'],"
              "  [NaN, Math.pow(2,123.2), Infinity, -1],"
              "  [new String('β'),{toString(){return 'γ'}}],"
              "]"
              ".map(v=>{var out = v.join('α'); return [out, out[out.length - 1],out.length]})"
              ".map(v=>njs.dump(v))"),
      njs_str("['',undefined,0],"
              "['βαγ','γ',3],"
              "['NaNα1.2215056097393134e+37αInfinityα-1','1',38],"
              "['βαγ','γ',3]") },

    { njs_str("var a = ['β','γ']; a.join('').length"),
      njs_str("2") },

    { njs_str("var a = []; a[5] = 5; a.join()"),
      njs_str(",,,,,5") },

    { njs_str("var a = [,null,undefined,false,true,0,1]; a.join()"),
      njs_str(",,,false,true,0,1") },

    { njs_str("var o = { toString: function() { return null } };"
              "[o].join()"),
      njs_str("null") },

    { njs_str("var o = { toString: function() { return undefined } };"
              "[o].join()"),
      njs_str("undefined") },

    { njs_str("var a = [0,,2,3];"
              "Object.defineProperty(Array.prototype, 1, {get: ()=> {a[32] = 32; return 1}, configurable:true});"
              "a.join()"),
    njs_str("0,1,2,3") },

    { njs_str("Array.prototype.join.call(new Uint8Array([0,1,2]))"),
      njs_str("0,1,2") },

    { njs_str("var a = []; a[5] = 5; a"),
      njs_str(",,,,,5") },

    { njs_str("var a = []; a.concat([],[1],[])"),
      njs_str("1") },

    { njs_str("var a = []; a[Symbol.isConcatSpreadable] = undefined; [].concat(a).length"),
      njs_str("0") },

    { njs_str("var a = []; Object.defineProperty(a, Symbol.isConcatSpreadable, {get:()=>{throw 'Oops'}}); "
              "[].concat(a)"),
      njs_str("Oops") },

    { njs_str("var a = [].concat([1,2,3], {length:3, 1:4, 2:5, [Symbol.isConcatSpreadable]:1});"
              "njs.dump([a, a.length])"),
      njs_str("[[1,2,3,<empty>,4,5],6]") },

    { njs_str("njs.dump([].concat([1,2,3], {length:3, 1:4, 2:5}))"),
      njs_str("[1,2,3,{1:4,2:5,length:3}]") },

    { njs_str("Array.prototype[1] = 1; var x = [0]; x.length = 2; "
              "x.concat().hasOwnProperty('1') === true"),
      njs_str("true") },

    { njs_str(njs_declare_sparse_array("a", 64)
              "a[32] = 1; a = a.concat([1]);"
              "njs.dump([a[0], a[32],a.length])"),
      njs_str("[undefined,1,65]") },

    { njs_str(njs_declare_sparse_array("a", 64)
              "a[32] = 1; a = [1].concat(a);"
              "njs.dump([a[0], a[33],a.length])"),
      njs_str("[1,1,65]") },

    { njs_str("var a = [1]; a[1111111] = 2;"
              "var a2 = [3].concat(a, [4]);"
              "njs.dump(a2)"),
      njs_str("[3,1,<1111110 empty items>,2,4]") },

    { njs_str("var re = /abc/; re[Symbol.isConcatSpreadable] = true;"
              "re[0] = 1, re[1] = 2, re[2] = 3, re.length = 3;"
              "[].concat(re)"),
      njs_str("1,2,3") },

    { njs_str("var s = new String('yuck\\uD83D\\uDCA9'); s[Symbol.isConcatSpreadable] = true;"
              "[].concat(s)"),
      njs_str("y,u,c,k,💩") },

    { njs_str("var s = { toString: function() { return 'S' } };"
                 "var v = { toString: 8, valueOf: function() { return 'V' } };"
                 "var o = [9]; o.join = function() { return 'O' };"
                 "var a = [1,2,3,[4,5,6],s,v,o]; a.join('')"),
      njs_str("1234,5,6SVO") },

    { njs_str("var s = { toString: function() { return 'S' } };"
                 "var v = { toString: 8, valueOf: function() { return 'V' } };"
                 "var o = [9]; o.join = function() { return 'O' };"
                 "var a = [1,2,3,[4,5,6],s,v,o]; a"),
      njs_str("1,2,3,4,5,6,S,V,O") },

    /* Array.toString(). */

    { njs_str("var a = [1,2,3]; a.join = 'NO';"
                 "Object.prototype.toString = function () { return 'A' }; a"),
      njs_str("[object Array]") },

    { njs_str("Array.prototype.toString.call(1)"),
      njs_str("[object Number]") },

    { njs_str("Array.prototype.toString.call('abc')"),
      njs_str("[object String]") },

    { njs_str(njs_declare_sparse_array("a", 32769)
              "var s = a.toString(); [s.length]"),
      njs_str("32768") },

    /* Empty array elements. */

    { njs_str("[,,]"),
      njs_str(",") },

    { njs_str("[,,,]"),
      njs_str(",,") },

    { njs_str("[1,2,]"),
      njs_str("1,2") },

    { njs_str("[1,2,,3]"),
      njs_str("1,2,,3") },

    { njs_str("[,,].length"),
      njs_str("2") },

    { njs_str("[,,,].length"),
      njs_str("3") },

    { njs_str("[1,2,,3].length"),
      njs_str("4") },

    /**/

    { njs_str("var n = { toString: function() { return 1 } };   [1,2][n]"),
      njs_str("2") },

    { njs_str("var n = { toString: function() { return '1' } }; [1,2][n]"),
      njs_str("2") },

    { njs_str("var n = { toString: function() { return 1 },"
                          " valueOf:  function() { return 0 } };   [1,2][n]"),
      njs_str("2") },

    { njs_str("var n = { toString: function() { return 1.5 } };"
                 "var a = [1,2]; a[1.5] = 5; a[n]"),
      njs_str("5") },

    { njs_str("var n = { toString: function() { return 1.5 } };"
                 "var a = [1,2]; a[n] = 5; a[1.5]"),
      njs_str("5") },

    { njs_str("var n = { toString: function() { return '1.5' } };"
                 "var a = [1,2]; a[1.5] = 5; a[n]"),
      njs_str("5") },

    { njs_str("var n = { toString: function() { return '1.5' } };"
                 "var a = [1,2]; a[n] = 5; a[1.5]"),
      njs_str("5") },

    { njs_str("var n = { toString: function() { return 1.5 } };"
                 "var a = [1,2]; a[1.5] = 5; n in a"),
      njs_str("true") },

    { njs_str("var n = { toString: function() { return '1.5' } };"
                 "var a = [1,2]; a[1.5] = 5; '' + (n in a) + (delete a[n])"),
      njs_str("truetrue") },

    { njs_str("var o = {},  v = o;"
              "v[{toString: () => { v = 'V'; return 'a';}}] = 1;"
              "[v, o.a]"),
      njs_str("V,1") },

    { njs_str("var o = null; o[{toString:()=>{throw 'OOps'}}]"),
      njs_str("TypeError: cannot get property \"[object Object]\" of null") },

    { njs_str("var o = null; o[{toString:()=>{throw 'OOps'}}]()"),
      njs_str("TypeError: cannot get property \"[object Object]\" of null") },

    { njs_str("var o = null; o[{toString:()=>{throw 'OOps'}}] = 1"),
      njs_str("TypeError: cannot set property \"[object Object]\" of null") },

    { njs_str("var o = null; o[{toString:()=>{throw 'OOps'}}] += 1"),
      njs_str("TypeError: cannot get property \"[object Object]\" of null") },

    /**/

    { njs_str("Array.isArray()"),
      njs_str("false") },

    { njs_str("Array.isArray(1)"),
      njs_str("false") },

    { njs_str("Array.isArray(1) ? 'true' : 'false'"),
      njs_str("false") },

    { njs_str("Array.isArray([])"),
      njs_str("true") },

    { njs_str("Array.isArray([]) ? 'true' : 'false'"),
      njs_str("true") },

    { njs_str("["
              "  [undefined],"
              "  [null],"
              "  ['foo'],"
              "  ['foo', c => c.toUpperCase()],"
              "  [{length: 3, 1:'a', 2:'b'}],"
              "  [[7,,9], v => v*2],"
              "].map(args => { try { return Array.from.apply(Array,args) }"
              "                catch (e) {return e.toString()}})"),
      njs_str("TypeError: cannot convert null or undefined to object,"
              "TypeError: cannot convert null or undefined to object,"
              "f,o,o,"
              "F,O,O,"
              ",a,b,"
              "14,NaN,18"
              ) },

    { njs_str("function f() {return Array.from(arguments);}; f(1,2,3)"),
      njs_str("1,2,3") },

    { njs_str("Array.from({ length: 5 }, (v, i) => i)"),
      njs_str("0,1,2,3,4") },

    { njs_str("const range = (start, stop, step) =>"
              "Array.from({ length: (stop - start) / step + 1 }, (_, i) => start + i * step);"
              "range(1, 10, 2)"),
      njs_str("1,3,5,7,9") },

    { njs_str("var a = Array.from.call(Object, { length: 2, 0:7, 1:9 });"
              "[a[0], a[1], Array.isArray(a)]"),
      njs_str("7,9,false") },

    { njs_str("Array.of()"),
      njs_str("") },

    { njs_str("Array.of(1,2,3)"),
      njs_str("1,2,3") },

    { njs_str("Array.of(undefined,1)"),
      njs_str(",1") },

    { njs_str("Array.of(NaN,-1,{})"),
      njs_str("NaN,-1,[object Object]") },

    { njs_str("var a = [1,2,3]; a.concat(4, [5, 6, 7], 8)"),
      njs_str("1,2,3,4,5,6,7,8") },

    { njs_str("var a = []; a[100] = a.length; a[100] +' '+ a.length"),
      njs_str("0 101") },

    { njs_str("var a = [1,2]; a[100] = 100; a[100] +' '+ a.length"),
      njs_str("100 101") },

    { njs_str("var a = []; Object.defineProperty(a, 'length', {writable:0});"
              "Object.getOwnPropertyDescriptor(a, 'length').writable"),
      njs_str("false") },

    { njs_str("var a = []; Object.defineProperty(a, 'length', {writable:0});"
              "Object.defineProperty(a, 'length', {writable:true})"),
      njs_str("TypeError: Cannot redefine property: \"length\"") },

    { njs_str("var a = [0,1]; Object.defineProperty(a, 'length', {writable: false}); "
              "Object.defineProperty(a, 'length', {value:12})"),
      njs_str("TypeError: Cannot redefine property: \"length\"") },

    { njs_str("var a = [0,1]; Object.defineProperty(a, 'length', {writable: false}); "
              "Object.defineProperty(a, 'length', {value:2}); a.length"),
      njs_str("2") },

    { njs_str ("var a =[0,1,2]; Object.defineProperty(a, 100, {value:100});"
              "njs.dump(a);"),
      njs_str("[0,1,2,<97 empty items>,100]") },

    { njs_str("var a =[0,1,2]; Object.defineProperty(a, 3, {value:30});"
              "njs.dump(Object.getOwnPropertyDescriptor(a,3));"),
      njs_str("{value:30,writable:false,enumerable:false,configurable:false}") },

    { njs_str("var a =[0,1,2]; Object.defineProperty(a, 3, {value:30});"
              "a[3]=33;"),
      njs_str("TypeError: Cannot assign to read-only property \"3\" of array") },

    { njs_str("[1, 2, 3, 4, 5].copyWithin(0, 3)"),
      njs_str("4,5,3,4,5") },

    { njs_str("[1, 2, 3, 4, 5].copyWithin(0, 3, 4)"),
      njs_str("4,2,3,4,5") },

    { njs_str("[1, 2, 3, 4, 5].copyWithin(0, -2, -1)"),
      njs_str("4,2,3,4,5") },

    { njs_str("[1, 2, 3, 4, 5].copyWithin(100, 200, 500)"),
      njs_str("1,2,3,4,5") },

    { njs_str("[0, 1, , , 1].copyWithin(0, 1, 4)"),
      njs_str("1,,,,1") },

    { njs_str("[0, 1, 2, 3].copyWithin(0, 1, -10)"),
      njs_str("0,1,2,3") },

    { njs_str("var o = [0, 1, , , 1].copyWithin(0, 1, 4); typeof o"),
      njs_str("object") },

    { njs_str("[].copyWithin.call({length: 5, 3: 1}, 0, 3)"),
      njs_str("[object Object]") },

    { njs_str("var o = [1, 2, 3, 4]; Object.defineProperties(o, { 5: {value: 'abc'}});"
              "[].copyWithin.call(o, 0, 3, 4);"),
      njs_str("4,2,3,4,,abc") },

    { njs_str("var obj = {length: 5, 3: 1}; [].copyWithin.call(obj, 0, 3);"
              "Object.keys(obj)"),
      njs_str("0,3,length") },

    { njs_str("var obj = {length: 5, 1: 'a', 2: 'b', 3: 'c', 4: 'd', 5: 'e'};"
              "[].copyWithin.call(obj, 0, -2, -1);"
              "Object.keys(obj) + '|' + Object.values(obj)"),
      njs_str("0,1,2,3,4,5,length|c,a,b,c,d,e,5") },

    { njs_str("var o = {length:1}; Object.defineProperty(o, '0', {get:()=>{throw Error('Oops')}});"
              "Array.prototype.copyWithin.call(o, 0, 0)"),
      njs_str("Error: Oops") },

    { njs_str("Array.prototype.slice(1)"),
      njs_str("") },

    { njs_str("Array.prototype.slice(1,2)"),
      njs_str("") },

    { njs_str("Array.prototype.slice.call(undefined)"),
      njs_str("TypeError: cannot convert null or undefined to object") },

    { njs_str("Array.prototype.slice.call(1)"),
      njs_str("") },

    { njs_str("Array.prototype.slice.call(false)"),
      njs_str("") },

    { njs_str("Array.prototype.slice.call({'0':'a', '1':'b', length:1})"),
      njs_str("a") },

    { njs_str("Array.prototype.slice.call({'0':'a', '1':'b', length:2})"),
      njs_str("a,b") },

    { njs_str("Array.prototype.slice.call({'0':'a', '1':'b', length:4})"),
      njs_str("a,b,,") },

    { njs_str("Array.prototype.slice.call({'0':'a', '1':'b', length:2}, 1)"),
      njs_str("b") },

    { njs_str("Array.prototype.slice.call({'0':'a', '1':'b', length:2}, 1, 2)"),
      njs_str("b") },

    { njs_str("Array.prototype.slice.call({length:'2'})"),
      njs_str(",") },

    { njs_str("njs.dump(Array.prototype.slice.call({length: 3, 1: undefined }))"),
      njs_str("[<empty>,undefined,<empty>]") },

    { njs_str("Array.prototype.slice.call({length:new Number(3)})"),
      njs_str(",,") },

    { njs_str("Array.prototype.slice.call({length: { valueOf: function() { return 2; } }})"),
      njs_str(",") },

    { njs_str("Array.prototype.slice.call({ length: Object.create(null) })"),
      njs_str("TypeError: Cannot convert object to primitive value") },

    /* Large sparse slice goes through the non-fast keys path. */

    { njs_str("var a = []; a[10] = 'a'; a[40000] = 'b'; a.length = 50000;"
              "var s = a.slice(5, 45000);"
              "[s.length, s[5], s[39995], (10 in s), (40000 in s)].join(',')"),
      njs_str("44995,a,b,false,false") },

    { njs_str("Array.prototype.slice.call({length:-1})"),
      njs_str("") },

    { njs_str("Array.prototype[1] = 1; var x = [0]; x.length = 2;"
              "var a = x.slice(); a.hasOwnProperty('1')"),
      njs_str("true") },

    { njs_str("Array.prototype.slice.call('αβZγ')"),
      njs_str("α,β,Z,γ") },

    { njs_str("Array.prototype.slice.call('αβZγ', 1)"),
      njs_str("β,Z,γ") },

    { njs_str("Array.prototype.slice.call('αβZγ', 2)"),
      njs_str("Z,γ") },

    { njs_str("Array.prototype.slice.call('αβZγ', 3)"),
      njs_str("γ") },

    { njs_str("Array.prototype.slice.call('αβZγ', 4)"),
      njs_str("") },

    { njs_str("Array.prototype.slice.call('αβZγ', 0, 1)"),
      njs_str("α") },

    { njs_str("Array.prototype.slice.call('αβZγ', 1, 2)"),
      njs_str("β") },

    { njs_str("Array.prototype.slice.call('αβZγ').length"),
      njs_str("4") },

    { njs_str("Array.prototype.slice.call('αβZγ')[1].length"),
      njs_str("1") },

    { njs_str("Array.prototype.slice.call(new String('αβZγ'))"),
      njs_str("α,β,Z,γ") },

    { njs_str("1..__proto__.length = '2';"
                 "Array.prototype.slice.call(1, 0, 2)"),
      njs_str(",") },

    { njs_str("var a = [1, /**/, 3, 4];"
              "Object.defineProperty(a.__proto__, 1, {"
              "    get: () => {"
              "        a.length = 10**6;"
              "        return 2;"
              "    }"
              "});"
              "a.slice(1)"),
      njs_str("2,3,4") },

    { njs_str("Array.prototype.pop()"),
      njs_str("undefined") },

    { njs_str("var o = {0: 'a', 1: 'b', 2: 'c', 'length': 3};"
              "Array.prototype.pop.call(o); var res = o.length;"
              "Array.prototype.forEach.call(o, (v) => {res += ', ' + v}); res"),
      njs_str("2, a, b") },

    { njs_str("var obj = {}; obj.pop = Array.prototype.pop; obj.pop(); obj.length === 0"),
      njs_str("true") },

    { njs_str("Array.prototype[1] = 1; [0,,].pop()"),
      njs_str("1") },

    { njs_str("Array.prototype[1] = 1; var a = [0,,]; a.pop(); a.length"),
      njs_str("1") },

    { njs_str("Object.prototype[1] = 1; Object.prototype.length = 2; Array.prototype.pop.call({0:0})"),
      njs_str("1") },

    { njs_str("var a = []; Object.freeze(a); Object.getOwnPropertyDescriptor(a, 'length').writable"),
      njs_str("false") },

    { njs_str("var o = Object.freeze([0,1,2]); o.length=3"),
      njs_str("TypeError: Cannot assign to read-only property \"length\" of array") },

    { njs_str("var o = Object.freeze({0: 0, 1: 1, length: 2}); Array.prototype.pop.call(o)"),
      njs_str("TypeError: Cannot delete property \"1\" of object") },

    { njs_str("var i = 0; var o = {get length() {i++}};"
              "try {Array.prototype.pop.call(o);}"
              "catch (e) {i += '; ' + e} i"),
      njs_str("1; TypeError: Cannot set property \"length\" of object which has only a getter") },

    { njs_str("Array.prototype.pop.call({ length: 3 })"),
      njs_str("undefined") },

    { njs_str("var o = { length: 3 }; Array.prototype.pop.call(o); o.length"),
      njs_str("2") },

    { njs_str(njs_declare_sparse_array("a", 16)
              "a[a.length - 1] = 'z'; a[a.length -2] = 'y';"
              "Array.prototype.pop.call(a); [a.length, a[a.length - 1]]"),
      njs_str("15,y") },

    { njs_str("var a = new Array(1), arrayPrototypeGet0Calls = 0;"
              "Object.defineProperty(Array.prototype, '0', {"
              "    get() { Object.defineProperty(a, 'length', {writable: false});"
              "            arrayPrototypeGet0Calls++;"
              "    },"
              "});"
              "var e = null;"
              "try { a.pop(); } catch (ee) { e = ee.name };"
              "[e, a.length, arrayPrototypeGet0Calls]"),
      njs_str("TypeError,1,1") },

    { njs_str("[0,1].slice()"),
      njs_str("0,1") },

    { njs_str("[1,2,3,,,4].slice()"),
      njs_str("1,2,3,,,4") },

    { njs_str("[0,1].slice(undefined)"),
      njs_str("0,1") },

    { njs_str("[0,1].slice(undefined, undefined)"),
      njs_str("0,1") },

    { njs_str("[0,1,2,3,4].slice(1,4)"),
      njs_str("1,2,3") },

    { njs_str("[0,1,2,3,4].slice(6,7)"),
      njs_str("") },

    { njs_str("var a = [1,2,3,4,5], b = a.slice(3);"
              "b[0] +' '+ b[1] +' '+ b[2]"),
      njs_str("4 5 undefined") },

    { njs_str("var a = [1,2]; a.pop() +' '+ a.length +' '+ a"),
      njs_str("2 1 1") },

    { njs_str("var a = [1,2], len = a.push(3); len +' '+ a.pop() +' '+ a"),
      njs_str("3 3 1,2") },

    { njs_str("var a = [1,2], len = a.push(3,4,5);"
              "len +' '+ a.pop() +' '+ a"),
      njs_str("5 5 1,2,3,4") },

    { njs_str("var x = {'0': 'a', '1': 'b', '2': 'c', 'length': 3};"
              "Array.prototype.push.call(x, 'x', 'y', 'z', 123) +' '+ x[0] +' '+ x.length"),
      njs_str("7 a 7") },

    { njs_str("var x = {'0': 'a', '1': 'b', '2': 'c', 'length': 3}; var a = [];"
              "Array.prototype.push.call(x, 'x', 'y', 'z', 123);"
              "Array.prototype.forEach.call(x, (v) => a.push(v)); a"),
      njs_str("a,b,c,x,y,z,123") },

    { njs_str("var i = 0; var o = {get length() {i++}};"
              "try {Array.prototype.push.call(o);}"
              "catch (e) {i += '; ' + e} i"),
      njs_str("1; TypeError: Cannot set property \"length\" of object which has only a getter") },

    { njs_str("var x = []; x.length = 4294967295; var push = x.push(); push === 4294967295"),
      njs_str("true") },

    { njs_str("var x = []; x.length = 4294967295; x.push(); x.push(1)"),
      njs_str("RangeError: Invalid array length") },

    { njs_str("var x = []; x.length = 4294967295; x.push(); "
              "try {x.push('x')} catch (e) {}; x[4294967295]"),
      njs_str("x") },

    { njs_str("var x = []; x.length = 4294967295; x.push(); "
              "try {x.push('x')} catch (e) {}; x.length"),
      njs_str("4294967295") },

    { njs_str("["
              " [2**53-2, [1]],"
              " [2**53-2, [1,2]],"
              " [2**53-1, [1]],"
              " [2**53, []],"
              " [Number.POSITIVE_INFINITY, []],"
              "]"
              ".map(args=>{ try {return Array.prototype.push.apply({length:args[0]}, args[1])}"
              "             catch (e) {return e.name} })"),
      njs_str("9007199254740991,TypeError,TypeError,9007199254740991,9007199254740991") },

    { njs_str("Array.prototype.shift()"),
      njs_str("undefined") },

    { njs_str("var a = [1,2,3]; a.shift() +' '+ a[0] +' '+ a.length"),
      njs_str("1 2 2") },

    { njs_str("Array.prototype[0] = 1; var x = [,2]; x.length = 2; x.shift()"),
      njs_str("1") },

    { njs_str("var x = {'0': 'x', '1': 'y', '2': 'z', 'length': 3};"
              "Array.prototype.shift.call(x) +' '+ x[0] +' '+ x.length"),
      njs_str("x y 2") },

    { njs_str("var i = 0; var o = {get length() {i++}};"
              "try {Array.prototype.shift.call(o);}"
              "catch (e) {i += '; ' + e} i"),
      njs_str("1; TypeError: Cannot set property \"length\" of object which has only a getter") },

    { njs_str("var a = [1,2], len = a.unshift(3);"
                 "len +' '+ a +' '+ a.shift()"),
      njs_str("3 3,1,2 3") },

    { njs_str("var a = [1,2], len = a.unshift(3,4,5);"
                 "len +' '+ a +' '+ a.shift()"),
      njs_str("5 3,4,5,1,2 3") },

    { njs_str("var x = {'0': 'x', '1': 'y', '2': 'z', 'length': 3}; var a = [];"
              "Array.prototype.unshift.call(x, 'a', 'b', 'c');"
              "Array.prototype.forEach.call(x, (v) => a.push(v)); a + ', ' + x.length"),
      njs_str("a,b,c,x,y,z, 6") },

    { njs_str("var x = {}; x.length = 1; var a = [];"
              "Array.prototype.unshift.call(x, 'a', 'b', 1025, 'c', 'oh my');"
              "Array.prototype.forEach.call(x, (v) => a.push(v)); a + ', ' + x.length"),
      njs_str("a,b,1025,c,oh my, 6") },

    { njs_str("var x = {5: 1, 6: 2, length: 7}; var a = [];"
              "Array.prototype.unshift.call(x, '0');"
              "Array.prototype.forEach.call(x, (v) => a.push(v)); a + ', ' + x.length"),
      njs_str("0,1,2, 8") },

    { njs_str("var x = {5: 2, 10: 3, 11: 4, 12: 5, 20: 6, length: 21}; var a = [];"
              "Array.prototype.unshift.call(x, '0', '1');"
              "Array.prototype.forEach.call(x, (v, k) => a.push(k + ':' + v)); a + ', ' + x.length"),
      njs_str("0:0,1:1,7:2,12:3,13:4,14:5,22:6, 23") },

    { njs_str("var x = {0: 0, length: 2**32-2};"
              "Array.prototype.unshift.call(x, '0', '1'); Object.keys(x).sort()"),
      njs_str("0,1,2,length") },

    { njs_str("var x = {0: 0, length: 2**53-3};"
              "Array.prototype.unshift.call(x, '0', '1'); x.length"),
      njs_str("9007199254740991") },

    { njs_str("var x = {0: 0}; Array.prototype.unshift.call(x); x.length"),
      njs_str("0") },

    { njs_str("var obj = {'10000000': 'x', '10000001': 'y', '10000002': 'z'}; var a = [];"
              "obj.length = 90000000;"
              "Array.prototype.unshift.call(obj, 'a', 'b', 'c');"
              "Array.prototype.forEach.call(obj, (v) => a.push(v)); a"),
      njs_str("a,b,c,x,y,z")},

    { njs_str("var i = 0; var o = {get length() {i++}};"
              "try {Array.prototype.unshift.call(o);}"
              "catch (e) {i += '; ' + e} i"),
      njs_str("1; TypeError: Cannot set property \"length\" of object which has only a getter") },

    { njs_str("var a=[0], n = 64; while(--n) {a.push(n); a.shift()}; a"),
      njs_str("1") },

    { njs_str("Array.prototype.shift.call({ length: 3 })"),
      njs_str("undefined") },

    { njs_str("var o = { length: 3 }; Array.prototype.shift.call(o); o.length"),
      njs_str("2") },

    { njs_str("var a = [1,2,3];"
              "Object.defineProperty(a, '1', {enumerable:false});"
              "a.shift(); a"),
      njs_str("2,3") },

    { njs_str("var arr = [1,2];"
              "arr.shift();"
              "arr[2**20] = 3;"
              "arr[2**20]"),
      njs_str("3") },

    { njs_str("var a = []; a.splice()"),
      njs_str("") },

    { njs_str("[].splice(0,5,0)"),
      njs_str("") },

    { njs_str("[1,2,3,4,5].splice(-2,3,0)"),
      njs_str("4,5") },

    { njs_str("[].__proto__.splice(0,1,0)"),
      njs_str("") },

    { njs_str("var a = [];"
                 "a.splice(9,0,1,2).join(':') + '|' + a"),
      njs_str("|1,2") },

    { njs_str("var a = [0,1,2,3,4,5,6,7];"
                 "a.splice(3).join(':') + '|' + a"),
      njs_str("3:4:5:6:7|0,1,2") },

    { njs_str("var a = [0,1,2,3,4,5,6,7];"
                 "a.splice(3, 2).join(':') + '|' + a"),
      njs_str("3:4|0,1,2,5,6,7") },

    { njs_str("var a = [0,1,2,3,4,5,6,7];"
                 "a.splice(3, 2, 8, 9, 10, 11 ).join(':') + '|' + a"),
      njs_str("3:4|0,1,2,8,9,10,11,5,6,7") },

    { njs_str("["
              " [],"
              " [1],"
              " [1, 2],"
              " [1, 2, 'a'],"
              " [1, 2, 'a', 'b'],"
              " [1, 2, 'a', 'b', 'c'],"
              "]"
              ".map(args=>{var a = [0,1,3,4,5]; a.splice.apply(a, args); return a})"
              ".map(v=>v.join(''))"),
      njs_str("01345,0,045,0a45,0ab45,0abc45") },

    { njs_str("["
              " [],"
              " [1],"
              " [1, 1, 'a'],"
              " [1, 2, 'a'],"
              " [1, 2, 'a', 'b'],"
              " [1, 2, 'a', 'b', 'c'],"
              "]"
              ".map(args=>{var a = [0,1,3,4,5]; return a.splice.apply(a, args);})"
              ".map(v=>v.join(''))"),
      njs_str(",1345,1,13,13,13") },

    { njs_str("Object.prototype.splice = Array.prototype.splice;"
              "Object.prototype.join = Array.prototype.join;"
              "["
              " [],"
              " [1],"
              " [1, 2],"
              " [1, 1, 'a'],"
              " [1, 2, 'a'],"
              " [1, 2, 'a', 'b'],"
              " [1, 2, 'a', 'b', 'c'],"
              "]"
              ".map(args=>{var a = {0:0, 1:1, 2:3, 3:4, 4:5, length:5};"
              "            a.splice.apply(a, args); return a})"
              ".map(v=>v.join(''))"),
      njs_str("01345,0,045,0a345,0a45,0ab45,0abc45") },

    { njs_str("Object.prototype.splice = Array.prototype.splice;"
              "Object.prototype.join = Array.prototype.join;"
              "["
              " [],"
              " [1],"
              " [1, 0, 'a'],"
              " [1, 1, 'a'],"
              " [1, 2, 'a'],"
              " [1, 2, 'a', 'b'],"
              " [1, 2, 'a', 'b', 'c'],"
              "]"
              ".map(args=>{var a = {0:0, 1:1, 2:3, 3:4, 4:5, length:5};"
              "            return a.splice.apply(a, args);})"
              ".map(v=>v.join(''))"),
      njs_str(",1345,,1,13,13,13") },

    { njs_str("var a = ['x'];"
              "var d = a.splice(0, { valueOf() {  a.length = 0; return 10; } });"
              "njs.dump(d)"),
      njs_str("[<empty>]") },

    { njs_str("var a = ['a', 'b', 'c'];"
              "var d = a.splice(0, { valueOf() {  a.length = 2; return 3; } });"
              "njs.dump(d)"),
      njs_str("['a','b',<empty>]") },

#if NJS_HAVE_LARGE_STACK
    { njs_str("let arr = [ 'x' ];"
              "let a = { toString() {"
               "          new Float64Array(100).set(["
               "            {toString() {Array.prototype.splice.call(arr, a)}}"
               "          ])"
               "        }};"
               "a.toString()"),
      njs_str("RangeError: Maximum call stack size exceeded") },
#endif

    { njs_str("var o = { toString: () => {"
              "             for (var i = 0; i < 0x10; i++) {a.push(1)};"
              "             return {};"
              "}};"
              "var a = [o];"
              "a.join()"),
      njs_str("TypeError: Cannot convert object to primitive value") },

    { njs_str("Array.prototype.splice.call({0:0,1:1,2:2,3:3,length:4},0,3,4,5)"),
      njs_str("0,1,2") },

    { njs_str("var obj = {0:0,1:1,2:2,3:3,length:4};"
              "Array.prototype.splice.call(obj,0,3,4,5); obj[3]"),
      njs_str("undefined") },

    { njs_str("var obj = {4294967294: 'x', length:-1};"
              "Array.prototype.splice.call(obj, 4294967294, 1); obj.length"),
      njs_str("0") },

    { njs_str("var obj = {0:0, 1:1, 2:2};"
              "Object.defineProperty(obj, 'length', {value:3, writable:false});"
              "Array.prototype.splice.call(obj, 1, 2, 4)"),
      njs_str("TypeError: Cannot assign to read-only property \"length\" of object") },

    { njs_str("var obj = {'9007199254740988': 'A', '9007199254740989': 'B',"
              "           '9007199254740990': 'C', '9007199254740991': 'D', "
              "           length: 2 ** 53 + 2};"
              "Array.prototype.splice.call(obj, 2**53-3, 2 ** 53 + 4)"),
      njs_str("B,C") },

    { njs_str("var obj = {'9007199254740988': 'A', '9007199254740989': 'B',"
              "           '9007199254740990': 'C', '9007199254740991': 'D', "
              "           length: 2 ** 53 + 2};"
              "Array.prototype.splice.call(obj, 2**53-3, 2 ** 53 + 4);"
              "obj['9007199254740988'] == 'A' && obj['9007199254740991'] == 'D'"),
      njs_str("true") },

    { njs_str("var obj = {'9007199254740990': 'A', '9007199254740991': 'B',"
              "           length: 2 ** 53 - 1};"
              "Array.prototype.splice.call(obj, 2**53-2, 1, 'C');"
              "obj['9007199254740990'] == 'C' && obj['9007199254740991'] == 'B'"),
      njs_str("true") },

    { njs_str("var obj = {'9007199254740990': 'A', '9007199254740991': 'B',"
              "           length: 2 ** 53 - 1};"
              "Array.prototype.splice.call(obj, 2**53-2, 0, 'C');"),
      njs_str("TypeError: Invalid length") },

    { njs_str("var a = {1: 'B', length: 2};"
              "Array.prototype.splice.call(a, 0)"),
      njs_str(",B") },

    { njs_str("var a = new Uint8Array();"
              "a.__proto__ = [1,2,3];"
              "a.splice(0)"),
      njs_str(",,") },

    { njs_str("'/A/B/C/D/'.split('/').toSpliced(1,1).join('/')"),
      njs_str("/B/C/D/") },

    { njs_str("let r, arr = new Array(4);"
              "Object.defineProperty(arr, 0, { get: () => { throw 'Oops'; } });"
              "try { r = arr.toSpliced(0, 0); } catch (e) { }"
              "r.toString()"),
      njs_str("TypeError: cannot get property \"toString\" of undefined") },

    { njs_str("var a = []; a.reverse()"),
      njs_str("") },

    { njs_str("var a = [1]; a.reverse()"),
      njs_str("1") },

    { njs_str("var a = [1,2]; a.reverse()"),
      njs_str("2,1") },

    { njs_str("var a = [1,2,3]; a.reverse()"),
      njs_str("3,2,1") },

    { njs_str("var a = [1,2,3,4]; a.reverse()"),
      njs_str("4,3,2,1") },

    { njs_str("[1,2,3,,,].reverse()"),
      njs_str(",,3,2,1") },

    { njs_str("[,2,3,,,].reverse()"),
      njs_str(",,3,2,") },

    { njs_str("[,,,3,2,1].reverse()"),
      njs_str("1,2,3,,,") },

    { njs_str("var a = [,,2,1];"
              "Object.defineProperty(a.__proto__, 0, {"
              "    get: () => {"
              "        a.length = 10**6;"
              "        return 4;"
              "    },"
              "    set: (setval) => { Object.defineProperty(a, 0, { value: setval }); },"
              "});"
              "a.reverse();"
              "a.slice(0, 4)"),
      njs_str("1,2,,4") },

    { njs_str("var o = {1:true, 2:'', length:-2}; Array.prototype.reverse.call(o) === o"),
      njs_str("true") },

    { njs_str("["
              " ['a','b','c'],"
              " ['a','b','c','d'],"
              " [,'b','c','d'],"
              " ['a','b','c',],"
              " [,'b','c',],"
              "]"
              ".map(v=>Object.defineProperty(v, 1, {value:v[1], enumerable:false}))"
              ".map(v=>v.reverse().join(''))"),
      njs_str("cba,dcba,dcb,cba,cb") },

    { njs_str("Array.prototype[1] = 1; var x = [0]; x.length = 2; x.reverse(); x"),
      njs_str("1,0") },

    { njs_str("Array.prototype[0] = 0; var x = [,1]; x.reverse(); x"),
      njs_str("1,0") },

    { njs_str("let r, arr = new Array(4);"
              "Object.defineProperty(arr, 0, { get: () => { throw 'Oops'; } });"
              "try { r = arr.toReversed(0, 0); } catch (e) { }"
              "r.toString()"),
      njs_str("TypeError: cannot get property \"toString\" of undefined") },

    { njs_str("var a = [,3,2,1]; njs.dump([a.toReversed(),a])"),
      njs_str("[[1,2,3,undefined],[<empty>,3,2,1]]") },

    { njs_str("var a = [1,2,3,4]; a.indexOf()"),
      njs_str("-1") },

    { njs_str("var a = [1,2,3,4]; a.indexOf(5)"),
      njs_str("-1") },

    { njs_str("var a = [1,2,3,4]; a.indexOf(4, 3)"),
      njs_str("3") },

    { njs_str("var a = [1,2,3,4]; a.indexOf(4, 4)"),
      njs_str("-1") },

    { njs_str("var a = [1,2,3,4,3,4]; a.indexOf(3, '2')"),
      njs_str("2") },

    { njs_str("var a = [1,2,3,4,3,4]; a.indexOf(4, -1)"),
      njs_str("5") },

    { njs_str("var a = [1,2,3,4,3,4]; a.indexOf(3, -10)"),
      njs_str("2") },

    { njs_str("[].indexOf.bind(0)(0, 0)"),
      njs_str("-1") },

    { njs_str("var o = 'abcd';"
              "Array.prototype.indexOf.call(o, 'c')"),
      njs_str("2") },

    { njs_str("var o = {0: 'a', 1: 'b', 2: 'c'};"
              "Object.defineProperty(o, 'length', {get: () => 4});"
              "Object.defineProperty(o, '3', {get: () => 'd'});"
              "Array.prototype.indexOf.call(o, 'd')"),
      njs_str("3") },

    { njs_str("var i = 0; var o = {get length() {i++}};"
              "Array.prototype.indexOf.call(o); i"),
      njs_str("1") },

    { njs_str("var a = new Array(); a[100] =1; a[99999] = ''; a[10] = new Object(); "
              "a[5555] = 5.5; a[123456] = 'str'; a[5] = 1E+309; "
              "[1, '', 'str', 1E+309, 5.5, true, 5, 'str1', null, new Object()].map(v=>a.indexOf(v))"),
      njs_str("100,99999,123456,5,5555,-1,-1,-1,-1,-1") },

    { njs_str("Array.prototype.indexOf.call({199:true, 200:'200.59', length:200}, '200.59')"),
      njs_str("-1") },

    { njs_str("Array.prototype.indexOf.call({199:true, 200:'200.59', length:201}, '200.59')"),
      njs_str("200") },

    { njs_str("Array.prototype.indexOf.call({1:true, 2:'200.59', length:2}, '200.59')"),
      njs_str("-1") },

    { njs_str("Array.prototype.indexOf.call({1:true, 2:'200.59', length:3}, '200.59')"),
      njs_str("2") },

    { njs_str("var stopped = 0;"
              "var o = {length:3}; "
              "Object.defineProperty(o, '1',{get:()=>{throw 'Oops'}});"
              "Object.defineProperty(o, '2', {get:()=>stopped++});"
              "try { Array.prototype.indexOf.call(o, 7)} catch (e) {};"
              "stopped"),
      njs_str("0") },

    { njs_str("[].lastIndexOf(1, -1)"),
      njs_str("-1") },

    { njs_str("[undefined].lastIndexOf()"),
      njs_str("0") },

    { njs_str("[undefined].lastIndexOf(undefined)"),
      njs_str("0") },

    { njs_str("var a = [1,2,3,4]; a.lastIndexOf()"),
      njs_str("-1") },

    { njs_str("var a = [1,2,3,4]; a.lastIndexOf(5)"),
      njs_str("-1") },

    { njs_str("var a = [1,2,3,4,3,4]; a.lastIndexOf(1, 0)"),
      njs_str("0") },

    { njs_str("var a = [1,2,3,4,3,4]; a.lastIndexOf(3, '2')"),
      njs_str("2") },

    { njs_str("var a = [1,2,3,4,3,4]; a.lastIndexOf(1, 6)"),
      njs_str("0") },

    { njs_str("var a = [1,2,3,4,3,4]; a.lastIndexOf(2, 6)"),
      njs_str("1") },

    { njs_str("var a = [1,2,3,4,3,4]; a.lastIndexOf(4, -1)"),
      njs_str("5") },

    { njs_str("var a = [1,2,3,4,3,4]; a.lastIndexOf(4, -6)"),
      njs_str("-1") },

    { njs_str("var a = [1,2,3,4,3,4]; a.lastIndexOf(3, -10)"),
      njs_str("-1") },

    { njs_str("[1,2,3].lastIndexOf(1, -5.3)"),
      njs_str("-1") },

    { njs_str("[1,2,1].lastIndexOf(2,undefined)"),
      njs_str("-1") },

    { njs_str("[1,2,1].lastIndexOf(1,undefined)"),
      njs_str("0") },

    { njs_str("[1,2,1].lastIndexOf(1)"),
      njs_str("2") },

    { njs_str("var stopped = 0;"
              "var o = {length:3}; "
              "Object.defineProperty(o, '1', {get:()=>stopped++});"
              "Object.defineProperty(o, '2',{get:()=>{throw 'Oops'}});"
              "try { Array.prototype.lastIndexOf.call(o)} catch (e) {};"
              "stopped"),
      njs_str("0") },

    { njs_str("var o = 'addc';"
              "Array.prototype.lastIndexOf.call(o, 'd')"),
      njs_str("2") },

    { njs_str("var o = 'dddd';"
              "Array.prototype.lastIndexOf.call(o, 'd')"),
      njs_str("3") },

    { njs_str("var o = 'dabc';"
              "Array.prototype.lastIndexOf.call(o, 'd')"),
      njs_str("0") },

    { njs_str("var o = 'АБВГ';"
              "Array.prototype.lastIndexOf.call(o, 'Г')"),
      njs_str("3") },

    { njs_str("var o = 'ГВБА';"
              "Array.prototype.lastIndexOf.call(o, 'Г')"),
      njs_str("0") },

    { njs_str("var o = 'ВГБА';"
              "Array.prototype.lastIndexOf.call(o, 'Г')"),
      njs_str("1") },

    { njs_str("var o = {0: 'a', 1: 'd', 2: 'd'};"
              "Object.defineProperty(o, 'length', {get: () => 4});"
              "Object.defineProperty(o, '3', {get: () => 'd'});"
              "Array.prototype.lastIndexOf.call(o, 'd')"),
      njs_str("3") },

    { njs_str("var a = new Array(); a[100] =1; a[99999] = ''; a[10] = new Object(); "
              "a[5555] = 5.5; a[123456] = 'str'; a[5] = 1E+309; "
              "[1,'', 'str', 1E+309, 5.5, true, 5, 'str1', null, new Object()].map(v=>a.lastIndexOf(v))"),
      njs_str("100,99999,123456,5,5555,-1,-1,-1,-1,-1") },

    { njs_str("var obj = {'10000000': 'x', '10000001': 'y', '10000002': 'z'}; var a = [];"
              "obj.length = 90000000;"
              "Array.prototype.lastIndexOf.call(obj, 'y');"),
      njs_str("10000001")},

    { njs_str("var i = 0; var o = {get length() {i++}};"
              "Array.prototype.lastIndexOf.call(o); i"),
      njs_str("1") },

    { njs_str("Array.prototype.lastIndexOf.call({199:true, 200:'200.59', length:200}, '200.59')"),
      njs_str("-1") },

    { njs_str("Array.prototype.lastIndexOf.call({0:'undefined', length:0}, 'undefined')"),
      njs_str("-1") },

    { njs_str("[1,0,-1,-2].map(v => Array.prototype.lastIndexOf.call('Ф', 'Ф', v))"),
      njs_str("0,0,0,-1") },

    { njs_str("[''].lastIndexOf.call('00000000000000000000000000000а00')"),
      njs_str("-1") },

    { njs_str("var o = 'ГВБА';"
              "Array.prototype.lastIndexOf.call(o, 'Г', 0)"),
      njs_str("0") },

    { njs_str("var o = 'ГВБА';"
              "Array.prototype.lastIndexOf.call(o, 'Г', 4)"),
      njs_str("0") },

    { njs_str("[1,2,3,4].includes()"),
      njs_str("false") },

    { njs_str("[1,2,3,4].includes(5)"),
      njs_str("false") },

    { njs_str("[1,2,3,4].includes(4, 3)"),
      njs_str("true") },

    { njs_str("[1,2,3,4].includes(4, 4)"),
      njs_str("false") },

    { njs_str("[1,2,3,4,3,4].includes(3, '2')"),
      njs_str("true") },

    { njs_str("[1,2,3,4,3,4].includes(4, -1)"),
      njs_str("true") },

    { njs_str("[1,2,3,4,3,4].includes(3, -10)"),
      njs_str("true") },

    { njs_str("[1,2,3,NaN,3,4].includes(NaN)"),
      njs_str("true") },

    { njs_str("[1,2,3,4,5].includes(NaN)"),
      njs_str("false") },

    { njs_str("[].includes.bind(0)(0, 0)"),
      njs_str("false") },

    { njs_str("var o = {0: 'a', 1: 'b', 2: 'c'};"
              "Object.defineProperty(o, 'length', {get: () => 4});"
              "Object.defineProperty(o, '3', {get: () => 'd'});"
              "Array.prototype.includes.call(o, 'd')"),
      njs_str("true") },

    { njs_str("var obj = {'0': 'a', '1': 'b', '10000000': 'c', '10000001': 'd', '10000002': 'e'};"
              "var fromIndex = 1;"
              "obj.length = 90000000;"
              "Array.prototype.includes.call(obj, 'c', fromIndex);"),
      njs_str("true") },

    { njs_str("var obj = {'0': 'a', '1': 'b', '10000000': 'c', '10000001': 'd', '10000002': 'e'};"
              "var fromIndex = 1;"
              "obj.length = 90000000;"
              "Array.prototype.includes.call(obj, 'a', fromIndex);"),
      njs_str("false") },

    { njs_str("var stopped = 0;"
              "var o = {length:3}; "
              "Object.defineProperty(o, '1',{get:()=>{throw 'Oops'}});"
              "Object.defineProperty(o, '2', {get:()=>stopped++});"
              "try { Array.prototype.includes.call(o, 7)} catch (e) {};"
              "stopped"),
      njs_str("0") },

    { njs_str("var a = []; var s = { sum: 0 };"
                 "a.forEach(function(v, i, a) { this.sum += v }, s); s.sum"),
      njs_str("0") },

    { njs_str("var a = new Array(3); var s = { sum: 0 };"
                 "a.forEach(function(v, i, a) { this.sum += v }, s); s.sum"),
      njs_str("0") },

    { njs_str("var a = [,,,]; var s = { sum: 0 };"
                 "a.forEach(function(v, i, a) { this.sum += v }, s); s.sum"),
      njs_str("0") },

    { njs_str("var a = [1,2,3]; var s = { sum: 0 };"
                 "a.forEach(function(v, i, a) { this.sum += v }, s); s.sum"),
      njs_str("6") },

    { njs_str("var a = [1,2,3];"
                 "a.forEach(function(v, i, a) { a[i+3] = a.length }); a"),
      njs_str("1,2,3,3,4,5") },

    { njs_str("function f() { var c; [1].forEach(function(v) { c })}; f()"),
      njs_str("undefined") },

    { njs_str("var a = [1,2,3]; var s = { sum: 0 };"
                 "[].forEach.call(a, function(v, i, a) { this.sum += v }, s);"
                 "s.sum"),
      njs_str("6") },

    { njs_str("var a = [1,2,3]; var s = { sum: 0 };"
                 "[].forEach.apply(a,"
                                  "[ function(v, i, a) { this.sum += v }, s ]);"
                 "s.sum"),
      njs_str("6") },

    { njs_str("var a = []; var c = 0;"
                 "a.forEach(function(v, i, a) { c++ }); c"),
      njs_str("0") },

    { njs_str("var a = [,,,,]; var c = 0;"
                 "a.forEach(function(v, i, a) { c++ }); c"),
      njs_str("0") },

    { njs_str("var o = {0: 'a', 1: 'b', 2: 'c'};"
              "Object.defineProperty(o, 'length', {get: () => 4});"
              "Object.defineProperty(o, '3', {get: () => 'd'});"
              "var r = ''; Array.prototype.forEach.call(o, function(v, i, a) { r += v }); r"),
      njs_str("abcd") },

    { njs_str("var s = 't'; var t = '';"
              "Array.prototype.forEach.call(s, function (a, b, c) {t = typeof c;}); [t, typeof s];"),
      njs_str("object,string") },

    { njs_str("[].some(function(v) { return v > 1 })"),
      njs_str("false") },

    { njs_str("[11].some(function(v) { return 5 })"),
      njs_str("true") },

    { njs_str("[1,2,3].some(function(v) { return v > 1 })"),
      njs_str("true") },

    { njs_str("[1,2,3].some(function(v) { return v > 2 })"),
      njs_str("true") },

    { njs_str("[1,2,3].some(function(v) { return v > 3 })"),
      njs_str("false") },

    { njs_str("var o = {0: 'a', 1: 'b', 2: 'c', 'length': { valueOf: function() { return 3 }}};"
              "var r = Array.prototype.some.call(o, function(el, i, arr) {return el == 'c'}); r"),
      njs_str("true") },

    { njs_str("var o = {0: 'a', 1: 'b', 2: 'd', 'length': { valueOf: function() { return 3 }}};"
              "var r = Array.prototype.some.call(o, function(el, i, arr) {return el == 'c'}); r"),
      njs_str("false") },

    { njs_str("var o = {0: 'a', 1: 'b', 2: 'c'};"
              "Object.defineProperty(o, 'length', {get: () => 4});"
              "Object.defineProperty(o, '3', {get: () => 'd'});"
              "var r = Array.prototype.some.call(o, function(v, i, a) { return v === 'd' }); r"),
      njs_str("true") },

    { njs_str("[].every(function(v) { return v > 1 })"),
      njs_str("true") },

    { njs_str("var accessed = false;"
              "[1].every((v) => {accessed = true; return 0; }) === false && accessed === true"),
      njs_str("true") },

    { njs_str("[3,2,1].every(function(v) { return v > 3 })"),
      njs_str("false") },

    { njs_str("[3,2,1].every(function(v) { return v > 2 })"),
      njs_str("false") },

    { njs_str("[3,2,1].every(function(v) { return v > 0 })"),
      njs_str("true") },

    { njs_str("var o = {0: 'c', 1: 'b', 2: 'c', 'length': { valueOf() { return 3 }}};"
              "var r = Array.prototype.every.call(o, function(el, i, arr) {return el == 'c'}); r"),
      njs_str("false") },

    { njs_str("var o = {0: 'c', 1: 'c', 2: 'c', 'length': { valueOf() { return 3 }}};"
              "var r = Array.prototype.every.call(o, function(el, i, arr) {return el == 'c'}); r"),
      njs_str("true") },

    { njs_str("var obj = new Date(); obj.length = 1; obj[0] = 1;"
              "Array.prototype.every.call(obj, (val,idx,obj)=>!(obj instanceof Date))"),
      njs_str("false") },

    { njs_str("Array.prototype.every.call({0:11,1:9,length:2**32+1}, val=>val>10)"),
      njs_str("false") },

    { njs_str("var vis = false; var a = []; "
              "Object.defineProperty(a, '0', {get:()=>{vis = true; return 11;}, configurable:true});"
              "Object.defineProperty(a, '1', {get:()=>{if (vis) {return 9;} else {return 11}}, configurable:true});"
              "a.every(val=>val > 10)"),
      njs_str("false") },

    { njs_str("var o = {0: 'x', 1: 'y', 2: 'z'};"
              "Object.defineProperty(o, 'length', {get: () => 4});"
              "Object.defineProperty(o, '3', {get: () => 'a'});"
              "var r = Array.prototype.some.call(o, function(v, i, a) { return v === 'a' }); r"),
      njs_str("true") },

    { njs_str("var o = {0: 'a', 1: 'b', 2: 'c'};"
              "Object.defineProperty(o, 'length', {get: () => 4});"
              "Object.defineProperty(o, '3', {get: () => 'b'});"
              "var r = Array.prototype.some.call(o, function(v, i, a) { return v === 'y' }); r"),
      njs_str("false") },

    { njs_str("[].fill(1);"),
      njs_str("") },

    { njs_str("[1,2,3].fill(5);"),
      njs_str("5,5,5") },

    { njs_str("[1,2,3].fill(5, 0);"),
      njs_str("5,5,5") },

    { njs_str("[1,2,3].fill(5, 1);"),
      njs_str("1,5,5") },

    { njs_str("[1,2,3].fill(5, 4);"),
      njs_str("1,2,3") },

    { njs_str("[1,2,3].fill(5, -2);"),
      njs_str("1,5,5") },

    { njs_str("[1,2,3].fill(5, -3);"),
      njs_str("5,5,5") },

    { njs_str("[1,2,3].fill(5, -4);"),
      njs_str("5,5,5") },

    { njs_str("[1,2,3].fill(5, 1, 0);"),
      njs_str("1,2,3") },

    { njs_str("[1,2,3].fill(5, 1, 1);"),
      njs_str("1,2,3") },

    { njs_str("[1,2,3].fill(5, 1, 2);"),
      njs_str("1,5,3") },

    { njs_str("[1,2,3].fill(5, 1, 3);"),
      njs_str("1,5,5") },

    { njs_str("[1,2,3].fill(5, 1, 4);"),
      njs_str("1,5,5") },

    { njs_str("[1,2,3].fill(5, 1, -1);"),
      njs_str("1,5,3") },

    { njs_str("[1,2,3].fill(5, 1, -3);"),
      njs_str("1,2,3") },

    { njs_str("[1,2,3].fill(5, 1, -4);"),
      njs_str("1,2,3") },

    { njs_str("[1,2,3].fill(\"a\", 1, 2);"),
      njs_str("1,a,3") },

    { njs_str("[1,2,3].fill({a:\"b\"}, 1, 2);"),
      njs_str("1,[object Object],3") },

    { njs_str("Array(3).fill().reduce(function(a, x)"
                                 "{ return a + (x === undefined); }, 0)"),
      njs_str("3") },

    { njs_str("var a = Array.prototype.fill.apply("
                 "Object({length: 40}), [\"a\", 1, 20]); Object.values(a)"),
      njs_str("a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,40") },

    { njs_str("var a = Array.prototype.fill.apply({length: "
                 "{ valueOf: function() { return 40 }}}, [\"a\", 1, 20]);"
                 "Object.values(a)"),
      njs_str("a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,[object Object]") },

    { njs_str("[NaN, false, ''].map("
                 "(x) => Array.prototype.fill.call(x)"
                 ").every((x) => typeof x == 'object')"),
      njs_str("true") },

    { njs_str("var o = {}; Object.defineProperty(o, 'length', {get:()=>2}); "
                 "Array.prototype.slice.call(Array.prototype.fill.call(o, 1))"),
      njs_str("1,1") },

    { njs_str("var o = {}; Object.defineProperty(o, 'length', {get:()=>'0x0002'}); "
                 "Array.prototype.slice.call(Array.prototype.fill.call(o, 1))"),
      njs_str("1,1") },

    { njs_str("Array.prototype.slice.call({length:2**32})"),
      njs_str("RangeError: Invalid array length") },

    { njs_str("Array.prototype.slice.call({0:'x', [2**32-1]:'y',length:2**32}, 0, 2**32)"),
      njs_str("RangeError: Invalid array length") },

    { njs_str("Array.prototype.slice.call({length:2**32+2, [2**32]:'x', [2**32+1]:'y'}, 2**32)"),
      njs_str("x,y") },

    { njs_str("Array.prototype.slice.call({length:2**53+2, [2**53-3]:'x', [2**53-2]:'y', [2**53-1]:'z'}, 2**53-3)"),
      njs_str("x,y") },

    { njs_str("var o = {}; Object.defineProperty(o, 'length', {get:()=> {throw TypeError('Boom')}}); "
                 "Array.prototype.fill.call(o, 1)"),
      njs_str("TypeError: Boom") },

    { njs_str("var o = Object({length: 3});"
                 "Object.defineProperty(o, '0', {set: ()=>{throw TypeError('Boom')}});"
                 "Array.prototype.fill.call(o, 1)"),
      njs_str("TypeError: Boom") },

    { njs_str("var o = Object({length: 3});"
                 "Object.defineProperty(o, '0', {set: function(v){this.a = 2 * v}});"
                 "Array.prototype.fill.call(o, 2).a"),
      njs_str("4") },

    { njs_str("var a = (new Array(2**10)).fill(0);"
              "var start = {valueOf() {"
              "                 var len = a.length - 2;"
              "                 for (var i = 0; i < len; i++) { a.shift(); }; "
              "                 return 0;"
              "            }};"
              "a.fill('xxx', start)"),
      njs_str("xxx,xxx") },

    { njs_str("Array.prototype.fill.call(new Int32Array(1))"),
      njs_str("0") },

    { njs_str("ArrayBuffer()"),
      njs_str("TypeError: Constructor ArrayBuffer requires 'new'") },

    { njs_str("new ArrayBuffer()"),
      njs_str("[object ArrayBuffer]") },

    { njs_str("ArrayBuffer.prototype.constructor.name === 'ArrayBuffer'"),
      njs_str("true") },

    { njs_str("ArrayBuffer.prototype.constructor()"),
      njs_str("TypeError: Constructor ArrayBuffer requires 'new'") },

    { njs_str("ArrayBuffer.name"),
      njs_str("ArrayBuffer") },

    { njs_str("ArrayBuffer[Symbol.species]"),
      njs_str("[object Function]") },

    { njs_str("ArrayBuffer.prototype[Symbol.toStringTag]"),
      njs_str("ArrayBuffer") },

    { njs_str("var desc = Object.getOwnPropertyDescriptor(ArrayBuffer,"
              "Symbol.species); desc.get"),
      njs_str("[object Function]") },

    { njs_str("var ctor = ArrayBuffer[Symbol.species]; var a = new ctor(100);"
              "a.byteLength;"),
      njs_str("100") },

    { njs_str("var a = new ArrayBuffer(); a.byteLength"),
      njs_str("0") },

    { njs_str("var a = new ArrayBuffer.prototype.constructor(10); a.byteLength"),
      njs_str("10") },

    { njs_str("var get = Object.getOwnPropertyDescriptor(ArrayBuffer.prototype, 'byteLength').get;"
              "get.call([])"),
      njs_str("TypeError: Method ArrayBuffer.prototype.byteLength called on incompatible receiver") },

    { njs_str("[undefined, 1, 10, 1000, null, NaN, false, {}, [1,2,3], Object(1),'10',"
              " -1, -Infinity, Infinity, 2**50]"
              ".map(v=>{ var a; try { a = new ArrayBuffer(v) } catch (e) {return e.name} return a.byteLength})"),
      njs_str("0,1,10,1000,0,0,0,0,0,1,10,RangeError,RangeError,RangeError,RangeError") },

    { njs_str("var buffer = new ArrayBuffer(16);"
              "[[4,12], [-1,-1], [-1,10], [0, -1], [0, -16], [0,-17]]"
              ".map(pr=>buffer.slice(pr[0], pr[1]).byteLength)"),
      njs_str("8,0,0,15,0,0") },

    { njs_str("[false,NaN,1]"
              ".map(v=>(new Uint8Array(v)).length)"),
      njs_str("0,0,1") },

#define NJS_TYPED_ARRAY_LIST "[Uint8Array,Uint8ClampedArray,Int8Array,"     \
                             " Uint16Array,Int16Array,Uint32Array,"         \
                             " Int32Array, Float32Array,Float64Array]"

#define NJS_INT_TYPED_ARRAY_LIST   "[Uint8Array,Uint8ClampedArray,Int8Array," \
                                   " Uint16Array,Int16Array,Uint32Array,"     \
                                   " Int32Array]"

#define NJS_FLOAT_TYPED_ARRAY_LIST "[Float32Array,Float64Array]"

    { njs_str("var TypedArray = Object.getPrototypeOf(Uint8Array);"
              "[TypedArray.name, TypedArray.length]"),
      njs_str("TypedArray,0") },

    { njs_str("Object.getPrototypeOf(Uint8Array)()"),
      njs_str("TypeError: Abstract class TypedArray not directly constructable") },

    { njs_str("var TypedArray = Object.getPrototypeOf(Uint8Array);"
              NJS_TYPED_ARRAY_LIST
              ".every(v=>Object.getPrototypeOf(v) === TypedArray)"),
      njs_str("true") },

    { njs_str("var TypedArray = Object.getPrototypeOf(Uint8Array);"
              NJS_TYPED_ARRAY_LIST
              ".every(v=>Object.getPrototypeOf(v.prototype) === TypedArray.prototype)"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var a = new v.prototype.constructor(0); "
              "           return njs.dump(a) === `${v.name} []`})"),
      njs_str("true") },

    { njs_str("var global = this;"
              NJS_TYPED_ARRAY_LIST
              ".every(v=>ArrayBuffer.isView(new global[v.name]))"),
      njs_str("true") },

    { njs_str("var global = this;"
              NJS_TYPED_ARRAY_LIST
              ".every(v=>global[v.name][Symbol.species].name === v.name)"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var a = new v({length:2, '0':1, '1':2}); "
              "           return a[0] == 1 && a[1] == 2 && a.length == 2})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{try{ new v({length:Math.pow(2,53)}) } "
              "           catch(e) {return e.name == 'InternalError' || e.name == 'RangeError'}})"),
      njs_str("true") },

    { njs_str(NJS_FLOAT_TYPED_ARRAY_LIST
              ".every(v=>{var a = new v({length:5, 0: null, 2:42, 3:'7', 4:NaN, 5:Symbol('1')}); "
              "           return njs.dump(a) === `${v.name} [0,NaN,42,7,NaN]`})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var o = {length:2, '0':1}; Object.defineProperty(o, '1', {get(){throw 'Oops'}});"
              "           try {new v(o)} catch (e) { return e == 'Oops'}})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var a = new v(3); Object.defineProperty(a, '1', {value:1});"
              "           return njs.dump(a) === `${v.name} [0,1,0]`})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var a = new v([1,1,1]); Object.defineProperty(a, '1', {});"
              "           return njs.dump(a) === `${v.name} [1,1,1]`})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var a = new v([0]); var desc = Object.getOwnPropertyDescriptor(a, '0');"
              "           try { Object.defineProperty(a, '1', desc) } catch (e) { return e.name == 'TypeError' }})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{try {var a = new v([1,1]); Object.defineProperty(a, '1', {configurable:true})} "
              "           catch (e) { return e.message == 'Cannot redefine property: \"1\"'}})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{try {var a = new v([1,1]); Object.defineProperty(a, '1', {enumerable:false})} "
              "           catch (e) { return e.message == 'Cannot redefine property: \"1\"'}})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{try {var a = new v([1,1]); Object.defineProperty(a, '1', {writable:false})} "
              "           catch (e) { return e.message == 'Cannot redefine property: \"1\"'}})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{Object.defineProperty(v.prototype, '0', {set(){ throw 'Oops' }});"
              "           var t = new v([0]); var r = Object.create(t);"
              "           r[0] = 1; return true})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{try {var a = new v([1,1]); Object.defineProperty(a, '1', {get(){return 22}})} "
              "           catch (e) { return e.message == 'Cannot redefine property: \"1\"'}})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var a = new v(3);"
              "           return [a.hasOwnProperty('1'), a.hasOwnProperty('4')].toString() === 'true,false'})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var descs = Object.getOwnPropertyNames(v).sort().toString(); "
              "           return descs === 'BYTES_PER_ELEMENT,length,name,prototype'})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".map(v=>{var a = new ArrayBuffer(8); return (new v(a).length)})"),
      njs_str("8,8,8,4,4,2,2,2,1") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".map(v=>{var a = new v(1); a[0]--; return a[0]})"),
      njs_str("255,0,-1,65535,-1,4294967295,-1,-1,-1") },

    { njs_str(NJS_NOT_CANONICAL_INDICES
              ".every(v=>{var a = new Uint8Array([1,2]); return a[v] === undefined})"),
      njs_str("true") },

    { njs_str(NJS_NOT_CANONICAL_INDICES
              ".map(v=>{var a = new Uint8Array([1,2]); a[v] = 'a'; return a[v]})"),
      njs_str("a,,a,a,a,,,,,a") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{v.prototype[10] = 'foo'; return (new v(16))[10] === 0})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{v.prototype[20] = 'foo'; return (new v(16))[20] === undefined})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{v.prototype.foo = 'bar'; return (new v(16)).foo === 'bar'})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{v.prototype[-1] = 'foo'; return (new v(8))[-1] === undefined})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".map(v=>v.BYTES_PER_ELEMENT)"),
      njs_str("1,1,1,2,2,4,4,4,8") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>v.length === 3)"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var a = new v(1); return --a[0] == -1})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var a = v.of(); return njs.dump(a) === `${v.name} []`})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var a = v.of(1); return njs.dump(a) === `${v.name} [1]`})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var a = v.of(1,2,3,4,5); return njs.dump(a) === `${v.name} [1,2,3,4,5]`})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{ try{ v.of(Symbol()); } catch (e) { return e.name === 'TypeError'}})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{ try{ v.of.call(()=>1); } catch (e) { return e.name === 'TypeError'}})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{ try{ v.of.call(function(){}); } catch (e) { return e.name === 'TypeError'}})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var a = v.from([1,2]); return njs.dump(a) === `${v.name} [1,2]`})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var a = v.from([1,2], v=>2*v); return njs.dump(a) === `${v.name} [2,4]`})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var a = v.from([1,2], function(v){return v * this.m}, {m:3}); "
              "           return njs.dump(a) === `${v.name} [3,6]`})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var a = v.from([1,2], function(v){return v * this.m}, {m:3}); "
              "           return njs.dump(a) === `${v.name} [3,6]`})"),
      njs_str("true") },

    { njs_str(NJS_INT_TYPED_ARRAY_LIST
              ".every(v=>{var a = v.from({length:3, 0:1, 2:'a'});"
              "           return njs.dump(a) === `${v.name} [1,0,0]`})"),
      njs_str("true") },

    { njs_str(NJS_FLOAT_TYPED_ARRAY_LIST
              ".every(v=>{var a = v.from({length:3, 0:1, 2:'a'});"
              "           return njs.dump(a) === `${v.name} [1,NaN,NaN]`})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var a = new v(4); a.fill(42); return (a[0] === 42 && a.length == 4)})"),
      njs_str("true") },

    { njs_str(NJS_INT_TYPED_ARRAY_LIST
              ".every(v=>{var a = new v(1); a.fill({}); return a[0] === 0})"),
      njs_str("true") },

    { njs_str(NJS_FLOAT_TYPED_ARRAY_LIST
              ".every(v=>{var a = new v(1); a.fill({}); return isNaN(a[0])})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var a = new v([1,2,3]); a.fill({valueOf(){return 12}}, 1,2); "
              "       return (a[0] === 1 && a[1] === 12 && a[2] === 3 && a.length == 3)})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var a = new v([0,0,0,0,0]).fill(8, -1, -3); "
              "       return njs.dump(a) === `${v.name} [0,0,0,0,0]`;})"),
      njs_str("true") },

    { njs_str(NJS_INT_TYPED_ARRAY_LIST
              ".every(v=>{var a = new v([1,2,3]); a.fill('qq', 1, 2); "
              "       return (a[0] === 1 && a[1] === 0 && a[2] === 3 && a.length == 3)})"),
      njs_str("true") },

    { njs_str(NJS_FLOAT_TYPED_ARRAY_LIST
              ".every(v=>{var a = new v([1,2,3]); a.fill('qq', 1, 2); "
              "       return (a[0] === 1 && isNaN(a[1]) && a[2] === 3 && a.length == 3)})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var a = new v([1,2,3]); var d = Object.getOwnPropertyDescriptors(a)[1];"
              "       return (d.value === 2 && d.writable && d.enumerable && !d.configurable)})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var a = new v([1,2,3]); return Object.keys(a).toString() === '0,1,2'})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var a = new v([1,2,3]); return Object.values(a).toString() === '1,2,3'})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var a = new v([1,2,3]); return Object.entries(a).toString() === '0,1,1,2,2,3'})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{try {delete (new v(1))[0]} catch (e) { return e.name == 'TypeError'}})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{return delete (new v(1))[-1]; })"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var a = new v(8), b = new v(a.buffer); a[0] = 42; return b[0] === 42})"),
      njs_str("true") },

    { njs_str(NJS_INT_TYPED_ARRAY_LIST
              ".map(v=>{var init = new Uint8Array([1,2,3]);"
              "     try { return new v(init.buffer, 0, 2)} catch (e) {return e.name}})"),
      njs_str("1,2,1,2,1,2,RangeError,RangeError,RangeError,RangeError") },

    { njs_str(NJS_INT_TYPED_ARRAY_LIST
              ".map(v=>{var init = new Uint8Array([1,2,3]);"
              "     try { return new v(init.buffer, 1)} catch (e) {return e.name}})"),
      njs_str("2,3,2,3,2,3,RangeError,RangeError,RangeError,RangeError") },

    { njs_str(NJS_INT_TYPED_ARRAY_LIST
              ".map(v=>{var init = new Uint32Array([0xaabbccdd]);"
              "     try { return new v(init.buffer, 0, 2)} catch (e) {return e.name}})"),
      njs_str(njs_evar("221,204,221,204,-35,-52,52445,43707,-13091,-21829,RangeError,RangeError",
                       "170,187,170,187,-86,-69,43707,52445,-21829,-13091,RangeError,RangeError")) },

    { njs_str(NJS_INT_TYPED_ARRAY_LIST
              ".map(v=>{var init = new Uint32Array([0xaabbccdd]);"
              "     try { return new v(init.buffer, 1, 2)} catch (e) {return e.name}})"),
      njs_str(njs_evar("204,187,204,187,-52,-69,RangeError,RangeError,RangeError,RangeError",
                       "187,204,187,204,-69,-52,RangeError,RangeError,RangeError,RangeError")) },

    { njs_str(NJS_INT_TYPED_ARRAY_LIST
              ".map(v=>{var init = new Uint32Array([0xaabbccdd,0xdeadbeef]);"
              "     try { return new v(init.buffer, 0, 2)} catch (e) {return e.name}})"),
      njs_str(njs_evar("221,204,221,204,-35,-52,52445,43707,-13091,-21829,"
                       "2864434397,3735928559,-1430532899,-559038737",
                       "170,187,170,187,-86,-69,43707,52445,-21829,-13091,"
                       "2864434397,3735928559,-1430532899,-559038737")) },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var buffer1 = new ArrayBuffer(8 * v.BYTES_PER_ELEMENT);"
              "           var ta1 = new v(buffer1);"
              "           var ta2 = new v(ta1.buffer, 4 * v.BYTES_PER_ELEMENT); "
              "           ta1[5] = 100; ta1[7] = 101;"
              "           return ta2.toString() === '0,100,0,101'})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var a = new v([42,11]); return a.toString() === '42,11'})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var a = new v(3); a[1] = 42; return a.toString() === '0,42,0'})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var a = new v(0); return a.toString() === ''})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var a = new v([42,11]); return a.join('|') === '42|11'})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var a = new v([42,11]); return a.join('α').length === 5})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{return njs.dump(new v()) === `${v.name} []`})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{return njs.dump(new v([42,11])) === `${v.name} [42,11]`})"),
      njs_str("true") },

    { njs_str("var a = new Uint8Array(8); var b = new Uint32Array(a.buffer);"
              "a[0] = 0xff; a[1] = 0xff; a[2] = 0xff; a[3] = 0xff; b[0];"),
      njs_str("4294967295") },

    { njs_str("[1,300,-100]"
              ".map(v=>{var a = new Uint8Array(1); a[0] = v; return a[0];})"),
      njs_str("1,44,156") },

    { njs_str("[1,300,-100]"
              ".map(v=>{var a = new Uint8ClampedArray(1); a[0] = v; return a[0];})"),
      njs_str("1,255,0") },

    { njs_str("[1,300,-100]"
              ".map(v=>{var a = new Uint8ClampedArray(1); a.set([v], 0); return a[0];})"),
      njs_str("1,255,0") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var init = [1,2,3,4]; var a = new v(4);"
              "           a.set(init); return a.toString() === '1,2,3,4'})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var init = {length:4, 0:1,1:2,2:3,3:4}; var a = new v(4);"
              "           a.set(init); return a.toString() === '1,2,3,4'})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var init = new v([1,2,3,4]); var a = new v(init);"
              "           return a.toString() === '1,2,3,4'})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var init = new v([1,2,3,4]); var a = new v(4);"
              "           a.set(init); return a.toString() === '1,2,3,4'})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var init = {length:2, 0:1,1:2}; var a = new v(4);"
              "           a.set(init,2); return a.toString() === '0,0,1,2'})"),
      njs_str("true") },

    { njs_str(NJS_INT_TYPED_ARRAY_LIST
              ".every(v=>{var init = {length:4, 0:1,1:2,3:4}; var a = new v(4);"
              "           a.set(init); return a.toString() === '1,2,0,4'})"),
      njs_str("true") },

    { njs_str(NJS_FLOAT_TYPED_ARRAY_LIST
              ".every(v=>{var init = {length:4, 0:1,1:2,3:4}; var a = new v(4);"
              "           a.set(init); return a.toString() === '1,2,NaN,4'})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var init = [1,2,3]; var a = new v(4);"
              "           a.set(init); return a.toString() === '1,2,3,0'})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var init = new v([1,2,3]); var a = new v(4);"
              "           a.set(init); return a.toString() === '1,2,3,0'})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var init = [1,2,3,4]; var a = new v(4);"
              "           a.set(init, 0); return a.toString() === '1,2,3,4'})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var init = [1,2]; var a = new v(4);"
              "           a.set(init, 2); return a.toString() === '0,0,1,2'})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var init = new v([1,2]); var a = new v(4);"
              "           a.set(init,2); return a.toString() === '0,0,1,2'})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var init = [1,2,3,4]; var a = new v(4);"
              "           try {a.set(init,2)} catch (e) {return e.name == 'RangeError'};})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var init = [1,2,3,4]; var a = new v(4);"
              "           try {a.set(init,Infinity)} catch (e) {return e.name == 'RangeError'};})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var init = [1,2,3,4,5]; var a = new v(4);"
              "           try {a.set(init)} catch (e) {return e.name == 'RangeError'};})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var init = {length:5}; var a = new v(4);"
              "           try {a.set(init)} catch (e) {return e.name == 'RangeError'};})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var init = {length:3}; var a = new v(4);"
              "           try {a.set(init,2)} catch (e) {return e.name == 'RangeError'};})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var init = {length:3}; var a = new v(4);"
              "           try {a.set(init,Infinity)} catch (e) {return e.name == 'RangeError'};})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var init = new v([1,2,3,4,5]); var a = new v(4);"
              "           try {a.set(init)} catch (e) {return e.name == 'RangeError'};})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var init = new v([1,2,3]); var a = new v(4);"
              "           try {a.set(init,2)} catch (e) {return e.name == 'RangeError'};})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var init = new v([1,2,3]); var a = new v(4);"
              "           try {a.set(init,Infinity)} catch (e) {return e.name == 'RangeError'};})"),
      njs_str("true") },

    { njs_str(NJS_INT_TYPED_ARRAY_LIST
              ".map(v=>{try { var a = new v(1); $262.detachArrayBuffer(a.buffer); Object.entries(a)} "
              "catch (e) {return e.name}}).every(v=>v === 'TypeError')"),
      njs_str("true") },

    { njs_str("[-1,-1.00001,-Infinity]"
              ".every(v=>{ try {(new Uint8Array(10)).set([], v)} catch (ee) {return ee.name === 'RangeError'}})"),
      njs_str("true") },

    { njs_str("[0.1,2.5,{},{'1': '10'},[1000]]"
              ".map(v=>{var a = new Uint8Array(1); a.set([v], 0); return a[0]})"),
      njs_str("0,2,0,0,232") },

    { njs_str("[1.0, -1234.0]"
              ".map(v=>{var a = new Float32Array(1); a[0] = v; var b = new Uint8Array(a.buffer);"
              "         return (b[0] << 24 | b[1] << 16| b[2] <<8 | b[3]).toString(16).padStart(8, '0');})"),
      njs_str(njs_evar("0000803f,00409ac4",
                       "3f800000,-3b65c000")) },

    { njs_str("var a = new ArrayBuffer(0); a.slice(0, 0).byteLength"),
      njs_str("0") },

    { njs_str("var a = new ArrayBuffer(10); a.slice(1).byteLength"),
      njs_str("9") },

    { njs_str("var a = new ArrayBuffer(10); a.slice(1,2).byteLength"),
      njs_str("1") },

    { njs_str("var a = new ArrayBuffer(10); a.slice(0,-1).byteLength"),
      njs_str("9") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".map(v=>{var buffer = new ArrayBuffer(8); var view = new v(buffer);"
              "         view[0] = 511; return new Uint8Array(buffer.slice(0,4))})"),
      njs_str(njs_evar("255,0,0,0,255,0,0,0,255,0,0,0,255,1,0,0,255,1,"
                       "0,0,255,1,0,0,255,1,0,0,0,128,255,67,0,0,0,0",
                       "255,0,0,0,255,0,0,0,255,0,0,0,1,255,0,0,1,255,0,0,"
                       "0,0,1,255,0,0,1,255,67,255,128,0,64,127,240,0")) },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".map(v=>{var buffer = new ArrayBuffer(8); var view = new v(buffer);"
              "         view[view.length - 1] = 511; return new Uint8Array(buffer.slice(4))})"),
      njs_str(njs_evar("0,0,0,255,0,0,0,255,0,0,0,255,0,0,255,1,0,0,255,1,"
                       "255,1,0,0,255,1,0,0,0,128,255,67,0,240,127,64",
                       "0,0,0,255,0,0,0,255,0,0,0,255,0,0,1,255,0,0,1,255,"
                       "0,0,1,255,0,0,1,255,67,255,128,0,0,0,0,0")) },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".map(v=>{var buffer = new ArrayBuffer(8); var view = new v(buffer);"
              "         view[0] = 511; return new Uint8Array(buffer.slice(0,-4))})"),
      njs_str(njs_evar("255,0,0,0,255,0,0,0,255,0,0,0,255,1,0,0,255,1,0,0,"
                       "255,1,0,0,255,1,0,0,0,128,255,67,0,0,0,0",
                       "255,0,0,0,255,0,0,0,255,0,0,0,1,255,0,0,1,255,0,0,"
                       "0,0,1,255,0,0,1,255,67,255,128,0,64,127,240,0")) },

    { njs_str("var a = new Uint8Array(10); var b = a.slice(1); b.length"),
      njs_str("9") },

    { njs_str("var a = new Uint8Array(10); var b = a.slice(0,9); b.length"),
      njs_str("9") },

    { njs_str("var a = new Uint8Array(10); var b = a.slice(9,10); b.length"),
      njs_str("1") },

    { njs_str("var a = new Uint8Array(10); var b = a.slice(); b.length"),
      njs_str("10") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var a = new v([42]); "
              "           var r = a.slice();"
              "           return  njs.dump(r) === `${v.name} [42]`;})"),
      njs_str("true") },

    { njs_str(NJS_INT_TYPED_ARRAY_LIST
              ".map(v=>{var init = new Uint8Array([1,2,3,4,5,6,7,8]); var view = new v(init.buffer);"
              "         return view.slice(0,2)})"),
      njs_str(njs_evar("1,2,1,2,1,2,513,1027,513,1027,67305985,134678021,67305985,134678021",
                       "1,2,1,2,1,2,258,772,258,772,16909060,84281096,16909060,84281096")) },

    { njs_str(NJS_INT_TYPED_ARRAY_LIST
              ".map(v=>{var init = new Uint8Array([1,2,3,4,5,6,7,8]); var view = new v(init.buffer);"
              "         return view.slice(0,-2)})"),
      njs_str(njs_evar("1,2,3,4,5,6,1,2,3,4,5,6,1,2,3,4,5,6,513,1027,513,1027,,",
                       "1,2,3,4,5,6,1,2,3,4,5,6,1,2,3,4,5,6,258,772,258,772,,")) },

    { njs_str("var other = new Uint8Array([0xff,0xff,0xff,0xff]);"
              NJS_TYPED_ARRAY_LIST
              ".every(v=>{var a = new v([42]); "
              "           a.constructor = {[Symbol.species]: function () {return other;}}; "
              "           var r = a.slice(0,0);"
              "           return r == other && r.length == 4 && r[0] == 0xff;})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var a = new v([1,2,3]); "
              "           a.constructor = {[Symbol.species]: function () {return new v([0xff,0xee]);}}; "
              "           try {a.slice(0)} catch(e) {return e.name == 'TypeError'}})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var a = new v([1,2,3]); "
              "           a.constructor = {[Symbol.species]: function () {return new Date();}}; "
              "           try {a.slice(0)} catch(e) {return e.name == 'TypeError'}})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var a = new v(2); "
              "           a.constructor = {}; "
              "           a.constructor[Symbol.species] = function() { return new v()};"
              "           try {a.filter(v=>true)} catch(e) {return e.name == 'TypeError'}})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var a = new v([1,2,3]); "
              "           var r = a.slice(1,3);"
              "           return  a.buffer !== r.buffer;})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var a = new v([1,2,3]); "
              "           var r = a.slice(1,3);"
              "           a[1] = 0;"
              "           return  njs.dump(r) === `${v.name} [2,3]`;})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var a = new v([1,2,3,4]); "
              "           var r = a.subarray(1,3);"
              "           a[1] = 0;"
              "           return  njs.dump(r) === `${v.name} [0,3]`;})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var a = new v([1,2,3,4]); "
              "           a.subarray(1,3).fill(0);"
              "           return  njs.dump(a) === `${v.name} [1,0,0,4]`;})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var a = new v([1,2,3,4]); "
              "           a.subarray(1,10).fill(0);"
              "           return  njs.dump(a) === `${v.name} [1,0,0,0]`;})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var a = new v([1,2,3]); "
              "           var r = a.subarray(1,3);"
              "           return  a.buffer === r.buffer;})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var a = new v([1,2,3]); "
              "           return  a.subarray(3).length === 0;})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var a = new v([1,2,3,4]); a.copyWithin(2); "
              "           return a.toString() === '1,2,1,2'})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var a = new v([1,2,3,4]); a.copyWithin(2,1); "
              "           return a.toString() === '1,2,2,3'})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var a = new v([1,2,3,4]); a.copyWithin(2,1,2); "
              "           return a.toString() === '1,2,2,4'})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var a = new v([1,2,3,4]); a.copyWithin(-1,1,2); "
              "           return a.toString() === '1,2,3,2'})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var a = new v([1,2,3,4]); a.copyWithin(-1,-4,2); "
              "           return a.toString() === '1,2,3,1'})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var a = new v([1,2,3,4]); a.copyWithin(-1,-2); "
              "           return a.toString() === '1,2,3,3'})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var orig = new v([255,255,1,2,3,4,5]);"
              "           var a = new v(orig.buffer, 2* v.BYTES_PER_ELEMENT);"
              "           a.copyWithin(0,3);"
              "           return a.toString() === '4,5,3,4,5'})"),
      njs_str("true") },

    { njs_str("Uint8Array.prototype.every.call(1)"),
      njs_str("TypeError: this is not a typed array") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{return (new v([1,2,3])).every(e=>e>0) === true})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{return (new v([1,2,3])).every(function(e) {"
              "              if (this != undefined) {throw 'Oops';}"
              "              return e > 0}) === true})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{return (new v([1,2,3])).every(function(e) {"
              "              if (this != 'QQ') {throw 'Oops';}"
              "              return e > 0}, 'QQ') === true})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{return (new v([1,2,3])).every(e=>e>1) === false})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var orig = new v([255,255,1,2,3,255]);"
              "           var a = new v(orig.buffer, 2 * v.BYTES_PER_ELEMENT, 3);"
              "           return a.every(e=>e<4)})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var collect = []; (new v([42,43])).forEach(e=>collect.push(e)); "
              "           return collect.join('|') === '42|43'})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{return (new v([7,10,3,8,5])).filter(q=>q%2).join('|') === '7|3|5'})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var orig = new v([255,255,7,10,3,8,5,255]);"
              "           var a = new v(orig.buffer, 2 * v.BYTES_PER_ELEMENT, 5);"
              "           return a.filter(q=>q%2).join('|') === '7|3|5'})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var orig = new v([255,255,1,2,3,255]);"
              "           var a = new v(orig.buffer, 2 * v.BYTES_PER_ELEMENT, 3);"
              "           return a.find(e=>e>2) === 3})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var orig = new v([255,255,1,2,3,255]);"
              "           var a = new v(orig.buffer, 2 * v.BYTES_PER_ELEMENT, 3);"
              "           return a.find(e=>e===255) === undefined})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var orig = new v([255,255,1,2,3,255]);"
              "           var a = new v(orig.buffer, 2 * v.BYTES_PER_ELEMENT, 3);"
              "           return a.findIndex(e=>e>2) === 2})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var orig = new v([255,255,1,2,3,255]);"
              "           var a = new v(orig.buffer, 2 * v.BYTES_PER_ELEMENT, 3);"
              "           return a.findIndex(e=>e===255) === -1})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{return (new v([1,2,3])).some(e=>e==2)})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var orig = new v([255,255,1,2,3,255]);"
              "           var a = new v(orig.buffer, 2 * v.BYTES_PER_ELEMENT, 3);"
              "           return a.some(e=>e==255)})"),
      njs_str("false") },

    { njs_str("Uint8Array.prototype.includes.call(1)"),
      njs_str("TypeError: this is not a typed array") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{return (new v()).includes(0, {valueOf(){throw 'Oops'}}) === false})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{return (new v([0,1,2,3])).includes(2) === true})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{return (new v([0,1,2,3])).includes(2,3) === false})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var a = new v(5);"
              "           return a.includes(0, 4) === true "
              "                  && a.includes(0, 5) === false;})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{return (new v([0,1,2,3])).includes(-0) === true})"),
      njs_str("true") },

    { njs_str(NJS_FLOAT_TYPED_ARRAY_LIST
              ".every(v=>{return (new v([42, 43, NaN, 41])).includes(NaN) === true})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var orig = new v([255,255,0,2,3,255]);"
              "           var a = new v(orig.buffer, 2 * v.BYTES_PER_ELEMENT, 3);"
              "           return a.includes(255) === false})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{return (new v()).indexOf(0, {valueOf(){throw 'Oops'}}) === -1})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{return (new v([3,2,1])).indexOf(2) === 1})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{return (new v([3,2,1])).indexOf(2,2) === -1})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{return (new v([3,2,1])).indexOf(2,Infinity) === -1})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{return (new v([3,2,1])).indexOf(2,-Infinity) === 1})"),
      njs_str("true") },

    { njs_str(NJS_FLOAT_TYPED_ARRAY_LIST
              ".every(v=>{return (new v([42, 43, NaN, 41])).indexOf(NaN) === -1})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{return (new v([3,2,1])).indexOf(257) === -1})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{return (new v([3,2,1])).indexOf(2.00001) === -1})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{return (new v([3,2,1,0])).indexOf(-0) === 3})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var a = new v(5);"
              "           return a.indexOf(0, 4) === 4"
              "                  && a.indexOf(0, 5) === -1;})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var orig = new v([255,255,0,2,3,255]);"
              "           var a = new v(orig.buffer, 2 * v.BYTES_PER_ELEMENT, 3);"
              "           return a.indexOf(255) === -1})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{return (new v([3,2,1,2])).lastIndexOf(2) === 3})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{return (new v([3,2,1,2])).lastIndexOf(4) === -1})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{return (new v([42, 43])).lastIndexOf(42,0) === 0})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{return (new v([42, 43, 43, 41])).lastIndexOf(43,Infinity) === 2})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{return (new v([42, 43, 43, 41])).lastIndexOf(43,-Infinity) === -1})"),
      njs_str("true") },

    { njs_str(NJS_FLOAT_TYPED_ARRAY_LIST
              ".every(v=>{return (new v([42, 43, NaN, 41])).lastIndexOf(NaN) === -1})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var orig = new v([255,255,0,2,3,255]);"
              "           var a = new v(orig.buffer, 2 * v.BYTES_PER_ELEMENT, 3);"
              "           return a.lastIndexOf(255) === -1})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{return (new v([3,2,1])).map(q=>2*q).join('|') === '6|4|2'})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var orig = new v([255,255,6,4,2,255]);"
              "           var a = new v(orig.buffer, 2 * v.BYTES_PER_ELEMENT, 3);"
              "           return a.map(q=>q/2).join('|') === '3|2|1'})"),
      njs_str("true") },

    { njs_str("const arr = new Uint8Array([1,2,3]);"
              "const sep = {toString(){$262.detachArrayBuffer(arr.buffer); return ','}};"
              "arr.join(sep)"),
      njs_str("TypeError: detached buffer") },

    { njs_str("Uint8Array.prototype.reduce.call(1)"),
      njs_str("TypeError: this is not a typed array") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{ try { (new v([])).reduce((p, q) => p + q) } "
              "            catch (e) { return e.name == 'TypeError'} })"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{ return (new v([])).reduce((p, q) => p + q, 10) == 10})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{ return (new v([7])).reduce((p, q) => p + q) == 7})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{ return (new v([7])).reduce((p, q) => p + q, 10) == 17})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{ return (new v([1,2,3])).reduce((p, q) => p + q) == 6})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{ return (new v([1,2,3])).reduce((p, q) => p + q, 10) == 16})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{ return (new v([1,2,3])).reduce((p, q) => p + q, '') == '123'})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{ return (new v([3,2,1])).reduce((p, q, i) => { "
              "             if (q + i != 3) {throw 'Oops'}; "
              "             return p + q;}) == 6})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{ var a = new v([3,2,1]); "
              "            return a.reduce((p, q, _, o) => { "
              "                 if (a != o) {throw 'Oops'};  "
              "                 return p + q;}) == 6})"),
      njs_str("true") },

    { njs_str("var a = [3,2,1]; a.reduce((p, v, _, o) => { if (a != o) {throw 'Oops'};return p + v})"),
      njs_str("6") },


    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{ try { (new v([])).reduceRight((p, q) => p + q) } "
              "            catch (e) { return e.name == 'TypeError'} })"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{ return (new v([])).reduceRight((p, q) => p + q, 10) == 10})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{ return (new v([7])).reduceRight((p, q) => p + q) == 7})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{ return (new v([7])).reduceRight((p, q) => p + q, 10) == 17})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{ return (new v([1,2,3])).reduceRight((p, q) => p + q) == 6})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{ return (new v([1,2,3])).reduceRight((p, q) => p + q, 10) == 16})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{ return (new v([1,2,3])).reduceRight((p, q) => p + q, '') == '321'})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{ return (new v([3,2,1])).reduceRight((p, q, i) => { "
              "             if (q + i != 3) {throw 'Oops'}; "
              "             return p + q;}) == 6})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{ var a = new v([3,2,1]); "
              "            return a.reduceRight((p, q, _, o) => { "
              "                 if (a != o) {throw 'Oops'};  "
              "                 return p + q;}) == 6})"),
      njs_str("true") },

    { njs_str("var a = [3,2,1]; a.reduceRight((p, v, _, o) => { if (a != o) {throw 'Oops'};return p + v})"),
      njs_str("6") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{ return (new v([1,2,3])).reverse().join('|') == '3|2|1'})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{ return (new v([1,2,3,4])).reverse().join('|') == '4|3|2|1'})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var a = new v([3,2,1]);"
              "           return [a.toReversed(), a].toString() === '1,2,3,3,2,1'})"),
      njs_str("true") },

    /* Same-type copies must honor the source view offset. */

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var a = (new v([0,1,2,3,4])).subarray(2);"
              "           return (new v(a)).toString() === '2,3,4'})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var a = (new v([0,1,2,3,4])).subarray(2);"
              "           return a.slice(1, 3).toString() === '3,4'})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var a = (new v([0,1,2,3,4])).subarray(2);"
              "           return a.toReversed().toString() === '4,3,2'})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var a = (new v([0,3,2,1,4])).subarray(2);"
              "           return a.toSorted().toString() === '1,2,4'})"),
      njs_str("true") },

    { njs_str("Uint8Array.prototype.sort.call(1)"),
      njs_str("TypeError: this is not a typed array") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var a = new v([]); a.sort(); "
              "           return a.toString() === ''})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var a = new v([5]); a.sort(); "
              "           return a.toString() === '5'})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var a = new v([3,3,2,1]); a.sort(); "
              "           return a.toString() === '1,2,3,3'})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var a = new v([3,3,2,1]); a.sort((x,y)=>x-y); "
              "           return a.toString() === '1,2,3,3'})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var a = (new v([255,255,3,3,2,1])).slice(2); a.sort(); "
              "           return a.toString() === '1,2,3,3'})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{ var a = [];"
              "            var b = {toString() {a.length = 65535; return 99;}};"
              "            for (var c = 0; c < 3; c++) { a[c] = b; }"
              "            var ta = new v(6); ta.set(a);"
              "            return ta.toString() == '99,99,99,0,0,0';"
              "          })"),
      njs_str("true") },

    { njs_str("(new Float32Array([255,255,NaN,3,NaN,Infinity,3,-Infinity,0,-0,2,1,-5])).slice(2).sort()"),
      njs_str("-Infinity,-5,0,0,1,2,3,3,Infinity,NaN,NaN") },

    { njs_str("(new Float64Array([255,255,NaN,3,NaN,Infinity,3,-Infinity,0,-0,2,1,-5])).slice(2).sort()"),
      njs_str("-Infinity,-5,0,0,1,2,3,3,Infinity,NaN,NaN") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var a = new v([3,2,1]);"
              "           return [a.toSorted(),a].toString() === '1,2,3,3,2,1'})"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every(v=>{var a = (new v([3,2,1]));"
              "           a.constructor = (v == Uint8Array) ? Uint32Array : Uint8Array;"
              "           return Object.getPrototypeOf(a.toSorted()) === v.prototype})"),
      njs_str("true") },

    { njs_str("(new DataView(new ArrayBuffer(3)))"),
      njs_str("[object DataView]") },

    { njs_str("var x = new ArrayBuffer(3); [typeof x, typeof new DataView(x)]"),
      njs_str("object,object") },

    { njs_str("(new DataView(new ArrayBuffer(3))).buffer"),
      njs_str("[object ArrayBuffer]") },

    { njs_str("(new DataView(new ArrayBuffer(3))).byteLength"),
      njs_str("3") },

    { njs_str("(new DataView(new ArrayBuffer(3), 1)).byteLength"),
      njs_str("2") },

    { njs_str("(new DataView(new ArrayBuffer(3), 3)).byteLength"),
      njs_str("0") },

    { njs_str("(new DataView(new ArrayBuffer(3), 1)).byteOffset"),
      njs_str("1") },

    { njs_str("(new DataView(new ArrayBuffer(3), 1, 1)).byteLength"),
      njs_str("1") },

    { njs_str("(new DataView(new ArrayBuffer(3), 4))"),
      njs_str("RangeError: byteOffset 4 is outside the bound of the buffer") },

    { njs_str("(new DataView(new ArrayBuffer(3), 1,3))"),
      njs_str("RangeError: Invalid DataView length: 3") },

    { njs_str("var u8 = new Uint8Array([255, 129, 130, 131, 4, 5, 6, 7, 8, 9, 255]); "
              "var dv = new DataView(u8.buffer, 1); "
              "['getUint8', 'getInt8',"
              " 'getUint16', 'getInt16',"
              " 'getUint32', 'getInt32',"
              " 'getFloat32','getFloat64'"
              "]"
              ".map(fn => [dv[fn](0), dv[fn](0,1), dv[fn](1), dv[fn](1,1)])"),
      njs_str("129,129,130,130,"
              "-127,-127,-126,-126,"
              "33154,33409,33411,33666,"
              "-32382,-32127,-32125,-31870,"
              "2172814084,75727489,2189624325,84181890,"
              "-2122153212,75727489,-2105342971,84181890,"
              "-4.794245620412925e-38,3.091780090135418e-36,-1.9251027092506622e-37,6.230764342760857e-36,"
              "-2.159546358334202e-301,5.447603729090798e-270,-1.4538065947240603e-296,3.72581468952343e-265") },

    { njs_str("var u8 = new Uint8Array(10);"
              "var dv = new DataView(u8.buffer, 1);"
              "var u8view = new Uint8Array(u8.buffer, 1);"
              "function run(test) {"
              "     var fn = test[0];"
              "     var val = test[1];"
              "     var size = parseInt(fn.match(/\\d+/)) / 8;"
              "     "
              "     return  [[0], [0,1],[1], [1,1]].map(args => {"
              "           var offset = args[0];"
              "           var le = args[1];"
              "           u8.fill(0); "
              "           dv[fn].apply(dv, [offset, val, le]);"
              "           return `[${u8view.subarray(0, offset + size)}]`;"
              "     })"
              "};"
              "["
              " ['setUint8',    129],"
              " ['setInt8',    -127],"
              " ['setUint16', 33154],"
              " ['setInt16', -32382],"
              " ['setUint32', 2172814084],"
              " ['setInt32', -2122153212],"
              " ['setFloat32', -4.794245620412925e-38],"
              " ['setFloat64', -2.159546358334202e-301],"
              "]"
              ".map(t => run(t))"),
      njs_str("[129],[129],[0,129],[0,129],"
              "[129],[129],[0,129],[0,129],"
              "[129,130],[130,129],[0,129,130],[0,130,129],"
              "[129,130],[130,129],[0,129,130],[0,130,129],"
              "[129,130,131,4],[4,131,130,129],[0,129,130,131,4],[0,4,131,130,129],"
              "[129,130,131,4],[4,131,130,129],[0,129,130,131,4],[0,4,131,130,129],"
              "[129,130,131,4],[4,131,130,129],[0,129,130,131,4],[0,4,131,130,129],"
              "[129,130,131,4,5,6,7,8],[8,7,6,5,4,131,130,129],[0,129,130,131,4,5,6,7,8],[0,8,7,6,5,4,131,130,129]"
              ) },

    { njs_str("var u8 = new Uint8Array([1,2,3]); "
              "var dv = new DataView(u8.buffer); "
              "dv.getUint16(2)"),
      njs_str("RangeError: index 2 is outside the bound of the buffer") },

#if NJS_HAVE_LARGE_STACK
    { njs_str("var o = Object({length: 3});"
                 "Object.defineProperty(o, '0', {set: function(v){this[0] = 2 * v}});"
                 "Array.prototype.fill.call(o, 2)"),
      njs_str("RangeError: Maximum call stack size exceeded") },
#endif

    { njs_str("var i = 0; var o = {get length() {i++}};"
              "Array.prototype.fill.call(o); i"),
      njs_str("1") },

    { njs_str("var a = [];"
                 "a.filter(function(v, i, a) { return v > 1 })"),
      njs_str("") },

    { njs_str("var a = [1,2,3,-1,5];"
                 "a.filter(function(v, i, a) { return v > 1 })"),
      njs_str("2,3,5") },

    { njs_str("var a = [1,2,3,4,5,6,7,8];"
                 "a.filter(function(v, i, a) { a.pop(); return v > 1 })"),
      njs_str("2,3,4") },

    { njs_str("var a = [1,2,3,4,5,6,7,8];"
                 "a.filter(function(v, i, a) { a.shift(); return v > 1 })"),
      njs_str("3,5,7") },

    { njs_str("var a = [1,2,3,4,5,6,7];"
                 "a.filter(function(v, i, a) { a.pop(); return v > 1 })"),
      njs_str("2,3,4") },

    { njs_str("var a = [1,2,3,4,5,6,7];"
                 "a.filter(function(v, i, a) { a.shift(); return v > 1 })"),
      njs_str("3,5,7") },

    { njs_str("var a = [1,2,3,4,5,6,7];"
                 "a.filter(function(v, i, a) { a[i] = v + 1; return true })"),
      njs_str("1,2,3,4,5,6,7") },

    { njs_str("var a = [1,2,3,4,5,6,7];"
                 "a.filter(function(v, i, a) { a[i+1] = v+10; return true })"),
      njs_str("1,11,21,31,41,51,61") },

    { njs_str("var o = {0: 'c', 1: 'b', 2: 'c', 'length': { valueOf() { return 3 }}};"
              "var r = Array.prototype.filter.call(o, function(el, i, arr) {return el == 'c'}); r"),
      njs_str("c,c") },

    { njs_str("var o = {0: 'c', 1: 'a', 2: 'b'};"
              "Object.defineProperty(o, 'length', {get: () => 4});"
              "Object.defineProperty(o, '3', {get: () => 'c'});"
              "var r = Array.prototype.filter.call(o, function(el, i, arr) { return el == 'c' }); r"),
      njs_str("c,c") },

    { njs_str("var a = [];"
                 "a.find(function(v, i, a) { return v > 1 })"),
      njs_str("undefined") },

    { njs_str("var a = [,NaN,0,-1];"
                 "a.find(function(v, i, a) { return v > 1 })"),
      njs_str("undefined") },

    { njs_str("var a = [,NaN,0,-1,2];"
                 "a.find(function(v, i, a) { return v > 1 })"),
      njs_str("2") },

    { njs_str("var a = [1,2,3,-1,5];"
                 "a.find(function(v, i, a) { return v > 1 })"),
      njs_str("2") },

    { njs_str("var a = [,1,,-1,5];"
                 "a.find(function(v, i, a) { return v > 1 })"),
      njs_str("5") },

    { njs_str("var a = [,1,,-1,5,6];"
                 "a.find(function(v, i, a) { return v > 1 })"),
      njs_str("5") },

    { njs_str("[].find(function(v) { return (v === undefined) })"),
      njs_str("undefined") },

    { njs_str("var a = [,3];"
                 "a.find(function(v) { return (v === 3 || v === undefined) })"),
      njs_str("undefined") },

    { njs_str("var a = [1,,3];"
                 "a.find(function(v) { return (v === 3 || v === undefined) })"),
      njs_str("undefined") },

    { njs_str("var a = [1,2,3,4,5,6];"
                 "a.find(function(v, i, a) { a.shift(); return v == 3 })"),
      njs_str("3") },

    { njs_str("var a = [1,2,3,4,5,6];"
              "a.find(function(v, i, a) { a.shift(); return v == 4 })"),
      njs_str("undefined") },

    { njs_str("var o = {0: 'a', 1: 'b', 2: 'c', 'length': { valueOf() { return 3 }}};"
              "var r = Array.prototype.find.call(o, function(el, i, arr) {return el == 'b'}); r"),
      njs_str("b") },

    { njs_str("var o = {0: 'a', 1: 'b', 2: 'c', 'length': { valueOf() { return 3 }}};"
              "var r = Array.prototype.find.call(o, function(el, i, arr) {delete o['1']; return el == 'c'}); r"),
      njs_str("c") },

    { njs_str("var o = {0: 'a', 1: 'b', 2: 'c'};"
              "Object.defineProperty(o, 'length', {get: () => 4});"
              "Object.defineProperty(o, '3', {get: () => 'd'});"
              "var r = Array.prototype.find.call(o, function(el, i, arr) { return el == 'd' }); r"),
      njs_str("d") },

    { njs_str("var i = 0; var o = {get length() {i++}};"
              "try {Array.prototype.filter.call(o);}"
              "catch (e) {i += '; ' + e}; i"),
      njs_str("1; TypeError: callback argument is not callable") },

    { njs_str("var callz = 0, res = [], arr = 'abc'.split('');"
              "void arr.find((k) => { if (0 == callz++) { arr.splice(1,1); } res.push(k) });"
              "res.join(',')"),
      njs_str("a,c,") },

    { njs_str("var a = [];"
                 "a.findIndex(function(v, i, a) { return v > 1 })"),
      njs_str("-1") },

    { njs_str("var a = [,NaN,0,-1];"
                 "a.findIndex(function(v, i, a) { return v > 1 })"),
      njs_str("-1") },

    { njs_str("var a = [,NaN,0,-1,2];"
                 "a.findIndex(function(v, i, a) { return v > 1 })"),
     njs_str("4") },

    { njs_str("var a = [1,2,3,-1,5];"
                 "a.findIndex(function(v, i, a) { return v > 1 })"),
      njs_str("1") },

    { njs_str("var a = [,1,,-1,5];"
                 "a.findIndex(function(v, i, a) { return v > 1 })"),
      njs_str("4") },

    { njs_str("var a = [,1,,-1,5,6];"
                 "a.findIndex(function(v, i, a) { return v > 1 })"),
      njs_str("4") },

    { njs_str("[].findIndex(function(v) { return (v === undefined) })"),
      njs_str("-1") },

    { njs_str("[,].findIndex(function(v) { return (v === undefined) })"),
      njs_str("0") },

    { njs_str("[1,2,,3].findIndex(function(el){return el === undefined})"),
      njs_str("2") },

    { njs_str("[,2,,3].findIndex(function(el){return el === undefined})"),
      njs_str("0") },

    { njs_str("var a = [1,2,3,4,5,6];"
                 "a.findIndex(function(v, i, a) { a.shift(); return v == 3 })"),
      njs_str("1") },

    { njs_str("var a = [1,2,3,4,5,6];"
                 "a.findIndex(function(v, i, a) { a.shift(); return v == 4 })"),
      njs_str("-1") },

    { njs_str("var o = {0: 'a', 1: 'b', 2: 'c', 'length': { valueOf() { return 3 }}};"
              "var r = Array.prototype.findIndex.call(o, function(el, i, arr) {return el == 'b'}); r"),
      njs_str("1") },

    { njs_str("var o = {0: 'a', 1: 'b', 2: 'c'};"
              "Object.defineProperty(o, 'length', {get: () => 4});"
              "Object.defineProperty(o, '3', {get: () => 'd'});"
              "var r = Array.prototype.findIndex.call(o, function(el, i, arr) { return el == 'd' }); r"),
      njs_str("3") },

    { njs_str("var callz = 0, res = [], arr = 'abc'.split('');"
              "void arr.findIndex((k) => { if (0 == callz++) { arr.splice(1,1); } res.push(k) });"
              "res.join(',')"),
      njs_str("a,c,") },

    { njs_str("var a = [];"
                 "a.map(function(v, i, a) { return v + 1 })"),
      njs_str("") },

    { njs_str("var a = [,,,];"
                 "a.map(function(v, i, a) { return v + 1 })"),
      njs_str(",,") },

    { njs_str("var a = [,,,1];"
                 "a.map(function(v, i, a) { return v + 1 })"),
      njs_str(",,,2") },

    { njs_str("var a = [1,2,3];"
                 "a.map(function(v, i, a) { return v + 1 })"),
      njs_str("2,3,4") },

    { njs_str("var a = [1,2,3,4,5,6];"
                 "a.map(function(v, i, a) { a.pop(); return v + 1 })"),
      njs_str("2,3,4,,,") },

    { njs_str("var a = [1,2,3,4,5,6];"
                 "a.map(function(v, i, a) { a.shift(); return v + 1 })"),
      njs_str("2,4,6,,,") },

    { njs_str("var o = {0: 'a', 1: 'b', 2: 'c', 'length': { valueOf() { return 3 }}};"
              "var r = Array.prototype.map.call(o, num => num + '1'); r"),
      njs_str("a1,b1,c1") },

    { njs_str("var o = {0: 'a', 1: 'b', 2: 'c'};"
              "Object.defineProperty(o, 'length', {get: () => 4});"
              "Object.defineProperty(o, '3', {get: () => 'd'});"
              "var r = Array.prototype.map.call(o, function(el, i, arr) { return el + '1' }); r"),
      njs_str("a1,b1,c1,d1") },

    { njs_str("Array.prototype.map.call(new String('abc'),"
             "                          (val, idx, obj) => {return obj instanceof String})"
              ".every(x => x === true)"),
      njs_str("true") },

    { njs_str("Array.prototype.map.call('abcdef', (val, idx, obj) => {return val === 100})"),
      njs_str("false,false,false,false,false,false") },

    { njs_str("function callbackfn(val, idx, obj) {return idx === 1 && typeof val === 'undefined';}"
              "var obj = {2: 2, length: 10};"
              "var res = Array.prototype.map.call(obj, callbackfn); typeof res[7]"),
      njs_str("undefined") },

    { njs_str("function callbackfn(val, idx, obj) {return idx === 1 && typeof val === 'undefined';}"
              "var obj = {2: 2, length: 9000};"
              "var res = Array.prototype.map.call(obj, callbackfn); typeof res[8000]"),
      njs_str("undefined") },

    { njs_str("var a = [1,2,3]; Object.defineProperty(a, '1', {enumerable:false});"
              "a.map(v=>v)"),
      njs_str("1,2,3") },

    { njs_str("Array.prototype.map.call({0:9, length:2**16}, val=>val<10).length"),
      njs_str("65536") },

    { njs_str("[].reduce((p, v) => p + v)"),
      njs_str("TypeError: Reduce of empty object with no initial value") },

    { njs_str("[].reduce((p, v) => p + v, 10)"),
      njs_str("10") },

    { njs_str("[,,].reduce((p, v) => p + v)"),
      njs_str("TypeError: Reduce of empty object with no initial value") },

    { njs_str("[,,].reduce((p, v) => p + v, 10)"),
      njs_str("10") },

    { njs_str("[1].reduce((p, v) => p + v)"),
      njs_str("1") },

    { njs_str("[1].reduce((p, v) => p + v, 10)"),
      njs_str("11") },

    { njs_str("[1,2,3].reduce((p, v) => p + v)"),
      njs_str("6") },

    { njs_str("[1,2,3].reduce((p, v) => p + v, 10)"),
      njs_str("16") },

    { njs_str("[3,2,1].reduce((p, v, i) => { if (v + i != 3) {throw 'Oops'};return p + v})"),
      njs_str("6") },

    { njs_str("var a = [3,2,1]; a.reduce((p, v, _, o) => { if (a != o) {throw 'Oops'};return p + v})"),
      njs_str("6") },

    { njs_str("[[0, 1], [2, 3], [4, 5]].reduce((a, b) => a.concat(b), [])"),
      njs_str("0,1,2,3,4,5") },

    { njs_str("var o = {0: 'a', 1: 'b', 2: 'c', 'length': { valueOf() { return 3 }}};"
              "var reducer = (a, b) => a + b;"
              "var a = Array.prototype.reduce.call(o, reducer); a"),
      njs_str("abc") },

    { njs_str("function reducer(a, b, i, arr) {"
              "   if (i == 2) Object.defineProperty(arr, i, {enumerable:false}); "
              "   return a + b;"
              "};"
              "Array.prototype.reduce.call([1,2,3,4], reducer)"),
      njs_str("10") },

    { njs_str("var o = {0: 'a', 1: 'b', 2: 'c'};"
              "Object.defineProperty(o, 'length', {get: () => 4});"
              "Object.defineProperty(o, '3', {get: () => 'd'});"
              "var r = Array.prototype.reduce.call(o, (a, b) => a + b); r"),
      njs_str("abcd") },

    { njs_str("var o = {1: 'b', 2: 'c', 3: 'd'};"
              "Object.defineProperty(o, 'length', {get: () => 4});"
              "Object.defineProperty(o, '0', {get: () => 'a'});"
              "var r = Array.prototype.reduce.call(o, (a, b) => a + b); r"),
      njs_str("abcd") },

    { njs_str("[].reduceRight((p, v) => p + v)"),
      njs_str("TypeError: Reduce of empty object with no initial value") },

    { njs_str("[].reduceRight((p, v) => p + v, 10)"),
      njs_str("10") },

    { njs_str("[,,].reduceRight((p, v) => p + v)"),
      njs_str("TypeError: Reduce of empty object with no initial value") },

    { njs_str("[,,].reduceRight((p, v) => p + v, 10)"),
      njs_str("10") },

    { njs_str("[1].reduceRight((p, v) => p + v)"),
      njs_str("1") },

    { njs_str("[1].reduceRight((p, v) => p + v, 10)"),
      njs_str("11") },

    { njs_str("[1,2,3].reduceRight((p, v) => p + v)"),
      njs_str("6") },

    { njs_str("[1,2,3].reduceRight((p, v) => p + v, 10)"),
      njs_str("16") },

    { njs_str("[3,2,1].reduceRight((p, v, i) => { if (v + i != 3) {throw 'Oops'};return p + v})"),
      njs_str("6") },

    { njs_str("var a = [1,2,3];"
              "a.reduceRight(function(p, v, _, a) { a.shift(); return p + v })"),
      njs_str("7") },
    { njs_str("var a = [1,2,3];"
              "a.reduceRight(function(p, v, _, a) { a.shift(); return p + v }, 10)"),
      njs_str("19") },

    { njs_str("var o = {0: 'a', 1: 'b', 2: 'c'};"
              "Object.defineProperty(o, 'length', {get: () => 4});"
              "Object.defineProperty(o, '3', {get: () => 'd'});"
              "Array.prototype.reduceRight.call(o, (p, v) => p + v)"),
      njs_str("dcba") },

    { njs_str("var i = 0; var o = {get length() {i++}};"
              "try {Array.prototype.reduceRight.call(o);}"
              "catch (e) {i += '; ' + e} i"),
      njs_str("1; TypeError: callback argument is not callable") },

    { njs_str("var m = [];"
              "[''].reduceRight.call('00000000000000000000000000000а00', (p, v, i, a) => {m.push(v)});"
              "m.join('')"),
      njs_str("0а00000000000000000000000000000") },

    { njs_str("function reducer(a, b, i, arr) {"
              "   if (i == 2) Object.defineProperty(arr, i, {enumerable:false}); "
              "   return a + b;"
              "};"
              "Array.prototype.reduceRight.call([1,2,3,4], reducer)"),
      njs_str("10") },

    { njs_str("Array.prototype[0] = 1; Array.prototype[1] = 2; Array.prototype[2] = 3;"
              "[,,].reduceRight((a,b)=>a+b)"),
      njs_str("3") },

    { njs_str("var a = ['1','2','3','4','5','6']; a.sort()"),
      njs_str("1,2,3,4,5,6") },

    { njs_str("var a = ['a', 'ab', '', 'aa']; a.sort()"),
      njs_str(",a,aa,ab") },

    { njs_str("var a = ['a', 'ab', '', 'aa']; a.sort()"),
      njs_str(",a,aa,ab") },

    { njs_str("var a = [23,1,8,5]; Object.defineProperty(a, '0', {enumerable:false});"
              "a.sort((x,y)=>x-y)"),
      njs_str("1,5,8,23") },

    { njs_str("var a = {0:23,1:1,2:8,3:5,length:4};"
              "Array.prototype.sort.call(a, (x,y)=>x-y);"
              "Array.prototype.join.call(a)"),
      njs_str("1,5,8,23") },

    { njs_str(njs_declare_sparse_array("a", 1024)
              "a[100] = 1; a[512] = -1; a[5] = undefined;"
              "a.sort();"
              "a[0] == -1 && a[1] == 1 && a[2] == undefined"),
      njs_str("true") },

    { njs_str(njs_declare_sparse_array("a", 1024)
              "a.fill(1, 256, 512); a.fill(undefined, 1000, 1010);"
              "Object.defineProperty(a, '256', {value: a[256], enumerable:false});"
              "a.sort();"
              "a[0] == 1 && a[255] == 1 && Object.getOwnPropertyDescriptor(a, '256').value == undefined"),
      njs_str("true") },

    { njs_str("var a = [23,1,,undefined,8,,5]; Object.defineProperty(a, '0', {enumerable:false});"
              "a.sort((x,y)=>x-y)"),
      njs_str("1,5,8,23,,,") },

    { njs_str("var o = { toString: function() { return 5 } };"
              "var a = [6,o,4,3,2,1]; a.sort(undefined)"),
      njs_str("1,2,3,4,5,6") },

    { njs_str("var a = [undefined,1]; a.sort()"),
      njs_str("1,") },

    { njs_str("var a = [,1]; a.sort()"),
      njs_str("1,") },

    { njs_str("var a = [,1,undefined]; a.sort()"),
      njs_str("1,,") },

    { njs_str("var a = ['1','2','3','4','5','6']; a.sort()"),
      njs_str("1,2,3,4,5,6") },

    { njs_str("var a = [1,2,3,4,5,6]; a.sort()"),
      njs_str("1,2,3,4,5,6") },

    { njs_str("var a = {0:3,1:2,2:1}; Array.prototype.sort.call(a) === a"),
      njs_str("true") },

    { njs_str("var a = {0:3,1:2,2:1,length:0}; Array.prototype.sort.call(a) === a"),
      njs_str("true") },

    { njs_str("var a = [1,2,3,4,5,6];"
              "a.sort(function(x, y) { return x - y })"),
      njs_str("1,2,3,4,5,6") },

    { njs_str("var a = Array(128).fill().map((v,i,a)=>a.length-i);"
              "a.sort((a,b)=>a-b);"
              "a.every((v,i,a)=> (i < 1 || v >= a[i-1]))"),
      njs_str("true") },

    { njs_str("var a = [2,2,2,1,1,1];"
              "a.sort(function(x, y) { return x - y })"),
      njs_str("1,1,1,2,2,2") },

    { njs_str("var a = [,,,2,2,2,1,1,1];"
              "a.sort(function(x, y) { return x - y })"),
      njs_str("1,1,1,2,2,2,,,") },

    { njs_str("var a = [,,,,];"
              "a.sort(function(x, y) { return x - y })"),
      njs_str(",,,") },

    { njs_str("var a = [,,undefined,undefined,,undefined];"
              "a.sort(function(x, y) { return x - y }); njs.dump(a)"),
      njs_str("[undefined,undefined,undefined,<3 empty items>]") },

    { njs_str("var a = [1,,undefined,8,undefined,,undefined,,2];"
              "a.sort(function(x, y) { return x - y }); njs.dump(a)"),
      njs_str("[1,2,8,undefined,undefined,undefined,<3 empty items>]") },

    { njs_str("var a = [1,,];"
              "a.sort(function(x, y) { return x - y })"),
      njs_str("1,") },

    { njs_str("var a = [{ n: 'A', r: 2 },"
              "         { n: 'B', r: 3 },"
              "         { n: 'C', r: 2 },"
              "         { n: 'D', r: 3 },"
              "         { n: 'E', r: 3 }];"
              "a.sort((a, b) => b.r - a.r).map(v=>v.n).join('')"),
      njs_str("BDEAC") },

    { njs_str("[1,2,3].sort(()=>-1)"),
      njs_str("3,2,1") },

    { njs_str("njs.dump([undefined,1,2,3].sort(()=>0))"),
      njs_str("[1,2,3,undefined]") },

    { njs_str("njs.dump([1,,2,3].sort(()=>0))"),
      njs_str("[1,2,3,<empty>]") },

    { njs_str("var count = 0;"
              "[4,3,2,1].sort(function(x, y) { if (count++ == 2) {throw Error('Oops'); }; return x - y })"),
      njs_str("Error: Oops") },

    { njs_str("[1,2].sort(1)"),
      njs_str("TypeError: comparefn must be callable or undefined") },

    { njs_str("var a = [1,2]; a.sort(() => {a.length = 65535}); a.length"),
      njs_str("65535") },

    { njs_str("var a = [];"
              "var shift = true;"
              "for (let i = 0; i < 64; i++) {"
              "    a[i] = { toString() {"
              "                 if (shift) { a.shift() };"
              "                 return (63 - i).toString().padStart(2, '0');"
              "             }"
              "           };"
              "}"
              "a.sort();"
              "shift = false;"
              "[a.length, a[0].toString(), a[63].toString()]"),
      njs_str("64,00,63") },

    { njs_str("var a = [];"
              "var shift = true;"
              "for (let i = 0; i < 64; i++) {"
              "    a[i] = { toString() {"
              "                 if (shift) { a.shift() };"
              "                 return (i).toString().padStart(2, '0');"
              "             }"
              "           };"
              "}"
              "a.sort();"
              "shift = false;"
              "[a.length, a[0].toString(), a[63].toString()]"),
      njs_str("64,00,63") },

    { njs_str("Object.prototype[2] = 4;"
              "njs.dump([undefined, 3, /*hole*/, 2, undefined, /*hole*/, 1].sort())"),
      njs_str("[1,2,3,4,undefined,undefined,<empty>]") },

    /* A prototype getter for a hole reallocates the array being sorted. */

    { njs_str("Object.defineProperty(Array.prototype, 1, {configurable: true,"
              "  get() { for (var i = 0; i < 1024; i++) { this.push(i); }"
              "          return 5; }});"
              "var a = [3]; a[2] = 7; a.length = 3;"
              "a.sort(function(x, y) { return x - y; });"
              "a[0] === 3 && a[1] === 5 && a[2] === 7"),
      njs_str("true") },

    { njs_str("var a = [3,2,1]; [a.toSorted(), a]"),
      njs_str("1,2,3,3,2,1") },

    { njs_str("var a = [3,,1]; njs.dump([a.toSorted(), a.sort()])"),
      njs_str("[[1,3,undefined],[1,3,<empty>]]") },

    { njs_str("var a = {length:3, 0:'Z', 2:'A'};"
              "njs.dump([Array.prototype.toSorted.call(a), Array.prototype.sort.call(a)])"),
      njs_str("[['A','Z',undefined],{0:'A',1:'Z',length:3}]") },

    { njs_str("var a = {length: 1}; a.__proto__ = {0:'A'};"
              "njs.dump([Array.prototype.toSorted.call(a), Array.prototype.sort.call(a)])"),
      njs_str("[['A'],{length:1}]") },

    { njs_str("Array.prototype.toSorted.call(true)"),
      njs_str("") },

    { njs_str("Array.prototype.toSorted.call({length: -2})"),
      njs_str("") },

    { njs_str("Array.prototype.toSorted.call({length: NaN})"),
      njs_str("") },

    { njs_str("Array.prototype.toSorted.call({length: 2**32})"),
      njs_str("RangeError: Invalid array length") },

    /*
      Array.prototype.keys()
      Array.prototype.values()
      Array.prototype.entries()
    */

    { njs_str("['keys', 'values', 'entries', Symbol.iterator]"
              ".every((x) => typeof Array.prototype[x] == 'function')"),
      njs_str("true") },

    { njs_str("['keys', 'values', 'entries', Symbol.iterator]"
              ".every((x) => Array.prototype[x].length === 0)"),
      njs_str("true") },

#if 0
    { njs_str("Array.prototype[Symbol.iterator] === Array.prototype.values"),
      njs_str("true") },
#endif

    { njs_str("['keys', 'values', 'entries', Symbol.iterator]"
              ".every((x) => typeof [][x]() == 'object')"),
      njs_str("true") },

    { njs_str("['keys', 'values', 'entries', Symbol.iterator]"
              ".every((x) => typeof [][x]().next == 'function')"),
      njs_str("true") },

    { njs_str("var i = [1,2,3].keys();"
              "[i.next(), i.next(), i.next(), i.next()].map((x) => x.value)"),
      njs_str("0,1,2,") },

    { njs_str("var i = [1,2,3].values();"
              "[i.next(), i.next(), i.next(), i.next()].map((x) => x.value)"),
      njs_str("1,2,3,") },

    { njs_str("[].values().constructor()"),
      njs_str("[object Object]") },

    { njs_str("var a = [], i = a.values();"
              "a.push(1); a.push(2); a.push(3);"
              "[i.next(), i.next(), i.next(), i.next()].map((x) => x.value)"),
      njs_str("1,2,3,") },

    { njs_str("var a = [], i = a.values(); i.next();"
              "a.push(1); a.push(2); a.push(3);"
              "[i.next(), i.next(), i.next(), i.next()].map((x) => x.value)"),
      njs_str(",,,") },

    { njs_str("var i = [1,2,3].entries();"
              "[i.next(), i.next(), i.next(), i.next()].map((x) => x.value)"),
      njs_str("0,1,1,2,2,3,") },

    { njs_str("var i = Array.prototype.keys.call('abc');"
              "[i.next(), i.next(), i.next(), i.next()].map((x) => x.done)"),
      njs_str("false,false,false,true") },

    { njs_str("var i = Array.prototype.values.call('abc');"
              "[i.next(), i.next(), i.next(), i.next()].map((x) => x.value)"),
      njs_str("a,b,c,") },

    { njs_str("var x = [true, 1, Symbol()];"
              "x.map((x) => Array.prototype.keys.call(x).next()).every((x) => x.done)"),
      njs_str("true") },

    { njs_str("var x = [true, 1, Symbol()];"
              "x.forEach((x) => Object.getPrototypeOf(Object(x)).length = 1);"
              "x.map((x) => Array.prototype.keys.call(x).next()).every((x) => !x.done)"),
      njs_str("true") },

    /*
      TypedArray.prototype.keys()
      TypedArray.prototype.values()
      TypedArray.prototype.entries()
    */

    { njs_str("['keys', 'values', 'entries', Symbol.iterator]"
              ".every((x) => typeof Buffer.prototype[x] == 'function')"),
      njs_str("true") },

    { njs_str("var i = Buffer.from([1,2,3]).keys();"
              "[i.next(), i.next(), i.next(), i.next()].map((x) => x.value)"),
      njs_str("0,1,2,") },

    { njs_str("var i = Buffer.from([1,2,3]).values();"
              "[i.next(), i.next(), i.next(), i.next()].map((x) => x.value)"),
      njs_str("1,2,3,") },

    { njs_str("var i = Buffer.from([1,2,3]).entries();"
              "[i.next(), i.next(), i.next(), i.next()].map((x) => x.value)"),
      njs_str("0,1,1,2,2,3,") },

    { njs_str("[true, 1, Symbol(), 'test', [], { length: 1 }]"
              ".map((x) => { try { Buffer.prototype.keys.call(x); return x; } catch (e) { return e; } })"
              ".every((x) => x instanceof TypeError)"),
      njs_str("true") },

    /* %IteratorPrototype% */

    { njs_str("var x = Object.getPrototypeOf(Object.getPrototypeOf([].keys()));"
              "typeof x[Symbol.iterator] == 'function'"),
      njs_str("true") },

    { njs_str("var x = Object.getPrototypeOf(Object.getPrototypeOf([].keys()));"
              "x[Symbol.iterator]() === x"),
      njs_str("true") },

    /* %ArrayIteratorPrototype% */

    { njs_str("var x = Object.getPrototypeOf([].keys());"
              "typeof x.next == 'function'"),
      njs_str("true") },

    { njs_str("var x = Object.getPrototypeOf([].keys());"
              "x[Symbol.toStringTag] == 'Array Iterator'"),
      njs_str("true") },

    /* %StringIteratorPrototype% */

    { njs_str("typeof String.prototype[Symbol.iterator] == 'function'"),
      njs_str("true") },

    { njs_str("var x = Object.getPrototypeOf(''[Symbol.iterator]());"
              "typeof x.next == 'function'"),
      njs_str("true") },

#if 0
    { njs_str("var x = Object.getPrototypeOf(''[Symbol.iterator]());"
              "x[Symbol.toStringTag] == 'String Iterator'"),
      njs_str("true") },
#else
    { njs_str("var x = Object.getPrototypeOf(''[Symbol.iterator]());"
              "x[Symbol.toStringTag] == 'Array Iterator'"),
      njs_str("true") },
#endif

    /* Template literal. */

    { njs_str("`"),
      njs_str("SyntaxError: Unterminated template literal") },

    { njs_str("`$"),
      njs_str("SyntaxError: Unterminated template literal") },

    { njs_str("`${"),
      njs_str("SyntaxError: Unexpected end of input") },

    { njs_str("`${a"),
      njs_str("SyntaxError: Missing \"}\" in template expression") },

    { njs_str("`${}"),
      njs_str("SyntaxError: Unexpected token \"}\"") },

    { njs_str("`${a}"),
      njs_str("SyntaxError: Unterminated template literal") },

    { njs_str("`${a}bc"),
      njs_str("SyntaxError: Unterminated template literal") },

    { njs_str("`\\"),
      njs_str("SyntaxError: Unterminated template literal") },

    { njs_str("`\\${a}bc"),
      njs_str("SyntaxError: Unterminated template literal") },

    { njs_str("`\\ud83d`"),
      njs_str("�") },

    { njs_str("`\\ud83d${1}`"),
      njs_str("�1") },

    { njs_str("var v = undefined; var u8 = 'α';"
              "[`undefined${u8}`.length, `undefineQ${u8}`.length]"),
      njs_str("10,10") },

    { njs_str("`text1\ntext2`;"),
      njs_str("text1\ntext2") },

    { njs_str("var o = 1; `o = \\`${o}\\``"),
      njs_str("o = `1`") },

    { njs_str("`\\unicode`"),
      njs_str("SyntaxError: Invalid Unicode code point \"\\unicode\"") },

    { njs_str("var a = 5; var b = 10;"
                 "`Fifteen is ${a + b} and \nnot ${2 * a + b}.`;"),
      njs_str("Fifteen is 15 and \nnot 20.") },

    { njs_str("var s = `1undefined`; s;"),
      njs_str("1undefined") },

    { njs_str("var s = '0'; s = `x${s += '1'}`;"),
      njs_str("x01") },

    { njs_str("var d = new Date(2011, 5, 24, 18, 45, 12, 625);"
                 "var something = 'test'; var one = 1; var two = 2;"
                 "`[${d.toISOString()}] the message contents ${something} ${one + two}`"),
      njs_str("[2011-06-24T18:45:12.625Z] the message contents test 3") },

    { njs_str("function isLargeScreen() { return false; }"
                 "var item = { isCollapsed: true };"
                 "`header ${ isLargeScreen() ? '' : `icon-${item.isCollapsed ? 'expander' : 'collapser'}` }`;"),
      njs_str("header icon-expander") },

    { njs_str("function foo(strings, person, age) { return `${strings[0]}${strings[1]}${person}${age}` };"
                 "var person = 'Mike'; var age = 21;"
                 "foo`That ${person} is a ${age}`;"),
      njs_str("That  is a Mike21") },

    { njs_str("`\n`.length"),
      njs_str("1") },

    /* Strings. */

    { njs_str("var a = '0123456789' + '012345';"
                 "var b = 'abcdefghij' + 'klmnop';"
                 "    a = b"),
      njs_str("abcdefghijklmnop") },

    { njs_str("String.prototype.my = function f() {return 7}; 'a'.my()"),
      njs_str("7") },

    { njs_str("'a'.my"),
      njs_str("undefined") },

    { njs_str("var a = '123'\n[2].toString();a"),
      njs_str("3") },

    { njs_str("'\xE5\x96\x9C\xE3\x81\xB6'"),
      njs_str("喜ぶ") },

    /* Broken UTF-8 literals.*/

    { njs_str("'\x96\xE5\x9C\xE3\x81\xB6'"),
      njs_str("��ぶ") },

    { njs_str("'\x96\xE5\x9C'"),
      njs_str("��") },

    { njs_str("'\x96\xE5'"),
      njs_str("��") },

    { njs_str("'\x96'"),
      njs_str("�") },

    { njs_str("'\xF3'"),
      njs_str("�") },

    { njs_str("'\xF3\xFF'"),
      njs_str("��") },

    { njs_str("'\x96\x96\xE5\x9C\xE3\x81\xB6'"),
      njs_str("���ぶ") },

    { njs_str("'\x9C\x96\xE5\xE3\x81\xB6'"),
      njs_str("���ぶ") },

    { njs_str("'\xE5\x9C\xE3\x81\xB6'"),
      njs_str("�ぶ") },

    { njs_str("'\xEF\xBF\xBD\xE3\x81\xB6'"),
      njs_str("�ぶ") },

    { njs_str("'\xE5\xF6\x9C\xE3\x81\xB6'"),
      njs_str("���ぶ") },

    { njs_str("var a = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\xF3'; "
                 "[a.length, a[33], a[34]]"),
      njs_str("35,a,�") },

    /* Spaces: U+0009U+000BU+000CU+0020U+00A0U+000AU+000DU+2028U+2029 */

    { njs_str("\x09\x0a\x0b\x0c\x0d \xc2\xa0'a'\xe2\x80\xa8+\xe2\x80\xa9'b'"),
      njs_str("ab") },

    /* Escape strings. */

    { njs_str("'\\a \\' \\\" \\\\ \\0 \\b \\f \\n \\r \\t \\v'"),
      njs_str("a ' \" \\ \0 \b \f \n \r \t \v") },

    { njs_str("'\\\n'"),
      njs_str("") },

    { njs_str("'\\\r'"),
      njs_str("") },

    { njs_str("'\\\r\n'"),
      njs_str("") },

    { njs_str("'a\\\nb'"),
      njs_str("ab") },

    { njs_str("'a\\\rb'"),
      njs_str("ab") },

    { njs_str("'a\\\r\nb'"),
      njs_str("ab") },

    { njs_str("'a\\\n\rb'"),
      njs_str("SyntaxError: Unterminated string \"'a\\\n\r\"") },

    { njs_str("'a\\\nb\nc'"),
      njs_str("SyntaxError: Unterminated string \"'a\\\nb\n\"") },

    { njs_str("'abcde"),
      njs_str("SyntaxError: Unterminated string \"'abcde\"") },

    { njs_str("'\\"),
      njs_str("SyntaxError: Unterminated string \"'\\\"") },

    { njs_str("'\\\r\n"),
      njs_str("SyntaxError: Unterminated string \"'\\\r\n\"") },

    { njs_str("'\\'"),
      njs_str("SyntaxError: Unterminated string \"'\\'\"") },

    { njs_str("'a\n"),
      njs_str("SyntaxError: Unterminated string \"'a\n\"") },

    { njs_str("'a\r"),
      njs_str("SyntaxError: Unterminated string \"'a\r\"") },

    { njs_str("\"a\n"),
      njs_str("SyntaxError: Unterminated string \"\"a\n\"") },

    { njs_str("'\\u03B1'"),
      njs_str("α") },

    { njs_str("'\\u'"),
      njs_str("SyntaxError: Invalid Unicode code point \"\\u\"") },

    { njs_str("'\\uzzzz'"),
      njs_str("SyntaxError: Invalid Unicode code point \"\\uzzzz\"") },

    { njs_str("'\\u03B'"),
      njs_str("SyntaxError: Invalid Unicode code point \"\\u03B\"") },

    { njs_str("'\\u03BG'"),
      njs_str("SyntaxError: Invalid Unicode code point \"\\u03BG\"") },

    { njs_str("'\\u03B '"),
      njs_str("SyntaxError: Invalid Unicode code point \"\\u03B \"") },

    { njs_str("'\\u{61}\\u{3B1}\\u{20AC}'"),
      njs_str("aα€") },

    { njs_str("'\\u'"),
      njs_str("SyntaxError: Invalid Unicode code point \"\\u\"") },

    { njs_str("'\\u{'"),
      njs_str("SyntaxError: Invalid Unicode code point \"\\u{\"") },

    { njs_str("'\\u{}'"),
      njs_str("SyntaxError: Invalid Unicode code point \"\\u{}\"") },

    { njs_str("'\\u{1234567}'"),
      njs_str("SyntaxError: Invalid Unicode code point \"\\u{1234567}\"") },

    { njs_str("'\\u{a00000}'"),
      njs_str("SyntaxError: Invalid Unicode code point \"\\u{a00000}\"") },

    { njs_str("'\\x61'"),
      njs_str("a") },

    { njs_str("''.length"),
      njs_str("0") },

    { njs_str("'abc'.length"),
      njs_str("3") },

    { njs_str("'привет\\n'.length"),
      njs_str("7") },

    { njs_str("'привет\\n\\u{61}\\u{3B1}\\u{20AC}'.length"),
      njs_str("10") },

    { njs_str("'\\ud83d\\udc4d'"),
      njs_str("\xf0\x9f\x91\x8d") },

    { njs_str("'\\ud83d\\udc4d'.length"),
      njs_str("1") },

    { njs_str("'\\u00A0aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'.length"),
      njs_str("35") },

    { njs_str("'\\ud83d abc \\udc4d'"),
      njs_str("� abc �") },

    { njs_str("'\\ud83d'"),
      njs_str("�") },

    { njs_str("'\\ud83d\\uabcd'"),
      njs_str("�ꯍ") },

    { njs_str("'\\u{d800}\\u{dB00}'"),
      njs_str("��") },

    { njs_str("'\\u{d800}\\u{d7ff}'"),
      njs_str("�퟿") },

    { njs_str("'\\u{d800}['"),
      njs_str("�[") },

    { njs_str("'\\u{D800}\\u{'"),
      njs_str("SyntaxError: Invalid Unicode code point \"\\u{D800}\\u{\"") },

    { njs_str("'α' !== '\\α'"),
      njs_str("false") },

    { njs_str("'r' !== '\\r'"),
      njs_str("true") },

    { njs_str("'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaα'[32]"),
      njs_str("α") },

    { njs_str("'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaα'[33]"),
      njs_str("α") },

    { njs_str("'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaα'[34]"),
      njs_str("α") },

    { njs_str("'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaα'[35]"),
      njs_str("α") },

    /* Octal escape sequences are not allowed in strict mode.*/

    { njs_str("'\\0a'"),
      njs_str("\0a") },

    { njs_str("'\\1a'"),
      njs_str("SyntaxError: Octal escape sequences can't be used in untagged template literals or in strict mode code") },

    { njs_str("'a\\2a'"),
      njs_str("SyntaxError: Octal escape sequences can't be used in untagged template literals or in strict mode code") },

    { njs_str("'\\3a'"),
      njs_str("SyntaxError: Octal escape sequences can't be used in untagged template literals or in strict mode code") },

    { njs_str("'a\\4a'"),
      njs_str("SyntaxError: Octal escape sequences can't be used in untagged template literals or in strict mode code") },

    { njs_str("'\\5a'"),
      njs_str("SyntaxError: Octal escape sequences can't be used in untagged template literals or in strict mode code") },

    { njs_str("'a\\6a'"),
      njs_str("SyntaxError: Octal escape sequences can't be used in untagged template literals or in strict mode code") },

    { njs_str("'\\7a'"),
      njs_str("SyntaxError: Octal escape sequences can't be used in untagged template literals or in strict mode code") },

    { njs_str("'\\8a'"),
      njs_str("SyntaxError: The escapes \\8 and \\9 can't be used in untagged template literals or in strict mode code") },

    { njs_str("'\\9a'"),
      njs_str("SyntaxError: The escapes \\8 and \\9 can't be used in untagged template literals or in strict mode code") },

    { njs_str("'\\aa'"),
      njs_str("aa") },

    { njs_str("'\\*a'"),
      njs_str("*a") },

    { njs_str("`\\7`"),
      njs_str("SyntaxError: Octal escape sequences can't be used in untagged template literals or in strict mode code") },

    { njs_str("`\\9`"),
      njs_str("SyntaxError: The escapes \\8 and \\9 can't be used in untagged template literals or in strict mode code") },

    /* Octal escape sequences are allowed in tagged template literals in strict mode.*/

#if 0  /* FIXME: tag function runtime semantics */
    { njs_str("function x (s) {return s[0]}; x`\\7`"),
      njs_str("undefined") },

    { njs_str("function x (s) {return s[0]}; x`\\9`"),
      njs_str("undefined") },

    { njs_str("function x (s) {return s.raw[0]}; x`\\9`"),
      njs_str("\\9") },

    { njs_str("function x (s) {return s.raw[0]}; x`\\7`"),
      njs_str("\\7") },
#endif

    /* Broken UTF-8 literals.*/

    { njs_str("'\\a\x96\xE5\x9C\xE3\x81\xB6'"),
      njs_str("a��ぶ") },

    { njs_str("'\x96\\a\xE5\x9C'"),
      njs_str("�a�") },

    { njs_str("'\x96\xE5\\a'"),
      njs_str("��a") },

    { njs_str("'\\a\x96\\a'"),
      njs_str("a�a") },

    { njs_str("'\xF3\\a'"),
      njs_str("�a") },

    { njs_str("'\xF3\\a\xFF'"),
      njs_str("�a�") },

    { njs_str("'\\a\x96\x96\xE5\x9C\xE3\x81\xB6'"),
      njs_str("a���ぶ") },

    { njs_str("'\\a\x9C\x96\xE5\xE3\x81\xB6'"),
      njs_str("a���ぶ") },

    { njs_str("'\\a\xE5\x9C\xE3\x81\xB6'"),
      njs_str("a�ぶ") },

    { njs_str("'\\a\xEF\xBF\xBD\xE3\x81\xB6'"),
      njs_str("a�ぶ") },

    { njs_str("'\\a\xE5\xF6\x9C\xE3\x81\xB6'"),
      njs_str("a���ぶ") },

    { njs_str("var a = '\\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\xF3'; "
                 "[a.length, a[34], a[35]]"),
      njs_str("36,a,�") },

    { njs_str("''.hasOwnProperty('length')"),
      njs_str("true") },

    { njs_str("'abc'.hasOwnProperty('length')"),
      njs_str("true") },

    { njs_str("(new String('abc')).hasOwnProperty('length')"),
      njs_str("true") },

    { njs_str("'абв'.length"),
      njs_str("3") },

    { njs_str("(new TextEncoder()).encode('абв').length"),
      njs_str("6") },

    { njs_str("'αβγ'.length"),
      njs_str("3") },

    { njs_str("(new TextEncoder()).encode('αβγ').length"),
      njs_str("6") },

    { njs_str("'絵文字'.length"),
      njs_str("3") },

    { njs_str("(new TextEncoder()).encode('絵文字').length"),
      njs_str("9") },

    { njs_str("'えもじ'.length"),
      njs_str("3") },

    { njs_str("(new TextEncoder()).encode('えもじ').length"),
      njs_str("9") },

    { njs_str("'囲碁織'.length"),
      njs_str("3") },

    { njs_str("(new TextEncoder()).encode('囲碁織').length"),
      njs_str("9") },

    { njs_str("var a = 'abc'; a.length"),
      njs_str("3") },

    { njs_str("var a = 'abc'; a['length']"),
      njs_str("3") },

    { njs_str("var a = 'абв'; a.length"),
      njs_str("3") },

    { njs_str("var a = 'abc' + 'абв'; a.length"),
      njs_str("6") },

    { njs_str("var a = 'abc' + 1 + 'абв'; a +' '+ a.length"),
      njs_str("abc1абв 7") },

    { njs_str("var a = 1; a.length"),
      njs_str("undefined") },

    { njs_str("var a = 'abc'; a.concat('абв', 123)"),
      njs_str("abcабв123") },

    { njs_str("''.concat.call(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)"),
      njs_str("0123456789") },

    { njs_str("''.concat.apply(0, [1, 2, 3, 4, 5, 6, 7, 8, 9])"),
      njs_str("0123456789") },

    { njs_str("var f = ''.concat.bind(0, 1, 2, 3, 4); f(5, 6, 7, 8, 9)"),
      njs_str("0123456789") },

    { njs_str("var f = ''.concat.bind(0, 1, 2, 3, 4); f(Math.sqrt(25))"),
      njs_str("012345") },

    { njs_str("var f = String.prototype.concat.bind(0, 1); f(2)"),
      njs_str("012") },

    { njs_str("var f = Function.prototype.call.bind"
                 "                            (String.prototype.concat, 0, 1);"
                 "f(2)"),
      njs_str("012") },

    { njs_str("var f = String.prototype.concat.bind(0, 1);"
                 "var o = { toString: f }; o"),
      njs_str("01") },

    { njs_str("''.concat.bind(0, 1, 2, 3, 4).call(5, 6, 7, 8, 9)"),
      njs_str("012346789") },

    { njs_str("''.concat.bind(0, 1, 2, 3, 4).apply(5,[6, 7, 8, 9])"),
      njs_str("012346789") },

    { njs_str("var f = Array.prototype.join.bind([0, 1, 2]); f()"),
      njs_str("0,1,2") },

    { njs_str("var f = Array.prototype.join.bind([0, 1, 2]);"
                 "var o = { toString: f }; o"),
      njs_str("0,1,2") },

    { njs_str("var f = Array.prototype.join.bind([0, 1, 2]); f('.')"),
      njs_str("0.1.2") },

    { njs_str("var f = Array.prototype.join.bind([0, 1, 2], '.');"
                 "var o = { toString: f }; o"),
      njs_str("0.1.2") },

    { njs_str("var f = Array.prototype.toString.bind([0, 1, 2]); f()"),
      njs_str("0,1,2") },

    { njs_str("var f = Array.prototype.toString.bind([0, 1, 2]);"
                 "var o = { toString: f }; o"),
      njs_str("0,1,2") },

    { njs_str("var f = function F() {};"
              "[f.name, f.bind().name, f.bind().bind().name]"),
      njs_str("F,bound F,bound bound F") },

    { njs_str("var f = Object.defineProperty(function() {}, 'name', {value: 'F'});"
              "[f.name, f.bind().name, f.bind().bind().name]"),
      njs_str("F,bound F,bound bound F") },

    { njs_str("var f = Object.defineProperty(function() {}, 'name', {value: undefined});"
              "[f.name, f.bind().name, f.bind().bind().name]"),
      njs_str(",bound ,bound bound ") },

    { njs_str("var f = Object.defineProperty(function() {}, 'name', {get:()=>'F'});"
              "[f.name, f.bind().name]"),
      njs_str("F,bound F") },

    { njs_str("var s = Symbol('F'); var f = Object.defineProperty(function() {}, 'name', {get:()=>s});"
              "[f.name.description, f.bind().name]"),
      njs_str("F,bound ") },

    { njs_str("/a/[Symbol.replace].bind().name"),
      njs_str("bound [Symbol.replace]") },

    { njs_str("var f = Object.defineProperty(function() {}, 'name', {get:()=>{throw Error('Oops')}});"
              "f.bind().name"),
      njs_str("Error: Oops") },

    { njs_str("var f = function() {}; f.a = 'a'; [f.bind().a, f.a]"),
      njs_str(",a") },

    { njs_str("var f = function() {}; var bf = f.bind(); bf.b = 'b'; "
              "[f.b, bf.b]"),
      njs_str(",b") },

    { njs_str("function f(x,y) {return {args:arguments,length:arguments.length}};"
              "var nf = Function.prototype.bind.call(f, {}, 'a', 'b');"
              "var o = new nf();[o.length, o.args[0]]"),
      njs_str("2,a") },

    { njs_str("function f(x,y) {return {args:arguments,length:arguments.length}};"
              "var nf = Function.prototype.bind.call(f, {});"
              "var o = new nf('a', 'b');[o.length, o.args[0]]"),
      njs_str("2,a") },

    { njs_str("var f = function(a,b) { this.a = a; this.b = b; };"
              "f.prototype.X = 'X';"
              "var bf = f.bind(null, 1,2);"
              "var o = new bf(); "
              "[Object.keys(o), o.X,(o instanceof f) && (o instanceof bf),bf.prototype]"),
      njs_str("a,b,X,true,") },

    { njs_str("var bArray = Array.bind(null, 10,16); bArray()"),
      njs_str("10,16") },

    { njs_str("var bArray = Array.bind(null, 10,16); new bArray()"),
      njs_str("10,16") },

    { njs_str("var bArray = Array.bind(null, 10); new bArray(16)"),
      njs_str("10,16") },

    { njs_str("function f(x,y) {return {args:arguments,length:arguments.length}};"
              "var bf = f.bind({}, 'a'); var bbf = bf.bind({},'b'); var o = bbf('c');"
              "[o.args[0], o.args[2], o.length]"),
      njs_str("a,c,3") },

    { njs_str("var f = function (a, b) {return [this, a, b]};"
              "var b1 = f.bind('THIS', 'x');"
              "var b2 = b1.bind('WAKA', 'y');"
              "njs.dump([f(2,3), b1(3), b2()])"),
      njs_str("[[undefined,2,3],['THIS','x',3],['THIS','x','y']]") },

    { njs_str("var f = Math.max;"
              "var b1 = f.bind('THIS', 4);"
              "var b2 = b1.bind('WAKA', 5);"
              "njs.dump([f(2,3), b1(3), b2()])"),
      njs_str("[3,4,5]") },

    { njs_str("var s = { toString: function() { return '123' } };"
                 "var a = 'abc'; a.concat('абв', s)"),
      njs_str("abcабв123") },

    { njs_str("var r = /^\\x80$/; r.source + r.source.length"),
      njs_str("^\\x80$6") },

    { njs_str("var r = /^\\\\x80$/; r.source + r.source.length"),
      njs_str("^\\\\x80$7") },

    { njs_str("var s = 'x'.repeat(2**10).repeat(2**14);"
                 "var a = Array(200).fill(s);"
                 "String.prototype.concat.apply(s, a.slice(1))"),
      njs_str("RangeError: invalid string length") },

#if (NJS_64BIT)
    /*
     * Adversarial regex replace must throw RangeError instead of
     * OOM-killing the process.  The chain accumulates ~2GiB before the
     * cap trips, hence 64-bit only.
     */
    { njs_str("var s = 'x'.repeat(1 << 18);"
                 "var r = '$1'.repeat(1 << 14);"
                 "s.replace(/(.+)/g, r)"),
      njs_str("RangeError: invalid string length") },
#endif

    { njs_str("var a = 'abcdefgh'; a.substr(3, 15)"),
      njs_str("defgh") },

    { njs_str("'abcdefgh'.substr(3, 15)"),
      njs_str("defgh") },

    { njs_str("'abcdefghijklmno'.substr(3, 4)"),
      njs_str("defg") },

    { njs_str("'abcdefghijklmno'.substr(-3, 2)"),
      njs_str("mn") },

    { njs_str("'abcdefgh'.substr(100, 120)"),
      njs_str("") },

    { njs_str("('abc' + 'defgh').substr(1, 4)"),
      njs_str("bcde") },

    { njs_str("'abcdefghijklmno'.substring(3, 5)"),
      njs_str("de") },

    { njs_str("'abcdefgh'.substring(3)"),
      njs_str("defgh") },

    { njs_str("'abcdefgh'.substring(5, 3)"),
      njs_str("de") },

    { njs_str("'abcdefgh'.substring(100, 120)"),
      njs_str("") },

    { njs_str("'α'.repeat(32).substring(32)"),
      njs_str("") },

    { njs_str("'α'.repeat(32).substring(32,32)"),
      njs_str("") },

    { njs_str("'abcdefghijklmno'.slice(NaN, 5)"),
      njs_str("abcde") },

    { njs_str("'abcdefghijklmno'.slice(NaN, Infinity)"),
      njs_str("abcdefghijklmno") },

    { njs_str("'abcdefghijklmno'.slice(-Infinity, Infinity)"),
      njs_str("abcdefghijklmno") },

    { njs_str("'abcdefghijklmno'.slice('0', '5')"),
      njs_str("abcde") },

    { njs_str("'abcdefghijklmno'.slice(3, 5)"),
      njs_str("de") },

    { njs_str("'abcdefgh'.slice(3)"),
      njs_str("defgh") },

    { njs_str("'abcdefgh'.slice(undefined, undefined)"),
      njs_str("abcdefgh") },

    { njs_str("'abcdefgh'.slice(undefined)"),
      njs_str("abcdefgh") },

    { njs_str("'abcdefgh'.slice(undefined, 1)"),
      njs_str("a") },

    { njs_str("'abcdefgh'.slice(3, undefined)"),
      njs_str("defgh") },

    { njs_str("'abcde'.slice(50)"),
      njs_str("") },

    { njs_str("'abcde'.slice(1, 50)"),
      njs_str("bcde") },

    { njs_str("'abcdefgh'.slice(3, -2)"),
      njs_str("def") },

    { njs_str("'abcdefgh'.slice(5, 3)"),
      njs_str("") },

    { njs_str("'abcdefgh'.slice(100, 120)"),
      njs_str("") },

    { njs_str("String.prototype.substring(1, 5)"),
      njs_str("") },

    { njs_str("String.prototype.substr.call({toString:()=>{throw new Error('Oops')}})"),
      njs_str("Error: Oops") },

    { njs_str("String.prototype.slice(1, 5)"),
      njs_str("") },

    { njs_str("'abc'.charAt(1 + 1)"),
      njs_str("c") },

    { njs_str("'abc'.charAt(3)"),
      njs_str("") },

    { njs_str("'abc'.charAt(undefined)"),
      njs_str("a") },

    { njs_str("'abc'.charAt(null)"),
      njs_str("a") },

    { njs_str("'abc'.charAt(false)"),
      njs_str("a") },

    { njs_str("'abc'.charAt(true)"),
      njs_str("b") },

    { njs_str("'abc'.charAt(NaN)"),
      njs_str("a") },

    { njs_str("'abc'.charAt(Infinity)"),
      njs_str("") },

    { njs_str("'abc'.charAt(-Infinity)"),
      njs_str("") },

    { njs_str("var o = { valueOf: function() {return 2} };"
                 "'abc'.charAt(o)"),
      njs_str("c") },

    { njs_str("var o = { toString: function() {return '2'} };"
                 "'abc'.charAt(o)"),
      njs_str("c") },

    { njs_str("'abc'.charCodeAt(1 + 1)"),
      njs_str("99") },

    { njs_str("'abc'.charCodeAt(3)"),
      njs_str("NaN") },

    { njs_str("'abc'.charCodeAt(undefined)"),
      njs_str("97") },

    { njs_str("var a = 'abcdef'; a.3"),
      njs_str("SyntaxError: Unexpected token \".3\"") },

    { njs_str("'abcdef'[3]"),
      njs_str("d") },

    { njs_str("'abcdef'[0]"),
      njs_str("a") },

    { njs_str("'abcdef'[-1]"),
      njs_str("undefined") },

    { njs_str("'abcdef'[NaN]"),
      njs_str("undefined") },

    { njs_str("'abcdef'[3.5]"),
      njs_str("undefined") },

    { njs_str("'abcdef'[8]"),
      njs_str("undefined") },

    { njs_str("'abcdef'['1']"),
      njs_str("b") },

    { njs_str("'abcdef'[' 1']"),
      njs_str("undefined") },

    { njs_str("'abcdef'['1 ']"),
      njs_str("undefined") },

    { njs_str("'abcdef'['']"),
      njs_str("undefined") },

    { njs_str("'abcdef'['-']"),
      njs_str("undefined") },

    { njs_str("'abcdef'['-1']"),
      njs_str("undefined") },

    { njs_str("'abcdef'['01']"),
      njs_str("undefined") },

    { njs_str("'abcdef'['0x01']"),
      njs_str("undefined") },

    { njs_str("var a = 'abcdef', b = 1 + 2; a[b]"),
      njs_str("d") },

    /**/

    { njs_str("'abc'.toString()"),
      njs_str("abc") },

    { njs_str("''.toString.call('abc')"),
      njs_str("abc") },

    { njs_str("String.prototype.toString.call('abc')"),
      njs_str("abc") },

    { njs_str("String.prototype.toString.call(new String('abc'))"),
      njs_str("abc") },

    { njs_str("String.prototype.toString.call(1)"),
      njs_str("TypeError: unexpected value type:number") },

    { njs_str("'abc'.valueOf()"),
      njs_str("abc") },

    /**/

    { njs_str("var n = { toString: function() { return 1 } };   '12'[n]"),
      njs_str("2") },

    { njs_str("var n = { toString: function() { return '1' } }; '12'[n]"),
      njs_str("2") },

    { njs_str("var n = { toString: function() { return 1 },"
                          " valueOf:  function() { return 0 } };   '12'[n]"),
      njs_str("2") },

    { njs_str("var a = { toString: function() { return 1 } }; a"),
      njs_str("1") },

    { njs_str("var a = { valueOf: function() { return 1 } };  a"),
      njs_str("[object Object]") },

    { njs_str("var a = { toString: 2,"
                 "          valueOf: function() { return 1 } };  a"),
      njs_str("1") },

    { njs_str("var a = { toString: function() { return [] },"
                 "          valueOf: function() { return 1 } };  a"),
      njs_str("1") },

    { njs_str("var a = { toString: function() { return [] },"
                 "          valueOf: function() { return 1 } };"
                 "var o = {}; o[a] = 'test'"),
      njs_str("test") },

    { njs_str("({})[{}] = 'test'"),
      njs_str("test") },

    /**/

    { njs_str("'абвгдеёжзийклмнопрстуфхцчшщъыьэюя'.charCodeAt(5)"),
      njs_str("1077") },

    { njs_str("'12345абвгдеёжзийклмнопрстуфхцчшщъыьэюя'.charCodeAt(35)"),
      njs_str("1101") },

    { njs_str("'12345абвгдеёжзийклмнопрстуфхцчшщъыьэюя'.substring(35)"),
      njs_str("эюя") },

    { njs_str("'abcdef'.substr(-5, 4).substring(3, 1).charAt(1)"),
      njs_str("d") },

    { njs_str("'abcdef'.substr(2, 4).charAt(2)"),
      njs_str("e") },

    { njs_str("var a = 'abcdef'.substr(2, 4).charAt(2).length; a"),
      njs_str("1") },

    { njs_str("var a = 'abcdef'.substr(2, 4).charAt(2) + '1234'; a"),
      njs_str("e1234") },

    { njs_str("var a = ('abcdef'.substr(2, 5 * 2 - 6).charAt(2) + '1234')"
                 "         .length; a"),
      njs_str("5") },

    { njs_str("String.fromCharCode('_').charCodeAt(0)"),
      njs_str("0") },

    { njs_str("String.fromCodePoint('_')"),
      njs_str("RangeError: invalid code point") },

    { njs_str("String.fromCharCode(65.14)"),
      njs_str("A") },

    { njs_str("String.fromCodePoint(3.14)"),
      njs_str("RangeError: invalid code point") },

    { njs_str("String.fromCharCode(65.14 + 65536)"),
      njs_str("A") },

    { njs_str("String.fromCharCode(0xD83D, 0xDCA9)"),
      njs_str("💩") },

    { njs_str("String.fromCharCode(0xD83D, 0xDCA9).length"),
      njs_str("1") },

    { njs_str("String.fromCharCode(0xD83D)"),
      njs_str("�") },

    { njs_str("String.fromCharCode(0xD83D).length"),
      njs_str("1") },

    { njs_str("String.fromCharCode(0xD83D) + String.fromCharCode(0xDCA9)"),
      njs_str("��") },

    { njs_str("String.fromCodePoint(65 + 65536)"),
      njs_str("𐁁") },

    { njs_str("String.fromCodePoint(0xD83D, 0xDCA9)"),
      njs_str("💩") },

    { njs_str("String.fromCodePoint(0xD83D, 0xDCA9).length"),
      njs_str("1") },

    { njs_str("String.fromCodePoint(0xD83D)"),
      njs_str("�") },

    { njs_str("String.fromCodePoint(0xD83D).length"),
      njs_str("1") },

    { njs_str("String.fromCharCode(2**53 + 10)"),
      njs_str("\n") },

    { njs_str("String.fromCodePoint(1114111 + 1)"),
      njs_str("RangeError: invalid code point") },

    { njs_str("String.fromCharCode(65, 90) + String.fromCodePoint(65, 90)"),
      njs_str("AZAZ") },

    { njs_str("String.fromCharCode(945, 946, 947) + String.fromCodePoint(945, 946, 947)"),
      njs_str("αβγαβγ") },

    { njs_str("(function() {"
                 "    var n;"
                 "    for (n = 0; n <= 65536; n++) {"

                 /* From U+D800 to U+DFFF is surrogate pair. Not valid in UTF-8. */

                 "        if ((n < 0xD800 || n > 0xDFFF) && String.fromCharCode(n).charCodeAt(0) !== n)"
                 "            return n;"
                 "    }"
                 "    return -1"
                 "})()"),
      njs_str("65536") },

#if (!NJS_HAVE_MEMORY_SANITIZER) /* very long test under MSAN */
    { njs_str("(function() {"
                 "    var n;"
                 "    for (n = 0; n <= 1114111; n++) {"
                 "        if ((n < 0xD800 || n > 0xDFFF) && String.fromCodePoint(n).codePointAt(0) !== n)"
                 "            return n;"
                 "    }"
                 "    return -1"
                 "})()"),
      njs_str("-1") },
#endif

    { njs_str("var a = 'abcdef'; function f(a) {"
                 "return a.slice(a.indexOf('cd')) } f(a)"),
      njs_str("cdef") },

    { njs_str("var a = 'abcdef'; a.slice(a.indexOf('cd'))"),
      njs_str("cdef") },

    { njs_str("'abcdef'.indexOf('de', 2)"),
      njs_str("3") },

    { njs_str("'абвгдеёжзийклмнопрстуфхцчшщъыьэюя'.indexOf('лмно', 10)"),
      njs_str("12") },

    { njs_str("'abcdef'.indexOf('a', 10)"),
      njs_str("-1") },

    { njs_str("'abcdef'.indexOf('q', 0)"),
      njs_str("-1") },

    { njs_str("'abcdef'.indexOf('', 10)"),
      njs_str("6") },

    { njs_str("'abcdef'.indexOf('', 3)"),
      njs_str("3") },

    { njs_str("'12345'.indexOf()"),
      njs_str("-1") },

    { njs_str("''.indexOf('')"),
      njs_str("0") },

    { njs_str("'12345'.indexOf(45, '0')"),
      njs_str("3") },

    { njs_str("'12'.indexOf('12345')"),
      njs_str("-1") },

    { njs_str("''.indexOf.call(12345, 45, '0')"),
      njs_str("3") },

    { njs_str("var r = new String('undefined').indexOf(x); var x; r"),
      njs_str("0") },

    { njs_str("'aaa'.lastIndexOf()"),
      njs_str("-1") },

    { njs_str("'aaa'.lastIndexOf('')"),
      njs_str("3") },

    { njs_str("'aaa'.lastIndexOf('a')"),
      njs_str("2") },

    { njs_str("'aaa'.lastIndexOf('aa')"),
      njs_str("1") },

    { njs_str("'aaa'.lastIndexOf('aaa')"),
      njs_str("0") },

    { njs_str("'aaa'.lastIndexOf('aaaa')"),
      njs_str("-1") },

    { njs_str("'a'.repeat(16).lastIndexOf(String.fromCodePoint(65533).repeat(15))"),
      njs_str("-1") },

    { njs_str("('α'+'a'.repeat(15)).lastIndexOf(String.fromCodePoint(65533).repeat(15))"),
      njs_str("-1") },

    { njs_str("'abc abc abc abc'.lastIndexOf('abc')"),
      njs_str("12") },

    { njs_str("'abc abc abc abc'.lastIndexOf('abc', 11)"),
      njs_str("8") },

    { njs_str("'abc abc abc abc'.lastIndexOf('abc', 0)"),
      njs_str("0") },

    { njs_str("'abc abc abc abc'.lastIndexOf('', 0)"),
      njs_str("0") },

    { njs_str("'abc abc abc abc'.lastIndexOf('', 5)"),
      njs_str("5") },

    { njs_str("'abc abc абвгд abc'.lastIndexOf('абвгд')"),
      njs_str("8") },

    { njs_str("'abc abc абвгд abc'.lastIndexOf('абвгд', undefined)"),
      njs_str("8") },

    { njs_str("'abc abc абвгд abc'.lastIndexOf('абвгд', NaN)"),
      njs_str("8") },

    { njs_str("'abc abc абвгд abc'.lastIndexOf('абвгд', {})"),
      njs_str("8") },

    { njs_str("String.prototype.lastIndexOf.call({toString:()=>'abc abc абвгд abc'}, 'абвгд')"),
      njs_str("8") },

    { njs_str("'abc abc абвгдежз'.lastIndexOf('абвгд')"),
      njs_str("8") },

    { njs_str("'abc abc абвгдежз'.lastIndexOf('абвгд', 11)"),
      njs_str("8") },

    { njs_str("'abc abc абвгдежз'.lastIndexOf('абвгд', 12)"),
      njs_str("8") },

    { njs_str("'abc abc абвгдежз'.lastIndexOf('абвгд', 13)"),
      njs_str("8") },

    { njs_str("'abc abc абвгдежз'.lastIndexOf('абвгд', 14)"),
      njs_str("8") },

    { njs_str("'abc abc абвгдежз'.lastIndexOf('абвгд', 15)"),
      njs_str("8") },

    { njs_str("'abc abc абвгдежз'.lastIndexOf('')"),
      njs_str("16") },

    { njs_str("'abc abc абвгдежз'.lastIndexOf('', 12)"),
      njs_str("12") },

    { njs_str("''.lastIndexOf('')"),
      njs_str("0") },

    { njs_str("''.lastIndexOf()"),
      njs_str("-1") },

    { njs_str("''.lastIndexOf(undefined)"),
      njs_str("-1") },

    { njs_str("'β'.repeat(32).lastIndexOf('β')"),
      njs_str("31") },

    { njs_str("'β'.repeat(32).lastIndexOf('β'.repeat(32))"),
      njs_str("0") },

    { njs_str("'β'.repeat(32).lastIndexOf``"),
      njs_str("32") },

    { njs_str("JSON.stringify(Array(24).fill(true).map((v,i) => 'abc abc ab abc абвгдежзab'.lastIndexOf('abc', i)))"
                 "== JSON.stringify([].concat(Array(4).fill(0), Array(7).fill(4), Array(13).fill(11)))"),
      njs_str("true") },

    { njs_str("''.includes('')"),
      njs_str("true") },

    { njs_str("'12345'.includes()"),
      njs_str("false") },

    { njs_str("'абвгдеёжзийклмнопрстуфхцчшщъыьэюя'.includes('лмно', 10)"),
      njs_str("true") },

    { njs_str("'абв абв абвгдежз'.includes('абвгд', 7)"),
      njs_str("true") },

    { njs_str("'абв абв абвгдежз'.includes('абвгд', 8)"),
      njs_str("true") },

    { njs_str("'абв абв абвгдежз'.includes('абвгд', 9)"),
      njs_str("false") },

    { njs_str("var i = 0; var o = {get length() {i++}};"
              "Array.prototype.includes.call(o); i"),
      njs_str("1") },

    { njs_str("[,,,].includes(undefined)"),
      njs_str("true") },

    { njs_str("''.startsWith('')"),
      njs_str("true") },

    { njs_str("'12345'.startsWith()"),
      njs_str("false") },

    { njs_str("'abc'.startsWith('abc')"),
      njs_str("true") },

    { njs_str("'abc'.startsWith('abc', 1)"),
      njs_str("false") },

    { njs_str("'abc'.startsWith('abc', -1)"),
      njs_str("true") },

    { njs_str("'абв абв абвгдежз'.startsWith('абвгд', 8)"),
      njs_str("true") },

    { njs_str("'абв абв абвгдежз'.startsWith('абвгд', 9)"),
      njs_str("false") },

    { njs_str("''.endsWith('')"),
      njs_str("true") },

    { njs_str("'12345'.endsWith()"),
      njs_str("false") },

    { njs_str("'abc'.endsWith('abc')"),
      njs_str("true") },

    { njs_str("'abc'.endsWith('abc', 4)"),
      njs_str("true") },

    { njs_str("'abc'.endsWith('abc', 1)"),
      njs_str("false") },

    { njs_str("'abc'.endsWith('abc', -1)"),
      njs_str("true") },

    { njs_str("'абв абв абвгдежз'.endsWith('абвгд', 13)"),
      njs_str("true") },

    { njs_str("'абв абв абвгдежз'.endsWith('абвгд', 14)"),
      njs_str("false") },

    { njs_str("'\x00АБВГДЕЁЖЗ'.toLowerCase().length"),
      njs_str("10") },

    { njs_str("'ΑΒΓ'.toLowerCase()"),
      njs_str("αβγ") },

    { njs_str("'АБВ'.toLowerCase()"),
      njs_str("абв") },

    { njs_str("'Ȿ'.repeat(256).toLowerCase() === 'ȿ'.repeat(256)"),
      njs_str("true") },

    { njs_str("'abc'.toUpperCase()"),
      njs_str("ABC") },

    { njs_str("'αβγ'.toUpperCase()"),
      njs_str("ΑΒΓ") },

    { njs_str("'ȿ'.repeat(256).toUpperCase() === 'Ȿ'.repeat(256)"),
      njs_str("true") },

    { njs_str("'\x00абвгдеёжз'.toUpperCase().length"),
      njs_str("10") },

#if (!NJS_HAVE_MEMORY_SANITIZER) /* very long tests under MSAN */
    { njs_str("var a = [], code;"
                 "for (code = 0; code <= 1114111; code++) {"
                 "    var s = String.fromCodePoint(code);"
                 "    var n = s.toUpperCase();"
                 "    if (s != n && s != n.toLowerCase())"
                 "        a.push(code);"
                 "} a"),
      njs_str("181,305,383,453,456,459,498,837,962,976,977,981,982,1008,1009,1013,7296,7297,7298,7299,7300,7301,7302,7303,7304,7835,8126") },

    { njs_str("var a = [], code;"
                 "for (code = 0; code <= 1114111; code++) {"
                 "    var s = String.fromCodePoint(code);"
                 "    var n = s.toLowerCase();"
                 "    if (s != n && s != n.toUpperCase())"
                 "        a.push(code);"
                 "} a"),
      njs_str("304,453,456,459,498,1012,7838,8486,8490,8491") },
#endif

    { njs_str("'abc'.trimStart().trim().trimEnd()"),
      njs_str("abc") },

    { njs_str("''.trim()"),
      njs_str("") },

    { njs_str("'    '.trim()"),
      njs_str("") },

    { njs_str("'abc  '.trimEnd()"),
      njs_str("abc") },

    { njs_str("'   abc'.trimStart()"),
      njs_str("abc") },

    { njs_str("'   abc  '.trim()"),
      njs_str("abc") },

    { njs_str("'абв  '.trimEnd()"),
      njs_str("абв") },

    { njs_str("'   абв'.trimStart()"),
      njs_str("абв") },

    { njs_str("'   абв  '.trimStart().trimEnd()"),
      njs_str("абв") },

    { njs_str("["
              " String.fromCodePoint(0x2028),"
              " String.fromCodePoint(0x20, 0x2028),"
              " String.fromCodePoint(0x0009, 0x20, 0x2028),"
              " String.fromCodePoint(0xFEFF),"
              "].every(v => v.trimEnd() == '')"),
      njs_str("true") },

    { njs_str("'\\u2029abc\\uFEFF\\u2028'.trim()"),
      njs_str("abc") },

#if (!NJS_HAVE_MEMORY_SANITIZER) /* very long test under MSAN */
    { njs_str("var a = [], code;"
                 "for (code = 0; code <= 1114111; code++) {"
                 "    var ws = String.fromCodePoint(code);"
                 "    if ((ws + '-' + ws).trim() === '-')"
                 "        a.push(code);"
                 "} a"),
      njs_str("9,10,11,12,13,32,160,5760,8192,8193,8194,8195,8196,8197,8198,8199,8200,8201,8202,8232,8233,8239,8287,12288,65279") },
#endif

    { njs_str("'abcdefgh'.search()"),
      njs_str("0") },

    { njs_str("'abcdefgh'.search('')"),
      njs_str("0") },

    { njs_str("'abcdefgh'.search(undefined)"),
      njs_str("0") },

    { njs_str("'abcdefgh'.search(/def/)"),
      njs_str("3") },

    { njs_str("'abcdefgh'.search('def')"),
      njs_str("3") },

    { njs_str("'123456'.search('45')"),
      njs_str("3") },

    { njs_str("'123456'.search(45)"),
      njs_str("3") },

    { njs_str("'123456'.search(String(45))"),
      njs_str("3") },

    { njs_str("'123456'.search(Number('45'))"),
      njs_str("3") },

    { njs_str("var r = { toString: function() { return '45' } };"
                 "'123456'.search(r)"),
      njs_str("3") },

    { njs_str("var r = { toString: function() { return 45 } };"
                 "'123456'.search(r)"),
      njs_str("3") },

    { njs_str("var r = { toString: function() { return /45/ } };"
                 "'123456'.search(r)"),
      njs_str("TypeError: Cannot convert object to primitive value") },

    { njs_str("var r = { toString: function() { return /34/ },"
                 "          valueOf:  function() { return 45 } };"
                 "'123456'.search(r)"),
      njs_str("3") },

    { njs_str("'abc'.replace()"),
      njs_str("abc") },

    { njs_str("'abc'.replaceAll()"),
      njs_str("abc") },

    { njs_str("'ABC'.replace('B')"),
      njs_str("AundefinedC") },

    { njs_str("'ABCB'.replaceAll('B')"),
      njs_str("AundefinedCundefined") },

    { njs_str("'ABC'.replace('B', undefined)"),
      njs_str("AundefinedC") },

    { njs_str("'ABBC'.replaceAll('B', undefined)"),
      njs_str("AundefinedundefinedC") },

    { njs_str("'a'.repeat(16).replace('a'.repeat(17)) === 'a'.repeat(16)"),
      njs_str("true") },

    { njs_str("'a'.repeat(16).replaceAll('a'.repeat(17)) === 'a'.repeat(16)"),
      njs_str("true") },

    { njs_str("'α'.repeat(16).replace('α'.repeat(17)) === 'α'.repeat(16)"),
      njs_str("true") },

    { njs_str("'α'.repeat(16).replaceAll('α'.repeat(17)) === 'α'.repeat(16)"),
      njs_str("true") },

    { njs_str("'ABC'.replace('B', null)"),
      njs_str("AnullC") },

    { njs_str("'BABCB'.replaceAll('B', null)"),
      njs_str("nullAnullCnull") },

    { njs_str("'abc'.replace('c', 1)"),
      njs_str("ab1") },

    { njs_str("'cacbc'.replaceAll('c', 1)"),
      njs_str("1a1b1") },

    { njs_str("'abc'.replace('a', 'X')"),
      njs_str("Xbc") },

    { njs_str("'cabac'.replaceAll('a', 'X')"),
      njs_str("cXbXc") },

    { njs_str("'abc'.replace('b', 'X')"),
      njs_str("aXc") },

    { njs_str("'abc'.replaceAll('b', 'X')"),
      njs_str("aXc") },

    { njs_str("('a'.repeat(33) + 'bb').replace('bb', 'CC').slice(31)"),
      njs_str("aaCC") },

    { njs_str("('a'.repeat(33) + 'bb').replaceAll('b', 'C').slice(31)"),
      njs_str("aaCC") },

    { njs_str("var r = 'abc'.replace('c', 'X'); [r, r.length]"),
      njs_str("abX,3") },

    { njs_str("var r = 'acbc'.replaceAll('c', 'X'); [r, r.length]"),
      njs_str("aXbX,4") },

    { njs_str("var r = 'αβγ'.replace('α', 'X'); [r, r.length]"),
      njs_str("Xβγ,3") },

    { njs_str("var r = 'αβαγα'.replaceAll('α', 'X'); [r, r.length]"),
      njs_str("XβXγX,5") },

    { njs_str("var r = 'αβγ'.replace('β', 'X'); [r, r.length]"),
      njs_str("αXγ,3") },

    { njs_str("var r = 'αβγ'.replaceAll('β', 'X'); [r, r.length]"),
      njs_str("αXγ,3") },

    { njs_str("var r = 'αβγ'.replace('γ', 'X'); [r, r.length]"),
      njs_str("αβX,3") },

    { njs_str("var r = 'αβγγ'.replaceAll('γ', 'X'); [r, r.length]"),
      njs_str("αβXX,4") },

    { njs_str("var r = 'αβγ'.replace('', 'X'); [r, r.length]"),
      njs_str("Xαβγ,4") },

    { njs_str("var r = 'αβγ'.replaceAll('', 'X'); [r, r.length]"),
      njs_str("XαXβXγX,7") },

    { njs_str("var r = ''.replaceAll('', 'z'); [r, r.length]"),
      njs_str("z,1") },

    { njs_str("var r = 'α'.padStart(32).replaceAll('', 'z'); [r, r.length]"),
      njs_str("z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z zαz,65") },

    { njs_str("'abc'.replace('b', (m, o, s) => `|${s}|${o}|${m}|`)"),
      njs_str("a|abc|1|b|c") },

    { njs_str("'abcb'.replaceAll('b', (m, o, s) => `|${s}|${o}|${m}|`)"),
      njs_str("a|abcb|1|b|c|abcb|3|b|") },

    { njs_str("'abcdbe'.replace('b', '|$`X$\\'|')"),
      njs_str("a|aXcdbe|cdbe") },

    { njs_str("'abcdbe'.replaceAll('b', '|$`X$\\'|')"),
      njs_str("a|aXcdbe|cd|abcdXe|e") },

    { njs_str("var r = 'αβγ'.replace('β', \"$'\"); [r, r.length]"),
      njs_str("αγγ,3") },

    { njs_str("var r = 'αβγαβγ'.replaceAll('β', \"$'\"); [r, r.length]"),
      njs_str("αγαβγγαγγ,9") },

    { njs_str("var r = 'αβγ'.replace('β', \"$`\"); [r, r.length]"),
      njs_str("ααγ,3") },

    { njs_str("var r = 'αβγαβγ'.replaceAll('β', \"$`\"); [r, r.length]"),
      njs_str("ααγααβγαγ,9") },

    { njs_str("'ABC'.replace('B', '$<g>')"),
      njs_str("A$<g>C") },

    { njs_str("'ABCB'.replaceAll('B', '$<g>')"),
      njs_str("A$<g>C$<g>") },

    { njs_str("'ABC'.replace('B', '$23')"),
      njs_str("A$23C") },

    { njs_str("'ABBC'.replaceAll('B', '$23')"),
      njs_str("A$23$23C") },

    { njs_str("'undefined'.replace(void 0, 'x')"),
      njs_str("x") },

    { njs_str("'undefinedundefined'.replaceAll(void 0, 'x')"),
      njs_str("xx") },

    { njs_str("'12345'.replace(3, () => 0)"),
      njs_str("12045") },

    { njs_str("'123435'.replaceAll(3, () => 0)"),
      njs_str("120405") },

    { njs_str("var r = new String('undefined').replace(x, Function('return arguments[1]+42;')); var x; r"),
      njs_str("42") },

    { njs_str("var r = new String('undefined undefined').replaceAll(x, Function('return arguments[1]+42;')); var x; r"),
      njs_str("42 52") },

    { njs_str("'123'.replace(3, function() { return {toString: ()=>({})}; })"),
      njs_str("TypeError: Cannot convert object to primitive value") },

    { njs_str("'123'.replaceAll(3, function() { return {toString: ()=>({})}; })"),
      njs_str("TypeError: Cannot convert object to primitive value") },

    { njs_str("'12345'.replace(3, () => ({toString: () => 'aaaa'}))"),
      njs_str("12aaaa45") },

    { njs_str("'123435'.replaceAll(3, () => ({toString: () => 'aaaa'}))"),
      njs_str("12aaaa4aaaa5") },

    { njs_str("'ABC'.replace('B', () => {throw 'OOps'})"),
      njs_str("OOps") },

    { njs_str("'ABCB'.replaceAll('B', () => {throw 'OOps'})"),
      njs_str("OOps") },

    { njs_str("'abc'.replace(/a/, 'X')"),
      njs_str("Xbc") },

    { njs_str("'abc'.replaceAll(/a/, 'X')"),
      njs_str("TypeError: String.prototype.replaceAll called with a non-global RegExp argument") },

    { njs_str("'abac'.replaceAll(/a/g, 'X')"),
      njs_str("XbXc") },

    { njs_str("'abccd'.replace(/c/, 'X')"),
      njs_str("abXcd") },

    { njs_str("'abccd'.replaceAll(/c/g, 'X')"),
      njs_str("abXXd") },

    { njs_str("'abc'.replace(/c/, 'X')"),
      njs_str("abX") },

    { njs_str("'abc'.replaceAll(/c/g, 'X')"),
      njs_str("abX") },

    { njs_str("'abccd'.replace(/c+/, 'X')"),
      njs_str("abXd") },

    { njs_str("'acccbccd'.replaceAll(/c+/g, 'X')"),
      njs_str("aXbXd") },

    { njs_str("'abc'.replace(/f/, 'X')"),
      njs_str("abc") },

    { njs_str("'abc'.replaceAll(/f/g, 'X')"),
      njs_str("abc") },

    { njs_str("'AB=C==='.replace(/=*$/, '')"),
      njs_str("AB=C") },

    { njs_str("'AB=C==='.replaceAll(/=*$/g, '')"),
      njs_str("AB=C") },

    { njs_str("('a'.repeat(33) + 'bb').replace(/bb/, 'CC').slice(31)"),
      njs_str("aaCC") },

    { njs_str("('a'.repeat(33) + 'bb').replaceAll(/b/g, 'C').slice(31)"),
      njs_str("aaCC") },

    { njs_str("'abccd'.replace(/c/g, 'X')"),
      njs_str("abXXd") },

    { njs_str("'abccd'.replaceAll(/c/g, 'X')"),
      njs_str("abXXd") },

    { njs_str("('a'.repeat(33) + 'bb').replace(/bb/g, 'CC').slice(31)"),
      njs_str("aaCC") },

    { njs_str("('a'.repeat(33) + 'bb').replaceAll(/bb/g, 'CC').slice(31)"),
      njs_str("aaCC") },

    { njs_str("'abccd'.replace(/[ac]/g, 'X')"),
      njs_str("XbXXd") },

    { njs_str("'abccd'.replaceAll(/[ac]/g, 'X')"),
      njs_str("XbXXd") },

    { njs_str("'ab'.replace(/q*/g, 'X')"),
      njs_str("XaXbX") },

    { njs_str("'ab'.replaceAll(/q*/g, 'X')"),
      njs_str("XaXbX") },

    { njs_str("'αβ'.replace(/q*/g, 'X')"),
      njs_str("XαXβX") },

    { njs_str("'αβ'.replaceAll(/q*/g, 'X')"),
      njs_str("XαXβX") },

    { njs_str("'αβ'.replace(/(q)*/g, 'X')"),
      njs_str("XαXβX") },

    { njs_str("'αβ'.replaceAll(/(q)*/g, 'X')"),
      njs_str("XαXβX") },

    { njs_str("'αβ'.replace(/q*/g, 'γ')"),
      njs_str("γαγβγ") },

    { njs_str("'αβ'.replaceAll(/q*/g, 'γ')"),
      njs_str("γαγβγ") },

    { njs_str("':α:β:γ:'.replace(/:/g, '')"),
      njs_str("αβγ") },

    { njs_str("':α:β:γ:'.replaceAll(/:/g, '')"),
      njs_str("αβγ") },

    { njs_str("':α:β:γ:'.replace(/[αβγ]/g, '')"),
      njs_str("::::") },

    { njs_str("':α:β:γ:'.replaceAll(/[αβγ]/g, '')"),
      njs_str("::::") },

    { njs_str("'aabbccaa'.replace(/a*/g, '')"),
      njs_str("bbcc") },

    { njs_str("'aabbccaa'.replaceAll(/a*/g, '')"),
      njs_str("bbcc") },

    { njs_str("'aabbccaab'.replace(/z*/g, '')"),
      njs_str("aabbccaab") },

    { njs_str("'aabbccaab'.replaceAll(/z*/g, '')"),
      njs_str("aabbccaab") },

    { njs_str("''.replace(/a*/g, '')"),
      njs_str("") },

    { njs_str("''.replaceAll(/a*/g, '')"),
      njs_str("") },

    { njs_str("'abcde'.replace(/d/, (m, o, s) => `|${s}|${o}|${m}|`)"),
      njs_str("abc|abcde|3|d|e") },

    { njs_str("'abcdde'.replaceAll(/d/g, (m, o, s) => `|${s}|${o}|${m}|`)"),
      njs_str("abc|abcdde|3|d||abcdde|4|d|e") },

    { njs_str("'abcde'.replace(/(d)/, (m, p, o, s) => `|${s}|${o}|${m}|${p}|`)"),
      njs_str("abc|abcde|3|d|d|e") },

    { njs_str("'abcded'.replaceAll(/(d)/g, (m, p, o, s) => `|${s}|${o}|${m}|${p}|`)"),
      njs_str("abc|abcded|3|d|d|e|abcded|5|d|d|") },

    { njs_str("'abc'.replace(/b/, () => 1)"),
      njs_str("a1c") },

    { njs_str("'abcb'.replaceAll(/b/g, () => 1)"),
      njs_str("a1c1") },

    { njs_str("var n = 0; 'abbbc'.replace(/b/g, () => ++n)"),
      njs_str("a123c") },

    { njs_str("var n = 0; 'abbbc'.replaceAll(/b/g, () => ++n)"),
      njs_str("a123c") },

    { njs_str("'abc'.replace(/x/, (m, o, s) => `|${s}|${o}|${m}|`)"),
      njs_str("abc") },

    { njs_str("'abc'.replaceAll(/x/g, (m, o, s) => `|${s}|${o}|${m}|`)"),
      njs_str("abc") },

    { njs_str("'abc12345#$*%'.replace(/([^\\d]*)(\\d*)([^\\w]*)/,"
              "                       (_, p1, p2, p3) => [p1, p2, p3].join('-'))"),
      njs_str("abc-12345-#$*%") },

    { njs_str("'abc12345#$*%'.replaceAll(/([^\\d]*)(\\d*)([^\\w]*)/g,"
              "                       (_, p1, p2, p3) => [p1, p2, p3].join('-'))"),
      njs_str("abc-12345-#$*%--") },

    { njs_str("'abc'.replace(/(?<named>b)/, (m, p, o, s, gr) => `|${gr.named}|`)"),
      njs_str("a|b|c") },

    { njs_str("'abcb'.replaceAll(/(?<named>b)/g, (m, p, o, s, gr) => `|${gr.named}|`)"),
      njs_str("a|b|c|b|") },

    { njs_str("'ABC'.replace(/[A-Z]/g, m => '-' + m.toLowerCase())"),
      njs_str("-a-b-c") },

    { njs_str("'ABC'.replaceAll(/[A-Z]/g, m => '-' + m.toLowerCase())"),
      njs_str("-a-b-c") },

    { njs_str("'abc'.replace(/(b)c/g, '|$01|')"),
      njs_str("a|b|") },

    { njs_str("'abc'.replaceAll(/(b)c/g, '|$01|')"),
      njs_str("a|b|") },

    { njs_str("'abc'.replace(/(b)c/g, '@$0|$01|$00@')"),
      njs_str("a@$0|b|$00@") },

    { njs_str("'abc'.replaceAll(/(b)c/g, '@$0|$01|$00@')"),
      njs_str("a@$0|b|$00@") },

    { njs_str("'abcdeFGHIJ'.replace(/(a)(b)(c)(d)(e)(F)(G)(H)(I)(J)/, '$9|$10|$11|$01')"),
      njs_str("I|J|a1|a") },

    { njs_str("'abcdeFGHIJ abcdeFGHIJ'.replaceAll(/(a)(b)(c)(d)(e)(F)(G)(H)(I)(J)/g, '$9|$10|$11|$01')"),
      njs_str("I|J|a1|a I|J|a1|a") },

    { njs_str("'abcdbe'.replace(/(b)/g, '$2$23')"),
      njs_str("a$2$23cd$2$23e") },

    { njs_str("'abcdbe'.replaceAll(/(b)/g, '$2$23')"),
      njs_str("a$2$23cd$2$23e") },

    { njs_str("'abcdbe'.replace(/(b)/g, '$2$23X$$Y')"),
      njs_str("a$2$23X$Ycd$2$23X$Ye") },

    { njs_str("'abcdbe'.replaceAll(/(b)/g, '$2$23X$$Y')"),
      njs_str("a$2$23X$Ycd$2$23X$Ye") },

    { njs_str("'abcdbe'.replace(/b/, '|$`X$\\'|')"),
      njs_str("a|aXcdbe|cdbe") },

    { njs_str("'abcdbe'.replaceAll(/b/g, '|$`X$\\'|')"),
      njs_str("a|aXcdbe|cd|abcdXe|e") },

    { njs_str("'abcdbefbgh'.replace(/b/g, '|$`X$\\'|')"),
      njs_str("a|aXcdbefbgh|cd|abcdXefbgh|ef|abcdbefXgh|gh") },

    { njs_str("'abcdbefbgh'.replaceAll(/b/g, '|$`X$\\'|')"),
      njs_str("a|aXcdbefbgh|cd|abcdXefbgh|ef|abcdbefXgh|gh") },

    { njs_str("'abc12345#$*%'.replace(/([^\\d]*)(\\d*)([^\\w]*)/, '$1-$2-$3')"),
      njs_str("abc-12345-#$*%") },

    { njs_str("'abc12345#$*%'.replaceAll(/([^\\d]*)(\\d*)([^\\w]*)/g, '$1-$2-$3')"),
      njs_str("abc-12345-#$*%--") },

    { njs_str("'$1,$2'.replace(/(\\$(\\d))/g, '$$1-$1$2')"),
      njs_str("$1-$11,$1-$22") },

    { njs_str("'$1,$2'.replaceAll(/(\\$(\\d))/g, '$$1-$1$2')"),
      njs_str("$1-$11,$1-$22") },

    { njs_str("'ABC'.replace(/(h*)(z*)(g*)/g, '$1@$2α$3')"),
      njs_str("@αA@αB@αC@α") },

    { njs_str("'ABC'.replaceAll(/(h*)(z*)(g*)/g, '$1@$2α$3')"),
      njs_str("@αA@αB@αC@α") },

    { njs_str("'abc'.replace(/(h*)(z*)/g, '$1@$2#$3:')"),
      njs_str("@#$3:a@#$3:b@#$3:c@#$3:") },

    { njs_str("'abc'.replaceAll(/(h*)(z*)/g, '$1@$2#$3:')"),
      njs_str("@#$3:a@#$3:b@#$3:c@#$3:") },

    { njs_str("/b(c)(z)?(.)/[Symbol.replace]('abcde', '[$1$2$3]')"),
      njs_str("a[cd]e") },

    { njs_str("/b(c)(z)?(.)/[Symbol.replace]('abcde', '[$01$02$03$04$00]')"),
      njs_str("a[cd$04$00]e") },

    { njs_str("var r = /./; r.exec = () => {return {}};"
              "r[Symbol.replace]('ABCD', 'b')"),
      njs_str("b") },

    { njs_str("var r = /./; r.exec = () => {return {}};"
              "r[Symbol.replace]('ABCD', (m,p,o) => `${m}|${p}|${o}`)"),
      njs_str("undefined|0|ABCD") },

    { njs_str("var r = /./; r.exec = () => Buffer.from([]).toJSON().data;"
              "r[Symbol.replace]('ABCD', 'b')"),
      njs_str("b") },

    { njs_str("'α'.replace(/(h*)/g, '$1βγ')"),
      njs_str("βγαβγ") },

    { njs_str("'α'.replaceAll(/(h*)/g, '$1βγ')"),
      njs_str("βγαβγ") },

    { njs_str("'αg'.replace(/(h*)/g, '$1βγ')"),
      njs_str("βγαβγgβγ") },

    { njs_str("'αg'.replaceAll(/(h*)/g, '$1βγ')"),
      njs_str("βγαβγgβγ") },

    { njs_str("'αg'.replace(/(α*)/g, '$1βγ')"),
      njs_str("αβγβγgβγ") },

    { njs_str("'αg'.replaceAll(/(α*)/g, '$1βγ')"),
      njs_str("αβγβγgβγ") },

    { njs_str("'αg'.replace(/(h*)/g, 'fg$1βγ')"),
      njs_str("fgβγαfgβγgfgβγ") },

    { njs_str("'αg'.replaceAll(/(h*)/g, 'fg$1βγ')"),
      njs_str("fgβγαfgβγgfgβγ") },

    { njs_str("'αgβfγ'.replace(/(gβ)/g, 'n$1i')"),
      njs_str("αngβifγ") },

    { njs_str("'αgβfγ'.replaceAll(/(gβ)/g, 'n$1i')"),
      njs_str("αngβifγ") },

    { njs_str("'abc'.replace(/b/g, '|$&|')"),
      njs_str("a|b|c") },

    { njs_str("'abc'.replaceAll(/b/g, '|$&|')"),
      njs_str("a|b|c") },

    { njs_str("'ABC'.replace(/((A)B)/g, '($1|$&|$2)')"),
      njs_str("(AB|AB|A)C") },

    { njs_str("'ABC'.replaceAll(/((A)B)/g, '($1|$&|$2)')"),
      njs_str("(AB|AB|A)C") },

    { njs_str("'abc'.replace(/b/g, '$0')"),
      njs_str("a$0c") },

    { njs_str("'abc'.replaceAll(/b/g, '$0')"),
      njs_str("a$0c") },

    { njs_str("'abc'.replace(/^/g, '|$&|')"),
      njs_str("||abc") },

    { njs_str("'abc'.replaceAll(/^/g, '|$&|')"),
      njs_str("||abc") },

    { njs_str("('α'.repeat(30) + 'aa').replace(/a/g, '#')"),
      njs_str("αααααααααααααααααααααααααααααα##") },

    { njs_str("('α'.repeat(30) + 'aa').replaceAll(/a/g, '#')"),
      njs_str("αααααααααααααααααααααααααααααα##") },

    { njs_str("var uri ='/u/v1/Aa/bB?type=m3u8&mt=42';"
              "uri.replace(/^\\/u\\/v1\\/[^/]*\\/([^\?]*)\\?.*(mt=[^&]*).*$/, '$1|$2')"),
      njs_str("bB|mt=42") },

    { njs_str("var uri ='/u/v1/Aa/bB?type=m3u8&mt=42 /u/v1/Aa/bB?type=m3u8&mt=43';"
              "uri.replaceAll(/^\\/u\\/v1\\/[^/]*\\/([^\?]*)\\?.*(mt=[^&]*).*$/g, '$1|$2')"),
      njs_str("bB|mt=43") },

    { njs_str("'ABC'.replace(/B/, '$<g>')"),
      njs_str("A$<g>C") },

    { njs_str("'ABBC'.replaceAll(/B/g, '$<g>')"),
      njs_str("A$<g>$<g>C") },

    { njs_str("'ABC'.replace(/(?<b>B)/, '|$<b>|@$<a>@')"),
      njs_str("A|B|@@C") },

    { njs_str("'ABBC'.replaceAll(/(?<b>B)/g, '|$<b>|@$<a>@')"),
      njs_str("A|B|@@|B|@@C") },

    { njs_str("'ABC'.replace(/(?<b>B)/, '|$<BB|')"),
      njs_str("A|$<BB|C") },

    { njs_str("'ABCB'.replaceAll(/(?<b>B)/g, '|$<BB|')"),
      njs_str("A|$<BB|C|$<BB|") },

    { njs_str("'ABC'.replace(/(?<b>B)/, '|$<BB$$|>@')"),
      njs_str("A|@C") },

    { njs_str("'ABCB'.replaceAll(/(?<b>B)/g, '|$<BB$$|>@')"),
      njs_str("A|@C|@") },

    { njs_str("'α'.repeat(8).replace(/()/g, '$`') == 'α'.repeat(44)"),
      njs_str("true") },

    { njs_str("('β' + 'α'.repeat(33)+'β').replace(/(α+)(β+)/, (m, p1) => p1[32])"),
      njs_str("βα") },

    { njs_str("('β' + 'α'.repeat(33)+'β').replaceAll(/(α+)(β+)/g, (m, p1) => p1[32])"),
      njs_str("βα") },

    { njs_str("'abc'.replace(/(z*)/g, () => '@')"),
      njs_str("@a@b@c@") },

    { njs_str("'abc'.replaceAll(/(z*)/g, () => '@')"),
      njs_str("@a@b@c@") },

    { njs_str("'abc'.replace(/(a*)/g, () => '@')"),
      njs_str("@@b@c@") },

    { njs_str("'abc'.replaceAll(/(a*)/g, () => '@')"),
      njs_str("@@b@c@") },

    { njs_str("var O = RegExp.prototype[Symbol.replace];"
              "RegExp.prototype[Symbol.replace] = function (s, rep) { return O.call(this, s, `|${rep}|`); };"
              "'ABC'.replace(/B/, '+')"),
      njs_str("A|+|C") },

    { njs_str("var O = RegExp.prototype[Symbol.replace];"
              "RegExp.prototype[Symbol.replace] = function (s, rep) { return O.call(this, s, `|${rep}|`); };"
              "'ABC'.replaceAll(/B/g, '+')"),
      njs_str("A|+|C") },

    { njs_str("var O = RegExp.prototype.exec;"
              "function mangled(s) { var r = O.call(this, s);"
              "                      Object.defineProperty(r, '0', {enumerable:false}); "
              "                      return r; };"
              "RegExp.prototype.exec = mangled;"
              "'ABC'.replace(/(B)/, (m, p1, off, s) => `@${m}|${p1}|${off}|${s}@`)"),
      njs_str("A@B|B|1|ABC@C") },

    { njs_str("var O = RegExp.prototype.exec;"
              "function mangled(s) { var r = O.call(this, s);"
              "                      Object.defineProperty(r, '0', {enumerable:false}); "
              "                      return r; };"
              "RegExp.prototype.exec = mangled;"
              "'ABC'.replaceAll(/(B)/g, (m, p1, off, s) => `@${m}|${p1}|${off}|${s}@`)"),
      njs_str("TypeError: Object.defineProperty is called on non-object") },

    { njs_str("var O = RegExp.prototype.exec;"
              "function mangled(s) { var r = O.call(this, s);"
              "                      Object.defineProperty(r, 'groups', {value: {g:1}}); "
              "                      return r; };"
              "RegExp.prototype.exec = mangled;"
              "'ABC'.replace(/(B)/, '$<g>')"),
      njs_str("A1C") },

    { njs_str("var O = RegExp.prototype.exec;"
              "function mangled(s) { var r = O.call(this, s);"
              "                      Object.defineProperty(r, 'groups', {value: {g:1}}); "
              "                      return r; };"
              "RegExp.prototype.exec = mangled;"
              "'ABC'.replaceAll(/(B)/g, '$<g>')"),
      njs_str("TypeError: Object.defineProperty is called on non-object") },

    { njs_str("var O = RegExp.prototype.exec;"
              "function mangled(s) { var r = O.call(this, s);"
              "                      Object.defineProperty(r, 'groups', {value: {get g() {throw 'OOps'}}}); "
              "                      return r; };"
              "RegExp.prototype.exec = mangled;"
              "'ABC'.replace(/(B)/, '$<g>')"),
      njs_str("OOps") },

    { njs_str("var O = RegExp.prototype.exec;"
              "function mangled(s) { var r = O.call(this, s);"
              "                      Object.defineProperty(r, 'groups', {value: {get g() {throw 'OOps'}}}); "
              "                      return r; };"
              "RegExp.prototype.exec = mangled;"
              "'ABC'.replaceAll(/(B)/g, '$<g>')"),
      njs_str("TypeError: Object.defineProperty is called on non-object") },

    { njs_str("var name = /a/g[Symbol.replace].name; [name, typeof name]"),
      njs_str("[Symbol.replace],string") },

    { njs_str("RegExp.prototype[Symbol.replace].call()"),
      njs_str("TypeError: \"this\" is not object") },

    { njs_str("RegExp.prototype[Symbol.replace].call(1)"),
      njs_str("TypeError: \"this\" is not object") },

    { njs_str("RegExp.prototype[Symbol.replace].call(/b/, 'abc','B')"),
      njs_str("aBc") },

    { njs_str("var m; var r = /./; r.exec = function() { return []; };"
              "r[Symbol.replace]('foo', function() {m = arguments[0]}); [m, typeof m]"),
      njs_str("undefined,string") },

    { njs_str("var a = [];"
              "a[2] = '';"
              "var re = /any_regexp/;"
              "re.exec = function () {"
              "    return a;"
              "};"
              "'any_string'.replace(re)"),
      njs_str("undefinedg") },

    { njs_str("var cnt = 0;"
              "var a = [];"
              "a[2] = '';"
              "var re = /any_regexp/g;"
              "re.exec = function () {"
              "    if (cnt++ > 1) return null;"
              "    return a;"
              "};"
              "'any_string'.replace(re)"),
      njs_str("undefinedg") },

    { njs_str("var cnt = 0;"
              "var a = [];"
              "a[2] = '';"
              "var re = /any_regexp/g;"
              "re.exec = function () {"
              "    if (cnt++ > 1) return null;"
              "    return a;"
              "};"
              "'any_string'.replaceAll(re)"),
      njs_str("undefinedg") },

    { njs_str("var a = [];"
              "a[2] = {toString() {a[2**20] = 1; return 'X';}}; "
              "a[4] = 'Y';"
              "a[99] = 'Z';"
              "a[100] = '*';"
              "a[200] = '!';"
              "var re = /b/;"
              "re.exec = () => a;"
              "'abc'.replace(re, '@$1|$2|$3|$4|$99|$100|@')"),
      njs_str("@|X||Y|Z|0|@") },

    { njs_str("var cnt = 0;"
              "var a = [];"
              "a[2] = {toString() {a[2**20] = 1; return 'X';}}; "
              "a[4] = 'Y';"
              "a[99] = 'Z';"
              "a[100] = '*';"
              "a[200] = '!';"
              "var re = /b/g;"
              "re.exec = () => {if (cnt++ > 1) return null; return a};"
              "'abc'.replace(re, '@$1|$2|$3|$4|$99|$100|@')"),
      njs_str("@|X||Y|Z|0|@") },

    { njs_str("var cnt = 0;"
              "var a = [];"
              "a[2] = {toString() {a[2**20] = 1; return 'X';}}; "
              "a[4] = 'Y';"
              "a[99] = 'Z';"
              "a[100] = '*';"
              "a[200] = '!';"
              "var re = /b/g;"
              "re.exec = () => {if (cnt++ > 1) return null; return a};"
              "'abc'.replaceAll(re, '@$1|$2|$3|$4|$99|$100|@')"),
      njs_str("@|X||Y|Z|0|@") },

    { njs_str("var a = [];"
              "Object.defineProperty(a, 32768, {});"
              "var re = /any_regexp/;"
              "re.exec = function () {"
              "    return a;"
              "};"
              "'any_string'.replace(re)"),
      njs_str("undefinedg") },

    { njs_str("var cnt = 0;"
              "var a = [];"
              "Object.defineProperty(a, 32768, {});"
              "var re = /any_regexp/g;"
              "re.exec = function () {"
              "    if (cnt++ > 1) return null;"
              "    return a;"
              "};"
              "'any_string'.replace(re)"),
      njs_str("undefinedg") },

    { njs_str("var cnt = 0;"
              "var a = [];"
              "Object.defineProperty(a, 32768, {});"
              "var re = /any_regexp/g;"
              "re.exec = function () {"
              "    if (cnt++ > 1) return null;"
              "    return a;"
              "};"
              "'any_string'.replace(re)"),
      njs_str("undefinedg") },

    { njs_str("var r = /h/g;"
              "Object.defineProperty(r,'flags',{value: ''});"
              "''.replaceAll(r,'');"),
      njs_str("TypeError: String.prototype.replaceAll called with a non-global RegExp argument") },

    { njs_str("/=/"),
      njs_str("/=/") },

    { njs_str("/["),
      njs_str("SyntaxError: Unterminated RegExp \"/[\"") },

    { njs_str("/[][a"),
      njs_str("SyntaxError: Unterminated RegExp \"/[][a\"") },

    { njs_str("/[\\"),
      njs_str("SyntaxError: Unterminated RegExp \"/[\\\"") },

    { njs_str("/\\s*;\\s*/"),
      njs_str("/\\s*;\\s*/") },

#ifndef NJS_HAVE_PCRE2
    { njs_str("/]/"),
      njs_str("/\\]/") },

    { njs_str("RegExp(']')"),
      njs_str("/\\]/") },

    { njs_str("RegExp('[\\\\\\\\]]')"),
      njs_str("/[\\\\]\\]/") },

    { njs_str("/[\\\\]]/"),
      njs_str("/[\\\\]\\]/") },

    { njs_str("/\\]/"),
      njs_str("/\\]/") },

    { njs_str("RegExp('\\]')"),
      njs_str("/\\]/") },

    { njs_str("/ab]cd/"),
      njs_str("/ab\\]cd/") },

    { njs_str("/ab]/"),
      njs_str("/ab\\]/") },

    { njs_str("/]cd/"),
      njs_str("/\\]cd/") },
#endif

    { njs_str("RegExp('[][a')"),
      njs_str("SyntaxError: "
              njs_pcre_var("pcre_compile2(\"(?!)[a\") failed: missing terminating ] for character class at \"\"",
                           "pcre_compile(\"[][a\") failed: missing terminating ] for character class")) },

    { njs_str("RegExp('[][a][a')"),
      njs_str("SyntaxError: "
              njs_pcre_var("pcre_compile2(\"(?!)[a][a\") failed: missing terminating ] for character class at \"\"",
                           "pcre_compile(\"[][a][a\") failed: missing terminating ] for character class")) },

    { njs_str("RegExp('[\\\\')"),
      njs_str("SyntaxError: "
              njs_pcre_var("pcre_compile2(\"[\\\") failed: \\ at end of pattern at \"\"",
                           "pcre_compile(\"[\\\") failed: \\ at end of pattern")) },

    { njs_str("RegExp('[][a]')"),
      njs_str(njs_pcre_var("/(?!)[a]/", "/[][a]/")) },

    { njs_str("RegExp('\\\\0').source[1]"),
      njs_str("0") },

    { njs_str("RegExp(undefined, 'g').global"),
      njs_str("true") },

    { njs_str("RegExp('', 'g').global"),
      njs_str("true") },

    { njs_str("var x; RegExp(x, 'g')"),
      njs_str("/(?:)/g") },

    { njs_str("']'.match(/]/)"),
      njs_str("]") },

    { njs_str("'ab]cd'.match(/]/)"),
      njs_str("]") },

    { njs_str("'ab]'.match(/]/)"),
      njs_str("]") },

    { njs_str("']cd'.match(/]/)"),
      njs_str("]") },

    { njs_str("'ab]cd'.match(/\\]/)"),
      njs_str("]") },

    { njs_str("'abc'.match(/a*/g)"),
      njs_str("a,,,") },

    { njs_str("'abc'.match(/z*/g)"),
      njs_str(",,,") },

    { njs_str("'abc'.match(/.?/g)"),
      njs_str("a,b,c,") },

    { njs_str("''.match(/a*/g)"),
      njs_str("") },

    { njs_str("''.match(/.?/g)"),
      njs_str("") },

    { njs_str("'абв'.match(/я?/g)"),
      njs_str(",,,") },

    { njs_str("'αβγ'.match(/z*/g)"),
      njs_str(",,,") },

    { njs_str("'囲碁織'.match(/z*/g)"),
      njs_str(",,,") },

    { njs_str("'𝟘𝟙𝟚𝟛'.match(/z*/g)"),
      njs_str(",,,,") },

    { njs_str("'abcdefgh'.match()"),
      njs_str("") },

    { njs_str("'abcdefgh'.match('')"),
      njs_str("") },

    { njs_str("'abcdefgh'.match(undefined)"),
      njs_str("") },

    { njs_str("'abcdefgh'.match(/def/)"),
      njs_str("def") },

    { njs_str("'abcdefgh'.match('def')"),
      njs_str("def") },

    { njs_str("'123456'.match('45')"),
      njs_str("45") },

    { njs_str("'123456'.match(45)"),
      njs_str("45") },

    { njs_str("'123456'.match(String(45))"),
      njs_str("45") },

    { njs_str("'123456'.match(Number('45'))"),
      njs_str("45") },

    { njs_str("var r = { toString: function() { return '45' } };"
                 "'123456'.match(r)"),
      njs_str("45") },

    { njs_str("var r = { toString: function() { return 45 } };"
                 "'123456'.match(r)"),
      njs_str("45") },

    { njs_str("var r = { toString: function() { return /45/ } };"
                 "'123456'.match(r)"),
      njs_str("TypeError: Cannot convert object to primitive value") },

    { njs_str("var r = { toString: function() { return /34/ },"
                 "          valueOf:  function() { return 45 } };"
                 "'123456'.match(r)"),
      njs_str("45") },

    { njs_str("''.match(/^$/)"),
      njs_str("") },

    { njs_str("''.match(/^$/g)"),
      njs_str("") },

    { njs_str("'abcdefgh'.match(/def/)"),
      njs_str("def") },

    { njs_str("'abc abc abc'.match('abc')"),
      njs_str("abc") },

    { njs_str("'abc abc abc'.match(/abc/)"),
      njs_str("abc") },

    { njs_str("'abc abc abc'.match(/abc/g)"),
      njs_str("abc,abc,abc") },

    { njs_str("'abc ABC aBc'.match(/abc/ig)"),
      njs_str("abc,ABC,aBc") },

    { njs_str("var a = 'α'.match(/α/g)[0] + 'α';"
                 "a +' '+ a.length"),
      njs_str("αα 2") },

    { njs_str("('β' + 'α'.repeat(33) +'β').match(/α+/g)[0][32]"),
      njs_str("α") },

    { njs_str("'abc'.split()"),
      njs_str("abc") },

    { njs_str("'abc'.split(undefined)"),
      njs_str("abc") },

    { njs_str("''.split('').length"),
      njs_str("0") },

    { njs_str("'abc'.split('')"),
      njs_str("a,b,c") },

    { njs_str("'αβγ'.split('')"),
      njs_str("α,β,γ") },

    { njs_str("'囲碁織'.split('')"),
      njs_str("囲,碁,織") },

    { njs_str("'𝟘𝟙𝟚𝟛'.split('')"),
      njs_str("𝟘,𝟙,𝟚,𝟛") },

    { njs_str("'囲α碁α織'.split('α')"),
      njs_str("囲,碁,織") },

    { njs_str("'a'.repeat(16).split('a'.repeat(15))"),
      njs_str(",a") },

    { njs_str("('α'+'β'.repeat(33)).repeat(2).split('α')[1][32]"),
      njs_str("β") },

    { njs_str("'abc'.split('abc')"),
      njs_str(",") },

    { njs_str("'a bc def'.split(' ')"),
      njs_str("a,bc,def") },

    { njs_str("'a bc  def'.split(' ')"),
      njs_str("a,bc,,def") },

    { njs_str("'a bc  def'.split(' ', 3)"),
      njs_str("a,bc,") },

    { njs_str("'abc'.split('abc')"),
      njs_str(",") },

    { njs_str("'ab'.split('123')"),
      njs_str("ab") },

    { njs_str("''.split(/0/).length"),
      njs_str("1") },

    { njs_str("'abc'.split(/(?:)/)"),
      njs_str("a,b,c") },

    { njs_str("'a bc def'.split(/ /)"),
      njs_str("a,bc,def") },

    { njs_str("'a bc  def'.split(/ /)"),
      njs_str("a,bc,,def") },

    { njs_str("'abc'.split(/abc/)"),
      njs_str(",") },

    { njs_str("('α'.repeat(32)).split(/./).length"),
      njs_str("33") },

    { njs_str("'AbcDefGhi'.split(/([A-Z][a-z]+)/)"),
      njs_str(",Abc,,Def,,Ghi,") },

    { njs_str("'myCamelCaseString'.split(/(?=[A-Z])/)"),
      njs_str("my,Camel,Case,String") },

    { njs_str("var r = ' a'.split(/|()/); r+'|'+typeof r[0]+':'+typeof r[1]+':'+typeof r[2]"),
      njs_str(" ,,a|string:undefined:string") },

    { njs_str("'мояВерблюжьяСтрока'.split(/(?=[А-Я])/)"),
      njs_str("моя,Верблюжья,Строка") },

    { njs_str("`aaaaaaaaaaaaaaaaa`.split(/(.*)/)"),
      njs_str(",aaaaaaaaaaaaaaaaa,") },

    { njs_str("'Harry Trump ;Fred Barney; Helen Rigby ; Bill Abel ;Chris Hand '.split( /\\s*(?:;|$)\\s*/)"),
      njs_str("Harry Trump,Fred Barney,Helen Rigby,Bill Abel,Chris Hand,") },

    { njs_str("'Гарри Трамп ;Фрэд Барни; Хелен Ригби ; Билл Абель'.split(/\\s*;\\s*/)"),
      njs_str("Гарри Трамп,Фрэд Барни,Хелен Ригби,Билл Абель") },

    { njs_str("'Hello 1 world. Sentence number 2.'.split(/(\\d)/)"),
      njs_str("Hello ,1, world. Sentence number ,2,.") },

    { njs_str("'Привет 1 мир. Предложение номер 2.'.split(/(\\d)/)"),
      njs_str("Привет ,1, мир. Предложение номер ,2,.") },

    { njs_str("'0123456789'.split('').reverse().join('')"),
      njs_str("9876543210") },

    { njs_str("/-/[Symbol.split]('a-b-c')"),
      njs_str("a,b,c") },

    { njs_str("var O = RegExp.prototype[Symbol.split];"
              "RegExp.prototype[Symbol.split] = function (s, limit) { "
              "    return O.call(this, s, limit).map(v => `@${v}#`); "
              "};"
              "'2016-01-02'.split(/-/)"),
      njs_str("@2016#,@01#,@02#") },

    { njs_str("'abc'.repeat(3)"),
      njs_str("abcabcabc") },

    { njs_str("'абв'.repeat(3)"),
      njs_str("абвабвабв") },

    { njs_str("''.repeat(3)"),
      njs_str("") },

    { njs_str("'abc'.repeat(0)"),
      njs_str("") },

    { njs_str("'abc'.repeat(NaN)"),
      njs_str("") },

    { njs_str("'abc'.repeat(Infinity)"),
      njs_str("RangeError: invalid count value") },

    { njs_str("'abc'.repeat(-1)"),
      njs_str("RangeError: invalid count value") },

    { njs_str("''.repeat(-1)"),
      njs_str("RangeError: invalid count value") },

    { njs_str("'a'.repeat(2147483647)"),
      njs_str("RangeError: invalid string length") },

    { njs_str("'a'.repeat(2147483648)"),
      njs_str("RangeError: invalid string length") },

    { njs_str("'a'.repeat(Infinity)"),
      njs_str("RangeError: invalid count value") },

    { njs_str("'a'.repeat(NaN)"),
      njs_str("") },

    { njs_str("''.repeat(2147483646)"),
      njs_str("") },

    { njs_str("''.repeat(2147483647)"),
      njs_str("") },

    { njs_str("''.repeat(2147483648)"),
      njs_str("") },

    { njs_str("'aaaaaaaa'.repeat(2**64+1)"),
      njs_str("RangeError: invalid count value") },

    { njs_str("''.repeat(Infinity)"),
      njs_str("RangeError: invalid count value") },

    { njs_str("''.repeat(NaN)"),
      njs_str("") },

    { njs_str("String.prototype.repeat.call({},2)"),
      njs_str("[object Object][object Object]") },

    { njs_str("'abc'.padStart(7)"),
      njs_str("    abc") },

    { njs_str("'абв'.padStart(7)"),
      njs_str("    абв") },

    { njs_str("'abc'.padStart(3)"),
      njs_str("abc") },

    { njs_str("'абв'.padStart(0)"),
      njs_str("абв") },

    { njs_str("'abc'.padStart(NaN)"),
      njs_str("abc") },

    { njs_str("'abc'.padStart(2147483647)"),
      njs_str("RangeError: invalid string length") },

    { njs_str("'abc'.padStart(2147483646, '')"),
      njs_str("abc") },

    { njs_str("''.padStart(0, '')"),
      njs_str("") },

    { njs_str("'1'.padStart(5, 0)"),
      njs_str("00001") },

    { njs_str("''.padStart(1, 'я')"),
      njs_str("я") },

    { njs_str("'abc'.padStart(6, NaN)"),
      njs_str("NaNabc") },

    { njs_str("'abc'.padStart(11, 123)"),
      njs_str("12312312abc") },

    { njs_str("'abc'.padStart(6, 12345)"),
      njs_str("123abc") },

    { njs_str("'абв'.padStart(6, 'эюя')"),
      njs_str("эюяабв") },

    { njs_str("'абв'.padStart(4, 'эюя')"),
      njs_str("эабв") },

    { njs_str("'абв'.padStart(7, 'эюя')"),
      njs_str("эюяэабв") },

    { njs_str("'абв'.padStart(10, 'эю')"),
      njs_str("эюэюэюэабв") },

    { njs_str("'abc'.padStart(10, Symbol())"),
      njs_str("TypeError: Cannot convert a Symbol value to a string") },

    { njs_str("'1234'.padEnd(4)"),
      njs_str("1234") },

    { njs_str("'1234'.padEnd(-1)"),
      njs_str("1234") },

    { njs_str("'я'.padEnd(1)"),
      njs_str("я") },

    { njs_str("'1234'.padEnd(5)"),
      njs_str("1234 ") },

    { njs_str("'я'.padEnd(6)"),
      njs_str("я     ") },

    { njs_str("'я'.padEnd(2147483647)"),
      njs_str("RangeError: invalid string length") },

    { njs_str("'я'.padEnd(2147483646, '')"),
      njs_str("я") },

    { njs_str("''.padEnd(0, '')"),
      njs_str("") },

    { njs_str("'эю'.padEnd(3, 'я')"),
      njs_str("эюя") },

    { njs_str("''.padEnd(1, 0)"),
      njs_str("0") },

    { njs_str("'1234'.padEnd(8, 'abcd')"),
      njs_str("1234abcd") },

    { njs_str("'1234'.padEnd(10, 'abcd')"),
      njs_str("1234abcdab") },

    { njs_str("'1234'.padEnd(7, 'abcd')"),
      njs_str("1234abc") },

    { njs_str("'абв'.padEnd(5, 'ГД')"),
      njs_str("абвГД") },

    { njs_str("'абв'.padEnd(4, 'ГДУ')"),
      njs_str("абвГ") },

    { njs_str("'абвг'.padEnd(10, 'ДЕЖЗ')"),
      njs_str("абвгДЕЖЗДЕ") },

    { njs_str("'abc'.padEnd(10, Symbol())"),
      njs_str("TypeError: Cannot convert a Symbol value to a string") },

    { njs_str("encodeURI.name"),
      njs_str("encodeURI")},

    { njs_str("encodeURI.length"),
      njs_str("1")},

    { njs_str("encodeURI('012абв')"),
      njs_str("012%D0%B0%D0%B1%D0%B2")},

    { njs_str("encodeURI(String.fromCharCode(0xD800)+String.fromCharCode(0xDC00))"),
      njs_str("%EF%BF%BD%EF%BF%BD")},

    { njs_str("encodeURI('~}|{`_^]\\\\[@?>=<;:/.-,+*)(\\\'&%$#\"! ')"),
      njs_str("~%7D%7C%7B%60_%5E%5D%5C%5B@?%3E=%3C;:/.-,+*)('&%25$#%22!%20")},

    { njs_str("encodeURIComponent.name"),
      njs_str("encodeURIComponent")},

    { njs_str("encodeURIComponent.length"),
      njs_str("1")},

    { njs_str("encodeURIComponent('~}|{`_^]\\\\[@?>=<;:/.-,+*)(\\\'&%$#\"! ')"),
      njs_str("~%7D%7C%7B%60_%5E%5D%5C%5B%40%3F%3E%3D%3C%3B%3A%2F.-%2C%2B*)('%26%25%24%23%22!%20")},

    { njs_str("decodeURI.name"),
      njs_str("decodeURI")},

    { njs_str("decodeURI.length"),
      njs_str("1")},

    { njs_str("decodeURI('%00')"),
      njs_str("\0")},

    { njs_str("decodeURI('%3012%D0%B0%D0%B1%D0%B2')"),
      njs_str("012абв")},

    { njs_str("decodeURI('%7e%7d%7c%7b%60%5f%5e%5d%5c%5b%40%3f%3e%3d%3c%3b%3a%2f%2e%2c%2b%2a%29%28%27%26%25%24%23%22%21%20')"),
      njs_str("~}|{`_^]\\[%40%3f>%3d<%3b%3a%2f.%2c%2b*)('%26%%24%23\"! ")},

    { njs_str("decodeURIComponent.name"),
      njs_str("decodeURIComponent")},

    { njs_str("decodeURIComponent.length"),
      njs_str("1")},

    { njs_str("decodeURIComponent('%7e%7d%7c%7b%60%5f%5e%5d%5c%5b%40%3f%3e%3d%3c%3b%3a%2f%2e%2c%2b%2a%29%28%27%26%25%24%23%22%21%20')"),
      njs_str("~}|{`_^]\\[@?>=<;:/.,+*)('&%$#\"! ")},

    { njs_str("decodeURI('%41%42%43').length"),
      njs_str("3")},

    { njs_str("decodeURI('%D0%B0%D0%B1%D0%B2').length"),
      njs_str("3")},

    { njs_str("["
              " '%',"
              " '%0',"
              " '%QQ',"
              " '%C0%' + '0',"
              " '%C0%10',"
              " '%C0%80',"
              " '%DC%C7',"
              " '%80%81%82',"
              " '%EF%5C%A0',"
              " '%EF%A0%5E',"
              " '%E0%EF%' + '0',"
              " '%E0%EF%A0',"
              " '%E0%A0%EF',"
              " '%F0%A2%95%' + '0',"
              " '%FF%A2%95%BB',"
              "].every(v=>{try { decodeURI(v)} catch(e) {return e.name == 'URIError'}})"),
      njs_str("true")},

    { njs_str("["
              " 'abc',"
              " 'αβγ',"
              " '𝟘𝟙𝟚𝟛',"
              " String.fromCodePoint(0x20000),"
              "].every(v=>decodeURI(encodeURI(v)) === v)"),
      njs_str("true")},

    { njs_str("[encodeURI, encodeURIComponent, decodeURI, decodeURIComponent]"
              ".every(v=>{var r = v(); return (typeof r === 'string') && r === 'undefined';})"),
      njs_str("true")},

    /* btoa() */

    { njs_str("["
              " undefined,"
              " '',"
              " '\\x00',"
              " '\\x00\\x01',"
              " '\\x00\\x01\\x02',"
              " '\\x00\\xfe\\xff',"
              " String.fromCodePoint(0x100),"
              " String.fromCodePoint(0x00, 0x100),"
              " String.fromCodePoint(0x00, 0x01, 0x100),"
              "].map(v => { try { return btoa(v); } catch (e) { return '#'} })"),
      njs_str("dW5kZWZpbmVk,,AA==,AAE=,AAEC,AP7/,#,#,#")},

    /* atob() */

    { njs_str("function c(s) {"
              "    let cp = [];"
              "    for (var i = 0; i < s.length; i++) {"
              "        cp.push(s.codePointAt(i));"
              "    }"
              "    return cp;"
              "};"
              ""
              "["
              " undefined,"
              " '',"
              " '=',"
              " '==',"
              " '===',"
              " '====',"
              " 'AA@',"
              " '@',"
              " 'A==A',"
              " btoa(String.fromCharCode.apply(null, [1])),"
              " btoa(String.fromCharCode.apply(null, [1, 2])),"
              " btoa(String.fromCharCode.apply(null, [1, 2, 255])),"
              " btoa(String.fromCharCode.apply(null, [255, 1, 2, 3])),"
              "].map(v => { try { return njs.dump(c(atob(v))); } catch (e) { return '#'} })"),
      njs_str("#,[],#,#,#,#,#,#,#,[1],[1,2],[1,2,255],[255,1,2,3]")},

    { njs_str("function c(s) {"
              "    let cp = [];"
              "    for (var i = 0; i < s.length; i++) {"
              "        cp.push(s.codePointAt(i));"
              "    }"
              "    return cp;"
              "};"
              ""
              "["
              " 'CDRW',"
              " ' CDRW',"
              " 'C DRW',"
              " 'CD RW',"
              " 'CDR W',"
              " 'CDRW    ',"
              " ' C D R W ',"
              "].every(v => c(atob(v)).toString() == '8,52,86')"),
      njs_str("true")},

    { njs_str("atob('aGVsbG8=')"),
      njs_str("hello") },

    { njs_str("atob('aGVsbG8')"),
      njs_str("hello") },

    { njs_str("atob('TQ==')"),
      njs_str("M") },

    { njs_str("atob('TQ')"),
      njs_str("M") },

    /* Functions. */

    { njs_str("return"),
      njs_str("SyntaxError: Illegal return statement") },

    { njs_str("{return}"),
      njs_str("SyntaxError: Illegal return statement") },

    { njs_str("\n{\nreturn;\n}"),
      njs_str("SyntaxError: Illegal return statement") },

    { njs_str("function f () {return a +}"),
      njs_str("SyntaxError: Unexpected token \"}\"") },

    { njs_str("`${function(){return n=>}}`"),
      njs_str("SyntaxError: Unexpected token \"}\"") },

    { njs_str("(function(){return a +})"),
      njs_str("SyntaxError: Unexpected token \"}\"") },

    { njs_str("if (1) function f(){}"),
      njs_str("SyntaxError: Functions can only be declared at top level or inside a block") },

    { njs_str("if (1) { function f(){}}"),
      njs_str("undefined") },

    { njs_str("while (1) function f() { }"),
      njs_str("SyntaxError: Functions can only be declared at top level or inside a block") },

    { njs_str("while (1) { break; function f(){}}"),
      njs_str("undefined") },

    { njs_str("for (;;) function f() { }"),
      njs_str("SyntaxError: Functions can only be declared at top level or inside a block") },

    { njs_str("for (;;) { break; function f(){}}"),
      njs_str("undefined") },

    { njs_str("do function f() { } while (0)"),
      njs_str("SyntaxError: Functions can only be declared at top level or inside a block") },

    { njs_str("function f() { return 1; } { function f() { return 2; } } f()"),
      njs_str("1") },

    { njs_str("function f() { return 1; } { function f() { return 2; } { function f() { return 3; } }} f()"),
      njs_str("1") },

    { njs_str("{function f() {} {} f() }"),
      njs_str("undefined") },

    { njs_str("{ var f; function f() {} }"),
      njs_str("SyntaxError: \"f\" has already been declared") },

    { njs_str("{ function f() {} var f; }"),
      njs_str("SyntaxError: \"f\" has already been declared") },

    { njs_str("{ function f() {} { var f }}"),
      njs_str("SyntaxError: \"f\" has already been declared") },

#if NJS_HAVE_LARGE_STACK
    { njs_str("function f() { return f() } f()"),
      njs_str("RangeError: Maximum call stack size exceeded") },
#endif

    { njs_str("function () { } f()"),
      njs_str("SyntaxError: Unexpected token \"(\"") },

    { njs_str("function f() { }"),
      njs_str("undefined") },

    { njs_str("function f() { }; f.length"),
      njs_str("0") },

    { njs_str("function f() { }; f.length = 1"),
      njs_str("TypeError: Cannot assign to read-only property \"length\" of function") },

    { njs_str("function f(...rest) { }; f.length"),
      njs_str("0") },

    { njs_str("function f(...rest) { }; var binded = f.bind(this, [1,2]);"
                 "binded.length"),
      njs_str("0") },

    { njs_str("function f(a,a) { };"),
      njs_str("SyntaxError: Duplicate parameter names") },

    { njs_str("function f(a,b,a) { };"),
      njs_str("SyntaxError: Duplicate parameter names") },

    { njs_str("function f(a, ...a) { };"),
      njs_str("SyntaxError: Duplicate parameter names") },

    { njs_str("(function(a,a) { })"),
      njs_str("SyntaxError: Duplicate parameter names") },

    { njs_str("(function(a,...a) { })"),
      njs_str("SyntaxError: Duplicate parameter names") },

    { njs_str("(function f(a,a) { })"),
      njs_str("SyntaxError: Duplicate parameter names") },

    { njs_str("(function f(a,...a) { })"),
      njs_str("SyntaxError: Duplicate parameter names") },

    { njs_str("function f(a,b) { }; f.length"),
      njs_str("2") },

    { njs_str("function f(a,...rest) { }; f.length"),
      njs_str("1") },

    { njs_str("function f(...) {}"),
      njs_str("SyntaxError: Unexpected token \")\"") },

    { njs_str("(function (...) {})()"),
      njs_str("SyntaxError: Unexpected token \")\"") },

    { njs_str("function f(a,b) { }; var ff = f.bind(f, 1); ff.length"),
      njs_str("1") },

    { njs_str("Object((new Date(0)).toJSON())+0"),
      njs_str("1970-01-01T00:00:00.000Z0") },

    { njs_str("Object((new Array(0)).toString())+0"),
      njs_str("0") },

    { njs_str("JSON.parse.length"),
      njs_str("2") },

    { njs_str("JSON.parse.bind(JSON, '[]').length"),
      njs_str("1") },

    { njs_str("var o = {}; o.hasOwnProperty.length"),
      njs_str("1") },

    { njs_str("var x; function f() { }"),
      njs_str("undefined") },

    { njs_str("function f() { } f()"),
      njs_str("undefined") },

    { njs_str("function f() { ; } f()"),
      njs_str("undefined") },

    { njs_str("function f() { ;; } f()"),
      njs_str("undefined") },

    { njs_str("function f() { return } f()"),
      njs_str("undefined") },

    { njs_str("function f() { return; } f()"),
      njs_str("undefined") },

    { njs_str("function f() { return;; } f()"),
      njs_str("undefined") },

    { njs_str("function f() { return 1 } f()"),
      njs_str("1") },

    { njs_str("function f() { return 1; } f()"),
      njs_str("1") },

    { njs_str("function f() { return 1;; } f()"),
      njs_str("1") },

    { njs_str("function f() { return 1\n 2 } f()"),
      njs_str("1") },

    { njs_str("function f() { return 1\n 2 } f()"),
      njs_str("1") },

    { njs_str("(function f() { return 2.toString(); })()"),
      njs_str("SyntaxError: Unexpected token \"2.toString\"") },

    { njs_str("(function f() { return 2..toString(); })()"),
      njs_str("2") },

    { njs_str("function f(a) { if (a) return 'OK' } f(1)+f(0)"),
      njs_str("OKundefined") },

    { njs_str("function f(a) { if (a) return 'OK'; } f(1)+f(0)"),
      njs_str("OKundefined") },

    { njs_str("function f(a) { if (a) return 'OK';; } f(1)+f(0)"),
      njs_str("OKundefined") },

    { njs_str("var a = 1; a()"),
      njs_str("TypeError: number is not a function") },

    { njs_str("var o = {a:1}; o.a()"),
      njs_str("TypeError: number is not a function") },

    { njs_str("(function(){})()"),
      njs_str("undefined") },

    { njs_str("var q = 1; function x(a, b, c) { q = a } x(5); q"),
      njs_str("5") },

    { njs_str("function x(a) { while (a < 2) a++; return a + 1 } x(1) "),
      njs_str("3") },

    { njs_str("(function(){"
              "(function(){"
              "(function(){"
              "(function(){"
              "(function(){"
              "(function(){"
              "(function(){"
              "(function(){"
              "(function(){})"
              "})"
              "})"
              "})"
              "})"
              "})"
              "})"
              "})"
              "})"),
      njs_str("[object Function]") },

    { njs_str("Function.prototype.toString = function () {return 'X'};"
                 "eval"),
      njs_str("X") },

    { njs_str("var o = {f:function(x){ return x**2}}; o.f\n(2)"),
      njs_str("4") },

    { njs_str("var o = {f:function(x){ return x**2}}; o\n.f\n(2)"),
      njs_str("4") },

    { njs_str("var o = {f:function(x){ return x**2}}; o\n.\nf\n(2)"),
      njs_str("4") },

    { njs_str("function f(x){ return x**2}; [f(2)\n, f\n(2),\nf\n(\n2),\nf\n(\n2\n)]"),
      njs_str("4,4,4,4") },

    { njs_str("function f (x){ return x**2}; f\n(2)"),
      njs_str("4") },

    { njs_str("function f (x){ return x**2}; f\n(\n2)"),
      njs_str("4") },

    { njs_str("function f (x){ return x**2}; f\n(\n2\n)"),
      njs_str("4") },

    { njs_str("function f (x){ return x**2}; f\n(2\n)"),
      njs_str("4") },

    { njs_str("function f (x){ return x**2}; f(2\n)"),
      njs_str("4") },

    { njs_str("var fn = Function.prototype.call; fn.call(() => 1)"),
      njs_str("1") },

    { njs_str("var fn = Function.prototype.call; fn.call(fn, () => 1)"),
      njs_str("1") },

    { njs_str("var fn = Function.prototype.call; fn.call(fn, fn, () => 1)"),
      njs_str("1") },

    { njs_str("eval.call.call(Number)"),
      njs_str("0") },

    { njs_str("URIError.apply.apply(RegExp)"),
      njs_str("/(?:)/") },

    { njs_str("[0].some(function(){return Array.call.bind(isNaN)}())"),
      njs_str("false") },

    { njs_str("(function (undefined, NaN, Infinity){ return undefined + NaN + Infinity})('x', 'y', 'z')"),
      njs_str("xyz") },

    { njs_str("function f(undefined,NaN, Infinity){ return undefined + NaN + Infinity}; f('x', 'y', 'z')"),
      njs_str("xyz") },

    { njs_str("(function (Object, Array, Boolean){ return Object + Array + Boolean})('x', 'y', 'z')"),
      njs_str("xyz") },

    { njs_str("var n = 11, res;"
              "function a() {return b}"
              "res = a()(2);"
              "function b(k) {var x = b; return 1 + k + n} res"),
      njs_str("14") },

    { njs_str("var y = 9, res;"
              "function a(n) {function b() {return c(n + 2)} return b()}"
              "res = a(1);"
              "function c(m) {var x = c; return m + 3 + y} res"),
      njs_str("15") },

    { njs_str("var res;"
              "closure();"
              "res = globalThis.funcall(1);"
              "function closure() {"
              "    var y = 9, res;"
              "    globalThis.funcall = a;"
              "    function a(n) { function b() {return c(2)} return b() }"
              "    function c(m) {var x = c; return m + 3 + y}"
              "} res"),
      njs_str("14") },

    { njs_str("function a() {"
              "    var x = 1;"
              "    function b() {var n = x; x = undefined; return n}"
              "    return b;"
              "}"
              "[a()(), a()()];"),
      njs_str("1,1") },

    { njs_str("function a(obj, name) {!Object.prototype.hasOwnProperty.call(obj, name)}"
              "a(this, 'b');"
              "function b() {}"),
      njs_str("undefined") },

    { njs_str("function abc() {"
              "function x() {var a = x.arr; x.arr = 123; return a}"
              "return x;"
              "} [abc()(),abc()()]"),
      njs_str(",") },

    { njs_str("function x() {var a = x.arr; x.arr = 123; return a} [x(),x()]"),
      njs_str(",123") },

    { njs_str("var obj;"
              "function make(desc) {obj = {'a': 123}}"
              "function a(desc) {make()}"
              "a(); obj.a"),
      njs_str("123") },

    { njs_str("var res;"
              "function cls() {"
              "    var obj = {'a': 123};"
              "    Object.defineProperty(obj, \"length\", {"
              "        get: function() {res = obj}"
              "    });"
              "    return obj;"
              "}"
              "var obj = cls();"
              "[].includes.call(obj); res.a"),
      njs_str("123") },

    { njs_str("function f(){} typeof(f)"),
      njs_str("function") },

    { njs_str("function let() {}"),
      njs_str("SyntaxError: Unexpected token \"let\"") },

    { njs_str("function static() {}"),
      njs_str("SyntaxError: Unexpected token \"static\"") },

    { njs_str("var arr = [];"
              "function fn(one) {"
              "    var x = one + 1;"
              "    let y = one + 2;"
              "    const u = one + 4;"
              "    {"
              "        {"
              "            let z = one + 3;"
              "            const v = one + 5;"
              "            function f() {"
              "                arr.push(one); arr.push(x);"
              "                arr.push(y);   arr.push(z);"
              "                arr.push(u);   arr.push(v);"
              "            }"
              "            f();"
              "        }"
              "    }"
              "}"
              "fn(1); arr"),
      njs_str("1,2,3,4,5,6") },

    { njs_str("function f(){};"
              "Object.defineProperty(f, 'length', {set: () => {}});"
              "Object.defineProperty(f, 'length', {value: 42});"
              "f.length"),
      njs_str("42") },

    { njs_str("function f(){}; f.name"),
      njs_str("f") },

    { njs_str("function f(){}; njs.dump(Object.getOwnPropertyDescriptor(f, 'name'))"),
      njs_str("{value:'f',writable:false,enumerable:false,configurable:true}") },

    { njs_str("function f(){}; Object.defineProperty(f, 'name', {value: 'F'}); f.name"),
      njs_str("F") },

    { njs_str("function f(){}; Object.defineProperty(f, 'name', {value: 'F'});"
              "njs.dump(Object.getOwnPropertyDescriptor(f, 'name'))"),
      njs_str("{value:'F',writable:false,enumerable:false,configurable:true}") },

    { njs_str("function f() {}; f.name = 'a'"),
      njs_str("TypeError: Cannot assign to read-only property \"name\" of function") },

    { njs_str("(function f () { return f.name})()"),
      njs_str("f") },

    { njs_str("var a = function () {}; a.name"),
      njs_str("a") },

    { njs_str("(function () {}).name"),
      njs_str("") },

    { njs_str("var a = (null, function () {}); a.name"),
      njs_str("") },

    { njs_str("var a = async function () {}; a.name"),
      njs_str("a") },

    { njs_str("let a = () => {}; a.name"),
      njs_str("a") },

    { njs_str("let a = async () => {}; a.name"),
      njs_str("a") },

    { njs_str("Function().name"),
      njs_str("anonymous") },

    { njs_str("var o = {f: function (){}, g: () => {}, h: async function(){}};"
              "[o.f.name, o.g.name, o.h.name]"),
      njs_str("f,g,h") },

    { njs_str("({t(){}}).t.name"),
      njs_str("t") },

    /* Function nesting depth. */

    { njs_str("() => () => () => () => () => () => () => () => () => () => () =>"
              "() => () => () => () => () => () => () => () => () => () => () =>"
              "() => () => () => () => () => () => () => () => () => () => () =>"
              "() => () => () => () => () => () => () => () => () => () => () =>"
              "() => () => () => () => () => () => () => () => () => () => () =>"
              "() => () => () => () => () => () => () => () => () => () => () =>"
              "() => () => () => () => () => () => () => () => () => () => () =>"
              "() => () => () => () => () => () => () => () => () => () => () =>"
              "() => () => () => () => () => () => () => () => () => () => () =>"
              "() => () => () => () => () => () => () => () => () => () => () =>"
              "() => () => () => () => () => () => () => () => () => () => () =>"
              "() => () => () => () => () => () => 1"),
      njs_str("[object Function]") },

    { njs_str("() => () => () => () => () => () => () => () => () => () => () =>"
              "() => () => () => () => () => () => () => () => () => () => () =>"
              "() => () => () => () => () => () => () => () => () => () => () =>"
              "() => () => () => () => () => () => () => () => () => () => () =>"
              "() => () => () => () => () => () => () => () => () => () => () =>"
              "() => () => () => () => () => () => () => () => () => () => () =>"
              "() => () => () => () => () => () => () => () => () => () => () =>"
              "() => () => () => () => () => () => () => () => () => () => () =>"
              "() => () => () => () => () => () => () => () => () => () => () =>"
              "() => () => () => () => () => () => () => () => () => () => () =>"
              "() => () => () => () => () => () => () => () => () => () => () =>"
              "() => () => () => () => () => () => () => 1"),
      njs_str("RangeError: Maximum function nesting depth exceeded") },

    /* Recursive factorial. */

    { njs_str("function f(a) {"
                 "    if (a > 1)"
                 "        return a * f(a - 1)\n"
                 "    return 1"
                 "}"
                 "f(10)"),
      njs_str("3628800") },

    /* Recursive factorial. */

    { njs_str("function f(a) { return (a > 1) ? a * f(a - 1) : 1 } f(10)"),
      njs_str("3628800") },

    { njs_str("var g = function f(a) { return (a > 1) ? a * f(a - 1) : 1 };"
                 "g(10)"),
      njs_str("3628800") },

    { njs_str("(function f(a) { return (a > 1) ? a * f(a - 1) : 1 })(10)"),
      njs_str("3628800") },

    /* Nested functions and closures. */

    { njs_str("function f() { var x = 4; "
                 "function g() { return x }; return g(); } f()"),
      njs_str("4") },

    { njs_str("function f(a) { function g(b) { return a + b } return g }"
                 "var k = f('a'); k('b')"),
      njs_str("ab") },

    { njs_str("function f(a) { return function(b) { return a + b } }"
                 "var k = f('a'); k('b')"),
      njs_str("ab") },

    { njs_str("function f(a) { return function(b) { return a + b } }"
                 "var k = f('a'), m = f('b'); k('c') + m('d')"),
      njs_str("acbd") },

    { njs_str("function f(a) { return "
                 "function(b) { return function(c) { return a + b + c } } }"
                 "var g = f('a'), k = g('b'), m = g('c'); k('d') + m('e')"),
      njs_str("abdace") },

    { njs_str("function f(a) {"
                 "function g() { return a }; return g; }"
                 "var y = f(4); y()"),
      njs_str("4") },

    { njs_str("function f() { var x = 4; "
                 "return function() { return x } }"
                 "var y = f(); y()"),
      njs_str("4") },

    { njs_str("function f() { var x = 4;"
                 "function g() { if (1) { return 2 + x; } }; return g }"
                 "var y = f(); y()"),
      njs_str("6") },

    { njs_str("var x; var y = 4;"
                 "function f() { function h() { x = 3; return y; } }"),
      njs_str("undefined") },

    { njs_str("function f() {"
                 "    var a = 'a';"
                 "    if (0) { a = 'b' };"
                 "    function f2() { return a };"
                 "    return f2"
                 "};"
                 "f()()"),
      njs_str("a") },

    { njs_str("function f() {"
                 "    var a = 'a'; "
                 "    if (0) { if (0) {a = 'b'} };"
                 "    function f2() { return a };"
                 "    return f2"
                 "};"
                 "f()()"),
      njs_str("a") },

    { njs_str("function f() { var a = f2(); }"),
      njs_str("undefined") },

    { njs_str("function f() { var a = f2(); } f();"),
      njs_str("ReferenceError: \"f2\" is not defined") },

    { njs_str("typeof Buffer !== 'undefined' ? Buffer : function Buffer(){}"),
      njs_str("[object Function]") },

    { njs_str("1 == 2 ? func() : '123'"),
      njs_str("123") },

    { njs_str("1 == 1 ? func() : '123'"),
      njs_str("ReferenceError: \"func\" is not defined") },

    { njs_str("function f(){ if (1 == 1) { 1 == 2 ? some_var : '123' } }; f()"),
      njs_str("undefined") },

    { njs_str("function f(){ if (1 == 1) { 1 == 1 ? some_var : '123' } }; f()"),
      njs_str("ReferenceError: \"some_var\" is not defined") },

    { njs_str("function f(){ if (1 == 1) { 1 == 2 ? some_func() : '123' } }; f()"),
      njs_str("undefined") },

    { njs_str("function f(){ if (1 == 1) { 1 == 1 ? some_func() : '123' } }; f()"),
      njs_str("ReferenceError: \"some_func\" is not defined") },

    { njs_str("(function(){ function f() {return f}; return f()})()"),
      njs_str("[object Function]") },

    { njs_str("function  f() {}; f.toString = ()=> 'F'; ({'F':1})[f]"),
      njs_str("1") },

    { njs_str("var a = ''; "
                 "function f(list) {"
                 "    function add(v) {a+=v};"
                 "    list.forEach(function(v) {add(v)});"
                 "};"
                 "f(['a', 'b', 'c']); a"),
      njs_str("abc") },

    { njs_str("var l = [];"
                 "var f = function() { "
                 "    function f2() { l.push(f); l.push(f2); }; "
                 "    l.push(f); l.push(f2); "
                 "    f2(); "
                 "}; "
                 "f(); "
                 "l.every(function(v) {return typeof v == 'function'})"),
      njs_str("true") },

    { njs_str("var l = [];"
                 "function baz() {"
                 "  function foo(v) {"
                 "     function bar() { foo(0); }"
                 "     l.push(v);"
                 "     if (v === 1) { bar(); }"
                 "  }"
                 "  foo(1);"
                 "}; baz(); l"),
      njs_str("1,0") },

    { njs_str("var gen = (function(){  "
                 "           var s = 0; "
                 "           return { inc: function() {s++}, "
                 "                    s: function() {return s} };});"
                 "var o1 = gen(); var o2 = gen();"
                 "[o1.s(),o2.s(),o1.inc(),o1.s(),o2.s(),o2.inc(),o1.s(),o2.s()]"),
      njs_str("0,0,,1,0,,1,1") },

    /* Recursive fibonacci. */

    { njs_str("function fibo(n) {"
                 "    if (n > 1)"
                 "        return fibo(n-1) + fibo(n-2)\n"
                 "     return 1"
                 "}"
                 "fibo(10)"),
      njs_str("89") },

    { njs_str("function fibo(n) {"
                 "    if (n > 1)"
                 "        return fibo(n-1) + fibo(n-2)\n"
                 "     return '.'"
                 "}"
                 "fibo(10).length"),
      njs_str("89") },

    { njs_str("function fibo(n) {"
                 "    if (n > 1)"
                 "        return fibo(n-1) + fibo(n-2)\n"
                 "     return 1"
                 "}"
                 "fibo('10')"),
      njs_str("89") },

    { njs_str("function add(a, b) { return a + b }"
                 "function mul(a, b) { return a * b }"
                 "function f(a, b) {"
                 "    return a + mul(add(1, 2), add(2, 3)) + b"
                 "}"
                 "f(30, 70)"),
      njs_str("115") },

    { njs_str("function a(x, y) { return x + y }"
                 "function b(x, y) { return x * y }"
                 "a(3, b(4, 5))"),
      njs_str("23") },

    { njs_str("function x(n) { return n }; x('12'.substr(1))"),
      njs_str("2") },

    { njs_str("function f(a) { a *= 2 } f(10)"),
      njs_str("undefined") },

    { njs_str("function f() { return 5 } f()"),
      njs_str("5") },

    { njs_str("function g(x) { return x + 1 }"
                 "function f(x) { return x } f(g)(2)"),
      njs_str("3") },

    { njs_str("function f() { return 5 } f(1)"),
      njs_str("5") },

    { njs_str("function f() {} f()"),
      njs_str("undefined") },

    { njs_str("function f() {;} f()"),
      njs_str("undefined") },

    { njs_str("function f(){return} f()"),
      njs_str("undefined") },

    { njs_str("function f(){return;} f()"),
      njs_str("undefined") },

    { njs_str("function f(){return\n1} f()"),
      njs_str("undefined") },

    { njs_str("function f(a) { return a + 1 } var b = f(2); b"),
      njs_str("3") },

    { njs_str("var f = function(a) { a *= 2; return a }; f(10)"),
      njs_str("20") },

    { njs_str("var f = function b(a) { a *= 2; return a }; f(10)"),
      njs_str("20") },

    { njs_str("var f = function b(a) { a *= 2; return a }; b(10)"),
      njs_str("ReferenceError: \"b\" is not defined") },

    { njs_str("var f; f = function(a) { a *= 2; return a }; f(10)"),
      njs_str("20") },

    { njs_str("var f; f = function b(a) { a *= 2; return a }; f(10)"),
      njs_str("20") },

    { njs_str("var a, f = a = function(a) { a *= 2; return a }; f(10)"),
      njs_str("20") },

    { njs_str("var a, f = a = function(a) { a *= 2; return a }; a(10)"),
      njs_str("20") },

    { njs_str("var f = function b(a) { a *= 2; return a } = 5"),
      njs_str("ReferenceError: Invalid left-hand side in assignment") },

    { njs_str("function a() { return { x:2} }; var b = a(); b.x"),
      njs_str("2") },

    { njs_str("var a = {}; function f(a) { return a + 1 } a.b = f(2); a.b"),
      njs_str("3") },

    { njs_str("(function(x) { return x + 1 })(2)"),
      njs_str("3") },

    { njs_str("(function(x) { return x + 1 }(2))"),
      njs_str("3") },

    { njs_str("var a = function() { return 1 }(); a"),
      njs_str("1") },

    { njs_str("var a = (function() { return 1 })(); a"),
      njs_str("1") },

    { njs_str("var a = (function(a) { return a + 1 })(2); a"),
      njs_str("3") },

    { njs_str("var a = (function(a) { return a + 1 }(2)); a"),
      njs_str("3") },

    { njs_str("var a = +function(a) { return a + 1 }(2); a"),
      njs_str("3") },

    { njs_str("var a = -function(a) { return a + 1 }(2); a"),
      njs_str("-3") },

    { njs_str("var a = !function(a) { return a + 1 }(2); a"),
      njs_str("false") },

    { njs_str("var a = ~function(a) { return a + 1 }(2); a"),
      njs_str("-4") },

    { njs_str("var a = void function(a) { return a + 1 }(2); a"),
      njs_str("undefined") },

    { njs_str("var a = true && function(a) { return a + 1 }(2); a"),
      njs_str("3") },

    { njs_str("var a; a = 0, function(a) { return a + 1 }(2); a"),
      njs_str("0") },

    { njs_str("var a = (0, function(a) { return a + 1 }(2)); a"),
      njs_str("3") },

    { njs_str("var a = 0, function(a) { return a + 1 }(2); a"),
      njs_str("SyntaxError: Unexpected token \"function\"") },

    { njs_str("var a = (0, function(a) { return a + 1 }(2)); a"),
      njs_str("3") },

    { njs_str("var a = +function f(a) { return a + 1 }(2);"
                 "var b = f(5); a"),
      njs_str("ReferenceError: \"f\" is not defined") },

    { njs_str("var o = { f: function(a) { return a * 2 } }; o.f(5)"),
      njs_str("10") },

    { njs_str("var o = {}; o.f = function(a) { return a * 2 }; o.f(5)"),
      njs_str("10") },

    { njs_str("var o = { x: 1, f: function() { return this.x } }; o.f()"),
      njs_str("1") },

    { njs_str("var o = { x: 1, f: function() { return this.x } }; (o.f)()"),
      njs_str("1") },

    { njs_str("var o = { x: 1, f: function(a) { return this.x += a } };"
                 "o.f(5) +' '+ o.x"),
      njs_str("6 6") },

    { njs_str("var f = function(a) { return 3 }; f.call()"),
      njs_str("3") },

    { njs_str("var f = function(a) { return this }; f.call(5)"),
      njs_str("5") },

    { njs_str("var f = function(a, b) { return this + a }; f.call(5, 1)"),
      njs_str("6") },

    { njs_str("var f = function(a, b) { return this + a + b };"
                 "f.call(5, 1, 2)"),
      njs_str("8") },

    { njs_str("var f = function(a) { return 3 }; f.apply()"),
      njs_str("3") },

    { njs_str("var f = function(a) { return this }; f.apply(5)"),
      njs_str("5") },

    { njs_str("var f = function(a) { return this + a }; f.apply(5, 1)"),
      njs_str("TypeError: second argument is not an array-like object") },

    { njs_str("var f = function(a, b) { return this + a + b };"
                 "f.apply(5, [1, 2])"),
      njs_str("8") },

    { njs_str("var f = function(a, b) { return this + a + b };"
                 "f.apply(5, [1, 2], 3)"),
      njs_str("8") },

    { njs_str("var f = function(a, b) { return this + a + b };"
                 "f.apply(5, {'length':2, '0':1, '1':2})"),
      njs_str("8") },

    { njs_str("var f = function(a, b) { return this + a + b };"
                 "f.apply(5, {'length':2, '0':1, '1':2, '2':3})"),
      njs_str("8") },

    { njs_str("var f = function(a, b, c) { return this + a + b + c};"
                 "f.apply(\"a\", {'length':2, '0':1, '1':2, '2':3})"),
      njs_str("a12undefined") },

    { njs_str("var f = function(a, b) { return this + a + b };"
                 "f.apply(5, {'length':3, '0':1, '1':2, '2':3})"),
      njs_str("8") },

    { njs_str("var f = function(a) { return this + a };"
                 "f.apply(5, {'nolength':3, '0':1, '1':2})"),
      njs_str("NaN") },

    { njs_str("var f = function(a) { return this };"
                 "f.apply(5, {'nolength':3, '0':1, '1':2})"),
      njs_str("5") },

    { njs_str("var f = function(a, b, c) { return this + a + b + c };"
                 "f.apply(\"a\", {'length':3, '0':1, '1':2})"),
      njs_str("a12undefined") },

    { njs_str("var f = function(a, b) { return this + a + b };"
                 "f.apply(\"a\", {'length':2, '0':undefined, '1':null})"),
      njs_str("aundefinednull") },

    { njs_str("var f = function() { return this };"
                 "f.apply(123, {})"),
      njs_str("123") },

    { njs_str("'Hello'.concat(' ', 'World')"),
      njs_str("Hello World") },

    { njs_str("'Value: '.concat(42, ' and ', 3.14)"),
      njs_str("Value: 42 and 3.14") },

    { njs_str("'Flags: '.concat(true, ' and ', false)"),
      njs_str("Flags: true and false") },

    { njs_str("'Values: '.concat(null, ' and ', undefined)"),
      njs_str("Values: null and undefined") },

    { njs_str("'Mixed: '.concat(123, ' ', true, ' ', null, ' ', undefined)"),
      njs_str("Mixed: 123 true null undefined") },

    { njs_str("'Special: '.concat(NaN, ' ', Infinity, ' ', -Infinity)"),
      njs_str("Special: NaN Infinity -Infinity") },

    { njs_str("'Numbers: '.concat(1234567890, ' ', 0.123456789, ' ', 1.23e-10)"),
      njs_str("Numbers: 1234567890 0.123456789 1.23e-10") },

    { njs_str("'Zero: '.concat(0, ' ', -0)"),
      njs_str("Zero: 0 0") },

    { njs_str("(function(index, ...rest){ return rest[index];})"
              ".apply({}, [1022].concat(Array(1023).fill(1).map((v,i)=>i.toString(16))))"),
      njs_str("3fe") },

    { njs_str("String.prototype.concat.apply('a', "
                 "{length:2, 0:{toString:function() {return 'b'}}, 1:'c'})"),
      njs_str("abc") },

    { njs_str("String.prototype.concat.apply('a',"
                 "{length: {valueOf: () => 2}, 0:'b', 1:'c'})"),
      njs_str("abc") },

    { njs_str("var o = {0:'b', 1:'c'}; Object.defineProperty(o, 'length', {get: () => 2});"
              "String.prototype.concat.apply('a', o)"),
      njs_str("abc") },

    { njs_str("var a = function() { return 1 } + ''; a"),
      njs_str("[object Function]") },

    { njs_str("''.concat.call()"),
      njs_str("TypeError: \"this\" argument is null or undefined") },

    { njs_str("''.concat.call('a', 'b', 'c')"),
      njs_str("abc") },

    { njs_str("''.concat.call('a')"),
      njs_str("a") },

    { njs_str("''.concat.call('a', [ 'b', 'c' ])"),
      njs_str("ab,c") },

    { njs_str("''.concat.call('a', [ 'b', 'c' ], 'd')"),
      njs_str("ab,cd") },

    { njs_str("''.concat.apply()"),
      njs_str("TypeError: \"this\" argument is null or undefined") },

    { njs_str("''.concat.apply('a')"),
      njs_str("a") },

    { njs_str("''.concat.apply('a', 'b')"),
      njs_str("TypeError: second argument is not an array-like object") },

    { njs_str("''.concat.apply('a', [ 'b', 'c' ])"),
      njs_str("abc") },

    { njs_str("''.concat.apply('a', [ 'b', 'c' ], 'd')"),
      njs_str("abc") },

    { njs_str("''.concat.apply('', Array(128).fill(1.23456789123e14)) == '123456789123000'.repeat(128)"),
      njs_str("true") },

    { njs_str("''.concat.apply('', Array(128).fill(0).map((v,i)=>Math.log2(i))).startsWith('-Infinity')"),
      njs_str("true") },

    { njs_str("''.concat.apply('', Array(256).fill(0).map((v,i)=> !(i % 2) ? Math.exp(i) : 'α'.repeat(Math.log2(i)))).endsWith('110ααααααα')"),
      njs_str("true") },

    { njs_str("[].join.call([1,2,3])"),
      njs_str("1,2,3") },

    { njs_str("[].join.call([1,2,3], ':')"),
      njs_str("1:2:3") },

    { njs_str("[].join.call([1,2,3], 55)"),
      njs_str("1552553") },

    { njs_str("[].join.call()"),
      njs_str("TypeError: cannot convert null or undefined to object") },

    { njs_str("[1,2,3].join(undefined)"),
      njs_str("1,2,3") },

    { njs_str("Array.prototype[1] = 1; var x = [0]; x.length = 2; x.join()"),
      njs_str("0,1") },

    { njs_str("Object.prototype[1] = 1; Object.prototype.length = 2; Array.prototype.join.call({0:0})"),
      njs_str("0,1") },

    { njs_str("var x = [0,,4]; x.length = 3; "
              "Object.defineProperty(Array.prototype, 1, "
                "{get:()=>{Object.defineProperty(x, 2, {value:'x', enumerable:false}); return 1}});"
              "x.join()"),
      njs_str("0,1,x") },

    { njs_str("[].slice.call()"),
      njs_str("TypeError: cannot convert null or undefined to object") },

    { njs_str("function f(a) {} ; var a = f; var b = f; a === b"),
      njs_str("true") },

    { njs_str("function f() {} ; f.toString()"),
      njs_str("[object Function]") },

    { njs_str("function f() {}; f"),
      njs_str("[object Function]") },

    { njs_str("function f() {}; f = f + 1; f"),
      njs_str("[object Function]1") },

    { njs_str("function a() { return 1 }"
                 "function b() { return a }"
                 "function c() { return b }"
                 "c()()()"),
      njs_str("1") },

    { njs_str("function f() {}; f += 1; f"),
      njs_str("[object Function]1") },

    { njs_str("function f() { function g() { g = undefined; }; g(); g(); };"
              "f()"),
      njs_str("TypeError: undefined is not a function") },

    { njs_str("function f() {}; function g() { return f }; g()"),
      njs_str("[object Function]") },

    { njs_str("function f(a) { return this+a }; var a = f; a.call('0', 1)"),
      njs_str("01") },

    { njs_str("function f(a) { return this+a }; f.call('0', 1)"),
      njs_str("01") },

    { njs_str("function f(a) { return this+a };"
                 "function g(f, a, b) { return f.call(a, b) }; g(f, '0', 1)"),
      njs_str("01") },

    { njs_str("function f(a) { return this+a };"
                 "var o = { g: function (f, a, b) { return f.call(a, b) } };"
                 "o.g(f, '0', 1)"),
      njs_str("01") },

    { njs_str("var concat = ''.concat; concat(1,2,3)"),
      njs_str("TypeError: \"this\" argument is null or undefined") },

    { njs_str("var concat = ''.concat; concat.call(1,2,3)"),
      njs_str("123") },

    { njs_str("var concat = ''.concat; concat.yes = 'OK';"
                 "concat.call(1,2,3, concat.yes)"),
      njs_str("123OK") },

    { njs_str("var f = function(a, b) { return this + a + b };"
                 "var b = f.bind('1'); b('2', '3')"),
      njs_str("123") },

    { njs_str("var f = function(a, b) { return this + a + b };"
                 "var b = f.bind('1', '2'); b('3')"),
      njs_str("123") },

    { njs_str("var f = function(a, b) { return this + a + b };"
                 "var b = f.bind('1', 2, '3'); b()"),
      njs_str("123") },

    { njs_str("var f = function(a, b) { return this + a + b };"
                 "var b = f.bind('1'); b.call('0', '2', '3')"),
      njs_str("123") },

    { njs_str("var f = function(a, b) { return this + a + b };"
                 "var b = f.bind('1', '2'); b.call('0', '3')"),
      njs_str("123") },

    { njs_str("var f = function(a, b) { return this + a + b };"
                 "var b = f.bind('1', '2', '3'); b.call('0')"),
      njs_str("123") },

    { njs_str("var f = function(a, b) { return this + a + b };"
                 "var b = f.bind('1', '2', '3'); b.call()"),
      njs_str("123") },

    { njs_str("var f = function(a, b) { return this + a + b };"
                 "var b = f.bind('1'); b.apply('0', ['2', '3'])"),
      njs_str("123") },

    { njs_str("var f = function(a, b) { return this + a + b };"
                 "var b = f.bind('1', '2'); b.apply('0', ['3'])"),
      njs_str("123") },

    { njs_str("var f = function(a, b) { return this + a + b };"
                 "var b = f.bind('1', '2', '3'); b.apply('0')"),
      njs_str("123") },

    { njs_str("var f = function(a, b) { return this + a + b };"
                 "var b = f.bind('1', '2', '3'); b.apply()"),
      njs_str("123") },

    { njs_str("function f(a, b) { return this + a + b }"
                 "var b = f.bind('1', '2', '3'); b.apply()"),
      njs_str("123") },

    { njs_str("function f() { var a; return (function() { a = 1; return a; }).bind()() } f()"),
      njs_str("1") },

    { njs_str("function f() { var a; function baz() { a = 1; return a; } return baz.bind()(); } f()"),
      njs_str("1") },

    { njs_str("(function(){ var a = 1; return (function() { return a; })})().bind()()"),
      njs_str("1") },

    { njs_str("var r = (function(){ var a = 1; return (function() { return {a,args:arguments}; })})().bind()('b');"
              "njs.dump(r)"),
      njs_str("{a:1,args:{0:'b'}}") },

    { njs_str("function f() { var a = 1; function baz() { return a; } return baz; } f().bind()()"),
      njs_str("1") },

    { njs_str("function f() { var t = 1; function baz() { return t; } return baz; }"
                 "f().bind()();"),
      njs_str("1") },

    { njs_str("(function(a) { var s = typeof g, q = g; var g = 1; s += typeof g; function g(b) { return a + b }; return q; })(1)(2)"),
      njs_str("3")},

    { njs_str("(function(a) { var g = f; var f = 1; function f() { return a; } return g; })(42)()"),
      njs_str("42") },

    { njs_str("function f(a, b) { return a + b }"
                 "f(3,4) === f.bind()(3,4)"),
      njs_str("true") },

    { njs_str("var obj = {prop:'abc'}; "
                 "var func = function(x) { "
                 "    return this === obj && x === 1 && arguments[0] === 1 "
                 "           && arguments.length === 1 && this.prop === 'abc';"
                 "};"
                 "Function.prototype.bind.call(func, obj, 1)()"),
      njs_str("true") },

    { njs_str("function F(a, b) { this.a = a + b }"
                 "var o = new F(1, 2);"
                 "o.a"),
      njs_str("3") },

    { njs_str("function F(a, b) { this.a = a + b; return { a: 7 } }"
                 "var o = new F(1, 2);"
                 "o.a"),
      njs_str("7") },

    { njs_str("let a = 1;"
              "function f(x, y) { return x + ':' + y; }"
              "f(a, a = 2)"),
      njs_str("1:2") },

    { njs_str("let a = 1, b = 4;"
              "function f(x, y) { return x + ':' + y; }"
              "f(a = b, b = 2)"),
      njs_str("4:2") },

    { njs_str("function f(x, y) { return x + ':' + y; }"
              "function g(a) { return f(a, a = 2); }"
              "g(1)"),
      njs_str("1:2") },

    { njs_str("let a = 1;"
              "let o = { m: function(x, y) { return x + ':' + y; } };"
              "o.m(a, a = 2)"),
      njs_str("1:2") },

    { njs_str("let a = 1;"
              "let o = { get m() { a = 9;"
              "    return function(x, y) { return x + ':' + y + ':' + a; };"
              "} };"
              "o.m(a, a = 2)"),
      njs_str("9:2:2") },

    { njs_str("let a = 1;"
              "let o = { get x() { a = 2; return 3; } };"
              "function f(x, y) { return x + ':' + y; }"
              "f(a, o.x)"),
      njs_str("1:3") },

    { njs_str("let a = 1;"
              "function f(x, y) { return x + ':' + y; }"
              "Object.defineProperty(globalThis, 'b', {"
              "    get: function() { a = 2; return 3; },"
              "    configurable: true"
              "});"
              "let r = f(a, b);"
              "delete globalThis.b;"
              "r"),
      njs_str("1:3") },

    { njs_str("let a = 1;"
              "function f(x, y, z) { return x + ':' + y + ':' + z; }"
              "f(a, (a = 2, a), a = 3)"),
      njs_str("1:2:3") },

    { njs_str("let a = 1;"
              "function f(x, y, z) { return x + ':' + y + ':' + z; }"
              "f(a, 0, a = 2)"),
      njs_str("1:0:2") },

    { njs_str("let a = 1;"
              "function f(x, y) { return x + ':' + y; }"
              "f(a, ++a)"),
      njs_str("1:2") },

    { njs_str("let a = 1;"
              "function f(x, y) { return x + ':' + y; }"
              "f(a, true ? (a = 2) : 0)"),
      njs_str("1:2") },

    { njs_str("let a = 0;"
              "function f(x, y) { return x + ':' + y; }"
              "f(a, a ||= 2)"),
      njs_str("0:2") },

    { njs_str("let a = 1;"
              "function f(x, y) { return x + ':' + y; }"
              "function g(v) { return v; }"
              "f(a, g(a = 2))"),
      njs_str("1:2") },

    { njs_str("function f(x, y) { return x + ':' + y; }"
              "function g() { let a = 1;"
              "    return function() { return f(a, a = 2); };"
              "}"
              "g()()"),
      njs_str("1:2") },

    { njs_str("let a = 1;"
              "function F(x, y) { this.v = x + ':' + y; }"
              "new F(a, a = 2).v"),
      njs_str("1:2") },

    { njs_str("let a = 1;"
              "function f(x, y, z) { return x + ':' + y + ':' + z; }"
              "f(a, [a = 2][0], { k: a = 3 }.k)"),
      njs_str("1:2:3") },

    { njs_str("let o = { x: 1 };"
              "function f(x, y) { return x + ':' + y; }"
              "f(o.x, o.x = 2)"),
      njs_str("1:2") },

    { njs_str("let a = 1;"
              "let f = function(x, y) { return 'orig:' + x + ':' + y; };"
              "f(a, (f = function() { return 'new'; }, a = 2))"),
      njs_str("orig:1:2") },

    { njs_str("function F(a, b) { return }"
                 "F.prototype.constructor === F"),
      njs_str("true") },

    { njs_str("function F() { return }"
                 "F.prototype.ok = 'OK';"
                 "var o = new F(); o.ok"),
      njs_str("OK") },

    { njs_str("function F() { return }"
                 "var o = new F();"
                 "o.constructor === F"),
      njs_str("true") },

    { njs_str("function F() { return }"
                 "var o = new F();"
                 "o.__proto__ === F.prototype"),
      njs_str("true") },

    { njs_str("var f = { F: function(){} }; var o = new f.F();"
                 "o.__proto__ === f.F.prototype"),
      njs_str("true") },

    { njs_str("function F(){}; typeof F.prototype"),
      njs_str("object") },

    { njs_str("var F = function (){}; typeof F.prototype"),
      njs_str("object") },

    { njs_str("var F = function (){}; F.prototype = NaN; ({}) instanceof F"),
      njs_str("TypeError: Function has non-object prototype in instanceof") },

    { njs_str("var F = function() {};"
              "[F, F].map((x)=>Object.getOwnPropertyDescriptor(x, 'prototype').writable)"
              ".every((x)=> x === true)"),
      njs_str("true") },

    { njs_str("var F = function() {}, a = {t: 1}, b = {t: 2}, x, y; "
              "F.prototype = a; x = new F();"
              "F.prototype = b; y = new F();"
              "x.t == 1 && y.t == 2"),
      njs_str("true") },

    { njs_str("function A(){}; A.tag = 'A'; var a = new A();"
              "(function B(){}).prototype = A.prototype;"
              "a.constructor.tag"),
      njs_str("A") },

    { njs_str("function A(){}; A.tag = 'A'; var a = new A();"
              "(function B(){}).prototype = a.constructor.prototype;"
              "a.constructor.tag"),
      njs_str("A") },

    { njs_str("var x = {}, y = function() {}, z; y.prototype = x; z = new y();"
              "(z instanceof y) && (z.__proto__ == y.prototype) && (x.isPrototypeOf(z))"),
      njs_str("true") },

    { njs_str("var x = {}, y = function() {}, z; y.prototype = x; z = new y();"
              "(z instanceof y) && (z.__proto__ == y.prototype) && (x.isPrototypeOf(z))"),
      njs_str("true") },

    { njs_str("[undefined, null, false, NaN, '']"
              ".map((x) => { var f = function() {}; f.prototype = x; "
              "              return Object.getPrototypeOf(new f()); })"
              ".every((x) => x == Object.prototype)"),
      njs_str("true") },

    { njs_str("[undefined, null, false, NaN, '']"
              ".map((x) => { var f = function() {}; f.prototype = x; return f; })"
              ".map((x) => { try { return ({} instanceof x) ? 1 : 2; } "
              "              catch (e) { return (e instanceof TypeError) ? 3 : 4; } })"
              ".every((x) => x == 3)"),
      njs_str("true")},

    { njs_str("new decodeURI('%00')"),
      njs_str("TypeError: function is not a constructor")},

    { njs_str("new ''.toString"),
      njs_str("TypeError: function is not a constructor")},

    { njs_str("function F() { return Number }"
                 "var o = new (F())(5);"
                 "typeof o +' '+ o"),
      njs_str("object 5") },

    { njs_str("function F() { return Number }"
                 "var o = new (F());"
                 "typeof o +' '+ o"),
      njs_str("object 0") },

    { njs_str("var o = new function F() { return Number }()(5);"
                 "typeof o +' '+ o"),
      njs_str("number 5") },

    { njs_str("var o = new (function F() { return Number }())(5);"
                 "typeof o +' '+ o"),
      njs_str("object 5") },

    { njs_str("var o = new (new function F() { return Number }())(5);"
                 "typeof o +' '+ o"),
      njs_str("object 5") },

    { njs_str("var o = new new function F() { return Number }()(5);"
                 "typeof o +' '+ o"),
      njs_str("object 5") },

    { njs_str("var b; function F(x) { return {a:x} }"
                 "function G(y) { b = y; return F }"
                 "var o = new G(3)(5);"
                 "b + ' ' + o.a"),
      njs_str("3 5") },

    { njs_str("var b; function F(x) { return {a:x} }"
                 "function G(y) { b = y; return F }"
                 "var o = new (new G(3))(5);"
                 "b + ' ' + o.a"),
      njs_str("3 5") },

    { njs_str("var b; function F(x) { return {a:x} }"
                 "function G(y) { b = y; return F }"
                 "var o = new new G(3)(5);"
                 "b + ' ' + o.a"),
      njs_str("3 5") },

    { njs_str("var b; function F(x) { return {a:x} }"
                 "var g = { G: function (y) { b = y; return F } };"
                 "var o = new new g.G(3)(5);"
                 "b + ' ' + o.a"),
      njs_str("3 5") },

    { njs_str("function a() { return function(x) { return x + 1 } }"
                 "var b = a(); b(2)"),
      njs_str("3") },

    /* arguments object. */

    { njs_str("arguments"),
      njs_str("SyntaxError: \"arguments\" object in global scope") },

    { njs_str("{arguments}"),
      njs_str("SyntaxError: \"arguments\" object in global scope") },

    { njs_str("var arguments"),
      njs_str("SyntaxError: Identifier \"arguments\" is forbidden in var declaration") },

    { njs_str("for (var arguments in []) {}"),
      njs_str("SyntaxError: Identifier \"arguments\" is forbidden in var declaration") },

    { njs_str("function arguments(){}"),
      njs_str("SyntaxError: Identifier \"arguments\" is forbidden in function declaration") },

    { njs_str("(function () {arguments = [];})"),
      njs_str("SyntaxError: Identifier \"arguments\" is forbidden as left-hand in assignment") },

    { njs_str("(function(){return arguments;})()"),
      njs_str("[object Arguments]") },

    { njs_str("(function(){return arguments[0];})(1,2,3)"),
      njs_str("1") },

    { njs_str("(function(){return arguments[2];})(1,2,3)"),
      njs_str("3") },

    { njs_str("(function(){return arguments[3];})(1,2,3)"),
      njs_str("undefined") },

    { njs_str("(function(a,b,c){return a;})(1,2,3)"),
      njs_str("1") },

    { njs_str("(function(a,b,c){arguments[0] = 4; return a;})(1,2,3)"),
      njs_str("1") },

    { njs_str("(function(a,b,c){a = 4; return arguments[0];})(1,2,3)"),
      njs_str("1") },

    { njs_str("function check(v) {if (v == false) {throw TypeError('Too few arguments')}}; "
                 "function f() {check(arguments.length > 1); return 1}; f()"),
      njs_str("TypeError: Too few arguments") },

    { njs_str("function check(v) {if (v == false) {throw TypeError('Too few arguments')}}; "
                 "function f() {check(arguments.length > 1); return 1}; f(1,2)"),
      njs_str("1") },

    { njs_str("(function(a,b){delete arguments[0]; return arguments[0]})(1,1)"),
      njs_str("undefined") },

    { njs_str("(function(){return arguments.length;})()"),
      njs_str("0") },

    { njs_str("(function(){return arguments.length;})(1,2,3)"),
      njs_str("3") },

    { njs_str("(function(){arguments.length = 1; return arguments.length;})(1,2,3)"),
      njs_str("1") },

     { njs_str("(function(){return arguments[3];}).bind(null, 0)('a','b','c')"),
       njs_str("c") },

    { njs_str("function sum() { var args = Array.prototype.slice.call(arguments); "
                 "return args.reduce(function(prev, curr) {return prev + curr})};"
                 "[sum(1), sum(1,2), sum(1,2,3), sum(1,2,3,4)]"),
      njs_str("1,3,6,10") },

    { njs_str("function concat(sep) { var args = Array.prototype.slice.call(arguments, 1); "
                 "return args.join(sep)};"
                 "[concat('.',1,2,3), concat('+',1,2,3,4)]"),
      njs_str("1.2.3,1+2+3+4") },

    /* strict mode restrictions */

    { njs_str("(function() {}).caller"),
      njs_str("TypeError: \"caller\", \"callee\", \"arguments\" properties may not be accessed") },

    { njs_str("(function() {}).arguments"),
      njs_str("TypeError: \"caller\", \"callee\", \"arguments\" properties may not be accessed") },

    { njs_str("var desc = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(Math.min), 'caller');"
              "desc.get === desc.set"),
      njs_str("true") },

    { njs_str("var desc = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(Math.min), 'caller');"
              "1/desc.get"),
      njs_str("NaN") },

    { njs_str("var p = Object.getPrototypeOf(function() {});"
              "var d = Object.getOwnPropertyDescriptor(p, 'caller');"
              "typeof d.get == 'function' && typeof d.get == typeof d.set"
              "                           && d.configurable && !d.enumerable"),
      njs_str("true") },

    { njs_str("var p = Object.getPrototypeOf(function() {});"
              "var d = Object.getOwnPropertyDescriptor(p, 'arguments');"
              "typeof d.get == 'function' && typeof d.get == typeof d.set"
              "                           && d.configurable && !d.enumerable"),
      njs_str("true") },

    { njs_str("(function(){return arguments.callee;})()"),
      njs_str("TypeError: \"caller\", \"callee\", \"arguments\" properties may not be accessed") },

    { njs_str("var f = function() { return arguments; };"
              "Object.getOwnPropertyDescriptor(f(), 'caller')"),
      njs_str("undefined") },

    { njs_str("var f = function() { return arguments; };"
              "var d = Object.getOwnPropertyDescriptor(f(), 'callee');"
              "typeof d.get == 'function' && typeof d.get == typeof d.set"
              "                           && !d.configurable && !d.enumerable"),
      njs_str("true") },

    /* rest parameters. */

    { njs_str("function myFoo(a,b,...other) { return other };"
                 "myFoo(1,2,3,4,5);" ),
      njs_str("3,4,5") },

    { njs_str("function myFoo(a,b,...other, c) { return other };"),
      njs_str("SyntaxError: Rest parameter must be last formal parameter") },

    { njs_str("function sum(a, b, c, ...other) { return a+b+c+other[2] };"
                 "sum(\"one \",2,\" three \",\"four \",\"five \",\"the long enough sixth argument \");"),
      njs_str("one 2 three the long enough sixth argument ") },

    { njs_str("function myFoo1(a,...other) { return other };"
                 "function myFoo2(a,b,...other) { return other };"
                 "myFoo1(1,2,3,4,5,myFoo2(1,2,3,4));"),
      njs_str("2,3,4,5,3,4") },

    { njs_str("function myFoo(...other) { return (other instanceof Array) };"
                 "myFoo(1);" ),
      njs_str("true") },

    { njs_str("function myFoo(a,...other) { return other.length };"
                 "myFoo(1,2,3,4,5);" ),
      njs_str("4") },

    { njs_str("function myFoo(a,b,...other) { return other };"
                 "myFoo(1,2);" ),
      njs_str("") },

    { njs_str("function f(...rest) {};"
              "function f(a, b) {return a + b};"
              "f(1,2)"),
      njs_str("3") },

    { njs_str("function f() { function q() {} };"
              "function f() { };"
              "f()"),
      njs_str("undefined") },

    /* arrow functions. */

    { njs_str("()"),
      njs_str("SyntaxError: Unexpected token \")\"") },

    { njs_str("() => "),
      njs_str("SyntaxError: Unexpected end of input") },

    { njs_str("() => {"),
      njs_str("SyntaxError: Unexpected end of input") },

    { njs_str("a\n => 1"),
      njs_str("SyntaxError: Unexpected token \"=>\"") },

    { njs_str("new (()=>1)"),
      njs_str("TypeError: function is not a constructor")},

    { njs_str("(\n) => {}"),
      njs_str("[object Function]") },

    { njs_str("a => 1"),
      njs_str("[object Function]") },

    { njs_str("({f:()=>1, g:()=>2}).f()"),
      njs_str("1") },

    { njs_str("var f = f => {return 1;}; f()"),
      njs_str("1") },

    { njs_str("var f = (f) => {return 1;}; f()"),
      njs_str("1") },

    { njs_str("var f = (f, a, b) => {return 1;}; f()"),
      njs_str("1") },

    { njs_str("var f = () => {return 1;}; f()"),
      njs_str("1") },

    { njs_str("(f => {return 1;})()"),
      njs_str("1") },

    { njs_str("((f) => {return 1;})()"),
      njs_str("1") },

    { njs_str("(((f) => {return 1;}))()"),
      njs_str("1") },

    { njs_str("var f = f => 1; f()"),
      njs_str("1") },

    { njs_str("() => 1"),
      njs_str("[object Function]") },

    { njs_str("var f = ()=>{}; f()"),
      njs_str("undefined") },

    { njs_str("var f = ()=>({}); f()"),
      njs_str("[object Object]") },

    { njs_str("var materials = ['Hydrogen', 'Helium', 'Lithium', 'Beryllium'];"
                 "materials.map(material => { return material.length; });"),
      njs_str("8,6,7,9") },

    { njs_str("var materials = ['Hydrogen', 'Helium', 'Lithium', 'Beryllium'];"
                 "materials.map(material => material.length);"),
      njs_str("8,6,7,9") },

    { njs_str("var materials = ['Hydrogen', 'Helium', 'Lithium', 'Beryllium'];"
                 "materials.map(material => { material.length });"),
      njs_str(",,,") },

    { njs_str("function f(a, b, c) {a = 1; return () => { return arguments[1]; };};"
                 "f(1, 2, 3)('a', 'b');"),
      njs_str("2") },

    { njs_str("var f = (...c) => { return (function() { return arguments.length; }).bind(null, c); };"
                 "var x = f(1,'a',false, {}); x()"),
      njs_str("1") },

    { njs_str("var f = (...c) => { return (function() { return arguments.length; }).bind(null, c); };"
                 "var x = f(1,'a',false, {}); x(1,2,3)"),
      njs_str("4") },

    { njs_str("function Car(){ this.age = 0; (() => { this.age++;})();}"
                 "(new Car()).age"),
      njs_str("1") },

    { njs_str("function Car(){ this.age = 0; (function(){ this.age++;})();}"
                 "(new Car()).age"),
      njs_str("TypeError: cannot get property \"age\" of undefined") },

    /* arrow functions + global this. */

    { njs_str("(() => this)()"),
      njs_str("[object global]") },

    { njs_str("(() => this).call('abc')"),
      njs_str("[object global]") },

    { njs_str("(() => this).apply('abc')"),
      njs_str("[object global]") },

    { njs_str("(() => this).bind('abc')()"),
      njs_str("[object global]") },

    { njs_str("(function() { return (() => this); })()()"),
      njs_str("undefined") },

    { njs_str("(function() { return (() => this); }).call('abc')()"),
      njs_str("abc") },

    { njs_str("(function() { return (() => this); }).bind('abc')()()"),
      njs_str("abc") },

    { njs_str("(function() { return (() => this); })"
                 ".call('abc').call('bca')"),
      njs_str("abc") },

    { njs_str("(function() { return (() => this); })"
                 ".call('abc').bind('bca')()"),
      njs_str("abc") },

    { njs_str("(function() { return function() { return () => this; }; })"
                 ".call('bca').call('abc')()"),
      njs_str("abc") },

     { njs_str("var f = () => 1; f.prototype"),
       njs_str("undefined") },

     { njs_str("var f = (a,b) => 0; f.length"),
       njs_str("2") },

    { njs_str("var o = Object.create(f => 1); o.length = 3"),
      njs_str("TypeError: Cannot assign to read-only property \"length\" of object") },

    /* Scopes. */

    { njs_str("function f(x) { a = x } var a; f(5); a"),
      njs_str("5") },

    { njs_str("function f(x) { var a = x } var a = 2; f(5); a"),
      njs_str("2") },

    { njs_str("function f(a) { return a } var a = '2'; a + f(5)"),
      njs_str("25") },

    { njs_str("for (var i = 0; i < 5; i++); i"),
      njs_str("5") },

    { njs_str("for (var i = 0, j; i < 5; i++); j"),
      njs_str("undefined") },

    { njs_str("for (var i = 0, j, k = 3; i < 5; i++); k"),
      njs_str("3") },

    { njs_str("var o = { a: 1, b: 2, c: 3 }, s = ''; "
                 "for (var i in o) { s += i }; s"),
      njs_str("abc") },

    { njs_str("var o = { a: 1, b: 2, c: 3 }; for (var i in o); i"),
      njs_str("c") },

    { njs_str("var o = {}; i = 7; for (var i in o); i"),
      njs_str("7") },

    { njs_str("var a = [1,2,3]; for (var i in a); i"),
      njs_str("2") },

    /* RegExp. */

    { njs_str("/"),
      njs_str("SyntaxError: Unterminated RegExp \"/\"") },

    { njs_str("/a\n/"),
      njs_str("SyntaxError: Unterminated RegExp \"/a\"") },

    { njs_str("/a\r/"),
      njs_str("SyntaxError: Unterminated RegExp \"/a\"") },

#ifndef NJS_HAVE_PCRE2
    { njs_str("/a\\q/"),
      njs_str("/a\\q/") },
#endif

    { njs_str("/\\\\/"),
      njs_str("/\\\\/") },

    { njs_str("/\\\\\\/"),
      njs_str("SyntaxError: Unterminated RegExp \"/\\\\\\/\"") },

    { njs_str("/\\\\\\\\/"),
      njs_str("/\\\\\\\\/") },

    { njs_str("/\\\\\\//"),
      njs_str("/\\\\\\//") },

    { njs_str("/[A-Z/]/"),
      njs_str("/[A-Z/]/") },

    { njs_str("/a/gim"),
      njs_str("/a/gim") },

    { njs_str("/a/y"),
      njs_str("/a/y") },

    { njs_str("/[A-Z\n]/"),
      njs_str("SyntaxError: Unterminated RegExp \"/[A-Z\"") },

    { njs_str("/[A-Z\\\n]/"),
      njs_str("SyntaxError: Unterminated RegExp \"/[A-Z\\\"") },

    { njs_str("/\\\n/"),
      njs_str("SyntaxError: Unterminated RegExp \"/\\\"") },

    { njs_str("/./x"),
      njs_str("SyntaxError: Invalid RegExp flags \"x\"") },

    { njs_str("/./.exec === RegExp.prototype.exec"),
      njs_str("true") },

    { njs_str("/./['exec'] === RegExp.prototype.exec"),
      njs_str("true") },

    { njs_str("/./[Symbol.replace] === RegExp.prototype[Symbol.replace]"),
      njs_str("true") },

    { njs_str("/^[A-Za-z0-9+/]{4}$/.test('////')"),
      njs_str("true") },

    { njs_str("'[]!\"#$%&\\'()*+,.\\/:;<=>?@\\^_`{|}-'.split('')"
                 ".every(ch=>/[\\]\\[!\"#$%&'()*+,.\\/:;<=>?@\\^_`{|}-]/.test(ch))"),
      njs_str("true") },

#ifndef NJS_HAVE_PCRE2
    { njs_str("/a\\q/.test('a\\q')"),
      njs_str("true") },
#endif

#ifdef PCRE2_EXTRA_ALLOW_SURROGATE_ESCAPES
    { njs_str("/\\u200d\\ud800-/"),
      njs_str("/\\u200d\\ud800-/") },
#endif

    { njs_str("/(\\.(?!com|org)|\\/)/.test('ah.info')"),
      njs_str("true") },

    { njs_str("/(/.test('')"),
      njs_str("SyntaxError: "
              njs_pcre_var("pcre_compile2(\"(\") failed: missing closing parenthesis at \"\"",
                           "pcre_compile(\"(\") failed: missing )")) },

    { njs_str("/+/.test('')"),
      njs_str("SyntaxError: "
              njs_pcre_var("pcre_compile2(\"+\") failed: quantifier does not follow a repeatable item",
                           "pcre_compile(\"+\") failed: nothing to repeat")) },

    { njs_str("/^$/.test('')"),
      njs_str("true") },

    { njs_str("var a = /\\d/; a.test('123')"),
      njs_str("true") },

    { njs_str("var a = /\\d/; a.test('abc')"),
      njs_str("false") },

    { njs_str("/\\d/.test('123')"),
      njs_str("true") },

    { njs_str("/\\d/.test(123)"),
      njs_str("true") },

    { njs_str("/undef/.test()"),
      njs_str("true") },

    { njs_str("var s = { toString: function() { return 123 } };"
                 "/\\d/.test(s)"),
      njs_str("true") },

    { njs_str("/\\d/.test('abc')"),
      njs_str("false") },

    { njs_str("/abc/i.test('ABC')"),
      njs_str("true") },

#if (!NJS_HAVE_MEMORY_SANITIZER) /* FIXME */
    { njs_str("/абв/i.test('АБВ')"),
      njs_str("true") },
#endif

    { njs_str("var re = /<(?<key>[\\w\\-\\.\\:]+)>(?<body>.*?)<\\/\\1>/g;"
              "['<A>XXX</A>', '<A>XX</B>'].map(s=>re.test(s))"),
      njs_str("true,false") },

    { njs_str("/\\x80/.test('\\u0080')"),
      njs_str("true") },

    { njs_str("/α/.test('\\u03B1')"),
      njs_str("true") },

    { njs_str("/[A-Za-z]/.test('S')"),
      njs_str("true") },

    { njs_str("/[A-Za-z]/.test('ø')"),
      njs_str("false") },

    { njs_str("var r = /abc/y; r.test('abc'); r.lastIndex"),
      njs_str("3") },

    { njs_str("/\\d/.exec('123')"),
      njs_str("1") },

    { njs_str("/\\d/.exec(123)"),
      njs_str("1") },

    { njs_str("/undef/.exec()"),
      njs_str("undef") },

    { njs_str("var s = { toString: function() { return 123 } };"
                 "/\\d/.exec(s)"),
      njs_str("1") },

    { njs_str("var a = /^$/.exec(''); a.length +' '+ a"),
      njs_str("1 ") },

    { njs_str("var r = /3/g; r.exec('123') +' '+ r.exec('3')"),
      njs_str("3 null") },

#if (!NJS_HAVE_MEMORY_SANITIZER) /* FIXME */
    { njs_str("var r = /бв/ig;"
                 "var a = r.exec('АБВ');"
                 "r.lastIndex +' '+ a +' '+ "
                 "r.source +' '+ r.source.length +' '+ r"),
      njs_str("3 БВ бв 2 /бв/gi") },
#endif

    { njs_str("var descs = Object.getOwnPropertyDescriptors(RegExp('a'));"
              "Object.keys(descs)"),
      njs_str("lastIndex") },

    { njs_str("var props = Object.getOwnPropertyDescriptor(RegExp('a'), 'lastIndex');"
              "props.writable && !props.enumerable && !props.configurable"),
      njs_str("true") },

    { njs_str("var re = /a/; re.lastIndex"),
      njs_str("0") },

    { njs_str("var re = /aα/g; re.exec('aα'.repeat(32)); re.lastIndex"),
      njs_str("2") },

    { njs_str("var re = new RegExp('α'.repeat(33), 'g'); re.exec('α'.repeat(33)); re.lastIndex"),
      njs_str("33") },

    { njs_str("var re = new RegExp('α'.repeat(33), 'g'); re.exec('α'.repeat(33)); "
              "re.lastIndex = 67; re.lastIndex"),
      njs_str("67") },

    { njs_str("var re = /a/; re.lastIndex = 4; Object.create(re).lastIndex"),
      njs_str("4") },

    { njs_str("var re = /a/g; re.lastIndex = {valueOf(){throw 'Oops'}}; typeof re.lastIndex"),
      njs_str("object") },

    { njs_str("var re = /a/g; re.lastIndex = {valueOf(){throw 'Oops'}}; re.exec('a')"),
      njs_str("Oops") },

    { njs_str("var re = /a/; Object.defineProperty(re, 'lastIndex', {value:'qq'}); re.lastIndex"),
      njs_str("qq") },

    { njs_str("var re = /a/; re.lastIndex = 'qq'; Object.create(re).lastIndex"),
      njs_str("qq") },

    { njs_str("var re = /(?:ab|cd)\\d?/g; re.lastIndex=-1; re.test('aacd22 '); re.lastIndex"),
      njs_str("5") },

    { njs_str("var re = /(?:ab|cd)\\d?/g; re.lastIndex=-1; re.test('@@'); re.lastIndex"),
      njs_str("0") },

    { njs_str("var r = /a/; var gets = 0;"
              "var counter = { valueOf: function() { gets++; return 0; } };"
              "r.lastIndex = counter;"
              "njs.dump([r.exec('nbc'), r.lastIndex === counter, gets])"),
      njs_str("[null,true,1]") },

    /*
     * It seems that "/стоп/ig" fails on early PCRE versions.
     * It fails at least in 8.1 and works at least in 8.31.
     */

#if (!NJS_HAVE_MEMORY_SANITIZER) /* FIXME */
    { njs_str("var r = /Стоп/ig;"
                 "var a = r.exec('АБВДЕЁЖЗИКЛМНОПРСТУФХЦЧШЩЬЫЪЭЮЯСТОП');"
                 "r.lastIndex +' '+ a +' '+ r.source +' '+ r"),
      njs_str("35 СТОП Стоп /Стоп/gi") },
#endif

    { njs_str("var r = /quick\\s(brown).+?(jumps)/ig;"
                "var a = r.exec('The Quick Brown Fox Jumps Over The Lazy Dog');"
                "a[0] +' '+ a[1] +' '+ a[2] +' '+ a[3] +' '+ "
                "a.index +' '+ r.lastIndex +' '+ a.input"),
      njs_str("Quick Brown Fox Jumps Brown Jumps undefined "
                 "4 25 The Quick Brown Fox Jumps Over The Lazy Dog") },

    { njs_str("var r = /a/.exec('a'); ['groups' in r, typeof r.groups]"),
      njs_str("true,undefined") },

    { njs_str("var r = /(?<m>[0-9]{2})\\/(?<d>[0-9]{2})\\/(?<y>[0-9]{4})/;"
              "var g = r.exec('12/31/1986').groups;"
              "g.d + '.' + g.m + '.' + g.y"),
      njs_str("31.12.1986") },

#if (!NJS_HAVE_MEMORY_SANITIZER) /* PCRE bug in groups code */

    { njs_str("var g = /(?<r>(?<no>no)?(?<yes>yes)?)/.exec('yes').groups;"
              "[Object.keys(g).length,'no' in g, typeof g.no, g.yes, g.r]"),
      njs_str("3,true,undefined,yes,yes") },
#endif

    { njs_str("var s; var r = /./g; while (s = r.exec('abc')); s"),
      njs_str("null") },

    { njs_str("(/α/).exec('γαβγ').index"),
      njs_str("1") },

    { njs_str("var r = /LS/i.exec(false); r[0]"),
      njs_str("ls") },

    { njs_str("var r = (/^.+$/mg), s = 'ab\\nc'; [r.exec(s), r.exec(s)]"),
      njs_str("ab,c") },

    { njs_str("var r = (/^.+$/mg); [r.global, r.multiline, r.ignoreCase, r.sticky]"),
      njs_str("true,true,false,false") },

    { njs_str("['global', 'ignoreCase', 'multiline', 'sticky']"
              ".map(v => Object.getOwnPropertyDescriptor(RegExp.prototype, v))"
              ".every(desc => (typeof desc.get === 'function' && typeof desc.set === 'undefined'))"),
      njs_str("true") },

    { njs_str("var re = /./, re2 = /./y; re.lastIndex = 1; re2.lastIndex = 1;"
              "[re.exec('abc')[0], re2.exec('abc')[0]]"),
      njs_str("a,b") },

    { njs_str("var re = /c/, re2 = /c/y;"
              "njs.dump([re.exec('abc')[0], re2.exec('abc')])"),
      njs_str("['c',null]") },

    { njs_str("['global', 'ignoreCase', 'multiline']"
              ".map(v => Object.getOwnPropertyDescriptor(RegExp.prototype, v))"
              ".every(desc => (typeof desc.get === 'function' && typeof desc.set === 'undefined'))"),
      njs_str("true") },

    { njs_str("var r = /./; r"),
      njs_str("/./") },

    { njs_str("/[^]+|[^]+/.test('\\n| ')"),
      njs_str("true") },

    { njs_str("/[^]+|[^][^]/.test('|aa')"),
      njs_str("true") },

    { njs_str("/a[]/.test('a')"),
      njs_str("false") },

    { njs_str("/[]a/.test('a')"),
      njs_str("false") },

    { njs_str("/[#[]/.test('[')"),
      njs_str("true") },

    { njs_str("/[\\s[]/.test('[')"),
      njs_str("true") },

    { njs_str("/[#[^]/.test('[')"),
      njs_str("true") },

    { njs_str("/[#\\[]/.test('[')"),
      njs_str("true") },

    { njs_str("/[\\[^]/.test('[')"),
      njs_str("true") },

    { njs_str("/[^]abc]/.test('#abc]')"),
      njs_str("true") },

    { njs_str("/[[^]abc]/.test('[abc]')"),
      njs_str("true") },

    { njs_str("/[[^]abc]/.test('^abc]')"),
      njs_str("true") },

    { njs_str("/[]/.test('[]')"),
      njs_str("false") },

    { njs_str("/[[]/.test('[')"),
      njs_str("true") },

    { njs_str("/\\[]/.test('[]')"),
      njs_str("true") },

    { njs_str("/[]abc]/.test('abc]')"),
      njs_str("false") },

    { njs_str("/abc]/.test('abc]')"),
      njs_str("true") },

    { njs_str("/\\\\\\[]/.test('\\\\[]')"),
      njs_str("true") },

#ifdef NJS_HAVE_PCRE2
    { njs_str("/[]*a/.test('a')"),
      njs_str("true") },
#endif

    { njs_str("/Ca++BB/"),
      njs_str("SyntaxError: Invalid regular expression \"Ca++BB\" nothing to repeat") },

    { njs_str("/a*+/"),
      njs_str("SyntaxError: Invalid regular expression \"a*+\" nothing to repeat") },

    { njs_str("/a?+/"),
      njs_str("SyntaxError: Invalid regular expression \"a?+\" nothing to repeat") },

    { njs_str(" /\\[[]++\\]/"),
      njs_str("SyntaxError: Invalid regular expression \"\\[[]++\\]\" nothing to repeat") },

    { njs_str("/\\?+/"),
      njs_str("/\\?+/") },

    { njs_str("var r = new RegExp(); r"),
      njs_str("/(?:)/") },

    { njs_str("var r = new RegExp('.'); r"),
      njs_str("/./") },

    { njs_str("var r = new RegExp('.', 'igm'); r"),
      njs_str("/./gim") },

    { njs_str("var r = new RegExp('.', 'y'); r"),
      njs_str("/./y") },

    { njs_str("var r = new RegExp('abc'); r.test('00abc11')"),
      njs_str("true") },

    { njs_str("var r = new RegExp('abc', 'i'); r.test('00ABC11')"),
      njs_str("true") },

    { njs_str("RegExp('α'.repeat(33)).toString()[32]"),
      njs_str("α") },

    { njs_str("new RegExp('', 'x')"),
      njs_str("SyntaxError: Invalid RegExp flags \"x\"") },

    { njs_str("new RegExp('', 'g ')"),
      njs_str("SyntaxError: Invalid RegExp flags \"g \"") },

    { njs_str("new RegExp('', '')"),
      njs_str("/(?:)/") },

    { njs_str("new RegExp('', {toString:()=>'g'})"),
      njs_str("/(?:)/g") },

    { njs_str("RegExp({})"),
      njs_str("/[object Object]/") },

    { njs_str("RegExp(true)"),
      njs_str("/true/") },

    { njs_str("RegExp(undefined)"),
      njs_str("/(?:)/") },

    { njs_str("RegExp('abc', undefined)"),
      njs_str("/abc/") },

    { njs_str("RegExp('abc', {})"),
      njs_str("SyntaxError: Invalid RegExp flags \"[object Object]\"") },

    { njs_str("RegExp(/expr/)"),
      njs_str("/expr/") },

    { njs_str("RegExp(/expr/i).ignoreCase"),
      njs_str("true") },

    { njs_str("RegExp(/expr/, 'x')"),
      njs_str("SyntaxError: Invalid RegExp flags \"x\"") },

    { njs_str("RegExp(new RegExp('expr'))"),
      njs_str("/expr/") },

    { njs_str("RegExp(RegExp('[^]+|[^][^]')).test('| \\na')"),
      njs_str("true") },

    { njs_str("RegExp('a++')"),
      njs_str("SyntaxError: Invalid regular expression \"a++\" nothing to repeat") },

    { njs_str("RegExp('[a++]')"),
      njs_str("/[a++]/") },

    { njs_str("RegExp(new RegExp('expr')).multiline"),
      njs_str("false") },

    { njs_str("RegExp(new RegExp('expr'), 'm').multiline"),
      njs_str("true") },

    { njs_str("new RegExp('[')"),
      njs_str("SyntaxError: "
              njs_pcre_var("pcre_compile2(\"[\") failed: missing terminating ] for character class at \"\"",
                           "pcre_compile(\"[\") failed: missing terminating ] for character class")) },

    { njs_str("new RegExp('['.repeat(16))"),
      njs_str("SyntaxError: "
              njs_pcre_var("pcre_compile2(\"[[[[[[[[[[[[[[[[\") failed: missing terminating ] for character class at \"\"",
                           "pcre_compile(\"[[[[[[[[[[[[[[[[\") failed: missing terminating ] for character class")) },

    { njs_str("new RegExp('\\\\')"),
      njs_str("SyntaxError: "
              njs_pcre_var("pcre_compile2(\"\\\") failed: \\ at end of pattern at \"\"",
                           "pcre_compile(\"\\\") failed: \\ at end of pattern")) },

    { njs_str("[0].map(RegExp().toString)"),
      njs_str("TypeError: \"this\" argument is not an object") },

    { njs_str("var arr = /\\1(A)/.exec('AA');"
              "[arr[0], arr[1]]"),
      njs_str("A,A") },

    /* Non-standard ECMA-262 features. */

    /* 0x10400 is not a surrogate pair of 0xD801 and 0xDC00. */

    { njs_str("var chars = '𐐀'; chars.length +' '+ chars.charCodeAt(0)"),
      njs_str("1 66560") },

    /* es5id: 6.1, 0x104A0 is not a surrogate pair of 0xD801 and 0xDCA0. */

    { njs_str("var chars = '𐒠'; chars.length +' '+ chars.charCodeAt(0)"),
      njs_str("1 66720") },

    /* Error object. */

    { njs_str("Error()"),
      njs_str("Error") },

    { njs_str("new Error()"),
      njs_str("Error") },

    { njs_str("Error('e')"),
      njs_str("Error: e") },

    { njs_str("Error(123)"),
      njs_str("Error: 123") },

    { njs_str("Error({toString(){return 'e'}})"),
      njs_str("Error: e") },

    { njs_str("Error([1,'α'])"),
      njs_str("Error: 1,α") },

    { njs_str("var e = TypeError(Error('e')); e"),
      njs_str("TypeError: Error: e") },

    { njs_str("Error('α'.repeat(33)).toString().length"),
      njs_str("40") },

    { njs_str("var e = Error('e'); e.name = {toString(){return 'E'}}; e"),
      njs_str("E: e") },

    { njs_str("var e = Error('e'); Object.defineProperty(e, 'name', {get(){return 'E'}}); e"),
      njs_str("E: e") },

    { njs_str("var e = Error('e'); e.name = ''; e"),
      njs_str("e") },

    { njs_str("var e = Error(); e.name = ''; e"),
      njs_str("") },

    { njs_str("var e = Error(); e.name = ''; e.message = 'e'; e"),
      njs_str("e") },

    { njs_str("Error('e').name + ': ' + Error('e').message"),
      njs_str("Error: e") },

    { njs_str("Error(1)"),
      njs_str("Error: 1") },

    { njs_str("Error.__proto__ == Function.prototype"),
      njs_str("true") },

    { njs_str("Error.prototype.name"),
      njs_str("Error") },

    { njs_str("Error.prototype.message"),
      njs_str("") },

    { njs_str("Error.prototype.constructor == Error"),
      njs_str("true") },

    { njs_str("Error.prototype.hasOwnProperty('constructor')"),
      njs_str("true") },

    { njs_str("Error().__proto__ == Error.prototype"),
      njs_str("true") },

    { njs_str("Error().__proto__.__proto__ == Object.prototype"),
      njs_str("true") },

    { njs_str("Error.prototype.message = 'm';"
              "Error.prototype.name = 'n';"
              "new Error()"),
      njs_str("n: m") },

    { njs_str("var e = RangeError('e'); Object.preventExtensions(e);e"),
      njs_str("RangeError: e") },

    /* AggregateError. */

    { njs_str("AggregateError()"),
      njs_str("TypeError: first argument is not iterable") },

    { njs_str("AggregateError([1, 2, 3])"),
      njs_str("AggregateError") },

    { njs_str("let e = AggregateError([1, 2, 3], 'm'); e.message"),
      njs_str("m") },

    { njs_str("let e = AggregateError([1, 2, 3], 'm'); e.errors"),
      njs_str("1,2,3") },

    { njs_str("let e = AggregateError('abc'); e.errors"),
      njs_str("a,b,c") },

    { njs_str("let e = AggregateError('1234567'); e.errors"),
      njs_str("1,2,3,4,5,6,7") },

    { njs_str("let e = AggregateError([1, 2, 3], 'm'); e"),
      njs_str("AggregateError: m") },

    { njs_str("var v = Object.defineProperty([], 1025, {get: () => 1});"
              "AggregateError(v).errors[23]"),
      njs_str("undefined") },

    { njs_str("var v = Object.defineProperty([], 2**20, {get: () => 1});"
              "AggregateError(v).errors[2**19]"),
      njs_str("undefined") },

    /* Memory object is immutable. */

    { njs_str("var e = MemoryError('e'); e.name = 'E'"),
      njs_str("TypeError: Cannot add property \"name\", object is not extensible") },

    { njs_str("EvalError.prototype.name"),
      njs_str("EvalError") },

    { njs_str("InternalError.prototype.name"),
      njs_str("InternalError") },

    { njs_str("RangeError.prototype.name"),
      njs_str("RangeError") },

    { njs_str("ReferenceError.prototype.name"),
      njs_str("ReferenceError") },

    { njs_str("SyntaxError.prototype.name"),
      njs_str("SyntaxError") },

    { njs_str("TypeError.prototype.name"),
      njs_str("TypeError") },

    { njs_str("URIError.prototype.name"),
      njs_str("URIError") },

    { njs_str("MemoryError.prototype.name"),
      njs_str("InternalError") },


    /* NativeErrors. */

    { njs_str(
        "var global = this;"
        "function isValidNativeError(e) {"
        "   var inst;"
        "   var proto = Object.getPrototypeOf(e) === Error;"
        "   var proto2 = e.__proto__ === Error;"
        "   var iproto = e().__proto__ === e.prototype;"
        "   var iproto2 = e().__proto__.__proto__ === Error.prototype;"
        "   var tpof = typeof e() === 'object';"
        "   var ctor = e.prototype.constructor === e;"
        "   var msg = e.prototype.message === '';"
        "   var name = e('e').toString() === `${e.prototype.name}: e`;"
        "   var name2 = (inst = e('e'), inst.name = 'E', inst.toString() === 'E: e');"
        "   var name3 = (inst = e('e'), inst.name = '', inst.toString() === 'e');"
        "   var name4 = e().toString() === `${e.prototype.name}`;"
        "   var name_prop = Object.getOwnPropertyDescriptor(e.prototype, 'message');"
        "   name_prop = name_prop.writable && !name_prop.enumerable && name_prop.configurable;"
        "   var own_proto_ctor = e.prototype.hasOwnProperty('constructor');"
        "   var props = Object.getOwnPropertyDescriptor(global, e.prototype.name);"
        "   props = props.writable && !props.enumerable && props.configurable;"
        "   var same = e === global[e.prototype.name];"
        ""
        "   return proto && proto2 && iproto && iproto2 "
        "          && tpof && ctor && msg && name && name2 && name3 && name4 "
        "          && name_prop && own_proto_ctor && props && same;"
        "};"
        "["
        "  EvalError,"
        "  InternalError,"
        "  RangeError,"
        "  ReferenceError,"
        "  SyntaxError,"
        "  TypeError,"
        "  URIError,"
        "].every(e => isValidNativeError(e))"),
      njs_str("true") },

    /* Exceptions. */

    { njs_str("throw null"),
      njs_str("null") },

    { njs_str("var a; try { throw null } catch (e) { a = e } a"),
      njs_str("null") },

    { njs_str("var a; try { throw Error('e') } catch (e) { a = e.message } a"),
      njs_str("e") },

    { njs_str("var a; try { NaN.toString(NaN) } catch (e) { a = e.name } a"),
      njs_str("RangeError") },

    { njs_str("try { throw null } catch (e) { throw e }"),
      njs_str("null") },

    { njs_str("try { throw Error('e') } catch (e) { throw Error(e.message + '2') }"),
      njs_str("Error: e2") },

    { njs_str("try { throw null } catch (null) { throw e }"),
      njs_str("SyntaxError: Unexpected token \"null\"") },

    { njs_str("'a'.f()"),
      njs_str("TypeError: undefined is not a function") },

    { njs_str("1..f()"),
      njs_str("TypeError: undefined is not a function") },

    { njs_str("try {}"),
      njs_str("SyntaxError: Missing catch or finally after try") },

    { njs_str("try{}catch(a[]"),
      njs_str("SyntaxError: Unexpected token \"[\"") },

    { njs_str("function f(a) {return a;}; "
                 "function thrower() {throw TypeError('Oops')}; "
                 "f(thrower())"),
      njs_str("TypeError: Oops") },

    { njs_str("var a = 0; try { a = 5 }"
                 "catch (e) { a = 9 } finally { a++ } a"),
      njs_str("6") },

    { njs_str("var a = 0; try { throw 3 }"
                 "catch (e) { a = e } finally { a++ } a"),
      njs_str("4") },

    { njs_str("var a = 0; try { throw 3 }"
                 "catch (e) { throw e + 1 } finally { a++ }"),
      njs_str("4") },

    { njs_str("var a = 0; try { throw 3 }"
                 "catch (e) { a = e } finally { throw a }"),
      njs_str("3") },

    { njs_str("try { throw null } catch (e) { } finally { }"),
      njs_str("undefined") },

    { njs_str("var a = 0; try { throw 3 }"
                 "catch (e) { throw 4 } finally { throw a }"),
      njs_str("0") },

    { njs_str("var a = 0; try { a = 5 } finally { a++ } a"),
      njs_str("6") },

    { njs_str("var a = 0; try { throw 5 } finally { a++ }"),
      njs_str("5") },

    { njs_str("var a = 0; try { a = 5 } finally { throw 7 }"),
      njs_str("7") },

    { njs_str("function f(a) {"
                 "   if (a > 1) return f(a - 1);"
                 "   throw 9; return a }"
                 "var a = 0; try { a = f(5); a++ } catch(e) { a = e } a"),
      njs_str("9") },

    { njs_str("var a; try { try { throw 5 } catch (e) { a = e } throw 3 }"
                 "       catch(x) { a += x } a"),
      njs_str("8") },

    { njs_str("throw\nnull"),
      njs_str("SyntaxError: Illegal newline after throw") },

    { njs_str("for (var x in [1,2]) { try{ continue; } catch(e) {} } throw 1"),
      njs_str("1") },

    { njs_str("for (var x in [1,2]) { try{ break; } catch(e) {} } throw 1"),
      njs_str("1") },

    { njs_str("try\n {\n continue; } catch(e) {}"),
      njs_str("SyntaxError: Illegal continue statement") },

    { njs_str("var a = 1; "
                 "switch (a) {"
                 "default:"
                 "  try\n {\n continue; } "
                 "  catch(e) {}"
                 "}"),
      njs_str("SyntaxError: Illegal continue statement") },

    { njs_str("try\n {\n break; } catch(e) {}"),
      njs_str("SyntaxError: Illegal break statement") },

    { njs_str("try\n { }\n catch(e) {continue;}"),
      njs_str("SyntaxError: Illegal continue statement") },

    { njs_str("try { } catch(e) {break;}"),
      njs_str("SyntaxError: Illegal break statement") },

    { njs_str("try { continue; } finally {}"),
      njs_str("SyntaxError: Illegal continue statement") },

    { njs_str("try { break; } finally {}"),
      njs_str("SyntaxError: Illegal break statement") },

    { njs_str("try\n {\n try\n {\n continue; } finally {} } finally {}"),
      njs_str("SyntaxError: Illegal continue statement") },

    /* break from try in try/catch. */

    { njs_str("function f(n) {"
                 "    var pre = 0; var post = 0;"
                 "    for (var x in [1, 2, 3]) {"
                 "        pre++;"
                 "        try { "
                 "            if (n == 'b') {break;}"
                 "        }"
                 "        catch (e) {};"
                 "        post++"
                 "    }"
                 "    return [pre, post];"
                 "}; njs.dump([f(),f('b')])"),
      njs_str("[[3,3],"
                  "[1,0]]") },

    { njs_str("function f(v, n) {"
                 "    var pre = 0; var post = 0; var case2 = 0;"
                 "    switch (v) {"
                 "    case 1: "
                 "        pre++;"
                 "        try { "
                 "            if (n == 'b') {break;}"
                 "        }"
                 "        catch (e) {};"
                 "        post++;"
                 "        break;"
                 "    default:"
                 "        case2++;"
                 "    }"
                 "    return [pre, post, case2];"
                 "}; njs.dump([f(),f(1)])"),
      njs_str("[[0,0,1],"
                  "[1,1,0]]") },

    /* continue from try in try/catch. */

    { njs_str("function f(n) {"
                 "    var pre = 0; var post = 0;"
                 "    for (var x in [1, 2, 3]) {"
                 "        pre++;"
                 "        try { "
                 "            if (n == 'c') {continue;}"
                 "        }"
                 "        catch (e) {};"
                 "        post++"
                 "    }"
                 "    return [pre, post];"
                 "}; njs.dump([f(),f('c')])"),
      njs_str("[[3,3],"
                  "[3,0]]") },

    /* Multiple break/continue from try in try/catch. */

    { njs_str("function f(n) {"
                 "    var pre = 0; var mid = 0; var post = 0;"
                 "    for (var x in [1, 2, 3]) {"
                 "        pre++;"
                 "        try { "
                 "            if (n == 'c') {continue;}"
                 "            if (n == 'b') {break;}"
                 "            mid++;"
                 "            if (n == 'c2') {continue;}"
                 "            if (n == 'b2') {break;}"
                 "        }"
                 "        catch (e) {};"
                 "        post++"
                 "    }"
                 "    return [pre, mid, post];"
                 "}; njs.dump([f(),f('c'),f('b'),f('c2'),f('b2')])"),
      njs_str("[[3,3,3],"
                  "[3,0,0],"
                  "[1,0,0],"
                  "[3,3,0],"
                  "[1,1,0]]") },

    /* Multiple break/continue from catch in try/catch. */

    { njs_str("function f(t, n) {"
                 "    var pre = 0; var mid = 0; var post = 0;"
                 "    for (var x in [1, 2, 3]) {"
                 "        pre++;"
                 "        try { "
                 "            if (t) {throw 'a'}"
                 "        }"
                 "        catch (e) {"
                 "            if (n == 'c') {continue;}"
                 "            if (n == 'b') {break;}"
                 "            mid++;"
                 "            if (n == 'c2') {continue;}"
                 "            if (n == 'b2') {break;}"
                 "        };"
                 "        post++"
                 "    }"
                 "    return [pre, mid, post];"
                 "}; njs.dump([f(), f(1), f(1, 'c'), f(1, 'b'), f(1, 'c2'), f(1, 'b2')])"),
      njs_str("[[3,0,3],"
                  "[3,3,3],"
                  "[3,0,0],"
                  "[1,0,0],"
                  "[3,3,0],"
                  "[1,1,0]]") },

    /* break from try in try/finally. */

    { njs_str("function f(n) {"
                 "    var pre = 0; var mid = 0; var fin = 0; var post = 0;"
                 "    for (var x in [1, 2, 3]) {"
                 "        pre++;"
                 "        try { "
                 "            if (n == 'c') {continue;}"
                 "            if (n == 'b') {break;}"
                 "            mid++;"
                 "            if (n == 'c2') {continue;}"
                 "            if (n == 'b2') {break;}"
                 "        }"
                 "        finally {fin++};"
                 "        post++"
                 "    }"
                 "    return [pre, mid, fin, post];"
                 "}; njs.dump([f(),f('c'),f('b'),f('c2'),f('b2')])"),
      njs_str("[[3,3,3,3],"
                  "[3,0,3,0],"
                  "[1,0,1,0],"
                  "[3,3,3,0],"
                  "[1,1,1,0]]") },

    /* Multiple break/continue from try in try/catch/finally. */

    { njs_str("function f(n) {"
                 "    var pre = 0; var mid = 0; var fin = 0; var post = 0;"
                 "    for (var x in [1, 2, 3]) {"
                 "        pre++;"
                 "        try { "
                 "            if (n == 'c') {continue;}"
                 "            if (n == 'b') {break;}"
                 "            mid++;"
                 "            if (n == 'c2') {continue;}"
                 "            if (n == 'b2') {break;}"
                 "        }"
                 "        catch (e) {}"
                 "        finally {fin++};"
                 "        post++"
                 "    }"
                 "    return [pre, mid, fin, post];"
                 "}; njs.dump([f(),f('c'),f('b'),f('c2'),f('b2')])"),
      njs_str("[[3,3,3,3],"
                  "[3,0,3,0],"
                  "[1,0,1,0],"
                  "[3,3,3,0],"
                  "[1,1,1,0]]") },

    /* Multiple break/continue from catch in try/catch/finally. */

    { njs_str("function f(t, n) {"
                 "    var pre = 0; var mid = 0; var fin = 0; var post = 0;"
                 "    for (var x in [1, 2, 3]) {"
                 "        pre++;"
                 "        try {if (t) {throw 'a'}}"
                 "        catch (e) { "
                 "            if (n == 'c') {continue;}"
                 "            if (n == 'b') {break;}"
                 "            mid++;"
                 "            if (n == 'c2') {continue;}"
                 "            if (n == 'b2') {break;}"
                 "        }"
                 "        finally {fin++};"
                 "        post++"
                 "    }"
                 "    return [pre, mid, fin, post];"
                 "}; njs.dump([f(), f(1), f(1, 'c'), f(1, 'b'), f(1, 'c2'), f(1, 'b2')])"),
      njs_str("[[3,0,3,3],"
                  "[3,3,3,3],"
                  "[3,0,3,0],"
                  "[1,0,1,0],"
                  "[3,3,3,0],"
                  "[1,1,1,0]]") },

    /* Multiple return from try. */

    { njs_str("var r = 0; "
                 "function f(i, n) {"
                 "   try { "
                 "      var a = 'x'; "
                 "      if (i != 0) {"
                 "         return a.repeat(n);"
                 "      } else {"
                 "         return;"
                 "      }"
                 "   }"
                 "   catch (e) {  } "
                 "   finally { r++; }};"
                 "[f(1,1), f(1,2), f(0), r]"),
      njs_str("x,xx,,3") },

    { njs_str("var r = 0; "
                 "function f(i) {"
                 "   try { "
                 "      return i;"
                 "   }"
                 "   catch (e) {  } "
                 "   finally { r++; }};"
                 "[f(true), f(false), r]"),
      njs_str("true,false,2") },

    /* Multiple return from catch. */

    { njs_str("var r = 0; "
                 "function f(i, n) {"
                 "   try { "
                 "      throw 1;"
                 "   }"
                 "   catch (e) {  "
                 "      var a = 'x'; "
                 "      if (i != 0) {"
                 "         return a.repeat(n);"
                 "      } else {"
                 "         return;"
                 "      }"
                 "   } "
                 "   finally { r++; }};"
                 "[f(1,1), f(1,2), f(0), r]"),
      njs_str("x,xx,,3") },

    /* return overrun by finally. */

    { njs_str("function f() {"
                 "   try { "
                 "      return 'a';"
                 "   }"
                 "   catch (e) {  "
                 "   } "
                 "   finally { "
                 "      return 'b'; "
                 "   }}; "
                 "f()"),
      njs_str("b") },

    { njs_str("(function (f, val) { "
                 "  try { return f(val); } "
                 "  finally { return val; }"
                 "})(function () {throw 'a'}, 'v')"),
      njs_str("v") },

    { njs_str("(function() { try { return ['a'];} finally {} } )()"),
      njs_str("a") },

    { njs_str("function f(){}; try {f((new RegExp('a**')))} catch (e) { }"),
      njs_str("undefined") },

    { njs_str("function f(){}; try {f(f((new RegExp('a**'))))} catch (e) { }"),
      njs_str("undefined") },

    { njs_str("function f(){}; (function(){try {f(f((new RegExp('a**'))))} catch (e) { return 1}})()"),
      njs_str("1") },

    { njs_str("var before, during, after;"
              ""
              "try {"
              "    throw 'exception';"
              "} catch (err) {"
              "    before = err;"
              ""
              "    for (var err in { name: null }) {"
              "        during = err;"
              "    }"
              ""
              "    after = err;"
              "}"
              ""
              "[before === 'exception', during === 'name', after === 'name']"),
      njs_str("true,true,true") },

    { njs_str("var arr = [];"
              "foo = \"outside\";"
              ""
              "try {"
              "    throw new Error();"
              "}"
              "catch (foo) {"
              "    var foo = \"inside\";"
              "    arr.push(foo);"
              "}"
              ""
              "arr.push(foo);"
              "arr"),
      njs_str("inside,outside") },

    { njs_str("var o = { valueOf: function() { return '3' } }; --o"),
      njs_str("2") },

    { njs_str("var o = { valueOf: function() { return [3] } }; --o"),
      njs_str("NaN") },

    { njs_str("var o = { valueOf: function() { return '3' } }; 10 - o"),
      njs_str("7") },

    { njs_str("var o = { valueOf: function() { return [3] } }; 10 - o"),
      njs_str("NaN") },

    { njs_str("var o = { toString: function() { return 'OK' } }; 'o:' + o"),
      njs_str("o:OK") },

    { njs_str("var o = { toString: function() { return [1] } }; o"),
      njs_str("TypeError: Cannot convert object to primitive value") },

    { njs_str("var o = { toString: function() { return [1] } }; 'o:' + o"),
      njs_str("TypeError: Cannot convert object to primitive value") },

    { njs_str("var a = { valueOf: function() { return '3' } };"
                 "var b = { toString: function() { return 10 - a + 'OK' } };"
                 "var c = { toString: function() { return b + 'YES' } };"
                 "'c:' + c"),
      njs_str("c:7OKYES") },

    { njs_str("[1,2,3].valueOf()"),
      njs_str("1,2,3") },

    { njs_str("var o = { valueOf: function() { return 'OK' } };"
                 "o.valueOf()"),
      njs_str("OK") },

    { njs_str("false.__proto__ === true.__proto__"),
      njs_str("true") },

    { njs_str("0..__proto__ === 1..__proto__"),
      njs_str("true") },

    { njs_str("[].__proto__ === [1,2].__proto__"),
      njs_str("true") },

    { njs_str("/./.__proto__ === /a/.__proto__"),
      njs_str("true") },

    { njs_str("''.__proto__ === 'abc'.__proto__"),
      njs_str("true") },

    { njs_str("[].__proto__.join.call([1,2,3], ':')"),
      njs_str("1:2:3") },

    { njs_str("''.__proto__.concat.call('a', 'b', 'c')"),
      njs_str("abc") },

    { njs_str("/./.__proto__.test.call(/a{2}/, 'aaa')"),
      njs_str("true") },

    { njs_str("true instanceof Boolean"),
      njs_str("false") },

    { njs_str("1 instanceof Number"),
      njs_str("false") },

    { njs_str("'' instanceof String"),
      njs_str("false") },

    { njs_str("({}) instanceof Object"),
      njs_str("true") },

    { njs_str("[] instanceof []"),
      njs_str("TypeError: right argument is not callable") },

    { njs_str("[] instanceof Array"),
      njs_str("true") },

    { njs_str("[] instanceof Object"),
      njs_str("true") },

    { njs_str("/./ instanceof RegExp"),
      njs_str("true") },

    { njs_str("/./ instanceof Object"),
      njs_str("true") },

    { njs_str("Object.defineProperty(Function.prototype, \"prototype\", {get: ()=>Array.prototype});"
                 "[] instanceof Function.prototype"),
      njs_str("true") },

     { njs_str("Object.defineProperty(Function.prototype, \"prototype\", {get: ()=>{throw Error('Oops')}});"
                 "[] instanceof Function.prototype"),
      njs_str("Error: Oops") },

     { njs_str("var o = {};"
                 "Object.defineProperty(o, 'foo', { get: function() {return () => 1} });"
                 "o.foo()"),
      njs_str("1") },

    /* global this. */

    { njs_str("this"),
      njs_str("[object global]") },

    { njs_str("Object.getOwnPropertyDescriptor(this, 'NaN').value"),
      njs_str("NaN") },

    { njs_str("Object.getOwnPropertyDescriptors(this).NaN.value"),
      njs_str("NaN") },

    { njs_str("Object.getOwnPropertyNames(this).includes('NaN')"),
      njs_str("true") },

    { njs_str("this.a = 1; this.a"),
      njs_str("1") },

    { njs_str("this.a = 1; a"),
      njs_str("1") },

    { njs_str("this.a = 1; a = 3; this.a"),
      njs_str("3") },

    { njs_str("this.a = 1; ++a; this.a"),
      njs_str("2") },

    { njs_str("this.a = 1; a += 3; this.a"),
      njs_str("4") },

    { njs_str("var b=11;"
              "var t = function () {b += 5; return b};"
              "t() === 16 && b === 16 && this.b === 16" ),
      njs_str("true") },

    { njs_str("this.c=15;"
              "var t = function () {c += 5; return c};"
              "t() === 20 && c === 20 && this.c === 20" ),
      njs_str("true") },

    { njs_str("--undefined"),
      njs_str("TypeError: Cannot assign to read-only property \"undefined\" of object") },

    { njs_str("this.a = 2; this.b = 3; a * b - a"),
      njs_str("4") },

    { njs_str("this.a = 1; a()"),
      njs_str("TypeError: number is not a function") },

    { njs_str("this.a = ()=>1; a()"),
      njs_str("1") },

    { njs_str("var a = 1; this.a = 42; a"),
      njs_str("42") },

    { njs_str("var a = 1; global.a = 42; a"),
      njs_str("42") },

    { njs_str("var a = 1; globalThis.a = 42; a"),
      njs_str("42") },

    { njs_str("global.a = 1; globalThis.a"),
      njs_str("1") },

    { njs_str("var a = {}; globalThis.a === a"),
      njs_str("true") },

    { njs_str("globalThis.a = 1; var a; a"),
      njs_str("1") },

    { njs_str("var count = 0; function f() {return ++count}; [f(), global.f()]"),
      njs_str("1,2") },

    { njs_str("Object.defineProperty(global, 'a', {value:1}); a"),
      njs_str("1") },

    { njs_str("Object.defineProperty(global, 'a', {get:()=>123}); a"),
      njs_str("123") },

    { njs_str("Object.defineProperties(global, {a:{value:1}, b:{value:2}}); [a,b]"),
      njs_str("1,2") },

#if 0 /* FIXME: for scope. */
    { njs_str("var r1 = global.a; for (var a = 1; false;) {}; [r1, global.a]"),
      njs_str(",") },
#endif

    { njs_str("var global = this;"
              "function isImmutableConstant(v) {"
              "    var d = Object.getOwnPropertyDescriptor(global, v);"
              "    return !d.writable && !d.enumerable && !d.configurable;"
              "};"
              "['undefined', 'NaN', 'Infinity'].every((v)=>isImmutableConstant(v))"),
      njs_str("true") },

    { njs_str("this.undefined = 42"),
      njs_str("TypeError: Cannot assign to read-only property \"undefined\" of object") },

    { njs_str("this.Infinity = 42"),
      njs_str("TypeError: Cannot assign to read-only property \"Infinity\" of object") },

    { njs_str("this.NaN = 42"),
      njs_str("TypeError: Cannot assign to read-only property \"NaN\" of object") },

    { njs_str("typeof this.undefined"),
      njs_str("undefined") },

    { njs_str("typeof this.Infinity"),
      njs_str("number") },

    { njs_str("this.Infinity + 1"),
      njs_str("Infinity") },

    { njs_str("typeof this.NaN"),
      njs_str("number") },

    { njs_str("this.NaN + 1"),
      njs_str("NaN") },

    { njs_str("{this}"),
      njs_str("undefined") },

    { njs_str("if (1) {new this}"),
      njs_str("TypeError: object is not a function") },

    { njs_str("if (1) {this()}"),
      njs_str("TypeError: object is not a function") },

    { njs_str("var ex; try {new this} catch (e) {ex = e}; ex"),
      njs_str("TypeError: object is not a function") },

    { njs_str("var ex; try {({}) instanceof this} catch (e) {ex = e}; ex"),
      njs_str("TypeError: right argument is not callable") },

    { njs_str("delete global.global; global"),
      njs_str("ReferenceError: \"global\" is not defined") },

    { njs_str("njs"),
      njs_str("[object njs]") },

    { njs_str("var o = Object(); o"),
      njs_str("[object Object]") },

    { njs_str("var o = new Object(); o"),
      njs_str("[object Object]") },

    { njs_str("var o = new Object(1); o"),
      njs_str("1") },

    { njs_str("var o = {}; o === Object(o)"),
      njs_str("true") },

    { njs_str("var o = {}; o === new Object(o)"),
      njs_str("true") },

    { njs_str("var o = Object([]); Object.prototype.toString.call(o)"),
      njs_str("[object Array]") },

    { njs_str("Object.name"),
      njs_str("Object") },

    { njs_str("Object.length"),
      njs_str("1") },

    { njs_str("Object.__proto__ === Function.prototype"),
      njs_str("true") },

    { njs_str("Object.prototype.constructor === Object"),
      njs_str("true") },

    { njs_str("Object.prototype.hasOwnProperty('constructor')"),
      njs_str("true") },

    { njs_str("Object.prototype.__proto__ === null"),
      njs_str("true") },

    { njs_str("Object.prototype.__proto__ = {}"),
      njs_str("TypeError: Cyclic __proto__ value") },

    { njs_str("var o = {}; var o2 = Object.create(o); o.__proto__ = o2"),
      njs_str("TypeError: Cyclic __proto__ value") },

    { njs_str("Object.prototype.__proto__.f()"),
      njs_str("TypeError: cannot get property \"f\" of null") },

    { njs_str("var obj = Object.create(null); obj.one = 1;"
                 "var res = [];"
                 "for (var val in obj) res.push(val); res"),
      njs_str("one") },

    { njs_str("var o1 = Object.create(null); o1.one = 1;"
                 "var o2 = Object.create(o1); o2.two = 2;"
                 "var o3 = Object.create(o2); o3.three = 3;"
                 "var res = [];"
                 "for (var val in o3) res.push(val); res"),
      njs_str("three,two,one") },

    { njs_str("var o1 = Object.create(null); o1.one = 1;"
                 "var o2 = Object.create(o1);"
                 "var o3 = Object.create(o2); o3.three = 3;"
                 "var res = [];"
                 "for (var val in o3) res.push(val); res"),
      njs_str("three,one") },

    { njs_str("var o1 = Object.create(null); o1.one = 1;"
                 "var o2 = Object.create(o1);"
                 "var o3 = Object.create(o2);"
                 "var res = [];"
                 "for (var val in o3) res.push(val); res"),
      njs_str("one") },

    { njs_str("var o1 = Object.create(null); o1.one = 1;"
                 "var o2 = Object.create(o1); o2.two = 2;"
                 "var o3 = Object.create(o2); o3.three = 3;"
                 "o3.two = -2; o3.one = -1;"
                 "var res = [];"
                 "for (var val in o3) res.push(val); res"),
      njs_str("three,two,one") },

    { njs_str("var a = []; for(var p in 'abc') a.push(p); a"),
      njs_str("0,1,2") },

    { njs_str("var a = []; for(var p in Object('abc')) a.push(p); a"),
      njs_str("0,1,2") },

    { njs_str("var o = Object('abc'); var x = Object.create(o);"
                 "x.a = 1; x.b = 2;"
                 "var a = []; for(var p in x) a.push(p); a"),
      njs_str("a,b,0,1,2") },

    { njs_str("var o = Object.create(Math); o.abs = -5; Math.abs(o.abs)"),
      njs_str("5") },

    { njs_str("Object.prototype.toString.call(Object.prototype)"),
      njs_str("[object Object]") },

    { njs_str("Object.prototype.toString.call(new Array)"),
      njs_str("[object Array]") },

    { njs_str("Object.prototype.toString.call(new URIError)"),
      njs_str("[object Error]") },

    { njs_str("Object.prototype.toString.call(URIError.prototype)"),
      njs_str("[object Object]") },

    { njs_str("Object.prototype"),
      njs_str("[object Object]") },

    { njs_str("Object.prototype.valueOf.prototype"),
      njs_str("undefined") },

    { njs_str("Object.prototype.valueOf.call()"),
      njs_str("TypeError: cannot convert null or undefined to object") },

    { njs_str("Object.prototype.valueOf.call(null)"),
      njs_str("TypeError: cannot convert null or undefined to object") },

    { njs_str("[false, NaN, Symbol(), '']"
              ".map((x) => Object.prototype.valueOf.call(x))"
              ".map((x) => Object.prototype.toString.call(x))"),
      njs_str("[object Boolean],[object Number],[object Symbol],[object String]") },

    { njs_str("Object.constructor === Function"),
      njs_str("true") },

    { njs_str("({}).__proto__ === Object.prototype"),
      njs_str("true") },

    { njs_str("({}).__proto__ = 1"),
      njs_str("1") },

    { njs_str("({}).__proto__ = null"),
      njs_str("null") },

    { njs_str("({__proto__:null}).__proto__"),
      njs_str("undefined") },

    { njs_str("({__proto__:null, a:1}).a"),
      njs_str("1") },

    { njs_str("Object.getPrototypeOf({__proto__:null})"),
      njs_str("null") },

    { njs_str("Object.getPrototypeOf({__proto__:1}) === Object.prototype"),
      njs_str("true") },

    { njs_str("Object.getPrototypeOf({__proto__:Array.prototype}) === Array.prototype"),
      njs_str("true") },

    { njs_str("({__proto__: []}) instanceof Array"),
      njs_str("true") },

    { njs_str("({__proto__: Array.prototype}) instanceof Array"),
      njs_str("true") },

    { njs_str("var o = {};"
              "o.__proto__ = Array.prototype;"
              "Object.getPrototypeOf(o) === Array.prototype"),
      njs_str("true") },

    { njs_str("var o = Object.preventExtensions({});"
              "o.__proto__ = Array.prototype;"
              "Object.getPrototypeOf(o) === Object.prototype"),
      njs_str("true") },

    { njs_str("var o = {__proto__: Array.prototype, length:3}; o.fill('a')[2]"),
      njs_str("a") },

    { njs_str("({__proto__:null, __proto__: null})"),
      njs_str("SyntaxError: Duplicate __proto__ fields are not allowed in object literals") },

    { njs_str("({__proto__:null, '__proto__': null})"),
      njs_str("SyntaxError: Duplicate __proto__ fields are not allowed in object literals") },

    { njs_str("({__proto__:null, '\\x5f_proto__': null})"),
      njs_str("SyntaxError: Duplicate __proto__ fields are not allowed in object literals") },

    { njs_str("var __proto__ = 'a'; ({__proto__}).__proto__"),
      njs_str("a") },

    { njs_str("var __proto__ = 'a'; ({__proto__, '__proto__':'b'}).__proto__"),
      njs_str("a") },

    { njs_str("var __proto__ = 'a'; ({__proto__:null, __proto__}).__proto__"),
      njs_str("a") },

    { njs_str("({__proto__:null, ['__proto__']:'a'}).__proto__"),
      njs_str("a") },

    { njs_str("({__proto__() { return 123; }}).__proto__()"),
      njs_str("123") },

    { njs_str("({['__prot' + 'o__']: 123}).__proto__"),
      njs_str("123") },

    { njs_str("({}).__proto__.constructor === Object"),
      njs_str("true") },

    { njs_str("({}).constructor === Object"),
      njs_str("true") },

    { njs_str("({}).constructor()"),
      njs_str("[object Object]") },

    { njs_str("var a = Object.__proto__; a()"),
      njs_str("undefined") },

    { njs_str("Object.__proto__()"),
      njs_str("undefined") },

    { njs_str("var a = Array(3); a"),
      njs_str(",,") },

    { njs_str("var a = Array(); a.length"),
      njs_str("0") },

    { njs_str("var a = Array(0); a.length"),
      njs_str("0") },

    { njs_str("var a = Array(true); a"),
      njs_str("true") },

    { njs_str("var a = Array(1,'two',3); a"),
      njs_str("1,two,3") },

    { njs_str("var a = Array(-1)"),
      njs_str("RangeError: Invalid array length") },

    { njs_str("var a = Array(2.5)"),
      njs_str("RangeError: Invalid array length") },

    { njs_str("var a = Array(NaN)"),
      njs_str("RangeError: Invalid array length") },

    { njs_str("var a = Array(Infinity)"),
      njs_str("RangeError: Invalid array length") },

    { njs_str("var a = Array(1111111111); a[1111111112] = 1; a.length"),
      njs_str("1111111113") },

    { njs_str("var a = Array(1111111111); a[1111111112] = 1; a[1111111112]"),
      njs_str("1") },

    { njs_str("var a = Array(1111111111); a[1] = 2; a[1111111112] = 1; Object.keys(a)"),
      njs_str("1,1111111112") },

    { njs_str("var a = Array(1111111111); a[1] = 2; a[1111111112] = 1; Object.entries(a)"),
      njs_str("1,2,1111111112,1") },

    { njs_str("var x = Array(2**32)"),
      njs_str("RangeError: Invalid array length") },

    { njs_str("var x = Array(2**28)"),
      njs_str("undefined") },

    { njs_str("Array.prototype[2] = -1; var x = [0,1,3]; x.length = 2; x[2]"),
      njs_str("-1") },

    { njs_str("Array.prototype[1] = 1; var x = [0]; x.length = 2; x[1]"),
      njs_str("1") },

    { njs_str("var a = new Array(4); Object.defineProperty(a, '0', {enumerable:false}); a[2] = 's';"
              "Array.prototype.length"),
      njs_str("0") },

    { njs_str("var x = [0, 1, 2]; x[4294967294] = 4294967294; x.length = 2;"
              "njs.dump([x,x.length,Array.prototype.length])"),
      njs_str("[[0,1],2,0]") },

#if 0 /* TODO: length 2**53-1. */
    { njs_str("var x = Array(2**20), y = Array(2**12).fill(x);"
                 "Array.prototype.concat.apply(y[0], y.slice(1))"),
      njs_str("RangeError: Invalid array length") },
#endif

    { njs_str("var a = new Array(3); a"),
      njs_str(",,") },

    { njs_str("Array.name"),
      njs_str("Array") },

    { njs_str("Array.length"),
      njs_str("1") },

    { njs_str("delete this.Array; Array"),
      njs_str("ReferenceError: \"Array\" is not defined") },

    { njs_str("Array.__proto__ === Function.prototype"),
      njs_str("true") },

    { njs_str("Array.prototype.constructor === Array"),
      njs_str("true") },

    { njs_str("Array.prototype.hasOwnProperty('constructor')"),
      njs_str("true") },

    { njs_str("Array.prototype.__proto__ === Object.prototype"),
      njs_str("true") },

    { njs_str("Object.prototype.toString.call(Array.prototype)"),
      njs_str("[object Array]") },

    { njs_str("Array.prototype"),
      njs_str("") },

    { njs_str("Array.prototype.length"),
      njs_str("0") },

    { njs_str("Array.prototype.length = 3, Array.prototype"),
      njs_str(",,") },

    { njs_str("var o = Object.create(Array.prototype); o.length = 3;"
                 "[Array.prototype, Array.prototype.length, o.length]"),
      njs_str(",0,3") },

    { njs_str("var o = Object.create(Array.prototype);"
                 "Object.defineProperty(o, 'length', {value: 3});"
                 "[Array.prototype, Array.prototype.length, o.length]"),
      njs_str(",0,3") },

    { njs_str("Array.constructor === Function"),
      njs_str("true") },

    { njs_str("var a = []; a.join = 'OK'; a"),
      njs_str("[object Array]") },

    { njs_str("[].__proto__ === Array.prototype"),
      njs_str("true") },

    { njs_str("[].__proto__.constructor === Array"),
      njs_str("true") },

    { njs_str("[].constructor === Array"),
      njs_str("true") },

    { njs_str("([]).constructor()"),
      njs_str("") },

    { njs_str("Boolean()"),
      njs_str("false") },

    { njs_str("new Boolean()"),
      njs_str("false") },

    { njs_str("new Boolean"),
      njs_str("false") },

    { njs_str("Boolean(0)"),
      njs_str("false") },

    { njs_str("Boolean('')"),
      njs_str("false") },

    { njs_str("Boolean(1)"),
      njs_str("true") },

    { njs_str("Boolean('a')"),
      njs_str("true") },

    { njs_str("Boolean({})"),
      njs_str("true") },

    { njs_str("Boolean([])"),
      njs_str("true") },

    { njs_str("typeof Boolean(1)"),
      njs_str("boolean") },

    { njs_str("typeof new Boolean(1)"),
      njs_str("object") },

    { njs_str("typeof new Boolean"),
      njs_str("object") },

    { njs_str("Boolean.name"),
      njs_str("Boolean") },

    { njs_str("Boolean.length"),
      njs_str("1") },

    { njs_str("Boolean.__proto__ === Function.prototype"),
      njs_str("true") },

    { njs_str("Boolean.prototype.constructor === Boolean"),
      njs_str("true") },

    { njs_str("Boolean.prototype.constructor = 1;"
                 "Boolean.prototype.constructor"),
      njs_str("1") },

    { njs_str("var c = Boolean.prototype.constructor;"
                 "Boolean.prototype.constructor = 1;"
                 "[c(0), Boolean.prototype.constructor]"),
      njs_str("false,1") },

    { njs_str("Boolean.prototype.hasOwnProperty('constructor')"),
      njs_str("true") },

    { njs_str("Boolean.prototype.__proto__ === Object.prototype"),
      njs_str("true") },

    { njs_str("Object.prototype.toString.call(Boolean.prototype)"),
      njs_str("[object Boolean]") },

    { njs_str("Boolean.prototype"),
      njs_str("false") },

    { njs_str("Boolean.constructor === Function"),
      njs_str("true") },

    { njs_str("true.__proto__ === Boolean.prototype"),
      njs_str("true") },

    { njs_str("false.__proto__ === Boolean.prototype"),
      njs_str("true") },

    { njs_str("var b = Boolean(1); b.__proto__ === Boolean.prototype"),
      njs_str("true") },

    { njs_str("var b = new Boolean(1); b.__proto__ === Boolean.prototype"),
      njs_str("true") },

    { njs_str("Boolean(1).toString() === 'true'"),
      njs_str("true") },

    { njs_str("Boolean(0).toString() === 'false'"),
      njs_str("true") },

    { njs_str("Number()"),
      njs_str("0") },

    { njs_str("new Number()"),
      njs_str("0") },

    { njs_str("new Number"),
      njs_str("0") },

    { njs_str("new Number(undefined)"),
      njs_str("NaN") },

    { njs_str("new Number(null)"),
      njs_str("0") },

    { njs_str("new Number(true)"),
      njs_str("1") },

    { njs_str("new Number(false)"),
      njs_str("0") },

    { njs_str("Number(undefined)"),
      njs_str("NaN") },

    { njs_str("Number(null)"),
      njs_str("0") },

    { njs_str("Number(true)"),
      njs_str("1") },

    { njs_str("Number(false)"),
      njs_str("0") },

    { njs_str("Number('0b111')"),
      njs_str("7") },

    { njs_str("Number('0B111')"),
      njs_str("7") },

    { njs_str("Number('0B111 ')"),
      njs_str("7") },

    { njs_str("Number('0B111  1')"),
      njs_str("NaN") },

    { njs_str("Number('0b1_11')"),
      njs_str("NaN") },

    { njs_str("Number('-0b111')"),
      njs_str("NaN") },

    { njs_str("Number('0b111.')"),
      njs_str("NaN") },

    { njs_str("Number('0b111.1')"),
      njs_str("NaN") },

    { njs_str("Number(123)"),
      njs_str("123") },

    { njs_str("Number('123')"),
      njs_str("123") },

    { njs_str("Number('0o123')"),
      njs_str("83") },

    { njs_str("Number('0O123')"),
      njs_str("83") },

    { njs_str("Number('0O123   ')"),
      njs_str("83") },

    { njs_str("Number('0o1_23')"),
      njs_str("NaN") },

    { njs_str("Number('-0o123')"),
      njs_str("NaN") },

    { njs_str("Number('0o123.')"),
      njs_str("NaN") },

    { njs_str("Number('0o123.4')"),
      njs_str("NaN") },

    { njs_str("Number('0x123')"),
      njs_str("291") },

    { njs_str("Number('0X123')"),
      njs_str("291") },

    { njs_str("Number('0X123   ')"),
      njs_str("291") },

    { njs_str("Number('0x1_23')"),
      njs_str("NaN") },

    { njs_str("Number('-0x123')"),
      njs_str("NaN") },

    { njs_str("Number('0x123.')"),
      njs_str("NaN") },

    { njs_str("Number('0x123.4')"),
      njs_str("NaN") },

    { njs_str("['1', ' 1 ', '1\\t', '1\\n', '1\\r\\n'].reduce((a, x) => a + Number(x), 0)"),
      njs_str("5") },

    { njs_str("Number('0.'+'1'.repeat(128))"),
      njs_str("0.1111111111111111") },

    { njs_str("Number('1'.repeat(128))"),
      njs_str("1.1111111111111112e+127") },

    { njs_str("Number('1'.repeat(129))"),
      njs_str("1.1111111111111112e+128") },

    { njs_str("Number('1'.repeat(129))"),
      njs_str("1.1111111111111112e+128") },

    { njs_str("Number('1'.repeat(129)+'e-100')"),
      njs_str("1.1111111111111112e+28") },

    { njs_str("Number('1'.repeat(310))"),
      njs_str("Infinity") },

    { njs_str("var o = { valueOf: function() { return 123 } };"
                 "Number(o)"),
      njs_str("123") },

    { njs_str("var o = { valueOf: function() { return 123 } };"
                 "new Number(o)"),
      njs_str("123") },

    { njs_str("typeof Number(1)"),
      njs_str("number") },

    { njs_str("typeof new Number(1)"),
      njs_str("object") },

    { njs_str("typeof new Number"),
      njs_str("object") },

    { njs_str("Number.name"),
      njs_str("Number") },

    { njs_str("Number.length"),
      njs_str("1") },

    { njs_str("Number.__proto__ === Function.prototype"),
      njs_str("true") },

    { njs_str("Number.prototype.constructor === Number"),
      njs_str("true") },

    { njs_str("Number.prototype.hasOwnProperty('constructor')"),
      njs_str("true") },

    { njs_str("Number.prototype.__proto__ === Object.prototype"),
      njs_str("true") },

    { njs_str("Object.prototype.toString.call(Number.prototype)"),
      njs_str("[object Number]") },

    { njs_str("Number.prototype"),
      njs_str("0") },

    { njs_str("Number.constructor === Function"),
      njs_str("true") },

    { njs_str("0..__proto__ === Number.prototype"),
      njs_str("true") },

    { njs_str("var n = Number(1); n.__proto__ === Number.prototype"),
      njs_str("true") },

    { njs_str("var n = new Number(1); n.__proto__ === Number.prototype"),
      njs_str("true") },

    { njs_str("Number.isFinite()"),
      njs_str("false") },

    { njs_str("Number.isFinite(123)"),
      njs_str("true") },

    { njs_str("Number.isFinite('123')"),
      njs_str("false") },

    { njs_str("Number.isFinite(Infinity)"),
      njs_str("false") },

    { njs_str("Number.isFinite(NaN)"),
      njs_str("false") },

    { njs_str("Number.isInteger()"),
      njs_str("false") },

    { njs_str("Number.isInteger('123')"),
      njs_str("false") },

    { njs_str("Number.isInteger(123)"),
      njs_str("true") },

    { njs_str("Number.isInteger(-123.0)"),
      njs_str("true") },

    { njs_str("Number.isInteger(123.4)"),
      njs_str("false") },

    { njs_str("Number.isInteger(Infinity)"),
      njs_str("false") },

    { njs_str("Number.isInteger(NaN)"),
      njs_str("false") },

    { njs_str("Number.isSafeInteger()"),
      njs_str("false") },

    { njs_str("Number.isSafeInteger('123')"),
      njs_str("false") },

    { njs_str("Number.isSafeInteger(9007199254740991)"),
      njs_str("true") },

    { njs_str("Number.isSafeInteger(-9007199254740991.0)"),
      njs_str("true") },

    { njs_str("Number.isSafeInteger(9007199254740992)"),
      njs_str("false") },

    { njs_str("Number.isSafeInteger(-9007199254740992.0)"),
      njs_str("false") },

    { njs_str("Number.isSafeInteger(123.4)"),
      njs_str("false") },

    { njs_str("Number.isSafeInteger(Infinity)"),
      njs_str("false") },

    { njs_str("Number.isSafeInteger(-Infinity)"),
      njs_str("false") },

    { njs_str("Number.isSafeInteger(NaN)"),
      njs_str("false") },

    { njs_str("Number.isNaN()"),
      njs_str("false") },

    { njs_str("Number.isNaN('NaN')"),
      njs_str("false") },

    { njs_str("Number.isNaN(NaN)"),
      njs_str("true") },

    { njs_str("Number.isNaN(123)"),
      njs_str("false") },

    { njs_str("Number.isNaN(Infinity)"),
      njs_str("false") },

#if 0
    { njs_str("parseFloat === Number.parseFloat"),
      njs_str("true") },

    { njs_str("parseInt === Number.parseInt"),
      njs_str("true") },
#endif

    /* Symbol */

    { njs_str("typeof Symbol"),
      njs_str("function") },

    { njs_str("this.Symbol === Symbol"),
      njs_str("true") },

    { njs_str("Symbol.name"),
      njs_str("Symbol") },

    { njs_str("Object.getOwnPropertyDescriptor(Symbol, 'name').configurable"),
      njs_str("true") },

    { njs_str("Symbol.length"),
      njs_str("0") },

    { njs_str("Object.getOwnPropertyDescriptor(Symbol, 'length').configurable"),
      njs_str("true") },

    { njs_str("typeof Symbol.for"),
      njs_str("function") },

    { njs_str("Symbol.for.length"),
      njs_str("1") },

    { njs_str("typeof Symbol.keyFor"),
      njs_str("function") },

    { njs_str("Symbol.keyFor.length"),
      njs_str("1") },

    { njs_str("Symbol.prototype.constructor === Symbol"),
      njs_str("true") },

    { njs_str("Symbol.prototype.__proto__ === Object.prototype"),
      njs_str("true") },

    { njs_str("Object.prototype.toString.call(Symbol.prototype)"),
      njs_str("[object Symbol]") },

    { njs_str("Symbol.prototype.toString()"),
      njs_str("TypeError: unexpected value type:object") },

    { njs_str("Symbol.prototype[Symbol.toPrimitive].length"),
      njs_str("1") },

    { njs_str("Symbol.prototype[Symbol.toPrimitive].name"),
      njs_str("[Symbol.toPrimitive]") },

    { njs_str("Symbol.prototype[Symbol.toPrimitive].call(undefined)"),
      njs_str("TypeError: unexpected value type") },

    { njs_str("Symbol.prototype[Symbol.toPrimitive].call(null)"),
      njs_str("TypeError: unexpected value type") },

    { njs_str("Symbol.prototype[Symbol.toPrimitive].call(86)"),
      njs_str("TypeError: unexpected value type") },

    { njs_str("Symbol.prototype[Symbol.toPrimitive].call('')"),
      njs_str("TypeError: unexpected value type") },

    { njs_str("Symbol.prototype[Symbol.toPrimitive].call(true)"),
      njs_str("TypeError: unexpected value type") },

    { njs_str("Symbol.prototype[Symbol.toPrimitive].call({})"),
      njs_str("TypeError: unexpected value type") },

    { njs_str("Object(Symbol.toPrimitive)[Symbol.toPrimitive]() === Symbol.toPrimitive"),
      njs_str("true") },

    { njs_str("Symbol.toPrimitive[Symbol.toPrimitive]() === Symbol.toPrimitive"),
      njs_str("true") },

    { njs_str("new Symbol()"),
      njs_str("TypeError: Symbol is not a constructor") },

    { njs_str("typeof Symbol()"),
      njs_str("symbol") },

    { njs_str("typeof Symbol('desc')"),
      njs_str("symbol") },

    { njs_str("Symbol() === Symbol()"),
      njs_str("false") },

    { njs_str("Symbol('desc') === Symbol('desc')"),
      njs_str("false") },

    { njs_str("Symbol() == Symbol()"),
      njs_str("false") },

    { njs_str("Symbol('desc') == Symbol('desc')"),
      njs_str("false") },

    { njs_str("var syms = Array(6000).fill(0).map(() => Symbol());"
              "for (var i = 0; i < syms.length; i++) {"
              "    for (var j = i + 1; j < i + 3 && j < syms.length; j++) {"
              "        if (syms[i] === syms[j]) { throw `Failed: ${i} === ${j}`; }"
              "    }"
              "}"
              "true"),
      njs_str("true") },

    { njs_str("Symbol() == true"),
      njs_str("false") },

    { njs_str("Symbol() == false"),
      njs_str("false") },

    { njs_str("Symbol() != true"),
      njs_str("true") },

    { njs_str("Symbol() != 0"),
      njs_str("true") },

    { njs_str("Symbol() != ''"),
      njs_str("true") },

    { njs_str("Symbol() != undefined"),
      njs_str("true") },

    { njs_str("typeof Object(Symbol())"),
      njs_str("object") },

    { njs_str("typeof Object(Symbol('desc'))"),
      njs_str("object") },

    { njs_str("var x = Symbol(), o = Object(x); x == o"),
      njs_str("true") },

    { njs_str("var x = Symbol(), o = Object(x); o == x"),
      njs_str("true") },

    { njs_str("var x = Symbol(), o = Object(x); x !== o"),
      njs_str("true") },

    { njs_str("var x = Symbol(), o = Object(x); x === o.valueOf()"),
      njs_str("true") },

    { njs_str("var x = Symbol(); Object(x) == Object(x)"),
      njs_str("false") },

    { njs_str("!Symbol()"),
      njs_str("false") },

    { njs_str("!!Symbol()"),
      njs_str("true") },

    { njs_str("(Symbol('a') && Symbol('b')).toString()"),
      njs_str("Symbol(b)") },

    { njs_str("(Symbol('a') || Symbol('b')).toString()"),
      njs_str("Symbol(a)") },

    { njs_str("+Symbol()"),
      njs_str("TypeError: Cannot convert a Symbol value to a number") },

    { njs_str("-Symbol()"),
      njs_str("TypeError: Cannot convert a Symbol value to a number") },

    { njs_str("~Symbol()"),
      njs_str("TypeError: Cannot convert a Symbol value to a number") },

    { njs_str("var x = Symbol(); ++x"),
      njs_str("TypeError: Cannot convert a Symbol value to a number") },

    { njs_str("var x = Symbol(); x++"),
      njs_str("TypeError: Cannot convert a Symbol value to a number") },

    { njs_str("var x = Symbol(); --x"),
      njs_str("TypeError: Cannot convert a Symbol value to a number") },

    { njs_str("var x = Symbol(); x--"),
      njs_str("TypeError: Cannot convert a Symbol value to a number") },

    { njs_str("var msg = 'Cannot convert a Symbol value to a number',"
              "    ops = ['+', '-', '*', '**', '/', '%', '>>>', '>>', '<<',"
              "           '&', '|', '^', '<', '<=', '>', '>='],"
              "    test = (lhs, rhs, cls, msg, stop, op) => {"
              "        if (stop) {"
              "            return stop;"
              "        }"
              "        var op = `${lhs} ${op} ${rhs}`;"
              "        try {"
              "            (new Function(op))();"
              "        } catch (e) {"
              "            if (e instanceof cls && msg == e.message) {"
              "                return '';"
              "            }"
              "        }"
              "        return `'${op}' - failed`;"
              "   };"
              "ops.reduce(test.bind({}, 'Symbol()', '42', TypeError, msg), '') ||"
              "ops.reduce(test.bind({}, '42', 'Symbol()', TypeError, msg), '');"),
      njs_str("") },

    { njs_str("Symbol() > 'abc'"),
      njs_str("TypeError: Cannot convert a Symbol value to a number") },

    { njs_str("'abc' > Symbol()"),
      njs_str("TypeError: Cannot convert a Symbol value to a number") },

    { njs_str("'abc' + Symbol()"),
      njs_str("TypeError: Cannot convert a Symbol value to a string") },

    { njs_str("Symbol() + 'abc'"),
      njs_str("TypeError: Cannot convert a Symbol value to a string") },

    { njs_str("Math.min(Symbol())"),
      njs_str("TypeError: Cannot convert a Symbol value to a number") },

    { njs_str("[Symbol(), Symbol()].join()"),
      njs_str("TypeError: Cannot convert a Symbol value to a string") },

    { njs_str("Symbol().toString()"),
      njs_str("Symbol()") },

    { njs_str("Symbol('desc').toString()"),
      njs_str("Symbol(desc)") },

    { njs_str("Symbol('α'.repeat(16)).toString()"),
      njs_str("Symbol(αααααααααααααααα)") },

    { njs_str("Symbol(undefined).toString()"),
      njs_str("Symbol()") },

    { njs_str("Symbol(null).toString()"),
      njs_str("Symbol(null)") },

    { njs_str("Symbol(123).toString()"),
      njs_str("Symbol(123)") },

    { njs_str("Symbol(false).toString()"),
      njs_str("Symbol(false)") },

    { njs_str("Symbol(Symbol()).toString()"),
      njs_str("TypeError: Cannot convert a Symbol value to a string") },

    { njs_str("var all = [ 'asyncIterator',"
              "            'hasInstance',"
              "            'isConcatSpreadable',"
              "            'iterator',"
              "            'match',"
              "            'matchAll',"
              "            'replace',"
              "            'search',"
              "            'species',"
              "            'split',"
              "            'toPrimitive',"
              "            'toStringTag',"
              "            'unscopables' ]; "
              "Object.getOwnPropertyNames(Symbol)"
              ".filter((x) => typeof Symbol[x] == 'symbol')"
              ".length == all.length"),
      njs_str("true") },

    { njs_str("var all = [ 'asyncIterator',"
              "            'hasInstance',"
              "            'isConcatSpreadable',"
              "            'iterator',"
              "            'match',"
              "            'matchAll',"
              "            'replace',"
              "            'search',"
              "            'species',"
              "            'split',"
              "            'toPrimitive',"
              "            'toStringTag',"
              "            'unscopables' ]; "
              "Object.getOwnPropertyNames(Symbol)"
              ".filter((x) => typeof Symbol[x] == 'symbol')"
              ".filter((x, i) => !all.includes(x))"),
      njs_str("") },

    { njs_str("Object.getOwnPropertyNames(Symbol)"
              ".filter((x) => typeof Symbol[x] == 'symbol')"
              ".map(x => ({ k: x, v: Symbol[x] }))"
              ".every((x) => 'Symbol(Symbol.' + x.k + ')' == String(x.v))"),
      njs_str("true") },

    { njs_str("Symbol.for('desc').toString()"),
      njs_str("Symbol(desc)") },

    { njs_str("Symbol.for({toString: () => 'desc'}).description"),
      njs_str("desc") },

    { njs_str("Symbol.for().toString()"),
      njs_str("Symbol(undefined)") },

    { njs_str("Symbol.for('desc') === Symbol.for('desc')"),
      njs_str("true") },

    { njs_str("Symbol.keyFor(Symbol())"),
      njs_str("undefined") },

    { njs_str("Symbol.keyFor(Symbol('desc'))"),
      njs_str("undefined") },

    { njs_str("Symbol.keyFor(1)"),
      njs_str("TypeError: is not a symbol") },

    { njs_str("Symbol.keyFor(Symbol.for('desc'))"),
      njs_str("desc") },

    { njs_str("[ 'asyncIterator',"
              "  'hasInstance',"
              "  'isConcatSpreadable',"
              "  'iterator',"
              "  'match',"
              "  'matchAll',"
              "  'replace',"
              "  'search',"
              "  'species',"
              "  'split',"
              "  'toPrimitive',"
              "  'toStringTag',"
              "  'unscopables' ]"
              ".every(v => Symbol.keyFor(Symbol[v]) === undefined)"),
      njs_str("true") },

    { njs_str("typeof Symbol.prototype.description"),
      njs_str("TypeError: unexpected value type:object") },

    { njs_str("Symbol.prototype.description = 1"),
      njs_str("TypeError: Cannot set property \"description\" of object which has only a getter") },

    { njs_str("typeof Symbol().description"),
      njs_str("undefined") },

    { njs_str("Symbol('desc').description"),
      njs_str("desc") },

    { njs_str("Symbol.iterator.description"),
      njs_str("Symbol.iterator") },

    { njs_str("var o = {}; o[Symbol.isConcatSpreadable] = true; "
              "o[Symbol.isConcatSpreadable]"),
      njs_str("true") },

    { njs_str("var o = {[Symbol.isConcatSpreadable]:true}; "
              "o[Symbol.isConcatSpreadable]"),
      njs_str("true") },

    { njs_str("var o = {[Symbol.isConcatSpreadable]:true}; "
              "delete o[Symbol.isConcatSpreadable];"
              "o[Symbol.isConcatSpreadable]"),
      njs_str("undefined") },

    { njs_str("var o = {get [Symbol.isConcatSpreadable](){return true}}; "
              "o[Symbol.isConcatSpreadable]"),
      njs_str("true") },

    { njs_str("({[Symbol.isConcatSpreadable]:()=>true})[Symbol.isConcatSpreadable]()"),
      njs_str("true") },

    { njs_str("var o = {a:1, [Symbol.isConcatSpreadable]:true}; "
              "["
              " 'getOwnPropertyNames',"
              " 'keys', "
              " 'getOwnPropertySymbols',"
              " 'getOwnPropertyDescriptors',"
               "]"
              ".map(v=>Object[v](o)).map(v=>njs.dump(v))"),
      njs_str("['a'],['a'],[Symbol(Symbol.isConcatSpreadable)],"
              "{a:{value:1,writable:true,enumerable:true,configurable:true},"
              "Symbol(Symbol.isConcatSpreadable):{value:true,writable:true,enumerable:true,configurable:true}}") },

    { njs_str("var o = {}; o[Symbol.isConcatSpreadable] = true; "
              "Object.getOwnPropertyDescriptors(o)[Symbol.isConcatSpreadable].value"),
      njs_str("true") },

    { njs_str("var o = Object.defineProperties({}, {[Symbol.isConcatSpreadable]:{value:true}}); "
              "o[Symbol.isConcatSpreadable]"),
      njs_str("true") },

    { njs_str("var o = Object.defineProperty({}, Symbol.isConcatSpreadable, "
              "{configurable:false, writable:false, value:true}); "
              "o[Symbol.isConcatSpreadable]"),
      njs_str("true") },

    { njs_str("var o = {}; o[Symbol.isConcatSpreadable] = true; "
              "Object.getOwnPropertyDescriptor(o, Symbol.isConcatSpreadable).value"),
      njs_str("true") },

    { njs_str("var a = [1];"
              "var b = [2, /**/, 4, 5];"
              "Object.defineProperty(b.__proto__, 1, {"
              "    get: () => {"
              "        b.length = 10**6;"
              "        return 3;"
              "    }"
              "});"
              "a.concat(b)"),
      njs_str("1,2,3,4,5") },

    { njs_str("Boolean.prototype.length = 2;"
              "Boolean.prototype[0] = 'a';"
              "Boolean.prototype[1] = 'b';"
              "Boolean.prototype[Symbol.isConcatSpreadable] = true;"
              "[].concat(new Boolean(true))"),
      njs_str("a,b") },

    { njs_str("var o = {}, n = 5381 /* NJS_DJB_HASH_INIT */;"
              "while(n--) o[Symbol()] = 'test'; o[''];"),
      njs_str("undefined") },

    { njs_str("var symA = Symbol('A'); var obj = {[symA]:1}; Object.freeze(obj); "
              "obj[symA] = 2"),
      njs_str("TypeError: Cannot assign to read-only property \"Symbol(A)\" of object") },

    { njs_str("var symA = Symbol('A'); var obj = {[symA]:1}; Object.freeze(obj); "
              "delete obj[symA]"),
      njs_str("TypeError: Cannot delete property \"Symbol(A)\" of object") },

    { njs_str("typeof Object.getOwnPropertySymbols(globalThis);"),
      njs_str("object") },

    { njs_str("["
              " Object.prototype,"
              " Symbol.prototype,"
              " Math,"
              " JSON,"
              " process,"
              " njs,"
              " this,"
               "]"
              ".map(v=>Object.getOwnPropertyDescriptor(v, Symbol.toStringTag))"
              ".map(d=>{if (d && !d.writable && !d.enumerable && d.configurable) return d.value})"
              ".map(v=>njs.dump(v))"),
      njs_str("undefined,Symbol,Math,JSON,process,njs,global") },

    /* String */

    { njs_str("String()"),
      njs_str("") },

    { njs_str("new String()"),
      njs_str("") },

    { njs_str("new String"),
      njs_str("") },

    { njs_str("String(123)"),
      njs_str("123") },

    { njs_str("new String(123)"),
      njs_str("123") },

    { njs_str("String(Symbol())"),
      njs_str("Symbol()") },

    { njs_str("String(Symbol('desc'))"),
      njs_str("Symbol(desc)") },

    { njs_str("new String(Symbol())"),
      njs_str("TypeError: Cannot convert a Symbol value to a string") },

    { njs_str("String(Object(Symbol()))"),
      njs_str("TypeError: Cannot convert a Symbol value to a string") },

    { njs_str("Object('123').length"),
      njs_str("3") },

    { njs_str("new String(123).length"),
      njs_str("3") },

    { njs_str("new String(123).toString()"),
      njs_str("123") },

    { njs_str("String([1,2,3])"),
      njs_str("1,2,3") },

    { njs_str("new String([1,2,3])"),
      njs_str("1,2,3") },

    { njs_str("var s = new String('αβ'); s.one = 1; 'one' in s"),
      njs_str("true") },

    { njs_str("var s = new String('αβ'); 'one' in s"),
      njs_str("false") },

    { njs_str("var s = new String('αβ'); s.one = 1; '1' in s"),
      njs_str("true") },

    { njs_str("var s = new String('αβ'); s.one = 1; 1 in s"),
      njs_str("true") },

    { njs_str("var s = new String('αβ'); s.one = 1; 2 in s"),
      njs_str("false") },

    { njs_str("var s = new String('αβ'); s[1]"),
      njs_str("β") },

    { njs_str("Object.create(new String('αβ'))[1]"),
      njs_str("β") },

    { njs_str("var s = new String('αβ'); s[1] = 'b'"),
      njs_str("TypeError: Cannot assign to read-only property \"1\" of object") },

    { njs_str("var o = Object.create(new String('αβ')); o[1] = 'a'"),
      njs_str("TypeError: Cannot assign to read-only property \"1\" of object") },

    { njs_str("var s = new String('αβ'); s[4] = 'ab'; s[4]"),
      njs_str("ab") },

    { njs_str("Object.create(new String('αβ')).length"),
      njs_str("2") },

    { njs_str("var s = new String('αβ'); s.valueOf()[1]"),
      njs_str("β") },

    { njs_str("var o = { toString: function() { return 'OK' } };"
                 "String(o)"),
      njs_str("OK") },

    { njs_str("var o = { toString: function() { return 'OK' } };"
                 "new String(o)"),
      njs_str("OK") },

    { njs_str("typeof String('abc')"),
      njs_str("string") },

    { njs_str("typeof new String('abc')"),
      njs_str("object") },

    { njs_str("typeof new String"),
      njs_str("object") },

    { njs_str("String.name"),
      njs_str("String") },

    { njs_str("String.length"),
      njs_str("1") },

    /* values_hash long vs long string collision. */
    { njs_str("'XXXXXXXXXXXXXXXQWEEAB' + 'XXXXXXXXXXXXXXXZHGP'"),
      njs_str("XXXXXXXXXXXXXXXQWEEABXXXXXXXXXXXXXXXZHGP") },

    /* values_hash short vs long string collision. */
    { njs_str("'SHAAAB' + 'XXXXXXXXXXXXXXXUETBF'"),
      njs_str("SHAAABXXXXXXXXXXXXXXXUETBF") },

    /* values_hash long vs short string collision. */
    { njs_str("'XXXXXXXXXXXXXXXUETBF' + 'SHAAAB'"),
      njs_str("XXXXXXXXXXXXXXXUETBFSHAAAB") },

    /* values_hash short vs short string collision. */
    { njs_str("'XUBAAAB' + 'XGYXKY'"),
      njs_str("XUBAAABXGYXKY") },

    { njs_str("String.__proto__ === Function.prototype"),
      njs_str("true") },

    { njs_str("Object.prototype.toString.call(String.prototype)"),
      njs_str("[object String]") },

    { njs_str("String.prototype"),
      njs_str("") },

    { njs_str("String.prototype.length"),
      njs_str("0") },

    { njs_str("String.prototype.constructor === String"),
      njs_str("true") },

    { njs_str("String.prototype.hasOwnProperty('constructor')"),
      njs_str("true") },

    { njs_str("String.prototype.__proto__ === Object.prototype"),
      njs_str("true") },

    { njs_str("''.__proto__ === String.prototype"),
      njs_str("true") },

    { njs_str("String.constructor === Function"),
      njs_str("true") },

    { njs_str("'test'.__proto__ === String.prototype"),
      njs_str("true") },

    { njs_str("var s = String('abc'); s.__proto__ === String.prototype"),
      njs_str("true") },

    { njs_str("var s = new String('abc'); s.__proto__ === String.prototype"),
      njs_str("true") },

    { njs_str("'test'.constructor === String"),
      njs_str("true") },

    { njs_str("'test'.constructor.prototype === String.prototype"),
      njs_str("true") },

    { njs_str("var o = Object.create(String.prototype); o.length = 1"),
      njs_str("TypeError: Cannot assign to read-only property \"length\" of object") },

    { njs_str("Function.name"),
      njs_str("Function") },

    { njs_str("Function.length"),
      njs_str("1") },

    { njs_str("Function.__proto__ === Function.prototype"),
      njs_str("true") },

    { njs_str("Function.prototype.constructor === Function"),
      njs_str("true") },

    { njs_str("Function.prototype.hasOwnProperty('constructor')"),
      njs_str("true") },

    { njs_str("Function.prototype.__proto__ === Object.prototype"),
      njs_str("true") },

    { njs_str("Object.prototype.toString.call(Function.prototype)"),
      njs_str("[object Function]") },

    { njs_str("Function.prototype"),
      njs_str("[object Function]") },

    { njs_str("Function.prototype.length"),
      njs_str("0") },

    { njs_str("Function.constructor === Function"),
      njs_str("true") },

    { njs_str("Function.constructor()"),
      njs_str("[object Function]") },

    { njs_str("function f() {} f.__proto__ === Function.prototype"),
      njs_str("true") },

    { njs_str("Function()"),
      njs_str("[object Function]") },

    { njs_str("new Function();"),
      njs_str("[object Function]") },

    { njs_str("(function(){}).constructor === Function"),
      njs_str("true") },

    { njs_str("new Function('('.repeat(2**13));"),
      njs_str("SyntaxError: Unexpected token \"}\"") },

    { njs_str("new Function('{'.repeat(2**13));"),
      njs_str("SyntaxError: Unexpected token \")\"") },

    { njs_str("new Function('['.repeat(2**13));"),
      njs_str("SyntaxError: Unexpected token \"}\"") },

    { njs_str("new Function('`'.repeat(2**13));"),
      njs_str("[object Function]") },

    { njs_str("new Function('{['.repeat(2**13));"),
      njs_str("SyntaxError: Unexpected token \"}\"") },

    { njs_str("new Function('{;'.repeat(2**13));"),
      njs_str("SyntaxError: Unexpected token \")\"") },

    { njs_str("(new Function('1;'.repeat(2**13) + 'return 2'))()"),
      njs_str("2") },

    { njs_str("(new Function('return' + '~'.repeat(2**13) + '3'))()"),
      njs_str("3") },

    { njs_str("(new Function('return' + '~'.repeat(2**13+1) + '3'))()"),
      njs_str("-4") },

    { njs_str("new Function('new '.repeat(2**13));"),
      njs_str("SyntaxError: Unexpected token \"}\"") },

    { njs_str("(new Function('return ' + 'typeof '.repeat(2**13) + 'x'))()"),
      njs_str("string") },

    { njs_str("(new Function('return 5' + '** 1'.repeat(2**13)))()"),
      njs_str("5") },

    { njs_str("var a = (new Function('return [' + ','.repeat(2**16) + ']'))();"
              "njs.dump(a)"),
      njs_str("[<65536 empty items>]") },

    { njs_str("(new Function('var a = 7; return a' + '= a'.repeat(2**13)))()"),
      njs_str("7") },

    { njs_str("var a = (new Function('return [' + '1,'.repeat(2**13) + ']'))();"
              "a.push(5); [a[2**13 - 1], a[2**13]]"),
      njs_str("1,5") },

    { njs_str("var f = new Function('return 1;'); f();"),
      njs_str("1") },

    { njs_str("var sum = new Function('a', 'b', 'return a + b');"
              "sum(2, 4);"),
      njs_str("6") },

    { njs_str("var sum = new Function('a, b', 'return a + b');"
              "sum(2, 4);"),
      njs_str("6") },

    { njs_str("var sum = new Function('a, b', 'c', 'return a + b + c');"
              "sum(2, 4, 4);"),
      njs_str("10") },

    { njs_str("(new Function({ toString() { return '...a'; }}, { toString() { return 'return a;' }}))(1,2,3)"),
      njs_str("1,2,3") },

    { njs_str("var x = 10; function foo() { var x = 20; return new Function('return x;'); }"
              "var f = foo(); f()"),
      njs_str("10") },

    { njs_str("var fn = (function() { return new Function('return this'); }).call({}), o = {}; "
              "fn.call(o) == o && fn.bind(o).call(this) == o"),
      njs_str("true") },

    { njs_str("(new Function('return this'))() === globalThis"),
      njs_str("true") },

    { njs_str("var f = Function.call(this, 'return this.a');"
              "var r1 = f(); var a = 1; var r2 = f(); [r1,r2]"),
      njs_str(",1") },

    { njs_str("(new Function('a', 'return a')).length"),
      njs_str("1") },

    { njs_str("(new Function('a','b', 'return a + b')).length"),
      njs_str("2") },

    { njs_str("var o = {}; (new Function('return this')).call(o) === o"),
      njs_str("true") },

    { njs_str("(new Function('function foo(){return 1}; return foo()'))();"
              "foo"),
      njs_str("ReferenceError: \"foo\" is not defined") },

    { njs_str("this.NN = {}; var f = Function('eval = 42;'); f()"),
      njs_str("SyntaxError: Identifier \"eval\" is forbidden as left-hand in assignment") },

    { njs_str("new Function('}); let a; a; function o(){}; //')"),
      njs_str("SyntaxError: Unexpected token \"}\"") },

    { njs_str("new Function('}); let a; a; function o(){}; ({')"),
      njs_str("SyntaxError: single function literal required") },

    { njs_str("RegExp()"),
      njs_str("/(?:)/") },

    { njs_str("RegExp('')"),
      njs_str("/(?:)/") },

    { njs_str("RegExp(123)"),
      njs_str("/123/") },

    { njs_str("RegExp.name"),
      njs_str("RegExp") },

    { njs_str("RegExp.length"),
      njs_str("2") },

    { njs_str("RegExp.__proto__ === Function.prototype"),
      njs_str("true") },

    { njs_str("RegExp.prototype.constructor === RegExp"),
      njs_str("true") },

    { njs_str("RegExp.prototype.hasOwnProperty('constructor')"),
      njs_str("true") },

    { njs_str("RegExp.prototype.__proto__ === Object.prototype"),
      njs_str("true") },

    { njs_str("Object.prototype.toString.call(RegExp.prototype)"),
      njs_str("[object Object]") },

    { njs_str("RegExp.prototype"),
      njs_str("/(?:)/") },

    { njs_str("RegExp.constructor === Function"),
      njs_str("true") },

    { njs_str("/./.__proto__ === RegExp.prototype"),
      njs_str("true") },

    { njs_str("toString()"),
      njs_str("[object Undefined]") },

    { njs_str("toString() + Object.prototype.toString"),
      njs_str("[object Undefined][object Function]") },

#if 0
    { njs_str("toString === Object.prototype.toString"),
      njs_str("true") },

    { njs_str("Object.prototype.toString.yes = 'OK'; toString.yes"),
      njs_str("OK") },
#endif

    { njs_str("Object.prototype.toString.call()"),
      njs_str("[object Undefined]") },

    { njs_str("Object.prototype.toString.call().length"),
      njs_str("18") },

    { njs_str("Object.prototype.toString.call(undefined)"),
      njs_str("[object Undefined]") },

    { njs_str("Object.prototype.toString.call(null)"),
      njs_str("[object Null]") },

    { njs_str("Object.prototype.toString.call(true)"),
      njs_str("[object Boolean]") },

    { njs_str("Boolean.prototype[Symbol.toStringTag] = 'XXX';"
              "Object.prototype.toString.call(true)"),
      njs_str("[object XXX]") },

    { njs_str("Object.prototype.toString.call(1)"),
      njs_str("[object Number]") },

    { njs_str("Object.prototype.toString.call('')"),
      njs_str("[object String]") },

    { njs_str("Object.prototype.toString.call({})"),
      njs_str("[object Object]") },

    { njs_str("Object.prototype.toString.call([])"),
      njs_str("[object Array]") },

    { njs_str("var a = []; a[Symbol.toStringTag] = 'XXX';"
              "Object.prototype.toString.call(a)"),
      njs_str("[object XXX]") },

    { njs_str("Object.prototype.toString.call(new Object(true))"),
      njs_str("[object Boolean]") },

    { njs_str("Object.prototype.toString.call(new Number(1))"),
      njs_str("[object Number]") },

    { njs_str("Object.prototype.toString.call(new Object(1))"),
      njs_str("[object Number]") },

    { njs_str("Object.prototype.toString.call(new Object(Symbol()))"),
      njs_str("[object Symbol]") },

    { njs_str("Object.prototype.toString.call(new Object(Symbol('desc')))"),
      njs_str("[object Symbol]") },

    { njs_str("Object.prototype.toString.call(new Object(''))"),
      njs_str("[object String]") },

    { njs_str("Object.prototype.toString.call(function(){})"),
      njs_str("[object Function]") },

    { njs_str("var f = ()=>1; f[Symbol.toStringTag] = 'α'.repeat(32);"
              "var toStr = Object.prototype.toString.call(f); [toStr, toStr.length]"),
      njs_str("[object αααααααααααααααααααααααααααααααα],41") },

    { njs_str("Object.prototype.toString.call(/./)"),
      njs_str("[object RegExp]") },

    { njs_str("Object.prototype.toString.call(Math)"),
      njs_str("[object Math]") },

    { njs_str("Object.prototype.toString.call(JSON)"),
      njs_str("[object JSON]") },

    { njs_str("var p = { a:5 }; var o = Object.create(p); o.a"),
      njs_str("5") },

    { njs_str("var p = { a:5 }; var o = Object.create(p);"
                 "o.__proto__ === p"),
      njs_str("true") },

    /* Object.create() */

    { njs_str("var o = Object.create(Object.prototype);"
                 "o.__proto__ === Object.prototype"),
      njs_str("true") },

    { njs_str("var o = Object.create(null); '__proto__' in o"),
      njs_str("false") },

    { njs_str("Object.create()"),
      njs_str("TypeError: prototype may only be an object or null: undefined") },

    { njs_str("Object.create(1)"),
      njs_str("TypeError: prototype may only be an object or null: number") },

    { njs_str("var o = Object.create(null, { a: { value: 1 } }); o.a"),
      njs_str("1") },

    { njs_str("var o = Object.create({ a: 0 }, { a: { value: 1 } }); o.a"),
      njs_str("1") },

    { njs_str("var o = Object.create({ get a() { return this.b; } }, { b: { value: 1 } }); o.a"),
      njs_str("1") },

    { njs_str("var o = {a:1, b:2, c:3};"
                 "Object.keys(o)"),
      njs_str("a,b,c") },

    { njs_str("var a = []; a.one = 7; Object.keys(a)"),
      njs_str("one") },

    { njs_str("var a = [,,]; a.one = 7; Object.keys(a)"),
      njs_str("one") },

    { njs_str("var a = [,6,,3]; a.one = 7; Object.keys(a)"),
      njs_str("1,3,one") },

    { njs_str("var o = {a:1,b:2}; delete o.a; Object.keys(o)"),
      njs_str("b") },

    { njs_str("Object.keys()"),
      njs_str("TypeError: cannot convert undefined argument to object") },

    { njs_str("Object.keys('αβZ')"),
      njs_str("0,1,2") },

    { njs_str("Object.keys(new String('αβZ'))"),
      njs_str("0,1,2") },

    { njs_str("var s = new String('αβZ'); s.a = 1; Object.keys(s)"),
      njs_str("0,1,2,a") },

    { njs_str("var r = new RegExp('αbc'); r.a = 1; Object.keys(r)"),
      njs_str("a") },

    { njs_str("Object.keys(Object.create(new String('abc')))"),
      njs_str("") },

    { njs_str("Object.keys(1)"),
      njs_str("") },

    { njs_str("Object.keys(true)"),
      njs_str("") },

    { njs_str("var o = {a:3, b:2, c:1}; Object.values(o)"),
      njs_str("3,2,1") },

    { njs_str("Object.values('s')"),
      njs_str("s") },

    { njs_str("Object.values('абв abc')"),
      njs_str("а,б,в, ,a,b,c") },

    { njs_str("var s = new String('abc'); s.three = 3; Object.values(s)"),
      njs_str("a,b,c,3") },

    { njs_str("var a = [,,5,,4,,,3,2]; a.one = 1; Object.values(a)"),
      njs_str("5,4,3,2,1") },

    { njs_str("Object.values([{}, null, false, NaN, function() {}])"),
      njs_str("[object Object],,false,NaN,[object Function]") },

    { njs_str("Object.values(1)"),
      njs_str("") },

    { njs_str("Object.values(njs)[1] === njs.version"),
      njs_str("true") },

    { njs_str("njs.version.split('.')"
              ".map(v => parseInt(v)).reduce((p, c) => p * 256 + c) == njs.version_number"),
      njs_str("true") },

    { njs_str("Object.values(process)"),
      njs_str("") },

    { njs_str("Object.keys(process.env).sort()"),
      njs_str("DUP,TZ") },

    { njs_str("Object.values()"),
      njs_str("TypeError: cannot convert undefined argument to object") },

    { njs_str("Object.entries('abc')"),
      njs_str("0,a,1,b,2,c") },

    { njs_str("JSON.stringify(Object.entries('эюя'))"),
      njs_str("[[\"0\",\"э\"],[\"1\",\"ю\"],[\"2\",\"я\"]]") },

    { njs_str("var o = {a:\"а\", b:\"б\", c:\"ц\"};"
                 "JSON.stringify(Object.entries(o))"),
      njs_str("[[\"a\",\"а\"],[\"b\",\"б\"],[\"c\",\"ц\"]]") },

    { njs_str("JSON.stringify(Object.entries([0]))"),
      njs_str("[[\"0\",0]]") },

    { njs_str("var s = new String('αβ'); s.two = null; s[3] = true;"
                 "Object.entries(s)"),
      njs_str("0,α,1,β,3,true,two,") },

    { njs_str("Object.entries(true)"),
      njs_str("") },

    { njs_str("Object.entries(njs)[1][1] === njs.version"),
      njs_str("true") },

    { njs_str("Object.entries()"),
      njs_str("TypeError: cannot convert undefined argument to object") },

    { njs_str("var o = {}; Object.defineProperty(o, 'a', {}); o.a"),
      njs_str("undefined") },

    { njs_str("Object.defineProperty({}, 'a', {value:1})"),
      njs_str("[object Object]") },

    { njs_str("var o = {}; Object.defineProperty(o, 'a', {value:1}); o.a"),
      njs_str("1") },

    { njs_str("var o = {}; Object.defineProperty(o, 'a', Object.create({value:1})); o.a"),
      njs_str("1") },

    { njs_str("var o = {}; Object.defineProperty(o, 'a', {writable:'x', enumerable:'y', configurable:'z'});"
              "var d = Object.getOwnPropertyDescriptor(o, 'a');"
              "d.writable && d.enumerable && d.configurable"),
      njs_str("true") },

    { njs_str("var o = {a:1, c:2}; Object.defineProperty(o, 'b', {});"
                 "Object.keys(o)"),
      njs_str("a,c") },

    { njs_str("var o = {a:1, c:2};"
                 "Object.defineProperty(o, 'b', {enumerable:false});"
                 "Object.keys(o)"),
      njs_str("a,c") },

    { njs_str("var o = {a:1, c:3};"
                 "Object.defineProperty(o, 'b', {enumerable:true});"
                 "Object.keys(o)"),
      njs_str("a,c,b") },

    { njs_str("var o = {a:1, c:2}; Object.defineProperty(o, 'b', {});"
                 "Object.values(o)"),
      njs_str("1,2") },

    { njs_str("var o = {a:1, c:2};"
                 "Object.defineProperty(o, 'b', {enumerable:false, value:3});"
                 "Object.values(o)"),
      njs_str("1,2") },

    { njs_str("var o = {a:1, c:3};"
                 "Object.defineProperty(o, 'b', {enumerable:true, value:2});"
                 "Object.values(o)"),
      njs_str("1,3,2") },

    { njs_str("var o = { a: 'A', get b() { this.c = 'C'; return 'B'; } };"
              "Object.values(o).length"),
      njs_str("2") },

    { njs_str("var o = {a:1, c:2}; Object.defineProperty(o, 'b', {});"
                 "Object.entries(o)"),
      njs_str("a,1,c,2") },

    { njs_str("var o = {a:1, c:2};"
                 "Object.defineProperty(o, 'b', {enumerable:false, value:3});"
                 "Object.entries(o)"),
      njs_str("a,1,c,2") },

    { njs_str("var o = {a:1, c:3};"
                 "Object.defineProperty(o, 'b', {enumerable:true, value:2});"
                 "Object.entries(o)"),
      njs_str("a,1,c,3,b,2") },

    { njs_str("var o = { a: 'A', get b() { this.c = 'C'; return 'B'; } };"
              "Object.entries(o).length"),
      njs_str("2") },

    { njs_str("var o = {}; Object.defineProperty(o, 'a', {}); o.a = 1"),
      njs_str("TypeError: Cannot assign to read-only property \"a\" of object") },

    { njs_str("var o = {}; Object.defineProperty(o, 'a', {writable:false}); o.a = 1"),
      njs_str("TypeError: Cannot assign to read-only property \"a\" of object") },

    { njs_str("var o = {}; Object.defineProperty(o, 'a', {writable:true});"
                 "o.a = 1; o.a"),
      njs_str("1") },

    { njs_str("Object.defineProperty(Object.prototype, 'a', {writable:false});"
                 "var o = {a: 1}; [o.a++, o.a]"),
      njs_str("1,2") },

    { njs_str("var o = {};"
                 "Object.defineProperty(Object.prototype, 'a', {writable:false});"
                 "o.a = 1"),
      njs_str("TypeError: Cannot assign to read-only property \"a\" of object") },

    { njs_str("var o = {};"
                 "Object.defineProperty(Object.prototype, 'a', {writable:true});"
                 "o.a = 1; o.a"),
      njs_str("1") },

    { njs_str("var o = {a:1}; (o.a) = 2; o.a"),
      njs_str("2") },

    { njs_str("var o = {a:1}; (o.a)++; o.a"),
      njs_str("2") },

    { njs_str("var p = Object.create(Function);"
                 "Object.defineProperty(p, 'length', {writable: true});"
                 "p.length = 32; p.length"),
      njs_str("32") },

    { njs_str("var p = Object.create(Math.abs);"
                 "Object.defineProperty(p, 'length', {writable: true});"
                 "p.length = 23; p.length"),
      njs_str("23") },

    { njs_str("var o = {};"
                 "Object.defineProperty(o, 'a', {value:1}); delete o.a"),
      njs_str("TypeError: Cannot delete property \"a\" of object") },

    { njs_str("var o = {};"
                 "Object.defineProperty(o, 'a', {value:1, configurable:true});"
                 "delete o.a; o.a"),
      njs_str("undefined") },

    { njs_str("var o = {a:1}; delete (o.a); o.a"),
      njs_str("undefined") },

    { njs_str("var o = {};"
                 "Object.defineProperty(o, 'a', {value:1, configurable:false});"
                 "delete o.a"),
      njs_str("TypeError: Cannot delete property \"a\" of object") },

    { njs_str("var o = {};"
                 "Object.defineProperty(o, 'a', Object.create({value:2})); o.a"),
      njs_str("2") },

    { njs_str("var o = {};"
                 "Object.defineProperty(o, 'a', {configurable:false});"
                 "Object.defineProperty(o, 'a', {configurable:true})"),
      njs_str("TypeError: Cannot redefine property: \"a\"") },

    { njs_str("var o = {};"
                 "Object.defineProperty(o, 'a', {configurable:false});"
                 "Object.defineProperty(o, 'a', {enumerable:true})"),
      njs_str("TypeError: Cannot redefine property: \"a\"") },

    { njs_str("var o = {};"
                 "Object.defineProperty(o, 'a', {configurable:false});"
                 "Object.defineProperty(o, 'a', {writable:true})"),
      njs_str("TypeError: Cannot redefine property: \"a\"") },

    { njs_str("var o = {};"
                 "Object.defineProperty(o, 'a', {configurable:false});"
                 "Object.defineProperty(o, 'a', {enumerable:false}).a"),
      njs_str("undefined") },

    { njs_str("var o = {};"
                 "Object.defineProperty(o, 'a', {configurable:false});"
                 "Object.defineProperty(o, 'a', {}).a"),
      njs_str("undefined") },

    { njs_str("var o = {};"
                 "Object.defineProperty(o, 'a', {configurable:false, writable:true});"
                 "Object.defineProperty(o, 'a', {writable:false}).a"),
      njs_str("undefined") },

    { njs_str("var o = {};"
                 "Object.defineProperty(o, 'a', {configurable:true, writable:false});"
                 "Object.defineProperty(o, 'a', {writable:true}).a"),
      njs_str("undefined") },

    { njs_str("var o = {};"
                 "Object.defineProperty(o, 'a', {});"
                 "Object.defineProperty(o, 'a', {}).a"),
      njs_str("undefined") },

    { njs_str("var o = {};"
                 "Object.defineProperty(o, 'a', {value:1});"
                 "Object.defineProperty(o, 'a', {value:1}).a"),
      njs_str("1") },

    { njs_str("var o = {};"
                 "Object.defineProperty(o, 'a', {value:1});"
                 "Object.defineProperty(o, 'a', {value:2}).a"),
      njs_str("TypeError: Cannot redefine property: \"a\"") },

    { njs_str("var o = {};"
                 "Object.defineProperty(o, 'a', {configurable:true});"
                 "Object.defineProperty(o, 'a', {value:1}).a"),
      njs_str("1") },

    { njs_str("var o = {};"
                 "Object.defineProperty(o, 'a', {configurable:true, get:()=>1});"
                 "Object.defineProperty(o, 'a', {value:1});"
                 "var d = Object.getOwnPropertyDescriptor(o, 'a'); "
                 "[d.value, d.writable, d.enumerable, d.configurable, d.get, d.set]"),
      njs_str("1,false,false,true,,") },

    { njs_str("var o = {};"
                 "Object.defineProperty(o, 'a', {configurable:true, value:1});"
                 "Object.defineProperty(o, 'a', {set:()=>1});"
                 "var d = Object.getOwnPropertyDescriptor(o, 'a'); "
                 "[d.value, d.writable, d.enumerable, d.configurable, d.get, d.set]"),
      njs_str(",,false,true,,[object Function]") },

    { njs_str("var o = {}; Object.defineProperty(o, 'a', {get: ()=>1, configurable:true}); "
                 "Object.defineProperty(o, 'a', {value:123}); o.a =2"),
      njs_str("TypeError: Cannot assign to read-only property \"a\" of object") },

    { njs_str("var o = {}; Object.defineProperty(o, 'a', {get: ()=>1, configurable:true}); "
                 "Object.defineProperty(o, 'a', {writable:false}); o.a"),
      njs_str("undefined") },

    { njs_str("var o = {}; Object.defineProperty(o, 'a', {value: 1, configurable:true}); "
                 "Object.defineProperty(o, 'a', {get:()=>1}); o.a = 2"),
      njs_str("TypeError: Cannot set property \"a\" of object which has only a getter") },

    { njs_str("var o = Object.create(Object.defineProperty({}, 'x', { set: function(v) { this.y = v; }})); "
                 "o.x = 123; Object.getOwnPropertyDescriptor(o, 'y').value"),
      njs_str("123") },

    { njs_str("var o = {};"
                 "Object.defineProperty(o, 'a', { configurable: true, value: 0 });"
                 "Object.defineProperty(o, 'a', { value: 1 });"
                 "Object.defineProperty(o, 'a', { configurable: false, value: 2 }).a"),
      njs_str("2") },

    { njs_str("var o = {}; Object.defineProperty()"),
      njs_str("TypeError: Object.defineProperty is called on non-object") },

    { njs_str("var o = {}; Object.defineProperty(o)"),
      njs_str("TypeError: descriptor is not an object") },

    { njs_str("Object.defineProperty(Function.prototype, 'name', {value:'x'}).name"),
      njs_str("x") },

    { njs_str("Object.defineProperty(Function.prototype, 'xxx', {value:'x'}).xxx"),
      njs_str("x") },

    { njs_str("Object.defineProperty(Object, 'name', {value:'x'}).name"),
      njs_str("x") },

    { njs_str("Object.defineProperty(Object.prototype, 'toString', {value:1}).toString"),
      njs_str("1") },

    { njs_str("var o = Object.defineProperties({}, {a:{value:1}}); o.a"),
      njs_str("1") },

    { njs_str("var o = Object.defineProperties({}, {a:{enumerable:true}, b:{enumerable:true}});"
                 "Object.keys(o)"),
      njs_str("a,b") },

    { njs_str("var desc = Object.defineProperty({b:{value:1, enumerable:true}}, 'a', {});"
                 "var o = Object.defineProperties({}, desc);"
                 "Object.keys(o)"),
      njs_str("b") },

    { njs_str("var o = Object.defineProperties({}, { get x() { return { value: 1 }; } });"
              "Object.getOwnPropertyDescriptor(o, 'x').value"),
      njs_str("1") },

    { njs_str("Object.defineProperties({}, { get x() { return  1; } })"),
      njs_str("TypeError: property descriptor must be an object") },

    { njs_str("var obj = {}; var desc = {value:NaN}; Object.defineProperty(obj, 'foo', desc); "
              "Object.defineProperties(obj, { foo: desc } ).foo"),
      njs_str("NaN") },

    { njs_str("var obj = {}; var desc = {value:-0}; Object.defineProperty(obj, 'foo', desc); "
              "Object.defineProperties(obj, { foo: desc } ).foo"),
      njs_str("-0") },

    { njs_str("var obj = {}; var desc = {value:-0}; Object.defineProperty(obj, 'foo', {value:0}); "
              "Object.defineProperties(obj, { foo: desc } ).foo"),
      njs_str("TypeError: Cannot redefine property: \"foo\"") },

    { njs_str("var obj = {}; var desc = {value:0}; Object.defineProperty(obj, 'foo', {value:-0}); "
              "Object.defineProperties(obj, { foo: desc } ).foo"),
      njs_str("TypeError: Cannot redefine property: \"foo\"") },

    { njs_str("var descs = {a:{value:1}}; Object.defineProperty(descs, 'b', {value:{value:2}});"
              "var o = Object.defineProperties({}, descs);"
              "njs.dump([o.a, o.b])"),
      njs_str("[1,undefined]") },

    { njs_str("var descs = {a:{value:1}}; Object.defineProperty(descs, 'b', {value:{value:2}, enumerable:true});"
              "var o = Object.defineProperties({}, descs);"
              "njs.dump([o.a, o.b])"),
      njs_str("[1,2]") },

    { njs_str("var o = {a:1}; delete o.a;"
                 "Object.defineProperty(o, 'a', { value: 1 }); o.a"),
      njs_str("1") },

    { njs_str("var o = {a:1}; delete o.a;"
                 "Object.defineProperty(o, 'a', { value: 1 }); o.a = 2; o.a"),
      njs_str("TypeError: Cannot assign to read-only property \"a\" of object") },

    { njs_str("var o = {a:1}; delete o.a;"
                 "Object.defineProperty(o, 'a', { value: 1, writable:1 }); o.a = 2; o.a"),
      njs_str("2") },

    { njs_str("var o = {};"
                 "Object.defineProperty(o, new String('a'), { value: 1}); o.a"),
      njs_str("1") },

    { njs_str("var o = {};"
                 "Object.defineProperty(o, {toString:function(){return 'a'}}, { value: 1}); o.a"),
      njs_str("1") },

    { njs_str("var a = [1, 2];"
                 "Object.defineProperty(a, '1', {value: 5}); a[1]"),
      njs_str("5") },

    { njs_str("var a = [1, 2];"
                 "Object.defineProperty(a, '3', {}); njs.dump(a)"),
      njs_str("[1,2,<empty>,undefined]") },

    { njs_str("var a = [1, 2];"
                 "Object.defineProperty(a, 'length', {}); a"),
      njs_str("1,2") },

    { njs_str("var a = [1, 2];"
                 "Object.defineProperty(a, 'length', {value: 1}); a"),
      njs_str("1") },

    { njs_str("var a = [1, 2];"
                 "Object.defineProperty(a, 'length', {value: 5}); a"),
      njs_str("1,2,,,") },

    { njs_str("var o = Object.defineProperties({a:1}, {}); o.a"),
      njs_str("1") },

    { njs_str("var arr = [0, 1]; Object.defineProperty(arr, 'length', {value:3}); arr.length"),
      njs_str("3") },

    { njs_str("Object.defineProperty(Array.prototype, 'toString', { get: function() {return () => 1}});"
                 "'a' + []"),
      njs_str("a1") },

    { njs_str("Object.defineProperty(Array.prototype, 'toJSON', { get: function() {return () => 1}});"
                 "JSON.stringify([])"),
      njs_str("1") },

    { njs_str("Object.defineProperty(Array.prototype, 'join', { get: function() {return () => 1}});"
                 "([]).toString()"),
      njs_str("1") },

    { njs_str("var o = {}, desc = {};"
              "Object.defineProperty(desc, 'get', { get() { return () => 1 } });"
              "Object.defineProperty(o, 'a', desc); o.a"),
      njs_str("1") },

    { njs_str("Object.defineProperty(Error.prototype, 'message', { get() {return 'm'}});"
                 "Object.defineProperty(Error.prototype, 'name', { get() {return 'n'}});"
                 "Error()"),
      njs_str("n: m") },

    { njs_str("var o = {}, desc = {};"
              "Object.defineProperty(desc, 'value', { get() { return 'x'}});"
              "Object.defineProperty(o, 'a', desc); o.a"),
      njs_str("x") },

    { njs_str("var o = {}, desc = {};"
              "Object.defineProperty(desc, 'value', { get() { return 'x'}});"
              "Object.defineProperty(desc, 'enumerable', { get() { return !NaN}});"
              "Object.defineProperty(desc, 'writable', { get() { return 'x'}});"
              "Object.defineProperty(desc, 'configurable', { get() { return 1}});"
              "Object.defineProperty(o, 'a', desc);"
              "var d = Object.getOwnPropertyDescriptor(o, 'a');"
              "d.enumerable && d.writable && d.configurable"),
      njs_str("true") },

    { njs_str("const arr = [1,2];"
              "function f(arg) {"
              "        const desc = {get: arg};"
              "        Object.defineProperty(desc, 'set', desc);"
              "        Object.defineProperty(arr, 1, desc);"
              "}"
              "f(f);"
              "njs.dump(arr)"),
      njs_str("[1,'[Getter]']") },

    { njs_str("Object.defineProperties()"),
      njs_str("TypeError: Object.defineProperties is called on non-object") },

    { njs_str("Object.defineProperties(1, {})"),
      njs_str("TypeError: Object.defineProperties is called on non-object") },

    { njs_str("njs.dump(Object.defineProperties({}, 1))"),
      njs_str("{}") },

    { njs_str("Object.defineProperties(Object.freeze({b:1}), {b:{value:1}}).b"),
      njs_str("1") },

    { njs_str("Object.defineProperties(Object.freeze({b:1}), {b:{value:2}})"),
      njs_str("TypeError: Cannot redefine property: \"b\"") },

    { njs_str("Object.defineProperties(Object.freeze({b:1}), {c:{value:1}})"),
      njs_str("TypeError: Cannot add property \"c\", object is not extensible") },

    { njs_str("var o = {a:1}; o.hasOwnProperty('a')"),
      njs_str("true") },

    { njs_str("var o = Object.create({a:2}); o.hasOwnProperty('a')"),
      njs_str("false") },

    { njs_str("var o = {a:1}; o.hasOwnProperty('b')"),
      njs_str("false") },

    { njs_str("var a = []; a.hasOwnProperty('0')"),
      njs_str("false") },

    { njs_str("var a = [,,]; a.hasOwnProperty('0')"),
      njs_str("false") },

    { njs_str("var a = [3,,]; a.hasOwnProperty('0')"),
      njs_str("true") },

    { njs_str("var a = [,4]; a.hasOwnProperty('1')"),
      njs_str("true") },

    { njs_str("var a = [3,4]; a.hasOwnProperty('2')"),
      njs_str("false") },

    { njs_str("var a = [3,4]; a.one = 1; a.hasOwnProperty('one')"),
      njs_str("true") },

    { njs_str("var o = {a:1}; o.hasOwnProperty(o)"),
      njs_str("false") },

    { njs_str("var o = {a:1}; o.hasOwnProperty(1)"),
      njs_str("false") },

    { njs_str("var o = {a:1}; o.hasOwnProperty()"),
      njs_str("false") },

    { njs_str("[,].hasOwnProperty()"),
      njs_str("false") },

    { njs_str("[1,2].hasOwnProperty('len')"),
      njs_str("false") },

    { njs_str("[1,2].hasOwnProperty('0')"),
      njs_str("true") },

    { njs_str("[1,2].hasOwnProperty('2')"),
      njs_str("false") },

    { njs_str("[].hasOwnProperty('length')"),
      njs_str("true") },

    { njs_str("[1,2].hasOwnProperty('length')"),
      njs_str("true") },

    { njs_str("(new Array()).hasOwnProperty('length')"),
      njs_str("true") },

    { njs_str("(new Array(10)).hasOwnProperty('length')"),
      njs_str("true") },

    { njs_str("Object.valueOf.hasOwnProperty()"),
      njs_str("false") },

    { njs_str("1..hasOwnProperty('b')"),
      njs_str("false") },

    { njs_str("'s'.hasOwnProperty('b')"),
      njs_str("false") },

    { njs_str("'s'.hasOwnProperty('0')"),
      njs_str("true") },

    { njs_str("'s'.hasOwnProperty('1')"),
      njs_str("false") },

    { njs_str("Object.hasOwnProperty('hasOwnProperty')"),
      njs_str("false") },

    { njs_str("Object.prototype.hasOwnProperty('hasOwnProperty')"),
      njs_str("true") },

    { njs_str("var o = {a:1}; Object.hasOwn(o, 'a')"),
      njs_str("true") },

    { njs_str("var o = Object.create({a:2}); Object.hasOwn(o, 'a')"),
      njs_str("false") },

    { njs_str("var o = {a:1}; Object.hasOwn(o, 'b')"),
      njs_str("false") },

    { njs_str("var o = Object.create(null); o.a = 1; Object.hasOwn(o, 'a')"),
      njs_str("true") },

    { njs_str("var o = Object.create(null); Object.hasOwn(o, 'hasOwnProperty')"),
      njs_str("false") },

    { njs_str("var o = {hasOwnProperty: 1}; Object.hasOwn(o, 'hasOwnProperty')"),
      njs_str("true") },

    { njs_str("var o = {a:1}; o.hasOwnProperty = function(){return false}; "
              "Object.hasOwn(o, 'a')"),
      njs_str("true") },

    { njs_str("Object.hasOwn(null, 'a')"),
      njs_str("TypeError: cannot convert null argument to object") },

    { njs_str("Object.hasOwn(undefined, 'a')"),
      njs_str("TypeError: cannot convert undefined argument to object") },

    { njs_str("Object.hasOwn(1, 'toString')"),
      njs_str("true") },

    { njs_str("Object.hasOwn('abc', '0')"),
      njs_str("true") },

    { njs_str("Object.hasOwn('abc', '3')"),
      njs_str("false") },

    { njs_str("Object.hasOwn('abc', 'length')"),
      njs_str("true") },

    { njs_str("Object.hasOwn([1,2], '0')"),
      njs_str("true") },

    { njs_str("Object.hasOwn([,2], '0')"),
      njs_str("false") },

    { njs_str("Object.hasOwn([,2], '1')"),
      njs_str("true") },

    { njs_str("Object.hasOwn([], 'length')"),
      njs_str("true") },

    { njs_str("var s = Symbol('test'); var o = {}; o[s] = 1; Object.hasOwn(o, s)"),
      njs_str("true") },

    { njs_str("var s1 = Symbol('test'); var s2 = Symbol('test'); "
              "var o = {}; o[s1] = 1; Object.hasOwn(o, s2)"),
      njs_str("false") },

    { njs_str("Object.hasOwn({}, Symbol.iterator)"),
      njs_str("false") },

    { njs_str("Object.hasOwn()"),
      njs_str("TypeError: cannot convert ") },

    { njs_str("Object.hasOwn({})"),
      njs_str("false") },

    { njs_str("var o = {}; Object.hasOwn(o)"),
      njs_str("false") },

    { njs_str("Object.hasOwn.length"),
      njs_str("2") },

    { njs_str("Object.hasOwn.name"),
      njs_str("hasOwn") },

    { njs_str("var o = {};"
                 "Object.defineProperty(o, 'a', {get:undefined, set:undefined}).a"),
      njs_str("undefined") },

    { njs_str("var o = {};"
                 "Object.defineProperty(o, 'a', {get:1})"),
      njs_str("TypeError: Getter must be a function") },

    { njs_str("var o = {};"
                 "Object.defineProperty(o, 'a', {get:undefined}).a"),
      njs_str("undefined") },

    { njs_str("var o = {};"
                 "Object.defineProperty(o, 'a', {get:function(){return 1}}).a"),
      njs_str("1") },

    { njs_str("var o = {};"
                 "Object.defineProperty(o, 'a', {set:1})"),
      njs_str("TypeError: Setter must be a function") },

    { njs_str("var o = {};"
                 "Object.defineProperty(o, 'a', {set:undefined}); o.a"),
      njs_str("undefined") },

    { njs_str("var o = {};"
                 "Object.defineProperty(o, 'a', {set:undefined}); o.a = 4;"),
      njs_str("TypeError: Cannot set property \"a\" of object which has only a getter") },

    { njs_str("var o = {a: 0};"
                 "Object.defineProperty(o, 'b', {set:function(x){this.a = x / 2;}}); o.b = 4; o.a;"),
      njs_str("2") },

    { njs_str("var o = {};"
                 "Object.defineProperty(o, 'a', {value:undefined});"
                 "Object.defineProperty(o, 'a', {get:undefined})"),
      njs_str("TypeError: Cannot redefine property: \"a\"") },

    { njs_str("var o = {};"
                 "Object.defineProperty(o, 'a', {});"
                 "Object.defineProperty(o, 'a', {get:undefined})"),
      njs_str("TypeError: Cannot redefine property: \"a\"") },

    { njs_str("var o = {};"
                 "Object.defineProperty(o, 'a', {get:undefined});"
                 "Object.defineProperty(o, 'a', {get:undefined}).a"),
      njs_str("undefined") },

    { njs_str("var o = {};"
                 "Object.defineProperty(o, 'a', {get:undefined});"
                 "Object.defineProperty(o, 'a', {set:undefined}).a"),
      njs_str("undefined") },

    { njs_str("var o = {};"
                 "Object.defineProperty(o, 'a', {get:undefined});"
                 "Object.defineProperty(o, 'a', {}); o.a"),
      njs_str("undefined") },

    { njs_str("var o = {};"
                 "Object.defineProperty(o, 'a', {get:undefined});"
                 "Object.defineProperty(o, 'a', {set:function(){}})"),
      njs_str("TypeError: Cannot redefine property: \"a\"") },

    { njs_str("var o = {};"
                 "Object.defineProperty(o, 'a', {get:undefined});"
                 "Object.defineProperty(o, 'a', {get:function(){}})"),
      njs_str("TypeError: Cannot redefine property: \"a\"") },

    { njs_str("var o = {};"
                 "Object.defineProperty(o, 'a', {get:()=>1, configurable:true});"
                 "Object.defineProperty(o, 'a', {get:()=>2}); o.a"),
      njs_str("2") },

    { njs_str("var o = {};"
                 "Object.defineProperty(o, 'a', {set:function(v){this.aa=v;}, configurable:true});"
                 "Object.defineProperty(o, 'a', {get:function(){return this.aa}}); o.a = 1; o.a"),
      njs_str("1") },

    { njs_str("var o = {};"
                 "Object.defineProperty(o, 'a', {get:()=>1, configurable:true});"
                 "Object.defineProperty(o, 'a', {value:2}).a"),
      njs_str("2") },

    { njs_str("var o = {};"
                 "Object.defineProperty(o, 'a', {get:()=>1, configurable:true});"
                 "Object.defineProperty(o, 'a', {value:2});"
                 "var d = Object.getOwnPropertyDescriptor(o, 'a');"
                 "d.get === undefined && d.set === undefined"),
      njs_str("true") },

    { njs_str("var o = {};"
                 "Object.defineProperty(o, 'a', {value:1, configurable:true});"
                 "Object.defineProperty(o, 'a', {get:()=>2});"
                 "var d = Object.getOwnPropertyDescriptor(o, 'a');"
                 "d.writable === undefined && d.value === undefined"),
      njs_str("true") },

    { njs_str("Object.defineProperty(Date.prototype, 'year', {get: function() { return this.getFullYear();}});"
                 "var d = new Date(0); d.year"),
      njs_str("1970") },

    { njs_str("var o = [];"
                 "Object.defineProperty(o, 'fill', {get:undefined}).fill"),
      njs_str("undefined") },

    { njs_str("var o = [];"
                 "Object.defineProperty(o, 'length', {get:undefined})"),
      njs_str("TypeError: Cannot redefine property: \"length\"") },

    { njs_str("var o = {};"
                 "Object.defineProperty(o, 'foo', {get:()=>10});"
                 "Object.preventExtensions(o);Object.isFrozen(o)"),
      njs_str("true"), },

    { njs_str("var o = {}; Object.defineProperty(o, 'r', { get: function() { return this.r_value; } }); o.r_value = 1; o.r;"),
      njs_str("1") },

    { njs_str("var o = {}; Object.defineProperty(o, 'rw', { get: function() { return this.rw_value; }, set: function(x) { this.rw_value = x / 2; } }); o.rw = 10; o.rw"),
      njs_str("5") },

    { njs_str("var o = {}; function foo() {}; Object.defineProperty(o, 'a', {get: foo});"
                 "Object.getOwnPropertyDescriptor(o, 'a').get === foo"),
      njs_str("true") },

    { njs_str("var o = {}; Object.defineProperty(o, 'a', {get: undefined});"
                "JSON.stringify(Object.getOwnPropertyDescriptor(o, 'a')).set"),
      njs_str("undefined") },

    { njs_str("var a = []; Object.defineProperty(a, 4294967294, {value:100}); "
              "[a.hasOwnProperty('4294967294'), a.length, a[4294967294]]"),
      njs_str("true,4294967295,100") },

    { njs_str("var a = []; Object.defineProperty(a, 'length', {value:4294967294}); "
              "a.length"),
      njs_str("4294967294") },

    { njs_str("var a = []; Object.defineProperty(a, 'length', {value:4294967295}); "
              "a.length"),
      njs_str("4294967295") },

    { njs_str("njs.dump(Object.defineProperty([], 'length', {value:4294967295}))"),
      njs_str("[<4294967295 empty items>]") },

    { njs_str("var a = [1]; Object.defineProperty(a, '1', {get:()=>2}); "
              "[a[0], a[1], a.length]"),
      njs_str("1,2,2") },

    { njs_str("var a = [1,2,3]; Object.defineProperty(a, '1', {configurable:false}); "
              "[a[0], a[1], a.length]"),
      njs_str("1,2,3") },

    { njs_str("var a = [1,2,3]; Object.defineProperty(a, '1', {configurable:false}); "
              "delete a[1]"),
      njs_str("TypeError: Cannot delete property \"1\" of array") },

    { njs_str("var a = [1,2,3]; Object.defineProperty(a, '1', {configurable:false}); "
              "a.length = 1"),
      njs_str("TypeError: Cannot delete property \"1\" of array") },

    { njs_str("var a = [1,2,3]; Object.defineProperty(a, '1', {writable:false}); "
              "a[1]=4"),
      njs_str("TypeError: Cannot assign to read-only property \"1\" of array") },

    { njs_str("var a = [1,2,3]; Object.defineProperty(a, '1', {enumerable:false}); "
              "njs.dump([Object.keys(a), Object.values(a), Object.entries(a)])"),
      njs_str("[['0','2'],[1,3],[['0',1],['2',3]]]") },

    { njs_str("var a = [1]; Object.defineProperty(a, '1', {get:()=>2});"
              "Object.defineProperty(a, 'length', {value:1})"),
      njs_str("TypeError: Cannot delete property \"1\" of array") },

    { njs_str("var a = [1]; Object.defineProperty(a, '1', {get:()=>2});"
              "Object.defineProperty(a, 'length', {enumerable:true})"),
      njs_str("TypeError: Cannot redefine property: \"length\"") },

    { njs_str("var a = [1]; Object.defineProperty(a, '1', {get:()=>2, configurable:true});"
              "Object.defineProperty(a, 'length', {value:1}); a[1]"),
      njs_str("undefined") },

    { njs_str("var a = [1,2,3]; Object.defineProperty(a, '1', {enumerable:false});"
              "Object.getOwnPropertyDescriptor(a, '1').enumerable"),
      njs_str("false") },

    { njs_str("var args = (function(a, b, c) {return arguments;})(1,2,3); "
              "Object.defineProperty(args, \"length\", {value:6}); args.length"),
      njs_str("6") },

    { njs_str("var get = 'get'; var o = { get }; o.get"),
      njs_str("get") },

    { njs_str("var o = { get foo() { return 'bar'; } }; o.foo"),
      njs_str("bar") },

    { njs_str("var o = { get get() { return 'bar'; } }; o.get"),
      njs_str("bar") },

    { njs_str("var d = Object.getOwnPropertyDescriptor({ get a() { return 'bar'; } }, 'a');"
              "d.hasOwnProperty('set')"),
      njs_str("true") },

    { njs_str("var o = { get() { return 'bar'; } }; o.get()"),
      njs_str("bar") },

    { njs_str("var o = { get lazy() { delete this.lazy; return this.lazy = Math.pow(2,3)} };o.lazy"),
      njs_str("8") },

    { njs_str("var o = { get lazy() { delete this.lazy; return this.lazy = Math.pow(2,3)} }; o.lazy;"
              "Object.getOwnPropertyDescriptor(o, 'lazy').value"),
      njs_str("8") },

    { njs_str("var expr = 'foo'; var o = { get [expr]() { return 'bar'; } }; o.foo"),
      njs_str("bar") },

    { njs_str("var o = { get [{toString(){return 'get'}}]() { return 'bar'; } }; o.get"),
      njs_str("bar") },

    { njs_str("var o = { get [{toString(){return {} }}]() { return 'bar'; } }; o.get"),
      njs_str("InternalError: failed conversion of type \"object\" to string while property define") },

    { njs_str("var o = { get foo(v1, v2) { return 'bar'; } }; o.foo"),
      njs_str("SyntaxError: Getter must not have any formal parameters") },

    { njs_str("var o = { baz: 'bar', set foo(v) { this.baz = v; } }; o.foo = 'baz'; o.baz"),
      njs_str("baz") },

    { njs_str("var o = { baz: 'bar', set set(v) { this.baz = v; } }; o.set = 'baz'; o.baz"),
      njs_str("baz") },

    { njs_str("var expr = 'foo'; var o = { baz: 'bar', set [expr](v) { this.baz = v; } }; o.foo = 'baz'; o.baz"),
      njs_str("baz") },

    { njs_str("var o = { baz: 'bar', set foo(v1, v2) { this.baz = v; } }; o.foo = 'baz'; o.baz"),
      njs_str("SyntaxError: Setter must have exactly one formal parameter") },

    { njs_str("var o = { get foo() { return 'bar'; }, set foo(v) { this.baz = v; } }; o.foo"),
      njs_str("bar") },

    { njs_str("var expr = 'foo'; var o = { get [expr]() { return 'bar'; }, set [expr](v) { this.baz = v; } }; o.foo"),
      njs_str("bar") },

    { njs_str("Object.getOwnPropertyDescriptor({get foo() {}}, 'foo').enumerable"),
      njs_str("true") },

    { njs_str("Object.getOwnPropertyDescriptor({get foo() {}}, 'foo').configurable"),
      njs_str("true") },

    { njs_str("var p = { a:5 }; var o = Object.create(p);"
                 "Object.getPrototypeOf(o) === p"),
      njs_str("true") },

    { njs_str("var p = { a:5 }; var o = Object.create(p);"
                 "Object.getPrototypeOf(o) === o.__proto__"),
      njs_str("true") },

    { njs_str("var o = Object.create(Object.prototype);"
                 "Object.getPrototypeOf(o) === Object.prototype"),
      njs_str("true") },

    { njs_str("[true, 42, '', Symbol()]"
              ".every((x) => Object.getPrototypeOf(x) == Object.getPrototypeOf(Object(x)))"),
      njs_str("true") },

    /* Object.setPrototypeOf() */

    { njs_str("Object.setPrototypeOf()"),
      njs_str("TypeError: cannot convert undefined argument to object") },

    { njs_str("Object.setPrototypeOf(null)"),
      njs_str("TypeError: cannot convert null argument to object") },

    { njs_str("Object.setPrototypeOf({})"),
      njs_str("TypeError: prototype may only be an object or null: undefined") },

    { njs_str("Object.setPrototypeOf(Object.preventExtensions({}))"),
      njs_str("TypeError: prototype may only be an object or null: undefined") },

    { njs_str("[true, 42, '', Symbol()]"
              ".every((x) => Object.setPrototypeOf(x, {}) === x)"),
      njs_str("true") },

    { njs_str("Object.setPrototypeOf(Object.preventExtensions({}), {})"),
      njs_str("TypeError: Cannot set property \"prototype\", object is not extensible") },

    { njs_str("var p = {}, o = Object.create(p); Object.setPrototypeOf(p, o)"),
      njs_str("TypeError: Cyclic __proto__ value") },

    { njs_str("var p = {}, o = {}; Object.setPrototypeOf(o, p);"
              "p.isPrototypeOf(o)"),
      njs_str("true") },

    { njs_str("var p = {}, o = Object.create(p); Object.setPrototypeOf(o, null);"
              "Object.getPrototypeOf(o)"),
      njs_str("null") },

    { njs_str("typeof Object.setPrototypeOf({}, null)"),
      njs_str("object") },

    { njs_str("Object.setPrototypeOf(Object.getPrototypeOf(''), null).__proto__"),
      njs_str("undefined") },

    { njs_str("var p = {}; var o = Object.create(p);"
                 "p.isPrototypeOf(o)"),
      njs_str("true") },

    { njs_str("var pp = {}; var p = Object.create(pp);"
                 "var o = Object.create(p);"
                 "pp.isPrototypeOf(o)"),
      njs_str("true") },

    { njs_str("var p = {}; var o = Object.create(p);"
                 "o.isPrototypeOf(p)"),
      njs_str("false") },

    { njs_str("var p = {}; var o = Object.create(p);"
                 "o.isPrototypeOf()"),
      njs_str("false") },

    { njs_str("Object.valueOf.isPrototypeOf()"),
      njs_str("false") },

    { njs_str("var p = {}; var o = Object.create(p);"
                 "o.isPrototypeOf(1)"),
      njs_str("false") },

    { njs_str("var p = {}; var o = Object.create(p);"
                 "1..isPrototypeOf(p)"),
      njs_str("false") },

    { njs_str("Object.create(new String('asdf')).length"),
      njs_str("4") },

    { njs_str("Object.create(Object('123')).length"),
      njs_str("3") },

    { njs_str("Object.create([1,2]).length"),
      njs_str("2") },

    { njs_str("Object.create(function(a,b,c){}).length"),
      njs_str("3") },

    { njs_str("Object.create(Math).hasOwnProperty('abs')"),
      njs_str("false") },

    { njs_str("var m = Object.create(Math); m.abs = 3;"
                 "[m.hasOwnProperty('abs'), m.abs]"),
      njs_str("true,3") },

    { njs_str("var m = Object.create(Math); m.abs = Math.floor;"
                 "[m.hasOwnProperty('abs'), delete m.abs, m.abs(-1)]"),
      njs_str("true,true,1") },

    { njs_str("var Q = Object.create({}, {a: {value: 'AAA'}, [Symbol.toStringTag]:{value: 'TAG'}});"
              "Q[Symbol.toStringTag]"),
      njs_str("TAG") },

    { njs_str("Object.getOwnPropertyDescriptor({a:1}, 'a').value"),
      njs_str("1") },

    { njs_str("Object.getOwnPropertyDescriptor({a:1}, 'a').configurable"),
      njs_str("true") },

    { njs_str("Object.getOwnPropertyDescriptor({a:1}, 'a').enumerable"),
      njs_str("true") },

    { njs_str("Object.getOwnPropertyDescriptor({a:1}, 'a').writable"),
      njs_str("true") },

    { njs_str("Object.getOwnPropertyDescriptor({a:1}, 'b')"),
      njs_str("undefined") },

    { njs_str("Object.getOwnPropertyDescriptor({}, 'a')"),
      njs_str("undefined") },

    { njs_str("Object.getOwnPropertyDescriptor(Object.create({a:1}), 'a')"),
      njs_str("undefined") },

    { njs_str("Object.getOwnPropertyDescriptor([3,4], '1').value"),
      njs_str("4") },

    { njs_str("Object.getOwnPropertyDescriptor([3,4], 1).value"),
      njs_str("4") },

    { njs_str("Object.getOwnPropertyDescriptor([], 'length').value"),
      njs_str("0") },

    { njs_str("Object.getOwnPropertyDescriptor([], '0')"),
      njs_str("undefined") },

    { njs_str("Object.getOwnPropertyDescriptor([1,2], '1').value"),
      njs_str("2") },

    { njs_str("Object.getOwnPropertyDescriptor([1,2], new String('1')).value"),
      njs_str("2") },

    { njs_str("Object.getOwnPropertyDescriptor({undefined:1}, void 0).value"),
      njs_str("1") },

    { njs_str("Object.getOwnPropertyDescriptor([1,2], 1).value"),
      njs_str("2") },

    { njs_str("Object.getOwnPropertyDescriptor([1,,,3], '1')"),
      njs_str("undefined") },

    { njs_str("Object.getOwnPropertyDescriptor([1,2], '3')"),
      njs_str("undefined") },

    { njs_str("JSON.stringify(Object.getOwnPropertyDescriptor([3,4], 'length'))"),
      njs_str("{\"value\":2,\"writable\":true,\"enumerable\":false,\"configurable\":false}") },

    { njs_str("Object.getOwnPropertyDescriptor(Array.of, 'length').value"),
      njs_str("0") },

    { njs_str("Object.getOwnPropertyDescriptor('αβγδ', '1').value"),
      njs_str("β") },

    { njs_str("Object.getOwnPropertyDescriptor(new String('αβγδ'), '1').value"),
      njs_str("β") },

    { njs_str("var s = new String('αβγδ'); s.a = 1;"
                 "Object.getOwnPropertyDescriptor(s, 'a').value"),
      njs_str("1") },

    { njs_str("JSON.stringify(Object.getOwnPropertyDescriptor('αβγδ', '2'))"),
      njs_str("{\"value\":\"γ\",\"writable\":false,\"enumerable\":true,\"configurable\":false}") },

    { njs_str("JSON.stringify(Object.getOwnPropertyDescriptor(new String('abc'), 'length'))"),
      njs_str("{\"value\":3,\"writable\":false,\"enumerable\":false,\"configurable\":false}") },

    { njs_str("Object.getOwnPropertyDescriptor(1, '0')"),
      njs_str("undefined") },

    { njs_str("'αβγδ'.propertyIsEnumerable('0')"),
      njs_str("true") },

    { njs_str("({a:1}).propertyIsEnumerable({toString:function () {return 'a';}})"),
      njs_str("true") },

    { njs_str("'αβγδ'.propertyIsEnumerable('a')"),
      njs_str("false") },

    { njs_str("'αβγδ'.propertyIsEnumerable('length')"),
      njs_str("false") },

    { njs_str("var min = Object.getOwnPropertyDescriptor(Math, 'min').value;"
                 "[min(1,2), min(2,1), min(-1,1)]"),
      njs_str("1,1,-1") },

    { njs_str("Object.getOwnPropertyDescriptor()"),
      njs_str("TypeError: cannot convert undefined argument to object") },

    { njs_str("Object.getOwnPropertyDescriptor(undefined)"),
      njs_str("TypeError: cannot convert undefined argument to object") },

    { njs_str("var o = {}; o[void 0] = 'a'; Object.getOwnPropertyDescriptor(o).value"),
      njs_str("a") },

    { njs_str("var o = {}; o[void 0] = 'a'; Object.getOwnPropertyDescriptor(o, undefined).value"),
      njs_str("a") },

    { njs_str("Object.getOwnPropertyDescriptors()"),
      njs_str("TypeError: cannot convert undefined argument to object") },

    { njs_str("typeof Object.getOwnPropertyDescriptors(1)"),
      njs_str("object") },

    { njs_str("Object.keys(Object.getOwnPropertyDescriptors([]))"),
      njs_str("length") },

    { njs_str("Object.getOwnPropertyDescriptors(function(a,b,c) {}).length.value"),
      njs_str("3") },

    { njs_str("Object.values(Object.getOwnPropertyDescriptors('abc'))"
                 ".reduce(function(a, x) { return a += x.value; }, '')"),
      njs_str("abc3") },

    { njs_str("Object.getOwnPropertyNames()"),
      njs_str("TypeError: cannot convert undefined argument to object") },

    { njs_str("Array.isArray(Object.getOwnPropertyNames({}))"),
      njs_str("true") },

    { njs_str("Object.getOwnPropertyNames({a:1, b:1, c:1})"),
      njs_str("a,b,c") },

    { njs_str("Object.getOwnPropertyNames(Object.defineProperty({a:1}, 'b', {}))"),
      njs_str("a,b") },

    { njs_str("Object.getOwnPropertyNames(Object.defineProperty([], 'b', {}))"),
      njs_str("length,b") },

    { njs_str("Object.getOwnPropertyNames(Object.defineProperty(new String(), 'b', {}))"),
      njs_str("length,b") },

    { njs_str("Object.getOwnPropertyNames([1,2,3])"),
      njs_str("0,1,2,length") },

    { njs_str("Object.getOwnPropertyNames('abc')"),
      njs_str("0,1,2,length") },

    { njs_str("Object.getOwnPropertyNames(function() {})"),
      njs_str("length,name,prototype") },

    { njs_str("Object.getOwnPropertyNames(Array)"),
      njs_str("length,name,prototype,from,isArray,of") },

    { njs_str("Object.getOwnPropertyNames(Array.isArray)"),
      njs_str("length,name") },

    { njs_str("var not_arr_ind_1st = 0xFFFFFFFF, not_arr_ind_2nd = not_arr_ind_1st + 1,"
              "arr_ind_last =  not_arr_ind_1st - 1, arr_ind_pre_last = not_arr_ind_1st - 2;"
              "var o = {};"
              "o[not_arr_ind_2nd] = 'not_arr_ind_2nd';"
              "o[not_arr_ind_1st] = 'not_arr_ind_1st';"
              "o[arr_ind_pre_last] = 'arr_ind_pre_last';"
              "o[arr_ind_last] = 'arr_ind_last';"
              "Object.entries(o)"),
      njs_str("4294967293,arr_ind_pre_last,4294967294,arr_ind_last,"
              "4294967296,not_arr_ind_2nd,4294967295,not_arr_ind_1st")
    },

    /* Object.freeze() */

    { njs_str("[undefined, null, false, NaN, '', Symbol()]"
              ".every((x) => Object.is(Object.freeze(x), x))"),
      njs_str("true")
    },

    { njs_str("var buf = new ArrayBuffer(8);"
              NJS_TYPED_ARRAY_LIST
              ".every((ctr) => {Object.freeze(new ctr([])); "
              "                 Object.freeze(new ctr(buf, 8)); return true; })"),
      njs_str("true")
    },

    { njs_str("var buf = new ArrayBuffer(8);"
              NJS_TYPED_ARRAY_LIST
              ".map((ctr) => { try { Object.freeze(new ctr(buf)); } catch(e) { return e; } })"
              ".every((x) => x instanceof TypeError)"),
      njs_str("true")
    },

    { njs_str("Object.freeze([1]).pop()"),
      njs_str("TypeError: Cannot delete property \"0\" of array") },

    { njs_str("var a = Object.freeze([1]); a[0] = 2;"),
      njs_str("TypeError: Cannot assign to read-only property \"0\" of array") },

    { njs_str("var a = Object.freeze([1]); a[1] = 2;"),
      njs_str("TypeError: Cannot add property \"1\", object is not extensible") },

    { njs_str("var a = Object.freeze([1,,3]); a[1] = 2;"),
      njs_str("TypeError: Cannot add property \"1\", object is not extensible") },

    { njs_str("var o = { a: 1 }; delete o.a; Object.freeze(o).a = 2;"),
      njs_str("TypeError: Cannot add property \"a\", object is not extensible") },

    { njs_str("Object.defineProperty(Object.freeze({}), 'b', {})"),
      njs_str("TypeError: Cannot add property \"b\", object is not extensible") },

    { njs_str("Object.defineProperties(Object.freeze({}), {b:{}})"),
      njs_str("TypeError: Cannot add property \"b\", object is not extensible") },

    { njs_str("Object.freeze()"),
      njs_str("undefined") },

    { njs_str("var o = Object.freeze({a:1}); o.a = 2"),
      njs_str("TypeError: Cannot assign to read-only property \"a\" of object") },

    { njs_str("var o = Object.freeze({a:1}); delete o.a"),
      njs_str("TypeError: Cannot delete property \"a\" of object") },

    { njs_str("var o = Object.freeze({a:1}); o.b = 1; o.b"),
      njs_str("TypeError: Cannot add property \"b\", object is not extensible") },

    { njs_str("var o = Object.freeze(Object.create({a:1})); o.a = 2; o.a"),
      njs_str("TypeError: Cannot add property \"a\", object is not extensible") },

    { njs_str("var o = Object.freeze({a:{b:1}}); o.a.b = 2; o.a.b"),
      njs_str("2") },

    { njs_str("Object.defineProperty([1,2], 'a', {value:1}).a"),
      njs_str("1") },

    { njs_str("var a = []; a[0] = 101; Object.defineProperty(a, 0, {});"
              "a[0]"),
      njs_str("101") },

    { njs_str("var a = Object.freeze([1,2]);"
                 "Object.defineProperty(a, 'a', {value:1}).a"),
      njs_str("TypeError: Cannot add property \"a\", object is not extensible") },

    { njs_str("var a = [1,2]; a.a = 1; Object.freeze(a); delete a.a"),
      njs_str("TypeError: Cannot delete property \"a\" of array") },

    { njs_str("var a = [1,2]; a.a = 1; Object.freeze(a); a.a = 2"),
      njs_str("TypeError: Cannot assign to read-only property \"a\" of array") },

    { njs_str("var a = Object.freeze([1,2]); a.a = 1"),
      njs_str("TypeError: Cannot add property \"a\", object is not extensible") },

    { njs_str("Object.defineProperty(function() {}, 'a', {value:1}).a"),
      njs_str("1") },

    { njs_str("var f = Object.freeze(function() {});"
                 "Object.defineProperty(f, 'a', {value:1}).a"),
      njs_str("TypeError: Cannot add property \"a\", object is not extensible") },

    { njs_str("var f = function() {}; f.a = 1; Object.freeze(f); delete f.a"),
      njs_str("TypeError: Cannot delete property \"a\" of function") },

    { njs_str("var f = function() {}; f.a = 1; Object.freeze(f); f.a = 2"),
      njs_str("TypeError: Cannot assign to read-only property \"a\" of function") },

    { njs_str("var f = Object.freeze(function() {}); f.a = 1"),
      njs_str("TypeError: Cannot add property \"a\", object is not extensible") },

    { njs_str("Object.defineProperty(new Date(''), 'a', {value:1}).a"),
      njs_str("1") },

    { njs_str("var d = Object.freeze(new Date(''));"
                 "Object.defineProperty(d, 'a', {value:1}).a"),
      njs_str("TypeError: Cannot add property \"a\", object is not extensible") },

    { njs_str("var d = new Date(''); d.a = 1; Object.freeze(d);"
                 "delete d.a"),
      njs_str("TypeError: Cannot delete property \"a\" of date") },

    { njs_str("var d = new Date(''); d.a = 1; Object.freeze(d); d.a = 2"),
      njs_str("TypeError: Cannot assign to read-only property \"a\" of date") },

    { njs_str("var d = Object.freeze(new Date('')); d.a = 1"),
      njs_str("TypeError: Cannot add property \"a\", object is not extensible") },

    { njs_str("Object.defineProperty(new RegExp(''), 'a', {value:1}).a"),
      njs_str("1") },

    { njs_str("var r = Object.freeze(new RegExp(''));"
                 "Object.defineProperty(r, 'a', {value:1}).a"),
      njs_str("TypeError: Cannot add property \"a\", object is not extensible") },

    { njs_str("var r = new RegExp(''); r.a = 1; Object.freeze(r); delete r.a"),
      njs_str("TypeError: Cannot delete property \"a\" of regexp") },

    { njs_str("var r = new RegExp(''); r.a = 1; Object.freeze(r); r.a = 2"),
      njs_str("TypeError: Cannot assign to read-only property \"a\" of regexp") },

    { njs_str("var r = Object.freeze(new RegExp('')); r.a = 1"),
      njs_str("TypeError: Cannot add property \"a\", object is not extensible") },

    { njs_str("var o = Object.freeze({ get x() { return 10; } }); o.x"),
      njs_str("10") },

    { njs_str("var o = Object.freeze({ get x() { return 10; } });"
              "Object.getOwnPropertyDescriptors(o).x.get"),
      njs_str("[object Function]") },

    { njs_str("var o = Object.freeze({ get x() { return 10; } });"
              "Object.getOwnPropertyDescriptor(o, 'x').writable"),
      njs_str("undefined") },

    /* Object.isFrozen() */

    { njs_str("[undefined, null, false, NaN, '', Symbol()]"
              ".every((x) => Object.isFrozen(x))"),
      njs_str("true") },

    { njs_str("[[], {}]"
              ".every((x) => Object.isFrozen(Object.preventExtensions(x)))"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every((ctr) => !Object.isFrozen(new ctr([])))"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every((ctr) => Object.isFrozen(Object.preventExtensions(new ctr([]))))"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".map((ctr) => new ctr([]))"
              ".map((x) => { x.broken = true; return x; })"
              ".every((x) => !Object.isFrozen(Object.preventExtensions(x)))"),
      njs_str("true") },

    { njs_str("var buf = new ArrayBuffer(8);"
              NJS_TYPED_ARRAY_LIST
              ".every((ctr) => !Object.isFrozen(Object.preventExtensions(new ctr(buf))))"),
      njs_str("true") },

    { njs_str("[{a:1}, [1,2], function() {}, new Date(''), new RegExp('')]"
              ".every((x) => !Object.isFrozen(x))"),
      njs_str("true") },

    { njs_str("Object.isFrozen()"),
      njs_str("true") },

    { njs_str("Object.isFrozen(Object.defineProperties({}, {a:{value:1}}))"),
      njs_str("false") },

    { njs_str("var o = Object.defineProperties({}, {a:{}, b:{}});"
                 "o = Object.preventExtensions(o);"
                 "Object.isFrozen(o)"),
      njs_str("true") },

    { njs_str("var o = Object.defineProperties({}, {a:{}, b:{writable:1}});"
                 "o = Object.preventExtensions(o);"
                 "Object.isFrozen(o)"),
      njs_str("false") },

    { njs_str("var o = Object.defineProperties({}, {a:{writable:1}});"
                 "o = Object.preventExtensions(o);"
                 "Object.isFrozen(o)"),
      njs_str("false") },

    { njs_str("var o = Object.defineProperties({}, {a:{configurable:1}});"
                 "o = Object.preventExtensions(o);"
                 "Object.isFrozen(o)"),
      njs_str("false") },

    { njs_str("var o = Object.preventExtensions({a:1});"
                 "Object.isFrozen(o)"),
      njs_str("false") },

    { njs_str("var o = Object.freeze({a:1}); Object.isFrozen(o)"),
      njs_str("true") },

    /* Object.seal() */

    { njs_str("[undefined, null, false, NaN, '', Symbol()]"
              ".every((x) => Object.is(Object.seal(x), x))"),
      njs_str("true") },

    { njs_str("Object.seal()"),
      njs_str("undefined") },

    { njs_str("Object.seal([1]).pop()"),
      njs_str("TypeError: Cannot delete property \"0\" of array") },

    { njs_str("var a = Object.seal([1]); a[0] = 2; a"),
      njs_str("2") },

    { njs_str("var a = Object.seal([1]); a[1] = 2;"),
      njs_str("TypeError: Cannot add property \"1\", object is not extensible") },

    { njs_str("var a = Object.seal([1,,3]); a[1] = 2;"),
      njs_str("TypeError: Cannot add property \"1\", object is not extensible") },

    { njs_str("var o = { a: 1 }; delete o.a; Object.seal(o).a = 2"),
      njs_str("TypeError: Cannot add property \"a\", object is not extensible") },

    { njs_str("var o = Object.seal({a:1}); o.a = 2; o.a"),
      njs_str("2") },

    { njs_str("var o = Object.seal({a:1}); delete o.a"),
      njs_str("TypeError: Cannot delete property \"a\" of object") },

    { njs_str("var o = Object.seal({a:1}); o.b = 1; o.b"),
      njs_str("TypeError: Cannot add property \"b\", object is not extensible") },

    { njs_str("var o = Object.seal(Object.create({a:1})); o.a = 2; o.a"),
      njs_str("TypeError: Cannot add property \"a\", object is not extensible") },

    { njs_str("var o = Object.seal({a:{b:1}}); o.a.b = 2; o.a.b"),
      njs_str("2") },

    /* Object.isSealed() */

    { njs_str("[undefined, null, false, NaN, '', Symbol()]"
              ".every((x) => Object.isSealed(x))"),
      njs_str("true") },

    { njs_str("[[], {}]"
              ".every((x) => Object.isSealed(Object.preventExtensions(x)))"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every((ctr) => !Object.isSealed(new ctr([])))"),
      njs_str("true") },

    { njs_str(NJS_TYPED_ARRAY_LIST
              ".every((ctr) => Object.isSealed(Object.preventExtensions(new ctr([]))))"),
      njs_str("true") },

    { njs_str("var buf = new ArrayBuffer(8);"
              NJS_TYPED_ARRAY_LIST
              ".every((ctr) => Object.isSealed(Object.preventExtensions(new ctr(buf))))"),
      njs_str("true") },

    { njs_str("var buf = new ArrayBuffer(8);"
              NJS_TYPED_ARRAY_LIST
              ".map((ctr) => new ctr(buf))"
              ".map((x) => { x.broken = true; return x; })"
              ".every((x) => !Object.isSealed(Object.preventExtensions(x)))"),
      njs_str("true") },

    { njs_str("[{a:1}, [1,2], function() {}, new Date(''), new RegExp('')]"
              ".every((x) => !Object.isSealed(x))"),
      njs_str("true") },

    { njs_str("Object.isSealed()"),
      njs_str("true") },

    { njs_str("Object.isSealed(Object.defineProperties({}, {a:{value:1}}))"),
      njs_str("false") },

    { njs_str("var o = Object.defineProperties({}, {a:{}, b:{}});"
              "o = Object.preventExtensions(o);"
              "Object.isSealed(o)"),
      njs_str("true") },

    { njs_str("var o = Object.defineProperties({}, {a:{}, b:{writable:1}});"
              "o = Object.preventExtensions(o);"
              "Object.isSealed(o)"),
      njs_str("true") },

    { njs_str("var o = Object.defineProperties({}, {a:{writable:1}});"
              "o = Object.preventExtensions(o);"
              "Object.isSealed(o)"),
      njs_str("true") },

    { njs_str("var o = Object.defineProperties({}, {a:{configurable:1}});"
              "o = Object.preventExtensions(o);"
              "Object.isSealed(o)"),
      njs_str("false") },

    { njs_str("var o = Object.preventExtensions({a:1});"
              "Object.isFrozen(o)"),
      njs_str("false") },

    { njs_str("var o = Object.freeze({a:1}); Object.isFrozen(o)"),
      njs_str("true") },

    /* Object.preventExtensions() */

    { njs_str("var o = Object.preventExtensions({a:1});"
              "Object.defineProperty(o, 'b', {value:1})"),
      njs_str("TypeError: Cannot add property \"b\", object is not extensible") },

    { njs_str("var o = Object.preventExtensions({});"
              "Object.defineProperty(o, Symbol.unscopables, {})"),
      njs_str("TypeError: Cannot add property \"Symbol(Symbol.unscopables)\", object is not extensible") },

    { njs_str("var o = Object.preventExtensions({a:1});"
              "Object.defineProperties(o, {b:{value:1}})"),
      njs_str("TypeError: Cannot add property \"b\", object is not extensible") },

    { njs_str("var o = Object.preventExtensions({a:1}); o.a = 2; o.a"),
      njs_str("2") },

    { njs_str("var o = Object.preventExtensions({a:1}); delete o.a; o.a"),
      njs_str("undefined") },

    { njs_str("var o = Object.preventExtensions({a:1}); o.b = 1; o.b"),
      njs_str("TypeError: Cannot add property \"b\", object is not extensible") },

    { njs_str("var o = Object.preventExtensions({a:1}); o[Symbol.unscopables] = 1"),
      njs_str("TypeError: Cannot add property \"Symbol(Symbol.unscopables)\", object is not extensible") },

    { njs_str("var o = { a: 1 }; delete o.a; Object.preventExtensions(o).a = 1"),
      njs_str("TypeError: Cannot add property \"a\", object is not extensible") },

    { njs_str("Object.preventExtensions()"),
      njs_str("undefined") },

    { njs_str("Object.preventExtensions(1)"),
      njs_str("1") },

    { njs_str("Object.preventExtensions('')"),
      njs_str("") },

    { njs_str("Object.isExtensible({})"),
      njs_str("true") },

    { njs_str("Object.isExtensible([])"),
      njs_str("true") },

    { njs_str("var arrObj = [];Object.preventExtensions(arrObj); arrObj[1] = 1"),
      njs_str("TypeError: Cannot add property \"1\", object is not extensible") },

    { njs_str("var arrObj = [1,2];Object.preventExtensions(arrObj); arrObj[1] = 1"),
      njs_str("1") },

    { njs_str("Object.isExtensible(function() {})"),
      njs_str("true") },

    { njs_str("Object.isExtensible(new Date(''))"),
      njs_str("true") },

    { njs_str("Object.isExtensible(new RegExp(''))"),
      njs_str("true") },

    { njs_str("Object.isExtensible()"),
      njs_str("false") },

    { njs_str("Object.isExtensible(1)"),
      njs_str("false") },

    { njs_str("Object.isExtensible('')"),
      njs_str("false") },

    { njs_str("Object.isExtensible(Object.preventExtensions({}))"),
      njs_str("false") },

    { njs_str("Object.isExtensible(Object.preventExtensions([]))"),
      njs_str("false") },

    { njs_str("Object.isExtensible(Object.freeze({}))"),
      njs_str("false") },

    { njs_str("Object.isExtensible(Object.freeze([]))"),
      njs_str("false") },

    { njs_str("Object.isExtensible(undefined)"),
      njs_str("false") },

    /* Object.is() */

    { njs_str("typeof Object.is"),
      njs_str("function") },

    { njs_str("Object.is.length == 2"),
      njs_str("true") },

    { njs_str("Object.is()"),
      njs_str("true") },

    { njs_str("[undefined, null, false, NaN, '', Symbol(), {}]"
              ".map((x) => Object.is(x, x))"
              ".every((x) => x === true)"),
      njs_str("true") },

    { njs_str("[null, false, NaN, '', Symbol(), {}]"
              ".map((x) => Object.is(x) || Object.is(void 0, x))"
              ".every((x) => x === false)"),
      njs_str("true") },

    { njs_str("[false, NaN, '', Symbol()]"
              ".map((x) => Object.is(Object(x), Object(x)))"
              ".every((x) => x === false)"),
      njs_str("true") },

    { njs_str("Object.is(0, -0)"),
      njs_str("false") },

    { njs_str("Object.is(0, null)"),
      njs_str("false") },

    { njs_str("Object.is(42, '42')"),
      njs_str("false") },

    { njs_str(
        "var fail;"
        "function isConfigurableMethods(o) {"
        "    var except = ["
        "        'prototype',"
        "        'caller',"
        "        'arguments',"
        "        'description',"
        "    ];"
        "    return Object.getOwnPropertyNames(o)"
        "                 .filter(v => !except.includes(v)"
        "                              && typeof o[v] == 'function')"
        "                 .every(v => Object.getOwnPropertyDescriptor(o, v)"
        "                                   .configurable"
        "                             || !(fail = `${o.name}.${v}`));"
        "}"
        "["
        "    Boolean, Boolean.prototype,"
        "    Number, Number.prototype,"
        "    Symbol, Symbol.prototype,"
        "    String, String.prototype,"
        "    Object, Object.prototype,"
        "    Array, Array.prototype,"
        "    Function, Function.prototype,"
        "    RegExp, RegExp.prototype,"
        "    Date, Date.prototype,"
        "    Error, Error.prototype,"
        "    Math,"
        "    JSON,"
        "].every(obj => isConfigurableMethods(obj)) || fail"),

      njs_str("true") },

    { njs_str(
        "var fail;"
        "function isWritableMethods(o) {"
        "    var except = ["
        "        'prototype',"
        "        'caller',"
        "        'arguments',"
        "        'description',"
        "    ];"
        "    return Object.getOwnPropertyNames(o)"
        "                 .filter(v => !except.includes(v)"
        "                              && typeof o[v] == 'function')"
        "                 .every(v => Object.getOwnPropertyDescriptor(o, v)"
        "                                   .writable"
        "                             || !(fail = `${o.name}.${v}`));"
        "}"
        "["
        "    Boolean, Boolean.prototype,"
        "    Number, Number.prototype,"
        "    Symbol, Symbol.prototype,"
        "    String, String.prototype,"
        "    Object, Object.prototype,"
        "    Array, Array.prototype,"
        "    Function, Function.prototype,"
        "    RegExp, RegExp.prototype,"
        "    Date, Date.prototype,"
        "    Error, Error.prototype,"
        "    Math,"
        "    JSON,"
        "].every(obj => isWritableMethods(obj)) || fail"),

      njs_str("true") },

    { njs_str("new Date(undefined)"),
      njs_str("Invalid Date") },

    { njs_str("new Date(Infinity)"),
      njs_str("Invalid Date") },

    { njs_str("new Date(NaN)"),
      njs_str("Invalid Date") },

    { njs_str("new Date(1,undefined)"),
      njs_str("Invalid Date") },

    { njs_str("new Date(1,Infinity)"),
      njs_str("Invalid Date") },

    { njs_str("new Date(1,NaN)"),
      njs_str("Invalid Date") },

    { njs_str("new Date(8.65e15)"),
      njs_str("Invalid Date") },

    { njs_str("var d = new Date(1308895200000); new Date(d.getTime(), d.getTime())"),
      njs_str("Invalid Date") },

    { njs_str("new Date(275760, 1, 2**61)"),
      njs_str("Invalid Date") },

    { njs_str("new Date(275760, 1, 1, 2**61)"),
      njs_str("Invalid Date") },

    { njs_str("new Date(275760, 1, 1, 1, 2**61)"),
      njs_str("Invalid Date") },

    { njs_str("new Date(275760, 1, 1, 1, 1, 2**61)"),
      njs_str("Invalid Date") },

    { njs_str("new Date(275760, 1, 1, 1, 1, 1, 2**61)"),
      njs_str("Invalid Date") },

    { njs_str("njs.dump([new Date(8.65e15)])"),
      njs_str("[Invalid Date]") },

    { njs_str("new Date(0e0.o0)"),
      njs_str("Invalid Date") },

    { njs_str("(new Date(8.639e15)).getTime()"),
      njs_str("8639000000000000") },

    { njs_str("new Date(8.641e15)"),
      njs_str("Invalid Date") },

    { njs_str("(new Date(null)).getTime()"),
      njs_str("0") },

    { njs_str("(new Date(86400)).getTime()"),
      njs_str("86400") },

    { njs_str("Date().split(' ')[0] in {'Mon':1, 'Tue':1, 'Wed':1, 'Thu':1, 'Fri':1, 'Sat':1, 'Sun':1}"),
      njs_str("true") },

    { njs_str("var d = new Date(''); d +' '+ d.getTime()"),
      njs_str("Invalid Date NaN") },

    { njs_str("var d = new Date(1); d = d + ''; d.slice(0, 33)"),
      njs_str("Thu Jan 01 1970 00:00:00 GMT+0000") },

    { njs_str("var d = new Date({valueOf:()=>86400000}); d = d + ''; d.slice(0, 33)"),
      njs_str("Fri Jan 02 1970 00:00:00 GMT+0000") },

    { njs_str("(new Date({toString:()=>'2011'})).getTime()"),
      njs_str("1293840000000") },

    { njs_str("(new Date({valueOf: ()=>86400, toString:()=>'2011'})).getTime()"),
      njs_str("86400") },

    { njs_str("var d = new Date(1308895200000); d.getTime()"),
      njs_str("1308895200000") },

    { njs_str("var d = new Date(2011, 5, 24, 18, 45); d.getTime()"),
      njs_str("1308941100000") },

    { njs_str("var d = new Date(2011, 5, 24, 18, 45); d.valueOf()"),
      njs_str("1308941100000") },

    { njs_str("var d = new Date(2011, 5, 24, 18, 45);"
                 "d.toString().slice(0, 33)"),
      njs_str("Fri Jun 24 2011 18:45:00 GMT+0000") },

    { njs_str("var d = new Date(2011, 5, 24, 18, 45); d.toDateString()"),
      njs_str("Fri Jun 24 2011") },

    { njs_str("new Date(NaN).toDateString()"),
      njs_str("Invalid Date") },

    { njs_str("var d = new Date(2011, 5, 24, 18, 45);"
                 "d.toTimeString().slice(0, 17)"),
      njs_str("18:45:00 GMT+0000") },

    { njs_str("var d = new Date(2011, 5, 24, 18, 45); d.toUTCString()"),
      njs_str("Fri, 24 Jun 2011 18:45:00 GMT") },

    { njs_str("var d = new Date(2011, 5, 24, 18, 45, 12, 625);"
                 "d.toISOString()"),
      njs_str("2011-06-24T18:45:12.625Z") },

    { njs_str("var d = new Date(1999, 9, 10, 10, 10, 10, 10);"
              "var local = new Date(d.getTime() - d.getTimezoneOffset() * 60000);"
              "local.toISOString()"),
      njs_str("1999-10-10T10:10:10.010Z") },

#if (NJS_TIME_T_SIZE == 8)
    { njs_str("["
              "'-010000-01-01T00:00:00.000Z',"
              "'+010000-01-01T00:00:00.000Z',"
              "'0002-01-01T00:00:00.000Z',"
              "'0123-01-01T00:00:00.000Z',"
              "].every((iso)=> (new Date(iso)).toISOString() === iso)"),
      njs_str("true") },

    { njs_str("new Date('0020-01-01T00:00:00Z').toUTCString()"),
      njs_str("Wed, 01 Jan 0020 00:00:00 GMT") },

    { njs_str("new Date('0020-01-01T00:00:00Z').toString().slice(0, 15)"),
      njs_str("Wed Jan 01 0020") },

    { njs_str("(new Date('-000001-07-01T00:00Z')).toUTCString()"),
      njs_str("Thu, 01 Jul -0001 00:00:00 GMT") },

    { njs_str("(new Date('-000012-07-01T00:00Z')).toUTCString()"),
      njs_str("Fri, 01 Jul -0012 00:00:00 GMT") },

    { njs_str("(new Date('-000123-07-01T00:00Z')).toUTCString()"),
      njs_str("Sun, 01 Jul -0123 00:00:00 GMT") },

    { njs_str("(new Date('-001234-07-01T00:00Z')).toUTCString()"),
      njs_str("Fri, 01 Jul -1234 00:00:00 GMT") },

    { njs_str("(new Date('-012345-07-01T00:00Z')).toUTCString()"),
      njs_str("Thu, 01 Jul -12345 00:00:00 GMT") },

    { njs_str("new Date(NaN).toUTCString()"),
      njs_str("Invalid Date") },

    { njs_str("var d = new Date(-62167219200000); d.toISOString()"),
      njs_str("0000-01-01T00:00:00.000Z") },

    { njs_str("var d = new Date(-62135596800000); d.toISOString()"),
      njs_str("0001-01-01T00:00:00.000Z") },

    { njs_str("var d = new Date(-62198755200000); d.toISOString()"),
      njs_str("-000001-01-01T00:00:00.000Z") },

    { njs_str("new Date(NaN).toISOString()"),
      njs_str("RangeError: Invalid time value") },
#endif

    { njs_str("Date.UTC(2011, 5, 24, 6, 0)"),
      njs_str("1308895200000") },

    { njs_str("Date.UTC({valueOf:()=>2011}, 5, 24, 6, 0)"),
      njs_str("1308895200000") },

    { njs_str("Date.UTC()"),
      njs_str("NaN") },

    { njs_str("Date.UTC(Infinity)"),
      njs_str("NaN") },

    { njs_str("Date.UTC(Infinity, 0)"),
      njs_str("NaN") },

    { njs_str("Date.UTC(1970)"),
      njs_str("0") },

    { njs_str("Date.UTC(1968, 24)"),
      njs_str("0") },

    { njs_str("[-1,0,1,99,100].map(yr => Date.UTC(yr))"),
      njs_str("-62198755200000,-2208988800000,-2177452800000,915148800000,-59011459200000") },

    { njs_str("Date.UTC(1970.9, 0.9, 1.9, 0.9, 0.9, 0.9, 0.9)"),
      njs_str("0") },

    { njs_str("Date.UTC(-1970.9, -0.9, -0.9, -0.9, -0.9, -0.9, -0.9)"),
      njs_str("-124334438400000") },

    { njs_str("Date.UTC(275760, 8, 13, 0, 0, 0, 0)"),
      njs_str("8640000000000000") },

    { njs_str("Date.UTC(275760, 8, 13, 0, 0, 0, 1)"),
      njs_str("NaN") },

    { njs_str("Date.UTC(-271821, 3, 20, 0, 0, 0, 0)"),
      njs_str("-8640000000000000") },

    { njs_str("Date.UTC(-271821, 3, 20, 0, 0, 0, -1)"),
      njs_str("NaN") },

    { njs_str("Date.UTC(1970, 0)"),
      njs_str("0") },

    { njs_str("Date.UTC(1970, 0, 0)"),
      njs_str("-86400000") },

    { njs_str("Date.parse()"),
      njs_str("NaN") },

    { njs_str("Date.parse('2011')"),
      njs_str("1293840000000") },

    { njs_str("Date.parse('+002011')"),
      njs_str("1293840000000") },

    { njs_str("Date.parse('2011-06')"),
      njs_str("1306886400000") },

    { njs_str("Date.parse('2011-06-24')"),
      njs_str("1308873600000") },

    { njs_str("Date.parse('2011-06-24T06')"),
      njs_str("NaN") },

    { njs_str("Date.parse('2011-06-24T06:')"),
      njs_str("NaN") },

    { njs_str("Date.parse('2011-06-24T06:01:')"),
      njs_str("NaN") },

    { njs_str("Date.parse('2011-06-24T06:01Z')"),
      njs_str("1308895260000") },

    { njs_str("Date.parse('2011-06-24T06:01:02:')"),
      njs_str("NaN") },

    { njs_str("Date.parse('2011-06-24T06:01:02Z')"),
      njs_str("1308895262000") },

    { njs_str("Date.parse('2011-06-24T06:01:02.Z')"),
      njs_str("NaN") },

    { njs_str("Date.parse('2011-06-24T06:01:02.6Z')"),
      njs_str("1308895262600") },

    { njs_str("Date.parse('2011-06-24T06:01:02.62Z')"),
      njs_str("1308895262620") },

    { njs_str("Date.parse('2011-06-24T06:01:02:625Z')"),
      njs_str("NaN") },

    { njs_str("Date.parse('2011-06-24T06:01:02.625Z')"),
      njs_str("1308895262625") },

    { njs_str("Date.parse('2011-06-24T06:01:02.625+00:00')"),
      njs_str("1308895262625") },

    { njs_str("Date.parse('2011-06-24T06:01:02.625+0000')"),
      njs_str("1308895262625") },

    { njs_str("Date.parse('2011-06-24T06:01:02.625+00:0')"),
      njs_str("NaN") },

    { njs_str("Date.parse('2011-06-24T06:01:02.625+00:')"),
      njs_str("NaN") },

    { njs_str("Date.parse('2011-06-24T06:01:02.625+00')"),
      njs_str("NaN") },

    { njs_str("Date.parse('2011-06-24T06:01:02.625+0')"),
      njs_str("NaN") },

    { njs_str("Date.parse('2011-06-24T06:01:02.625+')"),
      njs_str("NaN") },

    { njs_str("Date.parse('2011-06-24T06:01:02.625-01:15')"),
      njs_str("1308899762625") },

    { njs_str("Date.parse('2011-06-24T06:01:02.625-01:60')"),
      njs_str("NaN") },

    { njs_str("Date.parse('2011-06-24T06:01:02.625-25:59')"),
      njs_str("NaN") },

    { njs_str("Date.parse('2011-06-24T06:01:02.625+01:15')"),
      njs_str("1308890762625") },

    { njs_str("Date.parse('2011-06-24T06:01:02.625-23:59')"),
      njs_str("1308981602625") },

    { njs_str("Date.parse('2011-06-24T06:01:02.625+23:59')"),
      njs_str("1308808922625") },

    { njs_str("Date.parse('2011-06-24T06:01:02.6255Z')"),
      njs_str("1308895262625") },

    { njs_str("Date.parse('2011-06-24T06:01:02.62555Z')"),
      njs_str("1308895262625") },

    { njs_str("Date.parse('2011-06-24T06:01:02.625555Z')"),
      njs_str("1308895262625") },

    { njs_str("Date.parse('2011-06-24T06:01:02.6255555Z')"),
      njs_str("1308895262625") },

    { njs_str("Date.parse('2011-06-24T06:01:02.625555555Z')"),
      njs_str("1308895262625") },

    { njs_str("Date.parse('2011-06-24T06:01:02.62555555599999Z')"),
      njs_str("1308895262625") },

    { njs_str("Date.parse('2011-06-24T06:01:02.625555Z5')"),
      njs_str("NaN") },

    { njs_str("var tzoffzet = new Date(0).getTimezoneOffset() * 60000;"
              "Date.parse('1970-01-01T00:00:00') == tzoffzet"),
      njs_str("true") },

    { njs_str("Date.parse('1970-01-01')"),
      njs_str("0") },

    { njs_str("var d = new Date(); var str = d.toISOString();"
                 "var diff = Date.parse(str) - Date.parse(str.substring(0, str.length - 1));"
                 "d.getTimezoneOffset() == -diff/1000/60"),
      njs_str("true") },

    { njs_str("Date.parse('24 Jun 2011')"),
      njs_str("1308873600000") },

    { njs_str("Date.parse('Fri, 24 Jun 2011 18:48')"),
      njs_str("1308941280000") },

    { njs_str("Date.parse('Fri, 24 Jun 2011 18:48:02')"),
      njs_str("1308941282000") },

    { njs_str("Date.parse('Fri, 24 Jun 2011 18:48:02 GMT')"),
      njs_str("1308941282000") },

    { njs_str("Date.parse('Fri, 24 Jun 2011 18:48:02 +1245')"),
      njs_str("1308895382000") },

    { njs_str("Date.parse('Jun 24 2011')"),
      njs_str("1308873600000") },

    { njs_str("Date.parse('Fri Jun 24 2011 18:48')"),
      njs_str("1308941280000") },

    { njs_str("Date.parse('Fri Jun 24 2011 18:48:02')"),
      njs_str("1308941282000") },

    { njs_str("Date.parse('Fri Jun 24 2011 18:48:02 GMT+1245')"),
      njs_str("1308895382000") },

    /* Jan 1, 1. */
    { njs_str("Date.parse('+000001-01-01T00:00:00.000Z')"),
      njs_str("-62135596800000") },

    /* Mar 2, 1 BCE. */
    { njs_str("Date.parse('+000000-03-02T00:00:00.000Z')"),
      njs_str("-62161948800000") },

    /* Mar 1, 1 BCE. */
    { njs_str("Date.parse('+000000-03-01T00:00:00.000Z')"),
      njs_str("-62162035200000") },

    /* Feb 29, 1 BCE. */
    { njs_str("Date.parse('+000000-02-29T00:00:00.000Z')"),
      njs_str("-62162121600000") },

    /* Feb 28, 1 BCE. */
    { njs_str("Date.parse('+000000-02-28T00:00:00.000Z')"),
      njs_str("-62162208000000") },

    /* Jan 1, 1 BCE. */
    { njs_str("Date.parse('+000000-01-01T00:00:00.000Z')"),
      njs_str("-62167219200000") },

    /* Jan 1, 2 BCE. */
    { njs_str("Date.parse('-000001-01-01T00:00:00.000Z')"),
      njs_str("-62198755200000") },

    { njs_str("var d = new Date(); d == Date.parse(d.toISOString())"),
      njs_str("false") },

    { njs_str("var s = Date(); s === Date(Date.parse(s))"),
      njs_str("true") },

    { njs_str("var n = Date.now(); n == new Date(n)"),
      njs_str("false") },

    { njs_str("var d = new Date(2011,0); d.getFullYear()"),
      njs_str("2011") },

    { njs_str("var d = new Date(2011, 0, 1, 0, 0, 0, -1); d.getFullYear()"),
      njs_str("2010") },

    { njs_str("var d = new Date(2011, 11, 31, 23, 59, 59, 999); d.getFullYear()"),
      njs_str("2011") },

    { njs_str("var d = new Date(2011, 11, 31, 23, 59, 59, 1000); d.getFullYear()"),
      njs_str("2012") },

    { njs_str("var d = new Date(2011, 5, 24, 18, 45); d.getFullYear()"),
      njs_str("2011") },

    { njs_str("var d = new Date(2011, 5, 24, 18, 45); d.getUTCFullYear()"),
      njs_str("2011") },

    { njs_str("var d = new Date(2011, 5); d.getMonth()"),
      njs_str("5") },

    { njs_str("var d = new Date(2011, 6, 0, 0, 0, 0, -1); d.getMonth()"),
      njs_str("5") },

    { njs_str("var d = new Date(2011, 6, 31, 23, 59, 59, 999); d.getMonth()"),
      njs_str("6") },

    { njs_str("var d = new Date(2011, 6, 31, 23, 59, 59, 1000); d.getMonth()"),
      njs_str("7") },

    { njs_str("var d = new Date(2011, 5, 24, 18, 45); d.getMonth()"),
      njs_str("5") },

    { njs_str("var d = new Date(2011, 5, 24, 18, 45); d.getUTCMonth()"),
      njs_str("5") },

    { njs_str("var d = new Date(2011, 5, 24, 18, 45); d.getDate()"),
      njs_str("24") },

    { njs_str("var d = new Date(2011, 5, 24, 18, 45); d.getUTCDate()"),
      njs_str("24") },

    { njs_str("var d = new Date(2011, 5, 24, 18, 45); d.getDay()"),
      njs_str("5") },

    { njs_str("var d = new Date(2011, 5, 24, 18, 45); d.getUTCDay()"),
      njs_str("5") },

    { njs_str("var d = new Date(2011, 5, 24, 18, 45); d.getHours()"),
      njs_str("18") },

    { njs_str("var d = new Date(2011, 5, 24, 18, 45); d.getUTCHours()"),
      njs_str("18") },

    { njs_str("var d = new Date(2011, 5, 24, 18, 45); d.getMinutes()"),
      njs_str("45") },

    { njs_str("var d = new Date(2011, 5, 24, 18, 45); d.getUTCMinutes()"),
      njs_str("45") },

    { njs_str("var d = new Date(2011, 5, 24, 18, 45, 12);"
                 "d.getSeconds()"),
      njs_str("12") },

    { njs_str("var d = new Date(2011, 5, 24, 18, 45, 12);"
                 "d.getUTCSeconds()"),
      njs_str("12") },

    { njs_str("var d = new Date(2011, 5, 24, 18, 45, 12, 625);"
                 "d.getMilliseconds()"),
      njs_str("625") },

    { njs_str("var d = new Date(2011, 5, 24, 18, 45, 12, 625);"
                 "d.getUTCMilliseconds()"),
      njs_str("625") },

    { njs_str("var d = new Date(2011, 5, 24, 18, 45, 12, 625);"
                 "d.getTimezoneOffset()"),
      njs_str("0") },

    { njs_str("var d = new Date(); d.setTime(1308895200000); d.getTime()"),
      njs_str("1308895200000") },

    { njs_str("var d = new Date(); d.setTime(); d.getTime()"),
      njs_str("NaN") },

    { njs_str("var d = new Date(); d.setTime(Infinity); d.getTime()"),
      njs_str("NaN") },

    { njs_str("var d = new Date(); d.setTime(8.64e15 +1); d.getTime()"),
      njs_str("NaN") },

    { njs_str("var d = new Date(NaN); d.setTime(0); d.getTime()"),
      njs_str("0") },

    { njs_str("var d = new Date(); d.setTime(8.64e15); d.getTime()"),
      njs_str("8640000000000000") },

    { njs_str("var d = new Date(1308895201625); d.setMilliseconds(5003);"
                 "d.getTime()"),
      njs_str("1308895206003") },

    { njs_str("var d = new Date(1308895201625); d.setSeconds(2, 5003);"
                 "d.getTime()"),
      njs_str("1308895207003") },

    { njs_str("var d = new Date(1308895201625); d.setSeconds(2);"
                 "d.getTime()"),
      njs_str("1308895202625") },

    { njs_str("var d = new Date(1308895323625); d.setMinutes(3, 2, 5003);"
                 "d.getTime()"),
      njs_str("1308895387003") },

    { njs_str("var d = new Date(1308895323625); d.setMinutes(3, 2);"
                 "d.getTime()"),
      njs_str("1308895382625") },

    { njs_str("var d = new Date(1308895323625); d.setMinutes(3);"
                 "d.getTime()"),
      njs_str("1308895383625") },

    { njs_str("var d = new Date(1308895323625); d.setUTCMinutes(3, 2, 5003);"
                 "d.getTime()"),
      njs_str("1308895387003") },

    { njs_str("var d = new Date(1308895323625); d.setUTCMinutes(3, 2, 5003, 111111);"
                 "d.getTime()"),
      njs_str("1308895387003") },

    { njs_str("var d = new Date(1308895323625); d.setUTCMinutes(3, 2);"
                 "d.getTime()"),
      njs_str("1308895382625") },

    { njs_str("var d = new Date(1308895323625); d.setUTCMinutes(3);"
                 "d.getTime()"),
      njs_str("1308895383625") },

    { njs_str("var d = new Date(1308895323625); d.setHours(20, 3, 2, 5003);"
                 "d.getTime()"),
      njs_str("1308945787003") },

    { njs_str("var d = new Date(1308895323625); d.setHours(20, 3, 2);"
                 "d.getTime()"),
      njs_str("1308945782625") },

    { njs_str("var d = new Date(1308895323625); d.setHours(20, 3);"
                 "d.getTime()"),
      njs_str("1308945783625") },

    { njs_str("var d = new Date(1308895323625); d.setHours(20);"
                 "d.getTime()"),
      njs_str("1308945723625") },

    { njs_str("var d = new Date(1308895323625);"
                 "d.setUTCHours(20, 3, 2, 5003); d.getTime()"),
      njs_str("1308945787003") },

    { njs_str("var d = new Date(1308895323625); d.setUTCHours(20, 3, 2);"
                 "d.getTime()"),
      njs_str("1308945782625") },

    { njs_str("var d = new Date(1308895323625); d.setUTCHours(20, 3);"
                 "d.getTime()"),
      njs_str("1308945783625") },

    { njs_str("var d = new Date(1308895323625); d.setUTCHours(20);"
                 "d.getTime()"),
      njs_str("1308945723625") },

    { njs_str("var d = new Date(1308895323625); d.setDate(10);"
                 "d.getTime()"),
      njs_str("1307685723625") },

    { njs_str("var d = new Date(1308895323625); d.setUTCDate(10);"
                 "d.getTime()"),
      njs_str("1307685723625") },

    { njs_str("var d = new Date(1308895323625); d.setMonth(2, 10);"
                 "d.getTime()"),
      njs_str("1299736923625") },

    { njs_str("var d = new Date(1308895323625); d.setUTCMonth(2, 10);"
                 "d.getTime()"),
      njs_str("1299736923625") },

    { njs_str("var d = new Date(1308895323625); d.setMonth(2);"
                 "d.getTime()"),
      njs_str("1300946523625") },

    { njs_str("var d = new Date(1308895323625); d.setMonth(2, undefined);"
                 "d.getTime()"),
      njs_str("NaN") },

    { njs_str("var d = new Date(1308895323625); d.setMonth(2, undefined)"),
      njs_str("NaN") },

    { njs_str("var d = new Date(1308895323625); d.setUTCMonth(2);"
                 "d.getTime()"),
      njs_str("1300946523625") },

    { njs_str("var d = new Date(1308895323625); d.setFullYear(2010, 2, 10);"
                 "d.getTime()"),
      njs_str("1268200923625") },

    { njs_str("var d = new Date(NaN); d.setFullYear(2010);"
                 "d.getTime() === (new Date(2010,0)).getTime()"),
      njs_str("true") },

    { njs_str("var d = new Date(1308895323625);"
                 "d.setUTCFullYear(2010, 2, 10); d.getTime()"),
      njs_str("1268200923625") },

    { njs_str("var d = new Date(1308895323625); d.setFullYear(2010, 2);"
                 "d.getTime()"),
      njs_str("1269410523625") },

    { njs_str("var d = new Date(1308895323625); d.setUTCFullYear(2010, 2);"
                 "d.getTime()"),
      njs_str("1269410523625") },

    { njs_str("var d = new Date(1308895323625); d.setFullYear(2010);"
                 "d.getTime()"),
      njs_str("1277359323625") },

    { njs_str("var date = new Date(2016, 6, 7, 11, 36, 23, 2); "
              "date.setFullYear(null) === new Date(-1, 18, 7, 11, 36, 23, 2).getTime()"),
      njs_str("true") },

    { njs_str("var d = new Date(1308895323625); d.setUTCFullYear(2010);"
                 "d.getTime()"),
      njs_str("1277359323625") },

    { njs_str("var d = new Date(2011, 5, 24, 18, 45, 12, 625);"
                 "d.toJSON(1)"),
      njs_str("2011-06-24T18:45:12.625Z") },

    { njs_str("var o = { toISOString: function() { return 'OK' } };"
                 "Date.prototype.toJSON.call(o, 1)"),
      njs_str("OK") },

    { njs_str("var d = new Date(); d.__proto__ === Date.prototype"),
      njs_str("true") },

    { njs_str("new Date(NaN)"),
      njs_str("Invalid Date") },

    { njs_str("new Date(0, 9e99)"),
      njs_str("Invalid Date") },

#ifndef NJS_SUNC
    { njs_str("new Date(-0).getTime()"),
      njs_str("0") },
#endif

    { njs_str("new Date(6.54321).valueOf()"),
      njs_str("6") },

    { njs_str("[0].map(new Date().getDate)"),
      njs_str("TypeError: cannot convert undefined to date") },

    { njs_str("new Date(eval)"),
      njs_str("Invalid Date") },

    { njs_str("Date.UTC(eval)"),
      njs_str("NaN") },

    { njs_str("Date.name"),
      njs_str("Date") },

    { njs_str("Date.length"),
      njs_str("7") },

    { njs_str("Date.__proto__ === Function.prototype"),
      njs_str("true") },

    { njs_str("Date.prototype.constructor === Date"),
      njs_str("true") },

    { njs_str("Date.prototype.hasOwnProperty('constructor')"),
      njs_str("true") },

    { njs_str("Date.prototype.__proto__ === Object.prototype"),
      njs_str("true") },

    { njs_str("njs.dump(Date.prototype)"),
      njs_str("{}") },

    { njs_str("Date.prototype.valueOf()"),
      njs_str("TypeError: cannot convert object to date") },

    { njs_str("Date.constructor === Function"),
      njs_str("true") },

    { njs_str("var y = Object.defineProperty({}, Symbol.toPrimitive, {"
              "    get: function() {"
              "        throw new Error('expected');"
              "    }"
              "});"
              "new Date(y);"),
      njs_str("Error: expected") },

    { njs_str("var y = {};"
              "y[Symbol.toPrimitive] = function() {"
              "     throw new Error('expected');"
              "};"
              "new Date(y);"),
      njs_str("Error: expected") },

    { njs_str("var y = {};"
              "var callCount = 0;"
              "var thisVal, args;"
              "y[Symbol.toPrimitive] = function() {"
              "    callCount += 1;"
              "    thisVal = this;"
              "    args = arguments;"
              "};"
              "new Date(y);"
              "callCount === 1 && thisVal === y && args.length === 1 && args[0] === 'default'"),
      njs_str("true") },

    { njs_str("var y = {};"
              "var retVal;"
              "y[Symbol.toPrimitive] = function() {"
              "    return retVal;"
              "};"
              "retVal = {};"
              "new Date(y);"),
      njs_str("TypeError") },

    { njs_str("var badToPrimitive = {};"
              "badToPrimitive[Symbol.toPrimitive] = function() {"
              "    throw new Error('expected');"
              "};"
              "new Date(badToPrimitive);"),
      njs_str("Error: expected") },

    { njs_str("var spyToPrimitive = {};"
              "var callCount = 0;"
              "var thisValue, args;"
              "spyToPrimitive[Symbol.toPrimitive] = function() {"
              "    thisValue = this;"
              "    args = arguments;"
              "    callCount += 1;"
              "};"
              "new Date(spyToPrimitive);"
              "callCount === 1 && thisValue === spyToPrimitive && args.length === 1 && args[0] === 'default';"),
      njs_str("true") },

    { njs_str("var poisonedObject = {};"
              "var poisonedDate = new Date();"
              "Object.defineProperty(poisonedObject, Symbol.toPrimitive, {"
              "    get: function() {"
              "        throw new Error('expected');"
              "    }"
              "});"
              "Object.defineProperty(poisonedDate, Symbol.toPrimitive, {"
              "    get: function() {"
              "        throw new Error('unexpected');"
              "    }"
              "});"
              "Date(poisonedObject);"
              "new Date(poisonedDate);"
              "new Date(poisonedObject);"),
      njs_str("Error: expected") },

    { njs_str("var faultyToPrimitive = {};"
              "var returnValue;"
              "faultyToPrimitive[Symbol.toPrimitive] = function() {"
              "    return returnValue;"
              "};"
              "returnValue = {};"
              "new Date(faultyToPrimitive);"),
      njs_str("TypeError") },

    { njs_str("var stringToPrimitive = {};"
              "stringToPrimitive[Symbol.toPrimitive] = function() {"
              "    return '2016-06-05T18:40:00.000Z';"
              "};"
              "new Date(stringToPrimitive).getTime() === 1465152000000"),
      njs_str("true") },

    { njs_str("Date.prototype[Symbol.toPrimitive].length === 1"),
      njs_str("true") },

    { njs_str("Date.prototype[Symbol.toPrimitive].name"),
      njs_str("[Symbol.toPrimitive]") },

    { njs_str("Date.prototype[Symbol.toPrimitive].call(undefined, 'string')"),
      njs_str("TypeError: cannot convert") },

    { njs_str("Date.prototype[Symbol.toPrimitive].call(null, 'string')"),
      njs_str("TypeError: cannot conver") },

    { njs_str("Date.prototype[Symbol.toPrimitive].call(86, 'string')"),
      njs_str("TypeError: cannot convert") },

    { njs_str("Date.prototype[Symbol.toPrimitive].call('', 'string')"),
      njs_str("TypeError: cannot convert") },

    { njs_str("Date.prototype[Symbol.toPrimitive].call(true, 'string')"),
      njs_str("TypeError: cannot convert") },

    /* eval(). */

    { njs_str("eval.name"),
      njs_str("eval") },

    { njs_str("eval.length"),
      njs_str("1") },

    { njs_str("eval.prototype"),
      njs_str("undefined") },

    { njs_str("eval.__proto__ === Function.prototype"),
      njs_str("true") },

    { njs_str("eval.constructor === Function"),
      njs_str("true") },

    { njs_str("eval()"),
      njs_str("InternalError: Not implemented") },

    { njs_str("delete this.eval; eval"),
      njs_str("ReferenceError: \"eval\" is not defined") },

    { njs_str("var d = Object.getOwnPropertyDescriptor(this, 'eval');"
              "d.writable && !d.enumerable && d.configurable"),
      njs_str("true") },

    /* Math. */

    { njs_str("Math.PI"),
      njs_str("3.141592653589793") },

    { njs_str("Math.abs()"),
      njs_str("NaN") },

    { njs_str("Math.abs(5)"),
      njs_str("5") },

    { njs_str("Math.abs(-5)"),
      njs_str("5") },

    { njs_str("Math.abs('5.0')"),
      njs_str("5") },

    { njs_str("Math.abs('abc')"),
      njs_str("NaN") },

    { njs_str("Math.acos()"),
      njs_str("NaN") },

    { njs_str("Math.acos(NaN)"),
      njs_str("NaN") },

    { njs_str("Math.acos('abc')"),
      njs_str("NaN") },

    { njs_str("Math.acos(1.1)"),
      njs_str("NaN") },

    { njs_str("Math.acos(-1.1)"),
      njs_str("NaN") },

    { njs_str("Math.acos('1')"),
      njs_str("0") },

    { njs_str("Math.acos(0) - Math.PI/2"),
      njs_str("0") },

    { njs_str("Math.acosh()"),
      njs_str("NaN") },

    { njs_str("Math.acosh('abc')"),
      njs_str("NaN") },

    { njs_str("Math.acosh(0.9)"),
      njs_str("NaN") },

    { njs_str("Math.acosh(1)"),
      njs_str("0") },

    { njs_str("Math.acosh('Infinity')"),
      njs_str("Infinity") },

    /*
     * The difference is Number.EPSILON on Linux/i686
     * and zero on other platforms.
     */
    { njs_str("Math.abs(Math.acosh((1/Math.E + Math.E)/2) - 1)"
                 " <= Number.EPSILON"),
      njs_str("true") },

    { njs_str("Math.asin()"),
      njs_str("NaN") },

    { njs_str("Math.asin(NaN)"),
      njs_str("NaN") },

    { njs_str("Math.asin('abc')"),
      njs_str("NaN") },

    { njs_str("Math.asin(1.1)"),
      njs_str("NaN") },

    { njs_str("Math.asin(-1.1)"),
      njs_str("NaN") },

    { njs_str("Math.asin(0)"),
      njs_str("0") },

    { njs_str("Math.asin('-0')"),
      njs_str("-0") },

    { njs_str("Math.asin(1) - Math.PI/2"),
      njs_str("0") },

    { njs_str("Math.asinh()"),
      njs_str("NaN") },

    { njs_str("Math.asinh('abc')"),
      njs_str("NaN") },

    { njs_str("Math.asinh(0)"),
      njs_str("0") },

    { njs_str("Math.asinh('-0')"),
      njs_str("-0") },

    { njs_str("Math.asinh(Infinity)"),
      njs_str("Infinity") },

    { njs_str("Math.asinh(-Infinity)"),
      njs_str("-Infinity") },

    { njs_str("Math.asinh((Math.E - 1/Math.E)/2)"),
      njs_str("1") },

    { njs_str("Math.atan()"),
      njs_str("NaN") },

    { njs_str("Math.atan(NaN)"),
      njs_str("NaN") },

    { njs_str("Math.atan('abc')"),
      njs_str("NaN") },

    { njs_str("Math.atan('Infinity') - Math.PI/2"),
      njs_str("0") },

    { njs_str("Math.atan(-Infinity) + Math.PI/2"),
      njs_str("0") },

    { njs_str("Math.atan(0)"),
      njs_str("0") },

    { njs_str("Math.atan('-0')"),
      njs_str("-0") },

    { njs_str("Math.atan(1) - Math.PI/4"),
      njs_str("0") },

    { njs_str("Math.atan2()"),
      njs_str("NaN") },

    { njs_str("Math.atan2(1)"),
      njs_str("NaN") },

    { njs_str("Math.atan2('abc', 1)"),
      njs_str("NaN") },

    { njs_str("Math.atan2(1, 0) - Math.PI/2"),
      njs_str("0") },

    { njs_str("Math.atan2('1', -0) - Math.PI/2"),
      njs_str("0") },

    { njs_str("Math.atan2(0, '1')"),
      njs_str("0") },

    { njs_str("Math.atan2(0, 0)"),
      njs_str("0") },

    { njs_str("Math.atan2(0, -0) - Math.PI"),
      njs_str("0") },

    { njs_str("Math.atan2('0', -1) - Math.PI"),
      njs_str("0") },

    { njs_str("Math.atan2(-0, '0.1')"),
      njs_str("-0") },

    { njs_str("Math.atan2(-0, 0)"),
      njs_str("-0") },

    { njs_str("Math.atan2(-0, -0) + Math.PI"),
      njs_str("0") },

    { njs_str("Math.atan2('-0', '-1') + Math.PI"),
      njs_str("0") },

    { njs_str("Math.atan2(-0.1, 0) + Math.PI/2"),
      njs_str("0") },

    { njs_str("Math.atan2(-1, -0) + Math.PI/2"),
      njs_str("0") },

    { njs_str("Math.atan2(1, 'Infinity')"),
      njs_str("0") },

    { njs_str("Math.atan2(0.1, -Infinity) - Math.PI"),
      njs_str("0") },

    { njs_str("Math.atan2(-1, Infinity)"),
      njs_str("-0") },

    { njs_str("Math.atan2('-0.1', -Infinity) + Math.PI"),
      njs_str("0") },

    { njs_str("Math.atan2(Infinity, -5) - Math.PI/2"),
      njs_str("0") },

    { njs_str("Math.atan2(-Infinity, 5) + Math.PI/2"),
      njs_str("0") },

    { njs_str("Math.atan2('Infinity', 'Infinity') - Math.PI/4"),
      njs_str("0") },

    { njs_str("Math.atan2(Infinity, -Infinity) - 3*Math.PI/4"),
      njs_str("0") },

    { njs_str("Math.atan2(-Infinity, 'Infinity') + Math.PI/4"),
      njs_str("0") },

    { njs_str("Math.atan2('-Infinity', -Infinity) + 3*Math.PI/4"),
      njs_str("0") },

    { njs_str("Math.atan2(1, 1) - Math.atan2(-5, -5) - Math.PI"),
      njs_str("0") },

    { njs_str("Math.atanh()"),
      njs_str("NaN") },

    { njs_str("Math.atanh('abc')"),
      njs_str("NaN") },

    { njs_str("Math.atanh(-1.1)"),
      njs_str("NaN") },

    { njs_str("Math.atanh(1.1)"),
      njs_str("NaN") },

    { njs_str("Math.atanh(1)"),
      njs_str("Infinity") },

    { njs_str("Math.atanh('-1')"),
      njs_str("-Infinity") },

    { njs_str("Math.atanh(0)"),
      njs_str("0") },

    { njs_str("Math.atanh(-0)"),
      njs_str("-0") },

    /*
     * The difference is Number.EPSILON on Linux/i686
     * and zero on other platforms.
     */
    { njs_str("Math.abs(1 - Math.atanh((Math.E - 1)/(Math.E + 1)) * 2)"
                 " <= Number.EPSILON"),
      njs_str("true") },

    { njs_str("Math.cbrt()"),
      njs_str("NaN") },

    { njs_str("Math.cbrt('abc')"),
      njs_str("NaN") },

    { njs_str("Math.cbrt(0)"),
      njs_str("0") },

    { njs_str("Math.cbrt('-0')"),
      njs_str("-0") },

    { njs_str("Math.cbrt(Infinity)"),
      njs_str("Infinity") },

    { njs_str("Math.cbrt(-Infinity)"),
      njs_str("-Infinity") },

    { njs_str("(Math.cbrt('27') - 3) < 1e-15"),
      njs_str("true") },

    { njs_str("Math.cbrt(-1)"),
      njs_str("-1") },

    { njs_str("Math.ceil()"),
      njs_str("NaN") },

    { njs_str("Math.ceil('abc')"),
      njs_str("NaN") },

    { njs_str("Math.ceil(0)"),
      njs_str("0") },

    { njs_str("Math.ceil('-0')"),
      njs_str("-0") },

    { njs_str("Math.ceil('Infinity')"),
      njs_str("Infinity") },

    { njs_str("Math.ceil(-Infinity)"),
      njs_str("-Infinity") },

    { njs_str("Math.ceil(-0.9)"),
      njs_str("-0") },

    { njs_str("Math.ceil(3.1)"),
      njs_str("4") },

    { njs_str("Math.clz32()"),
      njs_str("32") },

    { njs_str("Math.clz32('abc')"),
      njs_str("32") },

    { njs_str("Math.clz32(NaN)"),
      njs_str("32") },

    { njs_str("Math.clz32(Infinity)"),
      njs_str("32") },

    { njs_str("Math.clz32('1')"),
      njs_str("31") },

    { njs_str("Math.clz32(0)"),
      njs_str("32") },

    { njs_str("Math.clz32('65535')"),
      njs_str("16") },

    { njs_str("Math.clz32(-1)"),
      njs_str("0") },

    { njs_str("Math.clz32(4294967298)"),
      njs_str("30") },

    { njs_str("Math.cos()"),
      njs_str("NaN") },

    { njs_str("Math.cos('abc')"),
      njs_str("NaN") },

    { njs_str("Math.cos('0')"),
      njs_str("1") },

    { njs_str("Math.cos(-0)"),
      njs_str("1") },

    { njs_str("Math.cos(Infinity)"),
      njs_str("NaN") },

    { njs_str("Math.cos(-Infinity)"),
      njs_str("NaN") },

    { njs_str("Math.cos(Math.PI*2)"),
      njs_str("1") },

    { njs_str("Math.cosh()"),
      njs_str("NaN") },

    { njs_str("Math.cosh('abc')"),
      njs_str("NaN") },

    { njs_str("Math.cosh('0')"),
      njs_str("1") },

    { njs_str("Math.cosh(-0)"),
      njs_str("1") },

    { njs_str("Math.cosh(Infinity)"),
      njs_str("Infinity") },

    { njs_str("Math.cosh(-Infinity)"),
      njs_str("Infinity") },

    /*
     * The difference is Number.EPSILON on FreeBSD
     * and zero on other platforms.
     */
    { njs_str("Math.abs(Math.cosh(1) - (1/Math.E + Math.E)/2)"
                 " <= Number.EPSILON"),
      njs_str("true") },

    { njs_str("Math.exp()"),
      njs_str("NaN") },

    { njs_str("Math.exp('abc')"),
      njs_str("NaN") },

    { njs_str("Math.exp('0')"),
      njs_str("1") },

    { njs_str("Math.exp(-0)"),
      njs_str("1") },

    { njs_str("Math.exp(Infinity)"),
      njs_str("Infinity") },

    { njs_str("Math.exp(-Infinity)"),
      njs_str("0") },

    /*
     * The difference is 2 * Number.EPSILON on FreeBSD
     * and zero on other platforms.
     */
    { njs_str("Math.abs(Math.exp(1) - Math.E) <= 2 * Number.EPSILON"),
      njs_str("true") },

    { njs_str("Math.expm1()"),
      njs_str("NaN") },

    { njs_str("Math.expm1('abc')"),
      njs_str("NaN") },

    { njs_str("Math.expm1('0')"),
      njs_str("0") },

    { njs_str("Math.expm1(-0)"),
      njs_str("-0") },

    { njs_str("Math.expm1(Infinity)"),
      njs_str("Infinity") },

    { njs_str("Math.expm1(-Infinity)"),
      njs_str("-1") },

    /*
     * The difference is 2 * Number.EPSILON on FreeBSD, Solaris,
     * and MacOSX and zero on other platforms.
     */
    { njs_str("Math.abs(1 + Math.expm1(1) - Math.E) <= 2 * Number.EPSILON"),
      njs_str("true") },

    { njs_str("Math.floor()"),
      njs_str("NaN") },

    { njs_str("Math.floor('abc')"),
      njs_str("NaN") },

    { njs_str("Math.floor(0)"),
      njs_str("0") },

    { njs_str("Math.floor('-0')"),
      njs_str("-0") },

    { njs_str("Math.floor('Infinity')"),
      njs_str("Infinity") },

    { njs_str("Math.floor(-Infinity)"),
      njs_str("-Infinity") },

    { njs_str("Math.floor(0.9)"),
      njs_str("0") },

    { njs_str("Math.floor(-3.1)"),
      njs_str("-4") },

    { njs_str("Math.fround()"),
      njs_str("NaN") },

    { njs_str("Math.fround('abc')"),
      njs_str("NaN") },

    { njs_str("Math.fround(0)"),
      njs_str("0") },

    { njs_str("Math.fround('-0')"),
      njs_str("-0") },

    { njs_str("Math.fround('Infinity')"),
      njs_str("Infinity") },

    { njs_str("Math.fround(-Infinity)"),
      njs_str("-Infinity") },

    { njs_str("Math.fround('-1.5')"),
      njs_str("-1.5") },

    { njs_str("Math.fround(16777216)"),
      njs_str("16777216") },

    { njs_str("Math.fround(-16777217)"),
      njs_str("-16777216") },

    { njs_str("Math.hypot()"),
      njs_str("0") },

    { njs_str("Math.hypot(1, 2, 'abc')"),
      njs_str("NaN") },

    { njs_str("Math.hypot(1, NaN, 3)"),
      njs_str("NaN") },

    { njs_str("Math.hypot(1, NaN, -Infinity)"),
      njs_str("Infinity") },

    { njs_str("Math.hypot(-42)"),
      njs_str("42") },

    { njs_str("Math.hypot(8, -15)"),
      njs_str("17") },

    { njs_str("Math.hypot(3, -4, 12.0, '84', 132)"),
      njs_str("157") },

    { njs_str("Math.imul()"),
      njs_str("0") },

    { njs_str("Math.imul(1)"),
      njs_str("0") },

    { njs_str("Math.imul('a', 1)"),
      njs_str("0") },

    { njs_str("Math.imul(1, NaN)"),
      njs_str("0") },

    { njs_str("Math.imul(2, '3')"),
      njs_str("6") },

    { njs_str("Math.imul('3.9', -2.1)"),
      njs_str("-6") },

    { njs_str("Math.imul(2, 2147483647)"),
      njs_str("-2") },

    { njs_str("Math.imul(Number.MAX_SAFE_INTEGER, 2)"),
      njs_str("-2") },

    { njs_str("Math.imul(1, Number.MAX_SAFE_INTEGER + 1)"),
      njs_str("0") },

    { njs_str("Math.imul(2, Number.MIN_SAFE_INTEGER)"),
      njs_str("2") },

    { njs_str("Math.imul(Number.MIN_SAFE_INTEGER - 1, 1)"),
      njs_str("0") },

    { njs_str("Math.imul(2, 4294967297)"),
      njs_str("2") },

    { njs_str("Math.imul(-4294967297, 4294967297)"),
      njs_str("-1") },

    { njs_str("Math.imul(4294967297, -4294967298)"),
      njs_str("-2") },

    { njs_str("Math.imul(-4294967290, 4294967290)"),
      njs_str("-36") },

    { njs_str("Math.imul(-Infinity, 1)"),
      njs_str("0") },

    { njs_str("Math.imul(1, Infinity)"),
      njs_str("0") },

    { njs_str("Math.imul(Number.MAX_VALUE, 1)"),
      njs_str("0") },

    { njs_str("Math.imul(1, -Number.MAX_VALUE)"),
      njs_str("0") },

    { njs_str("Math.log()"),
      njs_str("NaN") },

    { njs_str("Math.log('abc')"),
      njs_str("NaN") },

    { njs_str("Math.log(-1)"),
      njs_str("NaN") },

    { njs_str("Math.log(0)"),
      njs_str("-Infinity") },

    { njs_str("Math.log('-0')"),
      njs_str("-Infinity") },

    { njs_str("Math.log(1)"),
      njs_str("0") },

    { njs_str("Math.log(Infinity)"),
      njs_str("Infinity") },

    { njs_str("Math.log(Math.E)"),
      njs_str("1") },

    { njs_str("Math.log10()"),
      njs_str("NaN") },

    { njs_str("Math.log10('abc')"),
      njs_str("NaN") },

    { njs_str("Math.log10(-1)"),
      njs_str("NaN") },

    { njs_str("Math.log10(0)"),
      njs_str("-Infinity") },

    { njs_str("Math.log10('-0')"),
      njs_str("-Infinity") },

    { njs_str("Math.log10(1)"),
      njs_str("0") },

    { njs_str("Math.log10(Infinity)"),
      njs_str("Infinity") },

    { njs_str("Math.log10(1000)"),
      njs_str("3") },

    { njs_str("Math.log1p()"),
      njs_str("NaN") },

    { njs_str("Math.log1p('abc')"),
      njs_str("NaN") },

    { njs_str("Math.log1p(-2)"),
      njs_str("NaN") },

    { njs_str("Math.log1p('-1')"),
      njs_str("-Infinity") },

    { njs_str("Math.log1p(0)"),
      njs_str("0") },

    { njs_str("Math.log1p(-0)"),
      njs_str("-0") },

    { njs_str("Math.log1p(Infinity)"),
      njs_str("Infinity") },

    { njs_str("Math.log1p(Math.E - 1)"),
      njs_str("1") },

    { njs_str("Math.log2()"),
      njs_str("NaN") },

    { njs_str("Math.log2('abc')"),
      njs_str("NaN") },

    { njs_str("Math.log2(-1)"),
      njs_str("NaN") },

    { njs_str("Math.log2(0)"),
      njs_str("-Infinity") },

    { njs_str("Math.log2('-0')"),
      njs_str("-Infinity") },

    { njs_str("Math.log2(1)"),
      njs_str("0") },

    { njs_str("Math.log2(Infinity)"),
      njs_str("Infinity") },

    { njs_str("Math.log2(128)"),
      njs_str("7") },

    { njs_str("Math.max()"),
      njs_str("-Infinity") },

    { njs_str("Math.max(0, -0)"),
      njs_str("0") },

    { njs_str("Math.max(-0, 0)"),
      njs_str("0") },

    { njs_str("Math.max(null)"),
      njs_str("0") },

    { njs_str("Math.max(undefined)"),
      njs_str("NaN") },

    { njs_str("Math.max(1, 2, 3, undefined)"),
      njs_str("NaN") },

    { njs_str("Math.max(1, 2, 3, NaN)"),
      njs_str("NaN") },

    { njs_str("Math.max('1', '2', '5')"),
      njs_str("5") },

    { njs_str("Math.max(5, {valueOf: function () {return 10}}, 6)"),
      njs_str("10") },

    { njs_str("Math.max(5, {valueOf: function () {return 10}}, 20)"),
      njs_str("20") },

    { njs_str("Math.max(5, undefined, 20)"),
      njs_str("NaN") },

    { njs_str("Math.max(-10, null, -30)"),
      njs_str("0") },

    { njs_str("Math.min()"),
      njs_str("Infinity") },

    { njs_str("Math.min(0, -0)"),
      njs_str("-0") },

    { njs_str("Math.min(-0, 0)"),
      njs_str("-0") },

    { njs_str("Math.min(null)"),
      njs_str("0") },

    { njs_str("Math.min(undefined)"),
      njs_str("NaN") },

    { njs_str("Math.min(1, 2, 3, undefined)"),
      njs_str("NaN") },

    { njs_str("Math.min(1, 2, 3, NaN)"),
      njs_str("NaN") },

    { njs_str("Math.min('1', '2', '5')"),
      njs_str("1") },

    { njs_str("Math.pow(2, 5)"),
      njs_str("32") },

    { njs_str("Math.pow(2)"),
      njs_str("NaN") },

    { njs_str("Math.pow()"),
      njs_str("NaN") },

    { njs_str("Math.pow(1, NaN)"),
      njs_str("NaN") },

    { njs_str("Math.pow(3, NaN)"),
      njs_str("NaN") },

    { njs_str("Math.pow('a', -0)"),
      njs_str("1") },

    { njs_str("Math.pow(1.1, Infinity)"),
      njs_str("Infinity") },

    { njs_str("Math.pow(-1.1, -Infinity)"),
      njs_str("0") },

    { njs_str("Math.pow(-1, Infinity)"),
      njs_str("NaN") },

    { njs_str("Math.pow(1, -Infinity)"),
      njs_str("NaN") },

    { njs_str("Math.pow(-0.9, Infinity)"),
      njs_str("0") },

    { njs_str("Math.pow(0.9, -Infinity)"),
      njs_str("Infinity") },

    { njs_str("Math.pow('Infinity', 0.1)"),
      njs_str("Infinity") },

    { njs_str("Math.pow(Infinity, '-0.1')"),
      njs_str("0") },

    { njs_str("Math.pow(-Infinity, 3)"),
      njs_str("-Infinity") },

    { njs_str("Math.pow('-Infinity', '3.1')"),
      njs_str("Infinity") },

    { njs_str("Math.pow(-Infinity, '-3')"),
      njs_str("-0") },

    { njs_str("Math.pow('-Infinity', -2)"),
      njs_str("0") },

    { njs_str("Math.pow('0', 0.1)"),
      njs_str("0") },

#ifndef __NetBSD__  /* NetBSD 7: pow(0, negative) == -Infinity. */
    { njs_str("Math.pow(0, '-0.1')"),
      njs_str("Infinity") },
#endif

    { njs_str("Math.pow(-0, 3)"),
      njs_str("-0") },

    { njs_str("Math.pow('-0', '3.1')"),
      njs_str("0") },

    { njs_str("Math.pow(-0, '-3')"),
      njs_str("-Infinity") },

#ifndef __NetBSD__  /* NetBSD 7: pow(0, negative) == -Infinity. */
    { njs_str("Math.pow('-0', -2)"),
      njs_str("Infinity") },
#endif

    { njs_str("Math.pow(-3, 0.1)"),
      njs_str("NaN") },

    { njs_str("var a = Math.random(); a >= 0 && a < 1"),
      njs_str("true") },

    { njs_str("Math.round()"),
      njs_str("NaN") },

    { njs_str("Math.round('abc')"),
      njs_str("NaN") },

    { njs_str("Math.round(0)"),
      njs_str("0") },

    { njs_str("Math.round('-0')"),
      njs_str("-0") },

    { njs_str("Math.round('Infinity')"),
      njs_str("Infinity") },

    { njs_str("Math.round(-Infinity)"),
      njs_str("-Infinity") },

    { njs_str("Math.round(0.4)"),
      njs_str("0") },

    { njs_str("Math.round('0.5')"),
      njs_str("1") },

    { njs_str("Math.round('-0.4')"),
      njs_str("-0") },

    { njs_str("Math.round(-0.5)"),
      njs_str("-0") },

    { njs_str("Math.round(-0.50000000000000001)"),
      njs_str("-0") },

    { njs_str("Math.round(-0.5000000000000001)"),
      njs_str("-1") },

    { njs_str("[0.500001, 0.5000001,0.50000001].map((v)=>Math.round((2**32) + v) - 2**32)"),
      njs_str("1,1,1") },

    { njs_str("[0.500001, 0.5000001,0.50000001].map((v)=>Math.round(-(2**32) + v) + 2**32)"),
      njs_str("1,1,1") },

    { njs_str("[0.500001, 0.5000001,0.50000001].map((v)=>Math.round((2**32) - v) - 2**32)"),
      njs_str("-1,0,0") },

    { njs_str("[0.500001, 0.5000001,0.50000001].map((v)=>Math.round(-(2**32) - v) + 2**32)"),
      njs_str("-1,0,0") },

    { njs_str("Math.sign(5)"),
      njs_str("1") },

    { njs_str("Math.sign(-5)"),
      njs_str("-1") },

    { njs_str("Math.sign(0)"),
      njs_str("0") },

    { njs_str("Math.sign(-0.0)"),
      njs_str("-0") },

    { njs_str("Math.sign(NaN)"),
      njs_str("NaN") },

    { njs_str("Math.sign()"),
      njs_str("NaN") },

    { njs_str("Math.sin()"),
      njs_str("NaN") },

    { njs_str("Math.sin('abc')"),
      njs_str("NaN") },

    { njs_str("Math.sin('0')"),
      njs_str("0") },

    { njs_str("Math.sin(-0)"),
      njs_str("-0") },

    { njs_str("Math.sin(Infinity)"),
      njs_str("NaN") },

    { njs_str("Math.sin(-Infinity)"),
      njs_str("NaN") },

    { njs_str("Math.sin(-Math.PI/2)"),
      njs_str("-1") },

    { njs_str("Math.sinh()"),
      njs_str("NaN") },

    { njs_str("Math.sinh('abc')"),
      njs_str("NaN") },

    { njs_str("Math.sinh('0')"),
      njs_str("0") },

    { njs_str("Math.sinh(-0)"),
      njs_str("-0") },

    { njs_str("Math.sinh(Infinity)"),
      njs_str("Infinity") },

    { njs_str("Math.sinh(-Infinity)"),
      njs_str("-Infinity") },

    /*
     * The difference is Number.EPSILON on Solaris
     * and zero on other platforms.
     */
    { njs_str("Math.abs(Math.sinh(1) - (Math.E - 1/Math.E)/2)"
                 " <= Number.EPSILON"),
      njs_str("true") },

    { njs_str("Math.sqrt()"),
      njs_str("NaN") },

    { njs_str("Math.sqrt('abc')"),
      njs_str("NaN") },

    { njs_str("Math.sqrt('0')"),
      njs_str("0") },

    { njs_str("Math.sqrt(-0)"),
      njs_str("-0") },

    { njs_str("Math.sqrt(Infinity)"),
      njs_str("Infinity") },

    { njs_str("Math.sqrt(-0.1)"),
      njs_str("NaN") },

    { njs_str("Math.sqrt('9.0')"),
      njs_str("3") },

    { njs_str("Math.tan()"),
      njs_str("NaN") },

    { njs_str("Math.tan('abc')"),
      njs_str("NaN") },

    { njs_str("Math.tan('0')"),
      njs_str("0") },

    { njs_str("Math.tan(-0)"),
      njs_str("-0") },

    { njs_str("Math.tan(Infinity)"),
      njs_str("NaN") },

    { njs_str("Math.tan(-Infinity)"),
      njs_str("NaN") },

    { njs_str("Math.tan(Math.PI/3) + Math.tan(-Math.PI/3)"),
      njs_str("0") },

    { njs_str("Math.tanh()"),
      njs_str("NaN") },

    { njs_str("Math.tanh('abc')"),
      njs_str("NaN") },

    { njs_str("Math.tanh('0')"),
      njs_str("0") },

    { njs_str("Math.tanh(-0)"),
      njs_str("-0") },

    { njs_str("Math.tanh(Infinity)"),
      njs_str("1") },

    { njs_str("Math.tanh(-Infinity)"),
      njs_str("-1") },

    { njs_str("Math.tanh(0.5) - (Math.E - 1)/(Math.E + 1)"),
      njs_str("0") },

    { njs_str("Math.trunc(3.9)"),
      njs_str("3") },

    { njs_str("Math.trunc(-3.9)"),
      njs_str("-3") },

    { njs_str("Math.trunc(0)"),
      njs_str("0") },

    { njs_str("Math.trunc(-0)"),
      njs_str("-0") },

    { njs_str("Math.trunc(0.9)"),
      njs_str("0") },

    { njs_str("Math.trunc(-0.9)"),
      njs_str("-0") },

    { njs_str("Math.trunc(Infinity)"),
      njs_str("Infinity") },

    { njs_str("Math.trunc(-Infinity)"),
      njs_str("-Infinity") },

    { njs_str("Math.trunc(NaN)"),
      njs_str("NaN") },

    { njs_str("Math.trunc()"),
      njs_str("NaN") },

    { njs_str("Math"),
      njs_str("[object Math]") },

    { njs_str("Math.x = function (x) {return 2*x;}; Math.x(3)"),
      njs_str("6") },

    { njs_str("isNaN"),
      njs_str("[object Function]") },

    { njs_str("isNaN.name"),
      njs_str("isNaN") },

    { njs_str("isNaN.length"),
      njs_str("1") },

    { njs_str("typeof isNaN"),
      njs_str("function") },

    { njs_str("typeof isNaN.length"),
      njs_str("number") },

    { njs_str("isNaN()"),
      njs_str("true") },

    { njs_str("isNaN(123)"),
      njs_str("false") },

    { njs_str("isNaN('123')"),
      njs_str("false") },

    { njs_str("isNaN('Infinity')"),
      njs_str("false") },

    { njs_str("isNaN('abc')"),
      njs_str("true") },

    { njs_str("isFinite"),
      njs_str("[object Function]") },

    { njs_str("isFinite.name"),
      njs_str("isFinite") },

    { njs_str("isFinite.length"),
      njs_str("1") },

    { njs_str("isFinite()"),
      njs_str("false") },

    { njs_str("isFinite(123)"),
      njs_str("true") },

    { njs_str("isFinite('123')"),
      njs_str("true") },

    { njs_str("isFinite('Infinity')"),
      njs_str("false") },

    { njs_str("isFinite('abc')"),
      njs_str("false") },

    { njs_str("parseInt.name"),
      njs_str("parseInt") },

    { njs_str("parseInt.length"),
      njs_str("2") },

    { njs_str("parseInt()"),
      njs_str("NaN") },

    { njs_str("parseInt('12345abc')"),
      njs_str("12345") },

    { njs_str("parseInt('123', 0)"),
      njs_str("123") },

    { njs_str("parseInt('0XaBc', 0)"),
      njs_str("2748") },

    { njs_str("parseInt(' 123')"),
      njs_str("123") },

    { njs_str("parseInt('\\u0009123')"),
      njs_str("123") },

    { njs_str("parseInt('\\u200A123')"),
      njs_str("123") },

    { njs_str("parseInt('1010', 2)"),
      njs_str("10") },

    { njs_str("parseInt('111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000', 2)"),
      njs_str("1.2379400392853803e+27") },

    { njs_str("parseInt('7777777777777777777777777777777777700000000000000000000000000000000', 8)"),
      njs_str("3.2138760885179806e+60") },

    { njs_str("parseInt('0x21bc2b266d3a3600000000000000000000000000000000000000000000000000000')"),
      njs_str("6.25e+79") },

    { njs_str("parseInt('aBc', 16)"),
      njs_str("2748") },

    { njs_str("parseInt('0XaBc')"),
      njs_str("2748") },

    { njs_str("parseInt('-0xabc')"),
      njs_str("-2748") },

    { njs_str("parseInt('njscript', 36)"),
      njs_str("1845449130881") },

    { njs_str("parseInt('0x')"),
      njs_str("NaN") },

    { njs_str("parseInt('z')"),
      njs_str("NaN") },

    { njs_str("parseInt('0xz')"),
      njs_str("NaN") },

    { njs_str("parseInt('0x', 16)"),
      njs_str("NaN") },

    { njs_str("parseInt('0x', 33)"),
      njs_str("0") },

    { njs_str("parseInt('0x', 34)"),
      njs_str("33") },

    { njs_str("parseInt('0', 1)"),
      njs_str("NaN") },

    { njs_str("parseInt('0', 37)"),
      njs_str("NaN") },

    { njs_str("1/parseInt('-0')"),
      njs_str("-Infinity") },

    { njs_str("parseInt('11', new Number(Infinity)) === parseInt('11', Infinity)"),
      njs_str("true") },

    { njs_str("parseInt('11', Number.POSITIVE_INFINITY)"),
      njs_str("11") },

    { njs_str("parseFloat.name"),
      njs_str("parseFloat") },

    { njs_str("parseFloat.length"),
      njs_str("1") },

    { njs_str("parseFloat('12345abc')"),
      njs_str("12345") },

    { njs_str("parseFloat()"),
      njs_str("NaN") },

    { njs_str("parseFloat('')"),
      njs_str("NaN") },

    { njs_str("parseFloat('     \t')"),
      njs_str("NaN") },

    { njs_str("parseFloat('\\u20281')"),
      njs_str("1") },

    { njs_str("parseFloat('e11')"),
      njs_str("NaN") },

    { njs_str("parseFloat({toString(){return '  1'}})"),
      njs_str("1") },

    { njs_str("parseFloat('1e2147483647')"),
      njs_str("Infinity") },

    { njs_str("parseFloat('1e-2147483647')"),
      njs_str("0") },

    { njs_str("parseFloat('1e-2147483648')"),
      njs_str("0") },

    { njs_str("parseFloat('1e' + '5'.repeat(16))"),
      njs_str("Infinity") },

    { njs_str("parseFloat('1e-' + '5'.repeat(16))"),
      njs_str("0") },

    { njs_str("parseFloat('0x')"),
      njs_str("0") },

    { njs_str("parseFloat('0xff')"),
      njs_str("0") },

    { njs_str("parseFloat('Infinity')"),
      njs_str("Infinity") },

    { njs_str("parseFloat(' Infinityzz')"),
      njs_str("Infinity") },

    { njs_str("parseFloat('Infinit')"),
      njs_str("NaN") },

    { njs_str("parseFloat('5.7e1')"),
      njs_str("57") },

    { njs_str("parseFloat('-5.7e-1')"),
      njs_str("-0.57") },

    { njs_str("parseFloat('-5.e-1')"),
      njs_str("-0.5") },

    { njs_str("parseFloat('5.7e+01')"),
      njs_str("57") },

    { njs_str("parseFloat(' 5.7e+01abc')"),
      njs_str("57") },

    { njs_str("parseFloat('-5.7e-1abc')"),
      njs_str("-0.57") },

    { njs_str("parseFloat('-5.7e')"),
      njs_str("-5.7") },

    { njs_str("parseFloat('-5.7e+')"),
      njs_str("-5.7") },

    { njs_str("parseFloat('-5.7e+abc')"),
      njs_str("-5.7") },

    { njs_str("parseFloat('5' + '0'.repeat(200))"),
      njs_str("5e+200") },

    { njs_str("parseFloat('500_000_000')"),
      njs_str("500") },

    /* debugger. */

    { njs_str("debugger"),
      njs_str("undefined") },

    { njs_str("debugger;"),
      njs_str("undefined") },

    { njs_str("while (false) debugger;"),
      njs_str("undefined") },

    { njs_str("1 + debugger"),
      njs_str("SyntaxError: Unexpected token \"debugger\"") },

    { njs_str("debugger + 1"),
      njs_str("SyntaxError: Unexpected token \"+\"") },

    /* Top-level objects. */

    { njs_str("var global = this;"
              "function isMutableObject(v) {"
              "    var d = Object.getOwnPropertyDescriptor(global, v);"
              "    /* Custom top-level objects are enumerable. */"
              "    var enumerable = (v in {'njs':1, 'process':1}) ^ !d.enumerable;"
              "    return d.writable && enumerable && d.configurable;"
              "};"
              "['njs', 'process', 'Math', 'JSON'].every((v)=>isMutableObject(v))"),
      njs_str("true") },

    { njs_str("njs === njs"),
      njs_str("true") },

    { njs_str("this.njs = 1; njs"),
      njs_str("1") },

    { njs_str("process === process"),
      njs_str("true") },

    { njs_str("this.process = 1; process"),
      njs_str("1") },

    { njs_str("Math === Math"),
      njs_str("true") },

    { njs_str("this.Math = 1; Math"),
      njs_str("1") },

    { njs_str("JSON"),
      njs_str("[object JSON]") },

    { njs_str("JSON === JSON"),
      njs_str("true") },

    { njs_str("this.JSON = 1; JSON"),
      njs_str("1") },

    { njs_str("delete this.JSON; JSON"),
      njs_str("ReferenceError: \"JSON\" is not defined") },

    /* Top-level constructors. */

    { njs_str(
        "var global = this;"
        "function isValidConstructor(c) {"
        "   var props = Object.getOwnPropertyDescriptor(global, c.name);"
        "   props = props.writable && !props.enumerable && props.configurable;"
        "   var same = c === global[c.name];"
        ""
        "   return props && same;"
        "};"
        "Object.getOwnPropertyNames(global)"
        ".filter((k)=>(global[k] && global[k].prototype && global[k].prototype.constructor))"
        ".map(k=>global[k])"
        ".every(c => isValidConstructor(c))"),
      njs_str("true") },

    /* JSON.parse() */

    { njs_str("JSON.parse('null')"),
      njs_str("null") },

    { njs_str("JSON.parse('true')"),
      njs_str("true") },

    { njs_str("JSON.parse('false')"),
      njs_str("false") },

    { njs_str("JSON.parse('0')"),
      njs_str("0") },

    { njs_str("JSON.parse('-1234.56e2')"),
      njs_str("-123456") },

    { njs_str("typeof(JSON.parse('true'))"),
      njs_str("boolean") },

    { njs_str("typeof(JSON.parse('false'))"),
      njs_str("boolean") },

    { njs_str("typeof(JSON.parse('1'))"),
      njs_str("number") },

    { njs_str("typeof(JSON.parse('\"\"'))"),
      njs_str("string") },

    { njs_str("typeof(JSON.parse('{}'))"),
      njs_str("object") },

    { njs_str("typeof(JSON.parse('[]'))"),
      njs_str("object") },

    { njs_str("JSON.parse('\"abc\"')"),
      njs_str("abc") },

    { njs_str("JSON.parse('\"\\\\\"\"')"),
      njs_str("\"") },

    { njs_str("JSON.parse('\"\\\\n\"')"),
      njs_str("\n") },

    { njs_str("JSON.parse('\"\\\\t\"')"),
      njs_str("\t") },

    { njs_str("JSON.parse('\"ab\\\\\"c\"')"),
      njs_str("ab\"c") },

    { njs_str("JSON.parse('\"abcdefghijklmopqr\\\\\"s\"')"),
      njs_str("abcdefghijklmopqr\"s") },

    { njs_str("JSON.parse('\"ab\\\\\"c\"').length"),
      njs_str("4") },

    { njs_str("JSON.parse('\"аб\\\\\"в\"')"),
      njs_str("аб\"в") },

    { njs_str("JSON.parse('\"аб\\\\\"в\"').length"),
      njs_str("4") },

    { njs_str("JSON.parse('\"абвгдеёжзийкл\"').length"),
      njs_str("13") },

    { njs_str("JSON.parse('[\"' + 'α'.repeat(33) + '\"]')[0][32]"),
      njs_str("α") },

    { njs_str("JSON.parse('\"\\\\u03B1\"')"),
      njs_str("α") },

    { njs_str("JSON.parse('\"\\\\uD801\\\\uDC00\"')"),
      njs_str("𐐀") },

    { njs_str("JSON.parse('\"\\\\u03B1\"') == JSON.parse('\"\\\\u03b1\"')"),
      njs_str("true") },

    { njs_str("JSON.parse('\"\\\\u03B1\"').length"),
      njs_str("1") },

    { njs_str("JSON.parse('{\"a\":1}').a"),
      njs_str("1") },

    { njs_str("JSON.parse('{\"a\":1,\"a\":2}').a"),
      njs_str("2") },

    { njs_str("JSON.parse('{   \"a\" :  \"b\"   }').a"),
      njs_str("b") },

    { njs_str("JSON.parse('{\"a\":{\"b\":1}}').a.b"),
      njs_str("1") },

    { njs_str("JSON.parse('[{}, true ,1.1e2, {\"a\":[3,\"b\"]}]')[3].a[1]"),
      njs_str("b") },

    { njs_str("var o = JSON.parse('{\"a\":2}');"
                 "Object.getOwnPropertyDescriptor(o, 'a').configurable"),
      njs_str("true") },

    { njs_str("var o = JSON.parse('{\"a\":2}');"
                 "Object.getOwnPropertyDescriptor(o, 'a').writable"),
      njs_str("true") },

    { njs_str("var o = JSON.parse('{\"a\":2}');"
                 "Object.getOwnPropertyDescriptor(o, 'a').enumerable"),
      njs_str("true") },

    { njs_str("var o = JSON.parse('{\"a\":2}');"
                 "o.a = 3; o.a"),
      njs_str("3") },

    { njs_str("var o = JSON.parse('{\"a\":2}');"
                 "o.b = 3; o.b"),
      njs_str("3") },

    { njs_str("JSON.parse('2') || 10"),
      njs_str("2") },

    { njs_str("JSON.parse('0') || 10"),
      njs_str("10") },

    { njs_str("JSON.parse('-0') || 10"),
      njs_str("10") },

    { njs_str("JSON.parse('\"a\"') || 10"),
      njs_str("a") },

    { njs_str("JSON.parse('\"\"') || 10"),
      njs_str("10") },

    { njs_str("JSON.parse('true') || 10"),
      njs_str("true") },

    { njs_str("JSON.parse('false') || 10"),
      njs_str("10") },

    { njs_str("JSON.parse('null') || 10"),
      njs_str("10") },

    { njs_str("var o = JSON.parse('{}', function(k, v) {return v;}); o"),
      njs_str("[object Object]") },

    { njs_str("var o = JSON.parse('{\"a\":2, \"b\":4, \"a\":{}}',"
                 "                    function(k, v) {return undefined;});"
                 "o"),
      njs_str("undefined") },

    { njs_str("var o = JSON.parse('{\"a\":2, \"c\":4, \"b\":\"x\"}',"
                 "  function(k, v) {if (k === '' || typeof v === 'number') return v });"
                 "Object.keys(o)"),
      njs_str("a,c") },

    { njs_str("var o = JSON.parse('{\"a\":2, \"b\":{}}',"
                 "                    function(k, v) {return k;});"
                 "o+typeof(o)"),
      njs_str("string") },

    { njs_str("var o = JSON.parse('[\"a\", \"b\"]',"
                 "                    function(k, v) {return v;});"
                 "o"),
      njs_str("a,b") },

    { njs_str("var o = JSON.parse('{\"a\":[1,{\"b\":1},3]}',"
                 "                    function(k, v) {return v;});"
                 "o.a[1].b"),
      njs_str("1") },

    { njs_str("var o = JSON.parse('{\"a\":[1,2]}',"
                 "  function(k, v) {if (k === '' || k === 'a') {return v;}});"
                 "o.a"),
      njs_str(",") },

    { njs_str("var o = JSON.parse('{\"a\":[1,2]}',"
                 "  function(k, v) {return (k === '' || k === 'a') ? v : v*2});"
                 "o.a"),
      njs_str("2,4") },

    { njs_str("var o = JSON.parse('{\"a\":2, \"b\":{\"c\":[\"xx\"]}}',"
                 "   function(k, v) {return typeof v === 'number' ? v * 2 : v;});"
                 "o.a+o.b.c[0]"),
      njs_str("4xx") },

    { njs_str("var o = JSON.parse('{\"aa\":{\"b\":1}, \"abb\":1, \"c\":1}',"
                 "   function(k, v) {return (k === '' || /^a/.test(k)) ? v : undefined;});"
                 "Object.keys(o)"),
      njs_str("aa,abb") },

    { njs_str("var o = JSON.parse('{\"a\":\"x\"}',"
                 "   function(k, v) {if (k === 'a') {this.b='y';} return v});"
                 "o.a+o.b"),
      njs_str("xy") },

    { njs_str("var o = JSON.parse('{\"a\":\"x\"}',"
                 "   function(k, v) {return (k === 'a' ? {x:1} : v)});"
                 "o.a.x"),
      njs_str("1") },

    { njs_str("var keys = []; var o = JSON.parse('{\"a\":2, \"b\":{\"c\":\"xx\"}}',"
                 "   function(k, v) {keys.push(k); return v;});"
                 "keys"),
      njs_str("a,c,b,") },

    { njs_str("var args = []; var o = JSON.parse('[2,{\"a\":3}]',"
                 "   function(k, v) {args.push(k+\":\"+v); return v;});"
                 "args.join('|')"),
      njs_str("0:2|a:3|1:[object Object]|:2,[object Object]") },

    { njs_str("JSON.parse('[0,1,2]', function(k, v) {"
              "    if (v == 2) {"
              "        return undefined;"
              "    }"
              "    return v;"
              "});"),
      njs_str("0,1,") },

    { njs_str("JSON.parse('[0,1,2]', function(k, v) {"
              "    if (v == 0) {"
              "        Object.defineProperty(this, '0', {value: undefined, enumerable: false});"
              "        return undefined;"
              "    }"
              "    return v;"
              "});"),
      njs_str(",1,2") },

    { njs_str("JSON.parse()"),
      njs_str("SyntaxError: Unexpected token at position 0") },

    { njs_str("JSON.parse([])"),
      njs_str("SyntaxError: Unexpected end of input at position 0") },

    { njs_str("JSON.parse('')"),
      njs_str("SyntaxError: Unexpected end of input at position 0") },

    { njs_str("JSON.parse('fals')"),
      njs_str("SyntaxError: Unexpected token at position 0") },

    { njs_str("JSON.parse(' t')"),
      njs_str("SyntaxError: Unexpected token at position 1") },

    { njs_str("JSON.parse('nu')"),
      njs_str("SyntaxError: Unexpected token at position 0") },

    { njs_str("JSON.parse('-')"),
      njs_str("SyntaxError: Unexpected number at position 0") },

    { njs_str("JSON.parse('--')"),
      njs_str("SyntaxError: Unexpected number at position 0") },

    { njs_str("JSON.parse('1-')"),
      njs_str("SyntaxError: Unexpected token at position 1") },

    { njs_str("JSON.parse('1ee1')"),
      njs_str("SyntaxError: Unexpected token at position 1") },

    { njs_str("JSON.parse('1eg')"),
      njs_str("SyntaxError: Unexpected token at position 1") },

    { njs_str("JSON.parse('0x01')"),
      njs_str("SyntaxError: Unexpected token at position 1") },

    { njs_str("JSON.parse('\"абв')"),
      njs_str("SyntaxError: Unexpected end of input at position 4") },

    { njs_str("JSON.parse('\"\b')"),
      njs_str("SyntaxError: Forbidden source char at position 1") },

    { njs_str("JSON.parse('\"\\\\u')"),
      njs_str("SyntaxError: Unexpected end of input at position 3") },

    { njs_str("JSON.parse('\"\\\\q\"')"),
      njs_str("SyntaxError: Unknown escape char at position 2") },

    { njs_str("JSON.parse('\"\\\\uDC01\"')"),
      njs_str("�") },

    { njs_str("JSON.parse('\"\\\\uD801\\\\uE000\"')"),
      njs_str("�") },

    { njs_str("JSON.parse('\"\\\\uD83D\"')"),
      njs_str("�") },

    { njs_str("JSON.parse('\"\\\\uD800\\\\uDB00\"')"),
      njs_str("��") },

    { njs_str("JSON.parse('\"\\\\ud800[\"')"),
      njs_str("�[") },

    { njs_str("JSON.parse('{')"),
      njs_str("SyntaxError: Unexpected end of input at position 1") },

    { njs_str("JSON.parse('{{')"),
      njs_str("SyntaxError: Unexpected token at position 1") },

    { njs_str("JSON.parse('{[')"),
      njs_str("SyntaxError: Unexpected token at position 1") },

    { njs_str("JSON.parse('{\"a\"')"),
      njs_str("SyntaxError: Unexpected token at position 4") },

    { njs_str("JSON.parse('{\"a\":')"),
      njs_str("SyntaxError: Unexpected end of input at position 5") },

    { njs_str("JSON.parse('{\"a\":{')"),
      njs_str("SyntaxError: Unexpected end of input at position 6") },

    { njs_str("JSON.parse('{\"a\":{}')"),
      njs_str("SyntaxError: Unexpected end of input at position 7") },

    { njs_str("JSON.parse('{\"a\":{}g')"),
      njs_str("SyntaxError: Unexpected token at position 7") },

    { njs_str("JSON.parse('{\"a\":{},')"),
      njs_str("SyntaxError: Unexpected end of input at position 8") },

    { njs_str("JSON.parse('{\"a\":{},}')"),
      njs_str("SyntaxError: Trailing comma at position 7") },

    { njs_str("JSON.parse('{\"a\":{},,')"),
      njs_str("SyntaxError: Unexpected token at position 8") },

    { njs_str("JSON.parse('{\"a\":{},,}')"),
      njs_str("SyntaxError: Unexpected token at position 8") },

    { njs_str("JSON.parse('[')"),
      njs_str("SyntaxError: Unexpected end of input at position 1") },

    { njs_str("JSON.parse('[q')"),
      njs_str("SyntaxError: Unexpected token at position 1") },

    { njs_str("JSON.parse('[\"a')"),
      njs_str("SyntaxError: Unexpected end of input at position 3") },

    { njs_str("JSON.parse('[1 ')"),
      njs_str("SyntaxError: Unexpected end of input at position 3") },

    { njs_str("JSON.parse('[1,]')"),
      njs_str("SyntaxError: Trailing comma at position 2") },

    { njs_str("JSON.parse('[1 , 5 ')"),
      njs_str("SyntaxError: Unexpected end of input at position 7") },

    { njs_str("JSON.parse('{\"a\":'.repeat(32))"),
      njs_str("SyntaxError: Nested too deep at position 155") },

    { njs_str("JSON.parse('['.repeat(32))"),
      njs_str("SyntaxError: Nested too deep at position 31") },

    { njs_str("var o = JSON.parse('{', function(k, v) {return v;});o"),
      njs_str("SyntaxError: Unexpected end of input at position 1") },

    { njs_str("var o = JSON.parse('{\"a\":1}', "
                 "                   function(k, v) {return v.a.a;}); o"),
      njs_str("TypeError: cannot get property \"a\" of undefined") },

    { njs_str("function func() {this[8] = 1; return new Int8Array(func)}"
              "JSON.parse('[1]', func);"),
      njs_str("") },

    { njs_str("JSON.parse(JSON.stringify([Array(2**16)]), v => v)"),
      njs_str("") },

    { njs_str("var order = []; function reviver(k, v) { order.push(k); };"
              "JSON.parse('{\"p1\":0,\"p2\":0,\"p1\":0,\"2\":0,\"1\":0}', reviver);"
              "order"),
      njs_str("1,2,p1,p2,") },

    { njs_str("function reviver(k, v) {"
              "    if (k == '0') Object.defineProperty(this, '1', {configurable: false});"
              "    if (k == '1') return;"
              "    return v;"
              " };"
              "JSON.parse('[1, 2]', reviver)"),
      njs_str("1,2") },

    { njs_str("JSON.parse('0', (k, v) => {throw 'Oops'})"),
      njs_str("Oops") },

    { njs_str("JSON.parse('{\"a\":1}', (k, v) => {if (k == 'a') {throw 'Oops'}; return v;})"),
      njs_str("Oops") },

    { njs_str("JSON.parse('[2,3,43]', (k, v) => {if (v == 43) {throw 'Oops'}; return v;})"),
      njs_str("Oops") },

    /* JSON.stringify() */

    { njs_str("JSON.stringify()"),
      njs_str("undefined") },

    { njs_str("JSON.stringify('')"),
      njs_str("\"\"") },

    { njs_str("JSON.stringify('abc')"),
      njs_str("\"abc\"") },

    { njs_str("JSON.stringify(new String('abc'))"),
      njs_str("\"abc\"") },

    { njs_str("var s = new String('abc'); s.toString = () => 'xxx'; "
              "JSON.stringify(s)"),
      njs_str("\"xxx\"") },

    { njs_str("JSON.stringify(123)"),
      njs_str("123") },

    { njs_str("JSON.stringify(-0)"),
      njs_str("0") },

    { njs_str("JSON.stringify(0.00000123)"),
      njs_str("0.00000123") },

    { njs_str("JSON.stringify(new Number(123))"),
      njs_str("123") },

    { njs_str("var n = new Number(8.5); n.valueOf = () => 42;"
              "JSON.stringify(n)"),
      njs_str("42") },

    { njs_str("JSON.stringify(true)"),
      njs_str("true") },

    { njs_str("JSON.stringify(false)"),
      njs_str("false") },

    { njs_str("JSON.stringify(new Boolean(1))"),
      njs_str("true") },

    { njs_str("JSON.stringify(new Boolean(0))"),
      njs_str("false") },

    { njs_str("JSON.stringify(null)"),
      njs_str("null") },

    { njs_str("JSON.stringify(undefined)"),
      njs_str("undefined") },

    { njs_str("JSON.stringify(Symbol())"),
      njs_str("undefined") },

    { njs_str("JSON.stringify({})"),
      njs_str("{}") },

    { njs_str("JSON.stringify([])"),
      njs_str("[]") },

    { njs_str("var a = [1]; a[2] = 'x'; JSON.stringify(a)"),
      njs_str("[1,null,\"x\"]") },

#if (!NJS_HAVE_MEMORY_SANITIZER) /* very long test under MSAN */
    { njs_str(njs_declare_sparse_array("a", 32769)
              "a[32] = 'a'; a[64] = 'b';"
              "var s = JSON.stringify(a); "
              "[s.length,s.substring(162,163),s.match(/null/g).length]"),
      njs_str("163844,a,32767") },
#endif

    { njs_str(njs_declare_sparse_array("a", 8)
              "a[2] = 'a'; a[4] = 'b'; a.length = 3;"
              "JSON.stringify(a)"),
      njs_str("[null,null,\"a\"]") },

    { njs_str(njs_declare_sparse_array("a", 8)
              "a[1] = 'a'; a[2] = 'b'; a.length = 3;"
              "JSON.stringify({a:1,b:2,c:3}, a)"),
      njs_str("{\"a\":1,\"b\":2}") },

    { njs_str("var a = [1,2,3];"
              "Object.defineProperty(a, '1', {enumerable:false});"
              "JSON.stringify(a)"),
      njs_str("[1,2,3]") },

    { njs_str("JSON.stringify({a:\"b\",c:19,e:null,t:true,f:false})"),
      njs_str("{\"a\":\"b\",\"c\":19,\"e\":null,\"t\":true,\"f\":false}") },

    { njs_str("JSON.stringify({a:1, b:undefined})"),
      njs_str("{\"a\":1}") },

    { njs_str("JSON.stringify({a:1, b:Symbol()})"),
      njs_str("{\"a\":1}") },

    { njs_str("var o = {a:1, c:2};"
                 "Object.defineProperty(o, 'b', {enumerable:false, value:3});"
                 "JSON.stringify(o)"),
      njs_str("{\"a\":1,\"c\":2}") },

    { njs_str("JSON.stringify({a:{}, b:[function(v){}]})"),
      njs_str("{\"a\":{},\"b\":[null]}") },

    { njs_str("JSON.stringify(RegExp())"),
      njs_str("{}") },

    { njs_str("JSON.stringify(Object(Symbol()))"),
      njs_str("{}") },

    { njs_str("var s = Object(Symbol()); s.test = 'test'; JSON.stringify(s)"),
      njs_str("{\"test\":\"test\"}") },

    { njs_str("JSON.stringify(SyntaxError('e'))"),
      njs_str("{}") },

    { njs_str("JSON.stringify(URIError('e'))"),
      njs_str("{}") },

    { njs_str("var e = URIError('e'); e.name = 'E'; JSON.stringify(e)"),
      njs_str("{\"name\":\"E\"}") },

    { njs_str("var e = URIError('e'); e.message = 'E'; JSON.stringify(e)"),
      njs_str("{}") },

    { njs_str("var e = URIError('e'); e.foo = 'E'; JSON.stringify(e)"),
      njs_str("{\"foo\":\"E\"}") },

    { njs_str("JSON.stringify({get key() {throw new Error('Oops')}})"),
      njs_str("Error: Oops") },

    { njs_str("JSON.stringify({toJSON() {throw new Error('Oops')}})"),
      njs_str("Error: Oops") },

    /* Ignoring named properties of an array. */

    { njs_str("var a = [1,2]; a.a = 1;"
                 "JSON.stringify(a)"),
      njs_str("[1,2]") },

    { njs_str("JSON.stringify({a:{b:{c:{d:1}, e:function(v){}}}})"),
      njs_str("{\"a\":{\"b\":{\"c\":{\"d\":1}}}}") },

    { njs_str("JSON.stringify([[\"b\",undefined],1,[5],{a:1}])"),
      njs_str("[[\"b\",null],1,[5],{\"a\":1}]") },

    { njs_str("var json = '{\"a\":{\"b\":{\"c\":{\"d\":1},\"e\":[true]}}}';"
                 "json == JSON.stringify(JSON.parse(json))"),
      njs_str("true") },

    { njs_str("var json = '{\"a\":\"абв\",\"b\":\"α\"}';"
                 "json == JSON.stringify(JSON.parse(json))"),
      njs_str("true") },

    /* Multibyte characters: z - 1 byte, α - 2 bytes, 𐐀 - 4 bytes */

    { njs_str("JSON.stringify('α𐐀z'.repeat(10))"),
      njs_str("\"α𐐀zα𐐀zα𐐀zα𐐀zα𐐀zα𐐀zα𐐀zα𐐀zα𐐀zα𐐀z\"") },

    { njs_str("JSON.stringify('α𐐀z'.repeat(10)).length"),
      njs_str("32") },

    { njs_str("JSON.stringify('α'.repeat(33))[32]"),
      njs_str("α") },

    { njs_str("JSON.stringify('a\\nbc')"),
      njs_str("\"a\\nbc\"") },

    { njs_str("JSON.stringify('а\tбв')"),
      njs_str("\"а\\tбв\"") },

    { njs_str("JSON.stringify('\\n\\t\\r\\\"\\f\\b')"),
      njs_str("\"\\n\\t\\r\\\"\\f\\b\"") },

    { njs_str("JSON.stringify('\x00\x01\x02\x1f')"),
      njs_str("\"\\u0000\\u0001\\u0002\\u001f\"") },

    { njs_str("JSON.stringify('abc\x00')"),
      njs_str("\"abc\\u0000\"") },

    { njs_str("JSON.stringify('\x00zz')"),
      njs_str("\"\\u0000zz\"") },

    { njs_str("JSON.stringify('\x00')"),
      njs_str("\"\\u0000\"") },

    { njs_str("JSON.stringify('a\x00z')"),
      njs_str("\"a\\u0000z\"") },

    { njs_str("JSON.stringify('\x00z\x00')"),
      njs_str("\"\\u0000z\\u0000\"") },

    { njs_str("var i, s, r = true;"
                 " for (i = 0; i < 128; i++) {"
                 "  s = 'α𐐀z'.repeat(i);"
                 "  r &= (JSON.stringify(s) == ('\"' + s + '\"'));"
                 "}; r"),
      njs_str("1") },

    { njs_str("JSON.stringify('\\u0000'.repeat(10)) == ('\"' + '\\\\u0000'.repeat(10) + '\"')"),
      njs_str("true") },

    { njs_str("JSON.stringify('abc'.repeat(100)).length"),
      njs_str("302") },

    { njs_str("JSON.stringify('абв'.repeat(100)).length"),
      njs_str("302") },

    /* Optional arguments. */

    { njs_str("JSON.stringify(undefined, undefined, 1)"),
      njs_str("undefined") },

    { njs_str("JSON.stringify([{a:1,b:{c:2}},1], undefined, 0)"),
      njs_str("[{\"a\":1,\"b\":{\"c\":2}},1]") },

    { njs_str("JSON.stringify([{a:1,b:{c:2}},1], undefined, 1)"),
      njs_str("[\n {\n  \"a\": 1,\n  \"b\": {\n   \"c\": 2\n  }\n },\n 1\n]") },

    { njs_str("JSON.stringify([{a:1,b:{c:2}},1], undefined, ' ')"),
      njs_str("[\n {\n  \"a\": 1,\n  \"b\": {\n   \"c\": 2\n  }\n },\n 1\n]") },

    { njs_str("JSON.stringify([{a:1,b:{c:2}},1], undefined, '#')"),
      njs_str("[\n#{\n##\"a\": 1,\n##\"b\": {\n###\"c\": 2\n##}\n#},\n#1\n]") },

    { njs_str("JSON.stringify([1], null, 'AAAAABBBBBC')"),
      njs_str("[\nAAAAABBBBB1\n]") },

    { njs_str("var s = new String('A'); s.toString = () => 'AAAAABBBBBC';"
              "JSON.stringify([1], null, s)"),
      njs_str("[\nAAAAABBBBB1\n]") },

    { njs_str("JSON.stringify([1], null, '!βββββ').length"),
      njs_str("11") },

    { njs_str("JSON.stringify([1], null, 'ABC') === JSON.stringify([1], null, new String('ABC'))"),
      njs_str("true") },

    { njs_str("JSON.stringify([1], null, '!!βββββββββββββββββ').length"),
      njs_str("15") },

    { njs_str("JSON.stringify([1], null, 11)"),
      njs_str("[\n          1\n]") },

    { njs_str("JSON.stringify([1], null, 5) === JSON.stringify([1], null, 5.9)"),
      njs_str("true") },

    { njs_str("JSON.stringify([1], null, 5) === JSON.stringify([1], null, new Number(5))"),
      njs_str("true") },

    { njs_str("var s = new Number(23); s.valueOf = () => 5;"
              "JSON.stringify([1], null, s)"),
      njs_str("[\n     1\n]") },

    { njs_str("JSON.stringify([{a:1,b:{c:2}},1], undefined, -1)"),
      njs_str("[{\"a\":1,\"b\":{\"c\":2}},1]") },

    { njs_str("JSON.stringify([{a:1,b:{c:2}},1], undefined, new Date())"),
      njs_str("[{\"a\":1,\"b\":{\"c\":2}},1]") },

    { njs_str("var o = Object.defineProperty({}, 'a', { get() { return ()=> 1}, enumerable: true });"
              "JSON.stringify(o)"),
      njs_str("{}") },

    { njs_str("var o = Object.defineProperty({}, 'a', { get: () => ({b:1, c:2}), enumerable: true });"
              "JSON.stringify(o)"),
      njs_str("{\"a\":{\"b\":1,\"c\":2}}") },

    { njs_str("var o = Object.defineProperty({}, 'a', { get: () => ({})});"
              "JSON.stringify(o)"),
      njs_str("{}") },

    { njs_str("JSON.stringify({toJSON:function(k){}})"),
      njs_str("undefined") },

    { njs_str("JSON.stringify({toJSON:function(k){return k}})"),
      njs_str("\"\"") },

    { njs_str("JSON.stringify(new Date(1308895323625))"),
      njs_str("\"2011-06-24T06:02:03.625Z\"") },

    { njs_str("JSON.stringify({a:new Date(1308895323625)})"),
      njs_str("{\"a\":\"2011-06-24T06:02:03.625Z\"}") },

    { njs_str("JSON.stringify({b:{toJSON:function(k){return undefined}}})"),
      njs_str("{}") },

    { njs_str("JSON.stringify({b:{toJSON:function(k){}},c:1})"),
      njs_str("{\"c\":1}") },

    { njs_str("JSON.stringify({b:{toJSON:function(k){return k}}})"),
      njs_str("{\"b\":\"b\"}") },

    { njs_str("JSON.stringify({a:1,b:new Date(1308895323625),c:2})"),
      njs_str("{\"a\":1,\"b\":\"2011-06-24T06:02:03.625Z\",\"c\":2}") },

    { njs_str("JSON.stringify({a:{b:new Date(1308895323625)}})"),
      njs_str("{\"a\":{\"b\":\"2011-06-24T06:02:03.625Z\"}}") },

    { njs_str("function key(k){return k}; function und(k){}"
                 "JSON.stringify([{toJSON:key},{toJSON:und},{toJSON:key}])"),
      njs_str("[\"0\",null,\"2\"]") },

    { njs_str("JSON.stringify({b:{a:1,c:[2]}}, function(k,v){return v})"),
      njs_str("{\"b\":{\"a\":1,\"c\":[2]}}") },

    { njs_str("JSON.stringify([{a:1}, 2], function(k,v){return v})"),
      njs_str("[{\"a\":1},2]") },

    { njs_str("JSON.stringify({a:{toJSON:function(k){}}}, function(k,v){return v})"),
      njs_str("{}") },

    { njs_str("JSON.stringify({a:{toJSON:function(k){return 1}}}, function(k,v){return v})"),
      njs_str("{\"a\":1}") },

    { njs_str("JSON.stringify([{toJSON:function(k){}}], function(k,v){return v})"),
      njs_str("[null]") },

    { njs_str("JSON.stringify([{toJSON:function(k){return 1}}], function(k,v){return v})"),
      njs_str("[1]") },

    { njs_str("JSON.stringify({a:new Date(1308895323625)}, function(k,v){return v})"),
      njs_str("{\"a\":\"2011-06-24T06:02:03.625Z\"}") },

    { njs_str("JSON.stringify([new Date(1308895323625)], function(k,v){return v})"),
      njs_str("[\"2011-06-24T06:02:03.625Z\"]") },

    { njs_str("JSON.stringify([new Date(1308895323625)], "
                 "  function(k,v){return (typeof v === 'string') ? v.toLowerCase() : v})"),
      njs_str("[\"2011-06-24t06:02:03.625z\"]") },

    { njs_str("JSON.stringify([new Date(1308895323625)], "
                 "  function(k,v){return (typeof v === 'string') ? v.toLowerCase() : v}, '#')"),
      njs_str("[\n#\"2011-06-24t06:02:03.625z\"\n]") },

    { njs_str("JSON.stringify({a:new Date(1308895323625),b:1,c:'a'}, "
                 "  function(k,v){return (typeof v === 'string') ? undefined : v})"),
      njs_str("{\"b\":1}") },

    { njs_str("JSON.stringify({a:new Date(1308895323625),b:1,c:'a'}, "
                 "  function(k,v){return (typeof v === 'string') ? undefined : v}, '#')"),
      njs_str("{\n#\"b\": 1\n}") },

    { njs_str("JSON.stringify([new Date(1308895323625),1,'a'], "
                 "  function(k,v){return (typeof v === 'string') ? undefined : v})"),
      njs_str("[null,1,null]") },

    { njs_str("var keys = []; var o = JSON.stringify({a:2, b:{c:1}},"
                 "   function(k, v) {keys.push(k); return v;});"
                 "keys"),
      njs_str(",a,b,c") },

    { njs_str("JSON.stringify(['a', 'b', 'c'], "
                 "    function(i, v) { if (i === '0') {return undefined} "
                 "                     else if (i == 1) {return 2} "
                 "                     else {return v}})"),
      njs_str("[null,2,\"c\"]") },

    { njs_str("JSON.stringify({a:2, b:{c:1}},"
                 "               function(k, v) {delete this['b']; return v;})"),
      njs_str("{\"a\":2}") },

    { njs_str("JSON.stringify(JSON.parse('{\"a\":1,\"b\":2}', "
                 "          function(k, v) {delete this['b']; return v;}))"),
      njs_str("{\"a\":1}") },

    { njs_str("var keys = []; var o = JSON.stringify([[1,2],{a:3}, 4],"
                 "   function(k, v) {keys.push(k); return v;});"
                 "keys"),
      njs_str(",0,0,1,1,a,2") },

    { njs_str("JSON.stringify({b:{a:1,c:[2]}}, ['a', undefined, 'b', {}, 'a'])"),
      njs_str("{\"b\":{\"a\":1}}") },

    { njs_str("JSON.stringify({b:{a:1,c:[2]}}, [new String('a'), new String('b')])"),
      njs_str("{\"b\":{\"a\":1}}") },

    { njs_str("JSON.stringify({'1':1,'2':2,'3':3}, [1, new Number(2)])"),
      njs_str("{\"1\":1,\"2\":2}") },

    { njs_str("var s = new String('str'); s.toString = () => 'xxx';"
              "JSON.stringify({str:1,xxx:2}, [s])"),
      njs_str("{\"xxx\":2}") },

    { njs_str("var n = new String(123); n.toString = () => '42';"
              "JSON.stringify({123:1,42:2}, [n])"),
      njs_str("{\"42\":2}") },

    { njs_str("var objs = []; var o = JSON.stringify({a:1},"
                 "   function(k, v) {objs.push(this); return v});"
                 "JSON.stringify(objs)"),
      njs_str("[{\"\":{\"a\":1}},{\"a\":1}]") },

    { njs_str("JSON.stringify({a: () => 1, b: Symbol(), c: undefined},"
                             "(k, v) => k.length ? String(v) : v)"),
      njs_str("{\"a\":\"[object Function]\",\"b\":\"Symbol()\",\"c\":\"undefined\"}") },

    { njs_str("var a = []; a[0] = a; JSON.stringify(a)"),
      njs_str("TypeError: Nested too deep or a cyclic structure") },

    { njs_str("var a = {}; a.a = a; JSON.stringify(a)"),
      njs_str("TypeError: Nested too deep or a cyclic structure") },

    { njs_str("var array = [1,2,3];"
              "array[1] = {get value() {"
              "    Object.defineProperty(array, '2', {get: () => 10}) }"
              "};"
              "JSON.stringify(array)"),
      njs_str("[1,{},10]") },

    { njs_str("var array = [1];"
              "array[1] = {get value() {array[10] = 10}}; JSON.stringify(array)"),
      njs_str("[1,{}]") },

    /* njs.dump(). */

    { njs_str("njs.dump({a:1, b:[1,,2,{c:new Boolean(1)}]})"),
      njs_str("{a:1,b:[1,<empty>,2,{c:[Boolean: true]}]}") },

    { njs_str("njs.dump([InternalError(),TypeError('msg'), new RegExp(), /^undef$/my, new Date(0)])"),
      njs_str("[InternalError,TypeError: msg,/(?:)/,/^undef$/my,1970-01-01T00:00:00.000Z]") },

    { njs_str("njs.dump(Array.prototype.slice.call({'1':'b', length:2}))"),
      njs_str("[<empty>,'b']") },

    { njs_str("var o = Object.defineProperty({}, 'a', { get: () => 1, enumerable: true }); njs.dump(o)"),
      njs_str("{a:'[Getter]'}") },

    { njs_str("var o = Object.defineProperty({}, 'a', { get: () => 1, set(){}, enumerable: true }); njs.dump(o)"),
      njs_str("{a:'[Getter/Setter]'}") },

    { njs_str("var o = Object.defineProperty({}, 'a', { set(){}, enumerable: true }); njs.dump(o)"),
      njs_str("{a:'[Setter]'}") },

    { njs_str("var a = []; a[0] = a; njs.dump(a)"),
      njs_str("[[Circular]]") },

    { njs_str("var a = []; njs.dump([a,a])"),
      njs_str("[[],[]]") },

    { njs_str("var O = {}; O.x = O; njs.dump(O)"),
      njs_str("{x:[Circular]}") },

    { njs_str("var O = {}; njs.dump({x:O, y:O})"),
      njs_str("{x:{},y:{}}") },

    { njs_str("var a = [], b = [a];  a[0] = b; njs.dump(a)"),
      njs_str("[[[Circular]]]") },

    { njs_str("var a = []; a.length = 2**31;"
              "njs.dump(a)"),
      njs_str("[<2147483648 empty items>]") },

    { njs_str("var a = ['a',,'c']; a.length = 2**31;"
              "njs.dump(a)"),
      njs_str("['a',<empty>,'c',<2147483645 empty items>]") },

    { njs_str("var a = [,'b','c']; a.length = 2**31;"
              "njs.dump(a)"),
      njs_str("[<empty>,'b','c',<2147483645 empty items>]") },

#if (!NJS_HAVE_MEMORY_SANITIZER) /* False-positive in MSAN? */
    { njs_str("var a = []; a[2**31] = 'Z'; a[0] = 'A'; njs.dump(a)"),
      njs_str("['A',<2147483647 empty items>,'Z']") },

    { njs_str("var a = []; a[2**31] = 'Z'; a[0] = 'A'; a.b = 'X'; njs.dump(a)"),
      njs_str("['A',<2147483647 empty items>,'Z',b:'X']") },

    { njs_str("var a = []; a[2**31] = 'Z'; a[0] = 'A'; a.b = 'X'; a.length = 3; njs.dump(a)"),
      njs_str("['A',<2 empty items>,b:'X']") },
#endif

    { njs_str("var a = [1,2,3];Object.defineProperty(a, '1', {get:()=>2});njs.dump(a)"),
      njs_str("[1,'[Getter]',3]") },

    { njs_str("var a = [1,2,3];Object.defineProperty(a, '1', {enumerable:false});njs.dump(a)"),
      njs_str("[1,2,3]") },

    { njs_str("njs.dump(-0)"),
      njs_str("-0") },

    { njs_str("njs.dump(Object(-0))"),
      njs_str("[Number: -0]") },

    { njs_str("njs.dump([0, -0])"),
      njs_str("[0,-0]") },

    { njs_str("njs.dump(Symbol())"),
      njs_str("Symbol()") },

    { njs_str("njs.dump(Object(Symbol()))"),
      njs_str("[Symbol: Symbol()]") },

    { njs_str("njs.dump(Symbol('desc'))"),
      njs_str("Symbol(desc)") },

    { njs_str("njs.dump(Object(Symbol('desc')))"),
      njs_str("[Symbol: Symbol(desc)]") },

    { njs_str("njs.dump(Symbol.iterator)"),
      njs_str("Symbol(Symbol.iterator)") },

    { njs_str("njs.dump(Object(Symbol.iterator))"),
      njs_str("[Symbol: Symbol(Symbol.iterator)]") },

    { njs_str("njs.dump(decodeURI)"),
      njs_str("[Function: decodeURI]") },

    { njs_str("delete decodeURI.name; njs.dump(decodeURI)"),
      njs_str("[Function]") },

    { njs_str("delete decodeURI.name; delete Function.prototype.name; "
              "decodeURI.name = 1; njs.dump(decodeURI)"),
      njs_str("[Function: native]") },

    { njs_str("delete decodeURI.name; delete Function.prototype.name; "
              "decodeURI.name = 'XXX'; njs.dump(decodeURI)"),
      njs_str("[Function: XXX]") },

    /* njs.on(). */

    { njs_str("njs.on(decodeURI)"),
      njs_str("TypeError: hook type is not a string") },

    { njs_str("njs.on('xxx')"),
      njs_str("TypeError: unknown hook type \"xxx\"") },

    { njs_str("njs.on('exit')"),
      njs_str("TypeError: callback is not a function or null") },

    { njs_str("njs.on('exit', null); 1"),
      njs_str("1") },

    { njs_str("njs.on('exit', ()=>{}); 1"),
      njs_str("1") },

    /* njs.memoryStats. */

    { njs_str("Object.keys(njs.memoryStats).sort()"),
      njs_str("cluster_size,nblocks,page_size,size") },

    { njs_str("typeof njs.memoryStats.size"),
      njs_str("number") },

    { njs_str("njs.memoryStats.size > 4096"),
      njs_str("true") },

    { njs_str("var size = njs.memoryStats.size;"
              "new Array(2**15);"
              "njs.memoryStats.size > size"),
      njs_str("true") },

    /* Built-in methods name. */

    { njs_str(
        "var fail;"
        "function isMethodsHaveName(o) {"
        "    var except = ["
        "        'prototype',"
        "        'constructor',"
        "        'caller',"
        "        'arguments',"
        "        'description',"
        "    ];"
        "    return Object.getOwnPropertyNames(o)"
        "                 .filter(v => !except.includes(v)"
        "                              && typeof o[v] == 'function')"
        "                 .every(v => o[v].name == v"
        "                             || !(fail = `${o.name}.${v}: ${o[v].name}`));"
        "}"
        "["
        "    Boolean, Boolean.prototype,"
        "    Number, Number.prototype,"
        "    Symbol, Symbol.prototype,"
        "    String, String.prototype,"
        "    Object, Object.prototype,"
        "    Array, Array.prototype,"
        "    Function, Function.prototype,"
        "    RegExp, RegExp.prototype,"
        "    Date, Date.prototype,"
        "    Error, Error.prototype,"
        "    Math,"
        "    JSON,"
        "].every(obj => isMethodsHaveName(obj)) || fail"),

      njs_str("true") },

    /* require(). */

    { njs_str("require('unknown_module')"),
      njs_str("Error: Cannot load module \"unknown_module\"") },

    { njs_str("require()"),
      njs_str("TypeError: missing path") },

    { njs_str("require.length"),
      njs_str("1") },

    { njs_str("require.name"),
      njs_str("require") },

    { njs_str("typeof require"),
      njs_str("function") },

    { njs_str("require.hasOwnProperty('length')"),
      njs_str("true") },

    /* Trick: number to boolean. */

    { njs_str("var a = 0; !!a"),
      njs_str("false") },

    { njs_str("var a = 5; !!a"),
      njs_str("true") },

    /* Trick: flooring. */

    { njs_str("var n = -10.12345; ~~n"),
      njs_str("-10") },

    { njs_str("var n = 10.12345; ~~n"),
      njs_str("10") },

    /* es5id: 8.2_A1_T1 */
    /* es5id: 8.2_A1_T2 */

    { njs_str("var x = null;"),
      njs_str("undefined") },

    /* es5id: 8.2_A2 */

    { njs_str("var null;"),
      njs_str("SyntaxError: Unexpected token \"null\"") },

    /* es5id: 8.2_A3 */

    { njs_str("typeof(null) === \"object\""),
      njs_str("true") },

    /* Module. */

    { njs_str("import * from y"),
      njs_str("SyntaxError: Non-default import is not supported") },

    { njs_str("import 'x' from y"),
      njs_str("SyntaxError: Non-default import is not supported") },

    { njs_str("import {x} from y"),
      njs_str("SyntaxError: Non-default import is not supported") },

    { njs_str("import switch from y"),
      njs_str("SyntaxError: Unexpected token \"switch\"") },

    { njs_str("import x from y"),
      njs_str("SyntaxError: Unexpected token \"y\"") },

    { njs_str("import x from {"),
      njs_str("SyntaxError: Unexpected token \"{\"") },

    { njs_str("import x from ''"),
      njs_str("ReferenceError: Cannot load module \"\"") },

    { njs_str("export"),
      njs_str("SyntaxError: Illegal export statement") },

    { njs_str("Object.assign(undefined)"),
      njs_str("TypeError: cannot convert null or undefined to object") },

    { njs_str("Object.assign(null)"),
      njs_str("TypeError: cannot convert null or undefined to object") },

    { njs_str("Object.assign({x:123}).toString()"),
      njs_str("[object Object]") },

    { njs_str("Object.assign({x:123}).x"),
      njs_str("123") },

    { njs_str("Object.assign(true)"),
      njs_str("true") },

    { njs_str("Object.assign(123)"),
      njs_str("123") },

    { njs_str("var o1 = {a:1, b:1, c:1}; var o2 = {b:2, c:2}; "
                 "var o3 = {c:3}; var obj = Object.assign({}, o1, o2, o3); "
                 "Object.values(obj);"),
      njs_str("1,2,3") },

    { njs_str("var v1 = 'abc'; var v2 = true; var v3 = 10; "
                 "var obj = Object.assign({}, v1, null, v2, undefined, v3); "
                 "Object.values(obj);"),
      njs_str("a,b,c") },

    { njs_str("Object.assign(true, {a:123})"),
      njs_str("true") },

    { njs_str("Object.assign(true, {a:123}).a"),
      njs_str("123") },

    { njs_str("var y = Object.create({s:123}); y.z = 456;"
                 "Object.assign({}, y).s;"),
      njs_str("undefined") },

    { njs_str("var obj = {s:123}; Object.defineProperty(obj,"
                 "'p1', {value:12, enumerable:false});"
                 "Object.assign({}, obj).p1"),
      njs_str("undefined") },

    { njs_str("var obj = {s:123}; Object.defineProperty(obj,"
                 "'x', {value:12, writable:false});"
                 "Object.assign(obj, {x:4})"),
      njs_str("TypeError: Cannot assign to read-only property \"x\" of object") },

    { njs_str("var obj = {foo:1, get bar() {return 2;}};"
                 "var copy = Object.assign({}, obj);"
                 "Object.getOwnPropertyDescriptor(copy, 'bar').get"),
      njs_str("undefined") },

    { njs_str("try{var x = Object.defineProperty({}, 'foo',"
                 "{value:1, writable:false});"
                 "Object.assign(x, {bar:2}, {foo:2});}catch(error){};"
                 "x.bar"),
      njs_str("2") },

    { njs_str("var a = Object.defineProperty({}, 'a',"
                 "{get(){Object.defineProperty(this, 'b',"
                 "{value:2,enumerable:false});"
                 "return 1}, enumerable:1}); a.b =1;"
                 "var x = Object.assign({}, a);x.b;"),
      njs_str("undefined") },

    /* let and const */

    { njs_str("var let = 123;"
              "let"),
      njs_str("SyntaxError: Unexpected token \"let\"") },

    { njs_str("var const = 123"),
      njs_str("SyntaxError: Unexpected token \"const\"") },

    /* Async */

    { njs_str("var async;"
              "function f() {"
              "    async\n"
              "    function foo() {}"
              "}"
              "f()"),
      njs_str("undefined") },

    { njs_str("var async;"
              "function f() {"
              "    async;"
              "    function foo() {}"
              "}"
              "f()"),
      njs_str("undefined") },

    { njs_str("var async;"
              "async\n"
              "function foo() {}"),
      njs_str("undefined") },

    { njs_str("new\""),
      njs_str("SyntaxError: Unterminated string \"\"\"") },

    { njs_str("new\"\\UFFFF"),
      njs_str("SyntaxError: Unterminated string \"\"\\UFFFF\"") },

    { njs_str("new/la"),
      njs_str("SyntaxError: Unterminated RegExp \"/la\"") },

    { njs_str("{name; {/ / /}"),
      njs_str("SyntaxError: Unexpected token \"}\"") },

    { njs_str("[(]"),
      njs_str("SyntaxError: Unexpected token \"]\"") },

#if 0 /* TODO spreading support. */
    { njs_str("[...]"),
      njs_str("SyntaxError: Unexpected token \"]\"") },

    { njs_str("var id = (x) => x, x = id(...[1,2,3]); typeof x"),
      njs_str("number") },
#endif

    { njs_str("switch () {}"),
      njs_str("SyntaxError: Unexpected token \")\"") },

    { njs_str("switch ([(]) {}"),
      njs_str("SyntaxError: Unexpected token \"]\"") },

    { njs_str("{{}{-}"),
      njs_str("SyntaxError: Unexpected token \"}\"") },

    { njs_str("{{}{+}"),
      njs_str("SyntaxError: Unexpected token \"}\"") },

    { njs_str("{{}{delete}"),
      njs_str("SyntaxError: Unexpected token \"}\"") },

    { njs_str("{{}{++}"),
      njs_str("SyntaxError: Unexpected token \"}\"") },

    { njs_str("{{}{++1}"),
      njs_str("ReferenceError: Invalid left-hand side in prefix operation") },

    { njs_str("{{}{1++}"),
      njs_str("ReferenceError: Invalid left-hand side in postfix operation") },

    { njs_str("{{}{1/}"),
      njs_str("SyntaxError: Unexpected token \"}\"") },

    { njs_str("{{}{1>>}"),
      njs_str("SyntaxError: Unexpected token \"}\"") },

    { njs_str("{{}{r=}"),
      njs_str("SyntaxError: Unexpected token \"}\"") },

    { njs_str("{{}{var a = }"),
      njs_str("SyntaxError: Unexpected token \"}\"") },

    { njs_str("{{}T=>}"),
      njs_str("SyntaxError: Unexpected token \"}\"") },

    { njs_str("{{}a = b +}"),
      njs_str("SyntaxError: Unexpected token \"}\"") },

    { njs_str("{{}a = b -}"),
      njs_str("SyntaxError: Unexpected token \"}\"") },

    { njs_str("{{}a = b *}"),
      njs_str("SyntaxError: Unexpected token \"}\"") },

    { njs_str("{{}a = b /}"),
      njs_str("SyntaxError: Unexpected token \"}\"") },

    { njs_str("{{}a = b %}"),
      njs_str("SyntaxError: Unexpected token \"}\"") },

    { njs_str("{{}a = b++}"),
      njs_str("ReferenceError: \"a\" is not defined") },

    { njs_str("{{}a = b--}"),
      njs_str("ReferenceError: \"a\" is not defined") },

    { njs_str("{{}a =}"),
      njs_str("SyntaxError: Unexpected token \"}\"") },

    { njs_str("{{}a +=}"),
      njs_str("SyntaxError: Unexpected token \"}\"") },

    { njs_str("{{}a -=}"),
      njs_str("SyntaxError: Unexpected token \"}\"") },

    { njs_str("{{}a *=}"),
      njs_str("SyntaxError: Unexpected token \"}\"") },

    { njs_str("{{}a /=}"),
      njs_str("SyntaxError: Unexpected token \"}\"") },

    { njs_str("{{}a %=}"),
      njs_str("SyntaxError: Unexpected token \"}\"") },

    { njs_str("{{}a ===}"),
      njs_str("SyntaxError: Unexpected token \"}\"") },

    { njs_str("{{}a ==}"),
      njs_str("SyntaxError: Unexpected token \"}\"") },

    { njs_str("{{}a !=}"),
      njs_str("SyntaxError: Unexpected token \"}\"") },

    { njs_str("{{}a !==}"),
      njs_str("SyntaxError: Unexpected token \"}\"") },

    { njs_str("{{}a >}"),
      njs_str("SyntaxError: Unexpected token \"}\"") },

    { njs_str("{{}a <}"),
      njs_str("SyntaxError: Unexpected token \"}\"") },

    { njs_str("{{}a <=}"),
      njs_str("SyntaxError: Unexpected token \"}\"") },

    { njs_str("{{}a &&}"),
      njs_str("SyntaxError: Unexpected token \"}\"") },

    { njs_str("{{}a ||}"),
      njs_str("SyntaxError: Unexpected token \"}\"") },

    { njs_str("{{}a ??}"),
      njs_str("SyntaxError: Unexpected token \"}\"") },

    { njs_str("{{}a &}"),
      njs_str("SyntaxError: Unexpected token \"}\"") },

    { njs_str("{{}a |}"),
      njs_str("SyntaxError: Unexpected token \"}\"") },

    { njs_str("{{}a ^}"),
      njs_str("SyntaxError: Unexpected token \"}\"") },

    { njs_str("{{}a <<}"),
      njs_str("SyntaxError: Unexpected token \"}\"") },

    { njs_str("{{}a >>}"),
      njs_str("SyntaxError: Unexpected token \"}\"") },

    { njs_str("{{}new}"),
      njs_str("SyntaxError: Unexpected token \"}\"") },

    { njs_str("{{}delete}"),
      njs_str("SyntaxError: Unexpected token \"}\"") },

    { njs_str("{{}void}"),
      njs_str("SyntaxError: Unexpected token \"}\"") },

    { njs_str("{{}typeof}"),
      njs_str("SyntaxError: Unexpected token \"}\"") },

    { njs_str("{{} ({a: 1, b: {}\n}\n})\n}"),
      njs_str("SyntaxError: Unexpected token \"}\"") },

    { njs_str("object?."),
      njs_str("SyntaxError: Unexpected end of input") },

    { njs_str("`${{a: 1, b}}`"),
      njs_str("ReferenceError: \"b\" is not defined") },

    { njs_str("`${{a: 1, b:}}`"),
      njs_str("SyntaxError: Unexpected token \"}\"") },

    { njs_str("`${{a: 1, b:,}}`"),
      njs_str("SyntaxError: Unexpected token \",\"") },

    { njs_str("`${{a: 1, b: 2,}}`"),
      njs_str("[object Object]") },

    { njs_str("`${{a: 1,, b: 2}}`"),
      njs_str("SyntaxError: Unexpected token \",\"") },

    { njs_str("`${{f(){-} - {}}`"),
      njs_str("SyntaxError: Unexpected token \"}\"") },

    { njs_str("for (;1-;) {}"),
      njs_str("SyntaxError: Unexpected token \";\"") },

    { njs_str("var str = String(str); str"),
      njs_str("undefined") },

    { njs_str("var t = \"123\"; t = parseInt(t); t"),
      njs_str("123") },

    /* let */

    { njs_str("let x"),
      njs_str("undefined") },

    { njs_str("let x = 123; x"),
      njs_str("123") },

    { njs_str("let x = [123]; x"),
      njs_str("123") },

    { njs_str("let x = () => x; x()"),
      njs_str("[object Function]") },

    { njs_str("let x = (() => x)()"),
      njs_str("ReferenceError: cannot access variable before initialization") },

    { njs_str("x; let x"),
      njs_str("ReferenceError: cannot access variable before initialization") },

    { njs_str("x; let x = 123"),
      njs_str("ReferenceError: cannot access variable before initialization") },

    { njs_str("let x = x + 123"),
      njs_str("ReferenceError: cannot access variable before initialization") },

    { njs_str("let x = (x, 1)"),
      njs_str("ReferenceError: cannot access variable before initialization") },

    { njs_str("let x = x"),
      njs_str("ReferenceError: cannot access variable before initialization") },

    { njs_str("let x; var x"),
      njs_str("SyntaxError: \"x\" has already been declared") },

    { njs_str("var x; let x"),
      njs_str("SyntaxError: \"x\" has already been declared") },

    { njs_str("let x; function x() {}"),
      njs_str("SyntaxError: \"x\" has already been declared") },

    { njs_str("function x() {} let x"),
      njs_str("SyntaxError: \"x\" has already been declared") },

    { njs_str("function x() {let x; var x}"),
      njs_str("SyntaxError: \"x\" has already been declared") },

    { njs_str("function x() {var x; let x}"),
      njs_str("SyntaxError: \"x\" has already been declared") },

    { njs_str("var x = function f() {let f}"),
      njs_str("undefined") },

    { njs_str("let a; let x = 1;"
              "{let x = 2; a = x}"
              "[x, a]"),
      njs_str("1,2") },

    { njs_str("let a; let x = 1;"
              "if (true) {let x = 2; a = x}"
              "[x, a]"),
      njs_str("1,2") },

    { njs_str("var a = 5, b = 10, arr = [];"
              "{let a = 4; var b = 1; arr.push(a); arr.push(b)}"
              "arr.push(a); arr.push(b); arr"),
      njs_str("4,1,5,1") },

    { njs_str("function func() {return x}"
              "let x = 123;"
              "func()"),
      njs_str("123") },

    { njs_str("function func() {return x}"
              "func();"
              "let x = 123"),
      njs_str("ReferenceError: cannot access variable before initialization") },

    { njs_str("function func() {return () => x}"
              "let x = 123;"
              "func()()"),
      njs_str("123") },

    { njs_str("function func() {x = x + 1; let x}"),
      njs_str("undefined") },

    { njs_str("function func() {return () => x}"
              "func()();"
              "let x = 123;"),
      njs_str("ReferenceError: cannot access variable before initialization") },

    { njs_str("var arr = [];"
              ""
              "for (var i = 0; i < 10; i++) {"
              "    let x = i;"
              ""
              "    arr.push( (n) => {x += n; return x} );"
              "}"
              ""
              "["
              "    arr[0](2), arr[1](1), arr[2](4), arr[3](7), arr[4](0),"
              "    arr[5](1), arr[6](2), arr[7](5), arr[8](8), arr[9](10)"
              "]"),
      njs_str("2,2,6,10,4,6,8,12,16,19") },

    { njs_str("var arr = [];"
              ""
              "for (let i = 0; i < 10; i++) {"
              "    arr.push( (n) => {i += n; return i} );"
              "}"
              ""
              "["
              "    arr[0](2), arr[1](1), arr[2](4), arr[3](7), arr[4](0),"
              "    arr[5](1), arr[6](2), arr[7](5), arr[8](8), arr[9](10)"
              "]"),
      njs_str("2,2,6,10,4,6,8,12,16,19") },

    { njs_str("for (let i = 0; i < 1; i++) {"
              "    let i = i + 2;"
              "}"),
      njs_str("ReferenceError: cannot access variable before initialization") },

    { njs_str("let arr = [], res = [];"
              "for (let i = 0, f = function() { return i }; i < 5; i++) {"
              "    arr.push(f);"
              "}"
              "for (let i = 0; i < 5; i++) {"
              "    res.push(arr[i]());"
              "} res"),
      njs_str("0,0,0,0,0") },

    { njs_str("let arr = [], res = [];"
              "for (let i = 0; arr.push(() => i), i < 10; i++) {}"
              "for (let k = 0; k < 10; k++) {res.push(arr[k]())}"
              "res"),
      njs_str("0,1,2,3,4,5,6,7,8,9") },

    { njs_str("let res = [];"
              "for (let n in [1,2,3]) {res.push(n)}"
              "res"),
      njs_str("0,1,2") },

    { njs_str("let arr = [], res = [];"
              ""
              "for (let n in [1,2,3]) {"
              "    arr.push(() => n);"
              "}"
              ""
              "for (let n in arr) {"
              "    res.push(arr[n]());"
              "}"
              "res"),
      njs_str("0,1,2") },

    { njs_str("let arr = [];"
              ""
              "for (let n in [1,2,3]) {"
              "    let n = 1;"
              "    arr.push(n);"
              "}"
              "arr"),
      njs_str("1,1,1") },

    { njs_str("for (let n in [1,2,3]) {"
              "    let n = n + 1;"
              "}"),
      njs_str("ReferenceError: cannot access variable before initialization") },

    { njs_str("for (let n in [1,2,3]) {}"
              "n"),
      njs_str("ReferenceError: \"n\" is not defined") },

    { njs_str("for (let n in [1,n,3]) {}"),
      njs_str("ReferenceError: cannot access variable before initialization") },

    { njs_str("(function() {"
              "function f() {return x + 1}"
              "function abc() {f()};"
              "abc();"
              "let x;"
              "}())"),
      njs_str("ReferenceError: cannot access variable before initialization") },

    { njs_str("function func() {var x = 1; {let x = x + 1} } func()"),
      njs_str("ReferenceError: cannot access variable before initialization") },

    { njs_str("if (false) let x = 1"),
      njs_str("SyntaxError: let declaration cannot appear in a single-statement context") },

    { njs_str("while (false) let x = 1"),
      njs_str("SyntaxError: let declaration cannot appear in a single-statement context") },

    { njs_str("for (;;) let x = 1"),
      njs_str("SyntaxError: let declaration cannot appear in a single-statement context") },

    { njs_str("try {} catch (e) {let e}"),
      njs_str("SyntaxError: \"e\" has already been declared") },

    { njs_str("let arr = [], x = 2;"
              "switch(true) {default: let x = 1; arr.push(x)}"
              "arr.push(x); arr"),
      njs_str("1,2") },

    { njs_str("switch(true) {case false: let x = 1; default: x = 2}"),
      njs_str("ReferenceError: cannot access variable before initialization") },

    { njs_str("let res;"
              "switch(true) {case true: let x = 1; default: x = 2; res = x} res"),
      njs_str("2") },

    { njs_str("let null"),
      njs_str("SyntaxError: Unexpected token \"null\"") },

    { njs_str("let continue"),
      njs_str("SyntaxError: Unexpected token \"continue\"") },

    { njs_str("let undefined"),
      njs_str("SyntaxError: \"undefined\" has already been declared") },

    { njs_str("let a = 1; globalThis.a"),
      njs_str("undefined") },

    { njs_str("if (false) {x = 2} else {x = 1} let x;"),
      njs_str("ReferenceError: cannot access variable before initialization") },

    { njs_str("let let"),
      njs_str("SyntaxError: Unexpected token \"let\"") },

    { njs_str("let null"),
      njs_str("SyntaxError: Unexpected token \"null\"") },

    { njs_str("function let() {}"),
      njs_str("SyntaxError: Unexpected token \"let\"") },

    { njs_str("function static() {}"),
      njs_str("SyntaxError: Unexpected token \"static\"") },

    /* const */

    { njs_str("const x"),
      njs_str("SyntaxError: missing initializer in const declaration") },

    { njs_str("const x = 1; x"),
      njs_str("1") },

    { njs_str("const x = 1; x = 1"),
      njs_str("TypeError: assignment to constant variable") },

    { njs_str("function abc() {const x}"),
      njs_str("SyntaxError: missing initializer in const declaration") },

    { njs_str("const x = [123]; x"),
      njs_str("123") },

    { njs_str("const x = () => x; x()"),
      njs_str("[object Function]") },

    { njs_str("const x = (() => x)()"),
      njs_str("ReferenceError: cannot access variable before initialization") },

    { njs_str("x; const x = 123"),
      njs_str("ReferenceError: cannot access variable before initialization") },

    { njs_str("const x = x + 123"),
      njs_str("ReferenceError: cannot access variable before initialization") },

    { njs_str("const x; var x"),
      njs_str("SyntaxError: \"x\" has already been declared") },

    { njs_str("const x; let x"),
      njs_str("SyntaxError: \"x\" has already been declared") },

    { njs_str("let x; const x"),
      njs_str("SyntaxError: \"x\" has already been declared") },

    { njs_str("const x = 1; function x() {}"),
      njs_str("SyntaxError: \"x\" has already been declared") },

    { njs_str("function x() {} const x = 1"),
      njs_str("SyntaxError: \"x\" has already been declared") },

    { njs_str("function x() {const x; var x}"),
      njs_str("SyntaxError: \"x\" has already been declared") },

    { njs_str("function x() {var x; const x}"),
      njs_str("SyntaxError: \"x\" has already been declared") },

    { njs_str("const x = function f() {const f = 1}"),
      njs_str("undefined") },

    { njs_str("let res; const x = 1;"
              "{const x = 2; res = x}"
              "[x, res]"),
      njs_str("1,2") },

    { njs_str("let res; const x = 1;"
              "if (true) {const x = 2; res = x}"
              "[x, res]"),
      njs_str("1,2") },

    { njs_str("function func() {return x}"
              "const x = 123;"
              "func()"),
      njs_str("123") },

    { njs_str("function func() {return x}"
              "func();"
              "const x = 123"),
      njs_str("ReferenceError: cannot access variable before initialization") },

    { njs_str("function func() {return () => x}"
              "const x = 123;"
              "func()()"),
      njs_str("123") },

    { njs_str("function func() {return () => x++}"
              "const x = 123;"
              "func()()"),
      njs_str("TypeError: assignment to constant variable") },

    { njs_str("for (const i = 0; i < 1; i++) {}"),
      njs_str("TypeError: assignment to constant variable") },

    { njs_str("let res = [];"
              "for (const n in [1,2,3]) {res.push(n)}"
              "res"),
      njs_str("0,1,2") },

    { njs_str("let arr = [], res = [];"
              ""
              "for (const n in [1,2,3]) {"
              "    arr.push(() => n);"
              "}"
              ""
              "for (let n in arr) {"
              "    res.push(arr[n]());"
              "}"
              "res"),
      njs_str("0,1,2") },

    { njs_str("let arr = [];"
              ""
              "for (const n in [1,2,3]) {"
              "    let n = 1;"
              "    arr.push(n);"
              "}"
              "arr"),
      njs_str("1,1,1") },

    { njs_str("for (const n in [1,2,3]) {"
              "    let n = n + 1;"
              "}"),
      njs_str("ReferenceError: cannot access variable before initialization") },

    { njs_str("for (const n in [1,2,3]) {}"
              "n"),
      njs_str("ReferenceError: \"n\" is not defined") },

    { njs_str("for (const n in [1,n,3]) {}"),
      njs_str("ReferenceError: cannot access variable before initialization") },

    { njs_str("(function() {"
              "function f() {return x + 1}"
              "function abc() {f()};"
              "abc();"
              "const x = 1;"
              "}())"),
      njs_str("ReferenceError: cannot access variable before initialization") },

    { njs_str("if (false) const x = 1"),
      njs_str("SyntaxError: const declaration cannot appear in a single-statement context") },

    { njs_str("while (false) const x = 1"),
      njs_str("SyntaxError: const declaration cannot appear in a single-statement context") },

    { njs_str("for (;;) const x = 1"),
      njs_str("SyntaxError: const declaration cannot appear in a single-statement context") },

    { njs_str("try {} catch (e) {const e = 1}"),
      njs_str("SyntaxError: \"e\" has already been declared") },

    { njs_str("let arr = []; const x = 2;"
              "switch(true) {default: const x = 1; arr.push(x)}"
              "arr.push(x); arr"),
      njs_str("1,2") },

    { njs_str("let res;"
              "switch(true) {case true: const x = 1; default: x = 2; res = x} res"),
      njs_str("TypeError: assignment to constant variable") },

    { njs_str("const null"),
      njs_str("SyntaxError: Unexpected token \"null\"") },

    { njs_str("const continue"),
      njs_str("SyntaxError: Unexpected token \"continue\"") },

    { njs_str("const undefined"),
      njs_str("SyntaxError: \"undefined\" has already been declared") },

    { njs_str("const a = 1; globalThis.a"),
      njs_str("undefined") },

    { njs_str("if (false) {x = 2} else {x = 1} const x = 0"),
      njs_str("ReferenceError: cannot access variable before initialization") },

    { njs_str("const const"),
      njs_str("SyntaxError: Unexpected token \"const\"") },

    /* Async/Await */

    { njs_str("async function f() {}; f.prototype"),
      njs_str("undefined") },

    { njs_str("async function f() {await 1}"),
      njs_str("undefined") },

    { njs_str("function f() {await 1}"),
      njs_str("SyntaxError: await is only valid in async functions") },

    { njs_str("async function f() {function a() {await 1}}"),
      njs_str("SyntaxError: await is only valid in async functions") },

    { njs_str("async function f() {() => {await 1}}"),
      njs_str("SyntaxError: await is only valid in async functions") },

    { njs_str("function f() {async () => {await 1}}"),
      njs_str("undefined") },

    { njs_str("let f = async () => {await 1}"),
      njs_str("undefined") },

    { njs_str("let f = () => {await 1}"),
      njs_str("SyntaxError: await is only valid in async functions") },

    { njs_str("(async function() {await 1})"),
      njs_str("[object AsyncFunction]") },

    { njs_str("(function() {await 1})"),
      njs_str("SyntaxError: await is only valid in async functions") },

    { njs_str("let ctor = Object.getPrototypeOf(async function(){}).constructor;"
              "ctor"),
      njs_str("[object Function]") },

    { njs_str("let ctor = Object.getPrototypeOf(async function(){}).constructor;"
              "ctor()"),
      njs_str("[object AsyncFunction]") },

    { njs_str("let ctor = Object.getPrototypeOf(async function(){}).constructor;"
              "new ctor();"),
      njs_str("[object AsyncFunction]") },

    { njs_str("let f = new Function('x', 'await 1; return x'); f(1)"),
      njs_str("SyntaxError: await is only valid in async functions") },

    { njs_str("new AsyncFunction()"),
      njs_str("ReferenceError: \"AsyncFunction\" is not defined") },

    { njs_str("(async function() {console.log(await 111)})"),
      njs_str("[object AsyncFunction]") },

    { njs_str("(async function() {console.log('Number: ' + await 111)})"),
      njs_str("[object AsyncFunction]") },

    { njs_str("(async function() {f(await 111)})"),
      njs_str("[object AsyncFunction]") },

    { njs_str("(async function() {f(f(1), await 111)})"),
      njs_str("[object AsyncFunction]") },

    { njs_str("async () => [await x(1)(),]; async () => [await x(1)()]"),
      njs_str("[object AsyncFunction]") },

    { njs_str("(async function() {f(1, 'a', await 111)})"),
      njs_str("[object AsyncFunction]") },

    { njs_str("(async function() {f('Number: ' + await 111)})"),
      njs_str("[object AsyncFunction]") },

    { njs_str("async function f1() {try {f(await f1)} catch(e) {}}"),
      njs_str("undefined") },

    { njs_str("(async () => (function (){}) `${(async () => 1)(await 1)}`)()"),
      njs_str("[object Promise]") },

    { njs_str("(async () => (function (){}) `${await 1}`)()"),
      njs_str("[object Promise]") },

    { njs_str("(async () => ({"
              "    x: 7,"
              "    t(...a) { return this.x + ':' + a[1]; }"
              "}).t`${await 2}`)()"),
      njs_str("[object Promise]") },

    { njs_str("async function af() {await encrypt({},}"),
      njs_str("SyntaxError: Unexpected token \"}\"") },

    { njs_str("let x = {async af() {await Promise.resolve(1)}}; x.af"),
      njs_str("[object AsyncFunction]") },

    { njs_str("let name = 'af', x = {async [name]() {await Promise.resolve(1)}}; x.af"),
      njs_str("[object AsyncFunction]") },
};


static njs_unit_test_t  njs_safe_test[] =
{
    { njs_str("(new Function('return this'))() === globalThis"),
      njs_str("true") },

    { njs_str("(new Function('return this;'))() === globalThis"),
      njs_str("true") },

    { njs_str("(new Function('return    this  '))() === globalThis"),
      njs_str("true") },

    { njs_str("(new Function('return thi'))()"),
      njs_str("TypeError: function constructor is disabled in \"safe\" mode") },

    { njs_str("(new Function('){return 1337})//', 'return this'))()"),
      njs_str("TypeError: function constructor is disabled in \"safe\" mode") },
};


static njs_unit_test_t  njs_denormals_test[] =
{
    { njs_str("2.2250738585072014e-308"),
      njs_str("2.2250738585072014e-308") },

#ifndef NJS_SUNC
    { njs_str("2.2250738585072014E-308.toString(2) == ('0.' + '0'.repeat(1021) + '1')"),
      njs_str("true") },

    { njs_str("Number.MAX_VALUE.toString(2) === ('1'.repeat(53) + '0'.repeat(971))"),
      njs_str("true") },

    { njs_str("Number('2.2250738585072014E-323')"),
      njs_str("2.5e-323") },

    { njs_str("Number('2.2250738585072014E-323') + 0"),
      njs_str("2.5e-323") },

    /* Smallest positive double (next_double(0)). */
    { njs_str("5E-324.toString(36) === '0.' + '0'.repeat(207) + '3'"),
      njs_str("true") },

    /* Maximum fraction length. */
    { njs_str("2.2250738585072014E-323.toString(2) == ('0.' + '0'.repeat(1071) + '101')"),
      njs_str("true") },

    /* Denormals. */
    { njs_str("var zeros = count => '0'.repeat(count);"
              "["
              "  [1.8858070859709815e-308, `0.${zeros(1022)}1101100011110111011100000100011001111101110001010111`],"
              "  [Number.MIN_VALUE, `0.${zeros(1021)}1`],"
              "  [-5.06631661953108e-309, `-0.${zeros(1024)}11101001001010000001101111010101011111111011010111`],"
              "  [6.22574126804e-313, `0.${zeros(1037)}11101010101101100111000110100111001`],"
              "  [-4e-323, `-0.${zeros(1070)}1`],"
              "].every(t=>t[0].toString(2) === t[1])"),
      njs_str("true") },

    { njs_str("4.94065645841246544176568792868e-324.toExponential()"),
      njs_str("5e-324") },

    { njs_str("4.94065645841246544176568792868e-324.toExponential(10)"),
      njs_str("4.9406564584e-324") },
#endif

};


static njs_unit_test_t  njs_fs_module_test[] =
{
    { njs_str("var fs = require('fs'); typeof fs"),
      njs_str("object") },

    { njs_str("var fs = require('fs'); Object.isExtensible(fs)"),
      njs_str("true") },

    { njs_str("require('fs') === require('fs')"),
      njs_str("true") },

    { njs_str("require('fs').a = 1; require('fs').a"),
      njs_str("1") },

    { njs_str("var fs = require('fs');"
              "fs.readFile()"),
      njs_str("TypeError: \"path\" must be a string or Buffer") },

    { njs_str("var fs = require('fs');"
              "var path = Buffer.from('/broken'); path[3] = 0;"
              "fs.readFile(path)"),
      njs_str("TypeError: \"path\" must be a Buffer without null bytes") },

    { njs_str("var fs = require('fs');"
              "fs.readFile('/njs_unknown_path')"),
      njs_str("TypeError: \"callback\" must be a function") },

    { njs_str("var fs = require('fs');"
              "fs.readFile('/njs_unknown_path', 'utf8')"),
      njs_str("TypeError: \"callback\" must be a function") },

    { njs_str("var fs = require('fs');"
              "fs.readFile('/njs_unknown_path', {flag:'xx'})"),
      njs_str("TypeError: \"callback\" must be a function") },

    { njs_str("var fs = require('fs');"
              "fs.readFile('/njs_unknown_path', {flag:'xx'}, 1)"),
      njs_str("TypeError: \"callback\" must be a function") },

    { njs_str("var fs = require('fs');"
              "fs.readFile('/njs_unknown_path', {flag:'xx'}, function () {})"),
      njs_str("TypeError: Unknown file open flags: \"xx\"") },

    { njs_str("var fs = require('fs');"
              "fs.readFile('/njs_unknown_path', {encoding:'ascii'}, function () {})"),
      njs_str("TypeError: \"ascii\" encoding is not supported") },

    { njs_str("var fs = require('fs');"
              "fs.readFile('/njs_unknown_path', 'ascii', function () {})"),
      njs_str("TypeError: \"ascii\" encoding is not supported") },

    /* require('fs').readFileSync() */

    { njs_str("var fs = require('fs');"
              "fs.readFileSync()"),
      njs_str("TypeError: \"path\" must be a string or Buffer") },

    { njs_str("var fs = require('fs');"
              "fs.readFileSync({})"),
      njs_str("TypeError: \"path\" must be a string or Buffer") },

    { njs_str("var fs = require('fs');"
              "fs.readFileSync('/njs_unknown_path', {flag:'xx'})"),
      njs_str("TypeError: Unknown file open flags: \"xx\"") },

    { njs_str("var fs = require('fs');"
              "fs.readFileSync(Buffer.from('/njs_unknown_path'), {encoding:'ascii'})"),
      njs_str("TypeError: \"ascii\" encoding is not supported") },

    { njs_str("var fs = require('fs');"
              "fs.readFileSync('/njs_unknown_path', 'ascii')"),
      njs_str("TypeError: \"ascii\" encoding is not supported") },

    { njs_str("var fs = require('fs');"
              "fs.readFileSync('/njs_unknown_path', true)"),
      njs_str("TypeError: Unknown options type (a string or object required)") },


    /* require('fs').writeFile() */

    { njs_str("var fs = require('fs');"
              "fs.writeFile()"),
      njs_str("TypeError: \"path\" must be a string or Buffer") },

    { njs_str("var fs = require('fs');"
              "fs.writeFile({}, '', function () {})"),
      njs_str("TypeError: \"path\" must be a string or Buffer") },

    { njs_str("var fs = require('fs');"
              "fs.writeFile('/njs_unknown_path')"),
      njs_str("TypeError: \"callback\" must be a function") },

    { njs_str("var fs = require('fs');"
              "fs.writeFile('/njs_unknown_path', '')"),
      njs_str("TypeError: \"callback\" must be a function") },

    { njs_str("var fs = require('fs');"
              "fs.writeFile('/njs_unknown_path', '', undefined)"),
      njs_str("TypeError: \"callback\" must be a function") },

    { njs_str("var fs = require('fs');"
              "fs.writeFile('/njs_unknown_path', '', 'utf8')"),
      njs_str("TypeError: \"callback\" must be a function") },

    { njs_str("var fs = require('fs');"
              "fs.writeFile('/njs_unknown_path', '', {flag:'xx'}, function () {})"),
      njs_str("TypeError: Unknown file open flags: \"xx\"") },

    { njs_str("var fs = require('fs');"
              "fs.writeFile('/njs_unknown_path', '', {encoding:'ascii'}, function () {})"),
      njs_str("TypeError: \"ascii\" encoding is not supported") },

    { njs_str("var fs = require('fs');"
              "fs.writeFile('/njs_unknown_path', '', 'ascii', function () {})"),
      njs_str("TypeError: \"ascii\" encoding is not supported") },

    { njs_str("var fs = require('fs');"
              "fs.writeFile('/njs_unknown_path', '', true, function () {})"),
      njs_str("TypeError: Unknown options type (a string or object required)") },

    /* require('fs').writeFileSync() */

    { njs_str("var fs = require('fs');"
              "fs.writeFileSync()"),
      njs_str("TypeError: \"path\" must be a string or Buffer") },

    { njs_str("var fs = require('fs');"
              "fs.writeFileSync({}, '')"),
      njs_str("TypeError: \"path\" must be a string or Buffer") },

    { njs_str("var fs = require('fs');"
              "fs.writeFileSync('/njs_unknown_path', '', {flag:'xx'})"),
      njs_str("TypeError: Unknown file open flags: \"xx\"") },

    { njs_str("var fs = require('fs');"
              "fs.writeFileSync('/njs_unknown_path', '', {encoding:'ascii'})"),
      njs_str("TypeError: \"ascii\" encoding is not supported") },

    { njs_str("var fs = require('fs');"
              "fs.writeFileSync('/njs_unknown_path', '', 'ascii')"),
      njs_str("TypeError: \"ascii\" encoding is not supported") },

    { njs_str("var fs = require('fs');"
              "fs.writeFileSync('/njs_unknown_path', '', true)"),
      njs_str("TypeError: Unknown options type (a string or object required)") },

    /* require('fs').renameSync() */

    { njs_str("var fs = require('fs');"
              "fs.renameSync()"),
      njs_str("TypeError: \"oldPath\" must be a string or Buffer") },

    { njs_str("var fs = require('fs');"
              "fs.renameSync('/njs_unknown_path')"),
      njs_str("TypeError: \"newPath\" must be a string or Buffer") },

    { njs_str("var fs = require('fs');"
              "[undefined, null, false, NaN, Symbol(), {}, Object('/njs_unknown_path')]"
              ".map((x) => { try { fs.renameSync(x, '/njs_unknown_path'); } "
              "              catch (e) { return (e instanceof Error); } })"
              ".every((x) => x === true)"),
      njs_str("true")},

    { njs_str("var fs = require('fs');"
              "[undefined, null, false, NaN, Symbol(), {}, Object('/njs_unknown_path')]"
              ".map((x) => { try { fs.renameSync('/njs_unknown_path', x); } "
              "              catch (e) { return (e instanceof Error); } })"
              ".every((x) => x === true)"),
      njs_str("true")},

    /* require('fs').access() */

    { njs_str("var fs = require('fs');"
              "fs.access()"),
      njs_str("TypeError: \"path\" must be a string or Buffer") },

    { njs_str("var fs = require('fs');"
              "fs.access('/njs_unknown_path')"),
      njs_str("TypeError: \"callback\" must be a function") },

    { njs_str("var fs = require('fs');"
              "fs.access('/njs_unknown_path', fs.constants.F_OK)"),
      njs_str("TypeError: \"callback\" must be a function") },

    { njs_str("var fs = require('fs');"
              "fs.access('/njs_unknown_path', 'fail', function () {})"),
      njs_str("TypeError: \"mode\" must be a number") },

    /* require('fs').accessSync() */

    { njs_str("var fs = require('fs');"
              "fs.accessSync()"),
      njs_str("TypeError: \"path\" must be a string or Buffer") },

    { njs_str("var fs = require('fs');"
              "fs.accessSync('/njs_unknown_path', 'fail')"),
      njs_str("TypeError: \"mode\" must be a number") },

    { njs_str("var "
              "fs = require('fs'),"
              "func = ["
                "'access',"
                "'accessSync',"
                "'readFile',"
                "'readFileSync',"
                "'writeFile',"
                "'writeFileSync',"
                "'appendFile',"
                "'appendFileSync',"
                "'rename',"
                "'renameSync',"
                "'symlink',"
                "'symlinkSync',"
                "'unlink',"
                "'unlinkSync',"
                "'realpath',"
                "'realpathSync',"
                "'mkdir',"
                "'mkdirSync',"
                "'rmdir',"
                "'rmdirSync',"
                "'readdir',"
                "'readdirSync',"
              "],"
              "test = (fname) =>"
                "[undefined, null, false, NaN, Symbol(), {}, Object('/njs_unknown_path')]"
                ".map((x) => { try { fs[fname](x); } "
                "              catch (e) { return (e instanceof Error); } })"
                ".every((x) => x === true);"
              "func.map(test).every((x) => x)"),
      njs_str("true")},

    /* require('fs').promises */

    { njs_str("var fs = require('fs');"
              "typeof fs.promises"),
      njs_str("object") },

    { njs_str("var "
              "fs = require('fs').promises,"
              "func = ["
                "'access',"
                "'readFile',"
                "'writeFile',"
                "'appendFile',"
                "'rename',"
                "'symlink',"
                "'unlink',"
                "'realpath',"
                "'mkdir',"
                "'rmdir',"
                "'readdir',"
              "];"
              "func.every((x) => typeof fs[x] == 'function')"),
      njs_str("true")},

    /* require('fs').constants */

    { njs_str("var fs = require('fs');"
              "typeof fs.constants"),
      njs_str("object") },

    { njs_str("var "
              "fsc = require('fs').constants,"
              "items = ["
                "'F_OK',"
                "'R_OK',"
                "'W_OK',"
                "'X_OK',"
              "];"
              "items.every((x) => typeof fsc[x] == 'number')"),
      njs_str("true")},

    /* require('fs').Dirent */

    { njs_str("var fs = require('fs');"
              "typeof fs.Dirent"),
      njs_str("function") },

    { njs_str("var fs = require('fs');"
              "fs.Dirent('file', 123)"),
      njs_str("TypeError: the Dirent constructor must be called with new") },

    { njs_str("var fs = require('fs');"
              "var e = new fs.Dirent('file', 123); [e.name, e.type]"),
      njs_str("file,123") },

    { njs_str("var "
              "fs = require('fs'),"
              "e = new fs.Dirent('file', 0),"
              "func = ["
                "'isDirectory',"
                "'isFile',"
                "'isBlockDevice',"
                "'isCharacterDevice',"
                "'isSymbolicLink',"
                "'isFIFO',"
                "'isSocket',"
              "];"
              "func.every((x) => typeof e[x] == 'function')"),
      njs_str("true")},
};


static njs_unit_test_t  njs_module_test[] =
{
    { njs_str("function f(){return 2}; var f; f()"),
      njs_str("SyntaxError: \"f\" has already been declared") },

    { njs_str("function f(){return 2}; var f = 1; f()"),
      njs_str("SyntaxError: \"f\" has already been declared") },

    { njs_str("function f(){return 1}; function f(){return 2}; f()"),
      njs_str("SyntaxError: \"f\" has already been declared") },

    { njs_str("var f = 1; function f() {};"),
      njs_str("SyntaxError: \"f\" has already been declared") },

    { njs_str("{ var f = 1; } function f() {};"),
      njs_str("SyntaxError: \"f\" has already been declared") },

    { njs_str("function f(v) {var f = v;}; f(1); f"),
      njs_str("[object Function]") },

};


static njs_unit_test_t  njs_externals_test[] =
{
    { njs_str("(new ExternalError('XXX')) instanceof ExternalError"),
      njs_str("true") },

    { njs_str("(new ExternalError('XXX')) instanceof Error"),
      njs_str("true") },

    { njs_str("(new ExternalError()).message"),
      njs_str("") },

    { njs_str("(new ExternalError('XXX')).message"),
      njs_str("XXX") },

    { njs_str("(new ExternalError('XXX')).constructor == ExternalError"),
      njs_str("true") },

    { njs_str("(new ExternalError('XXX')).name"),
      njs_str("ExternalError") },

    { njs_str("(new ExternalError('XXX')).__proto__.name"),
      njs_str("ExternalError") },

    { njs_str("(new ExternalError('XXX')).__proto__.__proto__.name"),
      njs_str("Error") },

    { njs_str("(new ExternalError('XXX'))"),
      njs_str("ExternalError: XXX") },

    { njs_str("(new ExternalError('XXX')).toString()"),
      njs_str("ExternalError: XXX") },

    { njs_str("njs.dump(new ExternalError('XXX'))"),
      njs_str("ExternalError: XXX") },

    { njs_str("JSON.stringify(new ExternalError('XXX'))"),
      njs_str("{}") },

    { njs_str("Object.getOwnPropertyNames(new ExternalError('XXX'))"),
      njs_str("message") },

    { njs_str("var ee; try{ $r.customException() } catch (e) { if (!(e instanceof ExternalError)) { throw 'Oops'} ee = e;}; ee.toString()"),
      njs_str("ExternalError: Oops") },

    { njs_str("typeof $r"),
      njs_str("object") },

    { njs_str("var a = $r.uri, b = $r2.uri, c = $r3.uri; a+b+c"),
      njs_str("АБВαβγabc") },

    { njs_str("var a = $r.uri; $r.uri = $r2.uri; $r2.uri = a; $r2.uri+$r.uri"),
      njs_str("АБВαβγ") },

    { njs_str("var a = $r.uri; a +' '+ a.length +' '+ a"),
      njs_str("АБВ 3 АБВ") },

    { njs_str("$r.uri = 'αβγ'; var a = $r.uri; a.length +' '+ a"),
      njs_str("3 αβγ") },

    { njs_str("$r.uri.length +' '+ $r.uri"),
      njs_str("3 АБВ") },

    { njs_str("var t; "
              "switch ($r3.uri) {"
              "case 'abc': "
              "  t='A'; "
              "  break; "
              "default: "
              "  t='F'; "
              "}; t"),
      njs_str("A") },

    { njs_str("$r.uri = $r.uri.substr(1); $r.uri.length +' '+ $r.uri"),
      njs_str("2 БВ") },

    { njs_str("'' + $r.props.a + $r2.props.a + $r.props.a"),
      njs_str("121") },

    { njs_str("var p1 = $r.props, p2 = $r2.props; '' + p2.a + p1.a"),
      njs_str("21") },

    { njs_str("$r.props = $r2.props; $r.props.a"),
      njs_str("2") },

    { njs_str("var p1 = $r.props, p2 = $r2.props; '' + p1.a + p2.a"),
      njs_str("12") },

    { njs_str("var p = $r3.props; p.a = 1"),
      njs_str("TypeError: Cannot assign to read-only property \"a\" of object") },

    { njs_str("var p = $r3.props; delete p.a"),
      njs_str("TypeError: Cannot delete property \"a\" of object") },

    { njs_str("$r.vars.p + $r2.vars.q + $r3.vars.k"),
      njs_str("pvalqvalkval") },

    { njs_str("$r.vars.unset"),
      njs_str("undefined") },

    { njs_str("['k', 'unknown'].map(v=>v in $r3.consts)"),
      njs_str("true,false") },

    { njs_str("['a', 'unknown'].map(v=>v in $r3.props)"),
      njs_str("true,false") },

    { njs_str("var v = $r3.vars; v.k"),
      njs_str("kval") },

    { njs_str("var v = $r3.vars; v.unset = 1; v.unset"),
      njs_str("1") },

    { njs_str("$r3.a = 1; Object.getOwnPropertyDescriptors($r3).a.value"),
      njs_str("1") },

    { njs_str("Object.defineProperty($r3.vars, 'a', {value:1}); $r3.vars.a"),
      njs_str("1") },

    { njs_str("$r3.vars.p = 'a'; delete $r3.vars.p; $r3.vars.p"),
      njs_str("undefined") },

    { njs_str("$r3.vars.p = 'a'; delete $r3.vars.p; $r3.vars.p = 'b'; $r3.vars.p"),
      njs_str("b") },

    { njs_str("$r3.vars.error = 1"),
      njs_str("Error: cannot set \"error\" prop") },

    { njs_str("delete $r3.vars.error"),
      njs_str("Error: cannot delete \"error\" prop") },

    { njs_str("delete $r3.vars.e"),
      njs_str("true") },

    { njs_str("delete $r.consts"),
      njs_str("true") },

    { njs_str("$r3.consts.k"),
      njs_str("kval") },

    { njs_str("$r3.consts.k = 1"),
      njs_str("TypeError: Cannot assign to read-only property \"k\" of object") },

    { njs_str("delete $r3.consts.k"),
      njs_str("TypeError: Cannot delete property \"k\" of object") },

    { njs_str("delete $r3.vars.p; $r3.vars.p"),
      njs_str("undefined") },

    { njs_str("var a = $r.host; a +' '+ a.length +' '+ a"),
      njs_str("АБВГДЕЁЖЗИЙ 11 АБВГДЕЁЖЗИЙ") },

    { njs_str("var a = $r.host; a.substr(1, 1)"),
      njs_str("Б") },

    { njs_str("var a = $r.header['User-Agent']; a +' '+ a.length +' '+ a"),
      njs_str("User-Agent|АБВ 14 User-Agent|АБВ") },

    { njs_str("var a='', p;"
                 "for (p in $r.header) { a += p +':'+ $r.header[p] +',' }"
                 "a"),
      njs_str("01:01|АБВ,02:02|АБВ,03:03|АБВ,") },

    { njs_str("$r.method('YES')"),
      njs_str("АБВ") },

    { njs_str("$r.create('XXX').uri"),
      njs_str("XXX") },

    { njs_str("$r.create.call([], 'XXX')"),
      njs_str("TypeError: \"this\" is not an external") },

    { njs_str("var sr = $r.create('XXX'); sr.uri = 'YYY'; sr.uri"),
      njs_str("YYY") },

    { njs_str("var sr = $r.create('XXX'), sr2 = $r.create('YYY');"
                 "sr.uri = 'ZZZ'; "
                 "sr.uri + sr2.uri"),
      njs_str("ZZZYYY") },

    { njs_str("var sr = $r.create('XXX'); sr.vars.p = 'a'; sr.vars.p"),
      njs_str("a") },

    { njs_str("var r = new ExternalConstructor('XXX'); r.uri"),
      njs_str("XXX") },

    { njs_str("var p; for (p in $r.method);"),
      njs_str("undefined") },

    { njs_str("'uri' in $r"),
      njs_str("true") },

    { njs_str("'one' in $r"),
      njs_str("false") },

    { njs_str("'a' in $r.props"),
      njs_str("true") },

    { njs_str("delete $r.uri"),
      njs_str("TypeError: Cannot delete property \"uri\" of object") },

    { njs_str("delete $shared.uri"),
      njs_str("TypeError: Cannot delete property \"uri\" of object") },

    { njs_str("delete $r.one"),
      njs_str("true") },

    { njs_str("delete $r.vars"),
      njs_str("TypeError: Cannot delete property \"vars\" of object") },

    { njs_str("delete $r.header; $r.header"),
      njs_str("undefined") },

    { njs_str("$r.header = 1; $r.header"),
      njs_str("1") },

    { njs_str("$r.method.call($r, 'YES')"),
      njs_str("АБВ") },

    { njs_str("var f = $r.method.bind($r); f('YES')"),
      njs_str("АБВ") },

    { njs_str("function f(fn, arg) {return fn(arg);}; f($r.method.bind($r), 'YES')"),
      njs_str("АБВ") },

    { njs_str("$r.method.apply($r, ['YES'])"),
      njs_str("АБВ") },

    { njs_str("$shared.method.apply($r, ['YES'])"),
      njs_str("АБВ") },

    { njs_str("$r.method.call([], 'YES')"),
      njs_str("TypeError: \"this\" is not an external") },

    { njs_str("$r.nonexistent"),
      njs_str("undefined") },

    { njs_str("$shared.nonexistent"),
      njs_str("undefined") },

    { njs_str("njs.dump($r).startsWith('External')"),
      njs_str("true") },

    { njs_str("Object.keys($r.header)"),
      njs_str("01,02,03") },

    { njs_str("Object.values($r.header)"),
      njs_str("01|АБВ,02|АБВ,03|АБВ") },

    { njs_str("njs.dump(Object.entries($r.header))"),
      njs_str("[['01','01|АБВ'],['02','02|АБВ'],['03','03|АБВ']]") },

    { njs_str("njs.dump($r.header)"),
      njs_str("Header {01:'01|АБВ',02:'02|АБВ',03:'03|АБВ'}") },

    { njs_str("njs.dump($r.header2)"),
      njs_str("Header2 {01:'01|АБВ',02:'02|АБВ',03:'03|АБВ'}") },

    { njs_str("var o = {b:$r.props.b}; o.b"),
      njs_str("42") },

    { njs_str("$r2.uri == 'αβγ' && $r2.uri === 'αβγ'"),
      njs_str("true") },

#if (NJS_HAVE_OPENSSL)
#define NCRYPTO "crypto,"
#else
#define NCRYPTO ""
#endif

    { njs_str("Object.keys(this).sort()"),
      njs_str("$262,$r,$r2,$r3,$shared,ExternalConstructor,ExternalError,"
              "ExternalNull," NCRYPTO "global,njs,process") },

    { njs_str("Object.getOwnPropertySymbols($r2)[0] == Symbol.toStringTag"),
      njs_str("true") },

    { njs_str("Object.getOwnPropertyDescriptors($r2)[Symbol.toStringTag].value"),
      njs_str("External") },

    { njs_str("Object.getPrototypeOf($r3) === Object.prototype"),
      njs_str("true") },

    { njs_str("Object.isExtensible($r3)"),
      njs_str("true") },

    { njs_str("$r3[0] = 0; $r3[1] = 1; $r3.length = 2;"
              "Array.prototype.join.call($r3, '|')"),
      njs_str("0|1") },

    { njs_str("$r3.toJSON = ()=> 'R3';"
              "JSON.stringify($r3)"),
      njs_str("\"R3\"") },

    { njs_str("$r3[0] = 0; $r3[1] = 1; $r3.length = 2;"
              "$r3.__proto__ = Array.prototype; $r3.join('|')"),
      njs_str("0|1") },

    { njs_str("[this, global, globalThis]"
              ".every(v=> { var r = njs.dump(v); return ['$r', 'global', njs.version].every(v=>r.includes(v))})"),
      njs_str("true") },

    { njs_str("var r = JSON.parse(JSON.stringify($r));"
              "[r.uri, r.host, r.props.a, njs.dump(r.vars), njs.dump(r.consts), r.header['02']]"),
      njs_str("АБВ,АБВГДЕЁЖЗИЙ,1,{},{},02|АБВ") },

    { njs_str("var s = (new TextDecoder()).decode($r.buffer); [s, s.length]"),
      njs_str("АБВГДЕЁЖЗИЙ,11") },

    { njs_str("var b = $r.buffer; "
              "b[4] = '@'.codePointAt(0); b[5] = '#'.codePointAt(0);"
              "var s = (new TextDecoder()).decode(b); [s, s.length]"),
      njs_str("АБ@#ГДЕЁЖЗИЙ,12") },

    { njs_str("var b = $r.buffer; "
              "b.copyWithin(16,0,6);"
              "var s = (new TextDecoder()).decode(b); [s, s.length]"),
      njs_str("АБВГДЕЁЖАБВ,11") },

    { njs_str("var b = $r.buffer; "
              "b.fill('#'.codePointAt(0));"
              "var s = (new TextDecoder()).decode(b); [s, s.length]"),
      njs_str("######################,22") },

    { njs_str("var b = $r.buffer; "
              "b.set(['@'.codePointAt(0), '#'.codePointAt(0)], 4);"
              "var s = (new TextDecoder()).decode(b); [s, s.length]"),
      njs_str("АБ@#ГДЕЁЖЗИЙ,12") },

    { njs_str("var b = $r.buffer; "
              "var u16 = new Uint16Array(b.buffer); u16.reverse();"
              "var s = (new TextDecoder()).decode(u16); [s, s.length]"),
      njs_str("ЙИЗЖЁЕДГВБА,11") },

    { njs_str("new Uint8Array($r.buffer.sort().slice(0,3))"),
      njs_str("129,144,145") },

    { njs_str("$r.buffer instanceof Buffer"),
      njs_str("true") },

    { njs_str("let ctor = Object.getPrototypeOf(async function(){}).constructor;"
              "let f = new ctor();"
              "$r.retval(f())"),
      njs_str("[object Promise]") },

    { njs_str("let ctor = Object.getPrototypeOf(async function(){}).constructor;"
              "let f = new ctor('x', 'await 1; return x');"
              "$r.retval(f(1))"),
      njs_str("[object Promise]") },

    { njs_str("let ctor = Object.getPrototypeOf(async function(){}).constructor;"
              "let f = new ctor('x', 'await 1; return x');"
              "f(1).then($r.retval)"),
      njs_str("1") },

    { njs_str("async function f() {"
              "    function g(v) { return v; }"
              "    return g(await Promise.resolve(1));"
              "}"
              "f().then($r.retval)"),
      njs_str("1") },

    { njs_str("async function f() {"
              "    return ({"
              "        g(v) { return v; }"
              "    }).g(await Promise.resolve(2));"
              "}"
              "f().then($r.retval)"),
      njs_str("2") },

    { njs_str("async function f() {"
              "    function g(a, b) { return a + b; }"
              "    return g(await Promise.resolve(1),"
              "             await Promise.resolve(2));"
              "}"
              "f().then($r.retval)"),
      njs_str("3") },

    { njs_str("async function f() {"
              "    return ({"
              "        k: 10,"
              "        g(a, b) { return this.k + a + b; }"
              "    }).g(await Promise.resolve(1),"
              "         await Promise.resolve(2));"
              "}"
              "f().then($r.retval)"),
      njs_str("13") },

    { njs_str("async function f() {"
              "    function C(v) { this.v = v; }"
              "    return (new C(await Promise.resolve(7))).v;"
              "}"
              "f().then($r.retval)"),
      njs_str("7") },

    { njs_str("async function f() {"
              "    return ({"
              "        g(v) { return v; }"
              "    })?.g(await Promise.resolve(9));"
              "}"
              "f().then($r.retval)"),
      njs_str("9") },

    { njs_str("async function f() {"
              "    return ((...a) => a[1])`${await Promise.resolve(1)}`;"
              "}"
              "f().then($r.retval)"),
      njs_str("1") },

    { njs_str("async function f() {"
              "    return ((...a) => a[1])`${await Promise.resolve(2)}`"
              "           + ':' +"
              "           ((...a) => a[1])`${await Promise.resolve(3)}`;"
              "}"
              "f().then($r.retval)"),
      njs_str("2:3") },

    { njs_str("async function f() {"
              "    return ({"
              "        x: 'X',"
              "        t(...a) { return this.x + ':' + a[1]; }"
              "    }).t`${await Promise.resolve(4)}`;"
              "}"
              "f().then($r.retval)"),
      njs_str("X:4") },

    { njs_str("async function f() {"
              "    return ((...a) => a[1] + ':' + a[2] + ':' + a[0].length)"
              "           `a${await Promise.resolve(2)}b"
              "${await Promise.resolve(3)}c`;"
              "}"
              "f().then($r.retval)"),
      njs_str("2:3:3") },

    { njs_str("async function f() {"
              "    var log = '';"
              "    function p(v) { log += v; return Promise.resolve(v); }"
              "    function t() { log += 'T'; return log; }"
              "    return t`${await p('A')}${await p('B')}`;"
              "}"
              "f().then($r.retval)"),
      njs_str("ABT") },

    { njs_str("$r.retval(Promise.all([async () => [await x('X')]]))"),
      njs_str("[object Promise]") },

    { njs_str("var r = [1].map(v => {"
              "    function C(a) {"
              "        a(a, parseInt);"
              "    };"
              ""
              "    Promise.all.apply(C);"
              "});"
              "r[0]"),
              /* TODO: RejectAbrupt() exception should not percolate */
      njs_str("TypeError: resolve is not callable") },

    { njs_str("Promise.all({length: 1025}) "
              ".then(v => $r.retval(v[0]))"),
              /* TODO: TypeError: object is not iterable */
      njs_str("undefined") },

    { njs_str("Promise.allSettled({length: 1025}) "
              ".then(v => $r.retval(v[0]))"),
              /* TODO: TypeError: object is not iterable */
      njs_str("undefined") },

    { njs_str("var r = [1].map(v => {"
              "    function C(a) {"
              "        a(a, parseInt);"
              "    };"
              ""
              "    Promise.race.apply(C);"
              "});"
              "r[0]"),
              /* TODO: RejectAbrupt() exception should not percolate */
      njs_str("TypeError: resolve is not callable") },

    { njs_str("let obj = { a: 1, b: 2};"
              "function cb(r) { r.retval(obj.a); }"
              "$r.subrequest($r)"
              ".then(reply => cb(reply))"),
      njs_str("1") },

    { njs_str("let obj = { a: 1, b: 2};"
              "function cb(r, select) { r.retval(obj[select]); }"
              "$r.subrequest('b')"
              ".then(select => cb($r, select))"),
      njs_str("2") },

    { njs_str("function pr(x) { return new Promise(resolve => {resolve(x + ':pr')}); };"
              "Promise.all(['a', 'b', 'c'].map(async (v) => {"
              "    return await pr(v + ':async');"
              "}))"
              ".then(v => $r.retval(v))"),
      njs_str("a:async:pr,b:async:pr,c:async:pr") },

    { njs_str("function pr(x) { return new Promise(resolve => {resolve(x + ':pr')}); };"
              "Promise.all(['a', 'b', 'c'].map(async (v) => {"
              "    let r = await pr(v + ':async');"
              "    let r2 = await pr(r + ':async2');"
              "    return r2 + ':r';"
              "}))"
              ".then(v => $r.retval(v))"),
      njs_str("a:async:pr:async2:pr:r,b:async:pr:async2:pr:r,c:async:pr:async2:pr:r") },

    { njs_str("async function f () {"
              "    var p = await Promise.race({length:1});"
              "    for (const v in 'test') { }"
              "};"
              "f().then(v => $r.retval('done'))"),
      njs_str("done") },
};


static njs_unit_test_t  njs_async_handler_test[] =
{
    { njs_str("globalThis.main = (function() {"
              "     function cb(r) { r.retval(1); }"
              "     function handler(r) {"
              "         r.subrequest(r)"
              "         .then(reply => cb(reply))"
              "     };"
              "     return {handler};"
              "})();"
              ),
      njs_str("1") },

    { njs_str("globalThis.main = (function() {"
              "     let obj = { a: 1, b: 2};"
              "     function cb(r) { r.retval(obj.a); }"
              "     function handler(r) {"
              "         r.subrequest(r)"
              "         .then(reply => cb(reply))"
              "     };"
              "     return {handler};"
              "})();"
              ),
      njs_str("1") },
};


static njs_unit_test_t  njs_shared_test[] =
{
    { njs_str("var cr = require('unknown')"),
      njs_str("Error: Cannot load module \"unknown\"\n"
              "    at require (native)\n"
              "    at main (:1)\n") },

    { njs_str("import cr from 'unknown'"),
      njs_str("Error: Cannot load module \"unknown\"") },

#if (NJS_HAVE_OPENSSL)

    { njs_str("var cr = require('crypto'); cr.createHash"),
      njs_str("[object Function]") },

    { njs_str("var cr = require('crypto'); cr.createHash('md5')"),
      njs_str("[object Hash]") },

    { njs_str("import cr from 'crypto'; cr.createHash"),
      njs_str("[object Function]") },

    { njs_str("import cr from 'crypto'; cr.createHash('md5')"),
      njs_str("[object Hash]") },
#endif

    { njs_str("var fs = require('fs'); fs.a = 1; fs.a"),
      njs_str("1") },

    { njs_str("require('fs').promises === require('fs').promises"),
      njs_str("true") },

    { njs_str("isFinite()"),
      njs_str("false") },

    { njs_str("Number.isFinite(function(){})"),
      njs_str("false") },

    { njs_str("isFin()"),
      njs_str("ReferenceError: \"isFin\" is not defined\n"
              "    at main (:1)\n") },

    { njs_str("isNaN(function(){})"),
      njs_str("true") },

    { njs_str("var a = $r.uri; $r.uri = $r2.uri; $r2.uri = a; $r2.uri + $r.uri"),
      njs_str("АБВαβγ") },

    { njs_str("njs.dump($r.props)"),
      njs_str("{a:'1',b:42,c:{d:1024}}") },

    { njs_str("njs.dump($shared.props)"),
      njs_str("{a:'11',b:42,c:{d:13}}") },

    { njs_str("var r = JSON.parse(JSON.stringify($shared));"
              "[r.uri, r.host, r.props.a, njs.dump(r.vars), njs.dump(r.consts), r.header['02']]"),
      njs_str("shared,АБВГДЕЁЖЗИЙ,11,{},{},02|АБВ") },

    { njs_str("$shared.toString()"),
      njs_str("[object External]") },

    { njs_str("$shared.toString().length"),
      njs_str("17") },

    { njs_str("delete $shared.method; $shared.method"),
      njs_str("undefined") },

    { njs_str("$shared.method = () => 1; $shared.method()"),
      njs_str("1") },

    { njs_str("$shared.method = function() {return this.props.a;}; $shared.method()"),
      njs_str("11") },

    { njs_str("var r; for (var i = 0; i < 2**10; i++) {r = $r.create('XXX').uri;}"),
      njs_str("undefined") },

    { njs_str("$r.vars.unset = 'a'; $r2.vars.unset = 'b';"
              "$r.vars.unset + $r2.vars.unset"),
      njs_str("ab") },

    { njs_str("$r.vars.unset = 1; $r2.vars.unset = 2;"
              "$r.vars.unset + $r2.vars.unset"),
      njs_str("3") },

    { njs_str("$r3.vars.p = 'a'; $r3.vars.p2 = 'b';"
              "$r3.vars.p + $r3.vars.p2"),
      njs_str("ab") },

    { njs_str("delete $r3.vars.p; $r3.vars.p"),
      njs_str("undefined") },

    { njs_str("var sr = $r.create('XXX'); sr.vars.p = 'a'; sr.vars.p"),
      njs_str("a") },

    { njs_str("$r.bind('XXX', 37); XXX"),
      njs_str("37") },

    { njs_str("var fs = require('fs'); fs.readFileSync()"),
      njs_str("TypeError: \"path\" must be a string or Buffer\n"
              "    at readFileSync (native)\n"
              "    at main (:1)\n") },

    { njs_str("import fs from 'fs'; fs.readFileSync()"),
      njs_str("TypeError: \"path\" must be a string or Buffer\n"
              "    at readFileSync (native)\n"
              "    at main (:1)\n") },

    { njs_str("var f = new Function('return 1;'); f();"),
      njs_str("1") },

    { njs_str("var sum = new Function('a', 'b', 'return a + b');"
              "sum(2, 4);"),
      njs_str("6") },

    { njs_str("var sum = new Function('a, b', 'return a + b');"
              "sum(2, 4);"),
      njs_str("6") },

    { njs_str("ExternalNull.get()"),
      njs_str("undefined") },

    { njs_str("ExternalNull.set(37); ExternalNull.get()"),
      njs_str("37") },

    { njs_str("ExternalNull.set(23); ExternalNull.set(37); ExternalNull.get()"),
      njs_str("37") },

    { njs_str("var v = Math.round(Math.random() * 1000); ExternalNull.set(v);"
              "ExternalNull.get() == v"),
      njs_str("true") },

#if (NJS_HAVE_OPENSSL)
    { njs_str("var cr = Object.entries(global).filter((v) => v[0] == 'crypto')[0][1];"
              "cr.abc = 1; cr.abc"),
      njs_str("1") },
#endif

    { njs_str("JSON.stringify(preload)"),
      njs_str("{\"a\":[1,{\"b\":2,\"c\":3}]}") },

    { njs_str("preload.a.prop = 1"),
      njs_str("TypeError: Cannot add property \"prop\", object is not extensible\n"
              "    at main (:1)\n") },

    { njs_str("preload.a[0] = 2"),
      njs_str("TypeError: Cannot assign to read-only property \"0\" of array\n"
              "    at main (:1)\n") },

    { njs_str("preload.a.push(2)"),
      njs_str("TypeError: undefined is not a function\n"
              "    at main (:1)\n") },

    { njs_str("Array.prototype.push.call(preload.a, 'waka')"),
      njs_str("TypeError: Cannot add property \"2\", object is not extensible\n"
              "    at push (native)\n"
              "    at call (native)\n"
              "    at main (:1)\n") },
};


static njs_unit_test_t  njs_tz_test[] =
{
     { njs_str("var d = new Date(1); d = d + ''; d.slice(0, 33)"),
       njs_str("Thu Jan 01 1970 12:45:00 GMT+1245") },

     { njs_str("var d = new Date(2011, 5, 24, 18, 45); d.getTime()"),
       njs_str("1308895200000") },

     { njs_str("var d = new Date(2011, 5, 24, 18, 45); d.valueOf()"),
       njs_str("1308895200000") },

     { njs_str("var d = new Date(2011, 5, 24, 18, 45);"
                  "d.toString().slice(0, 33)"),
       njs_str("Fri Jun 24 2011 18:45:00 GMT+1245") },

     { njs_str("var d = new Date(2011, 5, 24, 18, 45);"
                  "d.toTimeString().slice(0, 17)"),
       njs_str("18:45:00 GMT+1245") },

     { njs_str("var d = new Date(2011, 5, 24, 18, 45); d.toUTCString()"),
       njs_str("Fri, 24 Jun 2011 06:00:00 GMT") },

     { njs_str("var d = new Date(2011, 5, 24, 18, 45, 12, 625);"
                  "d.toISOString()"),
       njs_str("2011-06-24T06:00:12.625Z") },

     { njs_str("var d = new Date(2011, 5, 24, 18, 45); d.getUTCHours()"),
       njs_str("6") },

     { njs_str("var d = new Date(2011, 5, 24, 18, 45); d.getUTCMinutes()"),
       njs_str("0") },

     { njs_str("var d = new Date(2011, 5, 24, 18, 45, 12, 625);"
                  "d.getTimezoneOffset()"),
       njs_str("-765") },

     { njs_str("var d = new Date(1308895323625); d.setMinutes(3, 2, 5003);"
                  "d.getTime()"),
       njs_str("1308892687003") },

     { njs_str("var d = new Date(1308895323625); d.setMinutes(3, 2);"
                  "d.getTime()"),
       njs_str("1308892682625") },

     { njs_str("var d = new Date(1308895323625); d.setMinutes(3);"
                  "d.getTime()"),
       njs_str("1308892683625") },

     { njs_str("var d = new Date(1308895323625); d.setHours(20, 3, 2, 5003);"
                  "d.getTime()"),
       njs_str("1308899887003") },

     { njs_str("var d = new Date(1308895323625); d.setHours(20, 3, 2);"
                  "d.getTime()"),
       njs_str("1308899882625") },

     { njs_str("var d = new Date(1308895323625); d.setHours(20, 3);"
                  "d.getTime()"),
       njs_str("1308899883625") },

     { njs_str("var d = new Date(1308895323625); d.setHours(20);"
                  "d.getTime()"),
       njs_str("1308902523625") },

     { njs_str("var d = new Date(NaN); d.setHours(20);"
                  "d.getTime()"),
       njs_str("NaN") },

     { njs_str("var d = new Date(1308895323625); d.setMonth(2, 10);"
                  "d.getTime()"),
       njs_str("1299733323625") },

     { njs_str("var d = new Date(1308895323625); d.setMonth(2);"
                  "d.getTime()"),
       njs_str("1300942923625") },

     { njs_str("var d = new Date(1308895323625); d.setFullYear(2010, 2, 10);"
                  "d.getTime()"),
       njs_str("1268197323625") },

     { njs_str("var d = new Date(1308895323625); d.setFullYear(2010, 2);"
                  "d.getTime()"),
       njs_str("1269406923625") },

     { njs_str("var d = new Date(2011, 5, 24, 18, 45, 12, 625);"
                  "d.toJSON(1)"),
       njs_str("2011-06-24T06:00:12.625Z") },

     { njs_str("Date.parse('1970-09-28T06:00:00.000')"),
       njs_str("23303700000") },

#if (NJS_TIME_T_SIZE == 8)

     { njs_str("var d = new Date(-1, 0);"
                  "d.toISOString()"),
       njs_str("-000002-12-31T11:47:00.000Z") },

     { njs_str("var d = new Date(-1, 0);"
                  "d.getTime()"),
       njs_str("-62198799180000") },

     { njs_str("var d = new Date(-1, 0);"
                  "d.getTimezoneOffset()"),
       njs_str("-733") },
#endif

     { njs_str("var d = new Date(1970, 6);"
                  "d.getTimezoneOffset()"),
       njs_str("-765") },
};


static njs_unit_test_t  njs_regexp_optional_tests[] =
{
    { njs_str("/[\\\\u02E0-\\\\u02E4]/"),
      njs_str("/[\\\\u02E0-\\\\u02E4]/") },

    { njs_str("/[\\u02E0-\\u02E4]/"),
      njs_str("/[\\u02E0-\\u02E4]/") },

    { njs_str("RegExp('[\\\\u02E0-\\\\u02E4]')"),
      njs_str("/[\\u02E0-\\u02E4]/") },

    { njs_str("/[\\u0430-\\u044f]+/.test('тест')"),
      njs_str("true") },

    { njs_str("RegExp('[\\\\u0430-\\\\u044f]+').test('тест')"),
      njs_str("true") },

    { njs_str("RegExp('[\\\\u0430-\\\\u044f]+').exec('тест')[0]"),
      njs_str("тест") },

    { njs_str("/[\\uFDE0-\\uFFFD]/g; export default 1"),
      njs_str("SyntaxError: Illegal export statement") },

    { njs_str("RegExp(RegExp('\x00]]')).test('\x00]]')"),
      njs_str("true") },

    { njs_str("RegExp('\0').test('\0')"),
      njs_str("true") },

    { njs_str("RegExp('\x00').test('\0')"),
      njs_str("true") },

#ifndef NJS_HAVE_PCRE2
    { njs_str("RegExp('\x00\\\\x00').source"),
      njs_str("\\u0000\\x00") },

    { njs_str("/\\\0/"),
      njs_str("/\\\\u0000/") },

    { njs_str("RegExp('\\\\\\0').source"),
      njs_str("\\\\u0000") },
#endif

    { njs_str("RegExp('[\0]').test('\0')"),
      njs_str("true") },

    { njs_str("/[A-Za-z\\u00F8-\\u02FF]/.test('S')"),
      njs_str("true") },

    { njs_str("/[A-Za-z\\u00F8-\\u02FF]/.test('ø')"),
      njs_str("true") },

};


static njs_unit_test_t  njs_shell_test[] =
{
#define ENTER "\n\3"

    { njs_str("var a = 3" ENTER
              "a * 2" ENTER),
      njs_str("6") },

    { njs_str("var a = \"aa\\naa\"" ENTER
              "a" ENTER),
      njs_str("'aa\\naa'") },

    { njs_str("var a = 3" ENTER
              "var a = 'str'" ENTER
              "a" ENTER),
      njs_str("'str'") },

    { njs_str("var a = 2" ENTER
              "a *= 2" ENTER
              "a *= 2" ENTER
              "a *= 2" ENTER),
      njs_str("16") },

    { njs_str("var a = 2" ENTER
              "var b = 3" ENTER
              "a * b" ENTER),
      njs_str("6") },

    { njs_str("var a = 2; var b = 3;" ENTER
              "a * b" ENTER),
      njs_str("6") },

    { njs_str("function sq(f) { return f() * f() }" ENTER
               "sq(function () { return 3 })" ENTER),
      njs_str("9") },

    { njs_str("var e = Error(); e.name = {}; e" ENTER),
      njs_str("[object Object]\n    at main (:1)\n") },

    { njs_str("var a = []; Object.defineProperty(a, 'b', {enumerable: true, get: Object}); a" ENTER),
      njs_str("[\n b: '[Getter]'\n]") },

    { njs_str("var e = Error()" ENTER
              "Object.defineProperty(e, 'message', { configurable: true, set: Object })" ENTER
              "delete e.message; e" ENTER),
      njs_str("Error\n    at main (:1)\n") },

    { njs_str("var e = Error()" ENTER
              "Object.defineProperty(e, 'message', { configurable: true, get(){ return 'foo'} })" ENTER
              "e" ENTER),
      njs_str("Error: foo\n    at main (:1)\n") },

    { njs_str("function f() {};" ENTER
              "Object.defineProperty(f, 'name', { get() {void(0)} })" ENTER
              "f" ENTER),
      njs_str("[Function]") },

    /* Temporary indexes */

    { njs_str("var a = [1,2,3], i; for (i in a) {Object.seal({});}" ENTER),
      njs_str("undefined") },

    { njs_str("var i; for (i in [1,2,3]) {Object.seal({});}" ENTER),
      njs_str("undefined") },

    { njs_str("var a = 'A'; "
              "switch (a) {"
              "case 0: a += '0';"
              "case 1: a += '1';"
              "}; a" ENTER),
      njs_str("'A'") },

    { njs_str("var a = 0; try { a = 5 }"
              "catch (e) { a = 9 } finally { a++ } a" ENTER),
      njs_str("6") },

    { njs_str("/abc/i.test('ABC')" ENTER),
      njs_str("true") },

    /* Interactive mode. */

    { njs_str("var a = 1" ENTER
              "a" ENTER),
      njs_str("1") },

    { njs_str("Number.prototype.test = 'test'" ENTER
              "Number.prototype.test" ENTER),
      njs_str("'test'") },

    { njs_str("function f(a) {return a}" ENTER
              "function f(a) {return a}; f(2)" ENTER),
      njs_str("2") },

    { njs_str("function f() {return 1}" ENTER
              "function f(a) {return 1}; f(2)" ENTER),
      njs_str("1") },

    { njs_str("try {(new Function('function foo(){return 1}; ()=>{}breakhere'))} catch (e) {}" ENTER
              "foo()" ENTER),
      njs_str("ReferenceError: \"foo\" is not defined\n"
              "    at main (:1)\n") },

    /* Error handling */

    { njs_str("var a = ;" ENTER
              "2 + 2" ENTER),
      njs_str("4") },

    { njs_str("function f() { return b;" ENTER),
      njs_str("SyntaxError: Unexpected end of input") },

    { njs_str("function f() { return b;" ENTER
               "2 + 2" ENTER),
      njs_str("4") },

    { njs_str("function f() { return function() { return 1" ENTER
              "2 + 2" ENTER),
      njs_str("4") },

    { njs_str("function f() { return b;}" ENTER
              "2 + 2" ENTER),
      njs_str("4") },

    { njs_str("function f(o) { return o.a.a;}; f{{}}" ENTER
              "2 + 2" ENTER),
      njs_str("4") },

    { njs_str("function ff(o) {return o.a.a}" ENTER
              "function f(o) {try {return ff(o)} "
              "               finally {return 1}}" ENTER
              "f({})" ENTER),
      njs_str("1") },

    { njs_str("arguments" ENTER
              "function(){}()" ENTER),
      njs_str("SyntaxError: Unexpected token \"(\"") },

    { njs_str("var o = { toString: function() { return [1] } }; o" ENTER),
      njs_str("{\n toString: [Function: toString]\n}") },

    { njs_str("var o = { toString: function() { return [1] } }" ENTER
              "o.toString()" ENTER),
      njs_str("[\n 1\n]") },
};


static njs_unit_test_t  njs_backtraces_test[] =
{
    { njs_str("var e = new Error(); e[0] = 1"),
      njs_str("1") },

    { njs_str("function ff(o) {return o.a.a};"
              "function f(o) {return ff(o)};"
              "f({})"),
      njs_str("TypeError: cannot get property \"a\" of undefined\n"
              "    at ff (:1)\n"
              "    at f (:1)\n"
              "    at main (:1)\n") },

    { njs_str("function ff(o) {return o.a.a};"
              "function f(o) {try {return ff(o)} "
              "               finally {return o.a.a}};"
              "f({})"),
      njs_str("TypeError: cannot get property \"a\" of undefined\n"
              "    at f (:1)\n"
              "    at main (:1)\n") },

    { njs_str("function f(ff, o) {return ff(o)};"
              "f(function (o) {return o.a.a}, {})"),
      njs_str("TypeError: cannot get property \"a\" of undefined\n"
              "    at <anonymous> (:1)\n"
              "    at f (:1)\n"
              "    at main (:1)\n") },

    { njs_str("'str'.replace(/t/g,"
              "              function(m) {return m.a.a})"),
      njs_str("TypeError: cannot get property \"a\" of undefined\n"
              "    at <anonymous> (:1)\n"
              "    at [Symbol.replace] (native)\n"
              "    at replace (native)\n"
              "    at main (:1)\n") },

    { njs_str("function f(o) {return Object.keys(o)};"
              "f()"),
      njs_str("TypeError: cannot convert undefined argument to object\n"
              "    at keys (native)\n"
              "    at f (:1)\n"
              "    at main (:1)\n") },

    { njs_str("[].concat({}.a.a)"),
      njs_str("TypeError: cannot get property \"a\" of undefined\n"
              "    at main (:1)\n") },

    { njs_str("''.repeat(-1)"),
      njs_str("RangeError: invalid count value\n"
              "    at repeat (native)\n"
              "    at main (:1)\n") },

    { njs_str("Math.log({}.a.a)"),
      njs_str("TypeError: cannot get property \"a\" of undefined\n"
              "    at main (:1)\n") },

    { njs_str("var bound = Math.max.bind(null, {toString(){return {}}}); bound(1)"),
      njs_str("TypeError: Cannot convert object to primitive value\n"
              "    at max (native)\n"
              "    at main (:1)\n") },

    { njs_str("var ab = new ArrayBuffer(1);"
              "$262.detachArrayBuffer(ab);"
              "ab.slice(0)"),
      njs_str("TypeError: detached buffer\n"
              "    at slice (native)\n"
              "    at main (:1)\n") },

    { njs_str("Object.prototype()"),
      njs_str("TypeError: object is not a function\n"
               "    at main (:1)\n") },

    { njs_str("eval()"),
      njs_str("InternalError: Not implemented\n"
              "    at eval (native)\n"
              "    at main (:1)\n") },

    { njs_str("$shared.method({}.a.a)"),
      njs_str("TypeError: cannot get property \"a\" of undefined\n"
              "    at main (:1)\n") },

    { njs_str("new Function(\n\n@)"),
      njs_str("SyntaxError: Unexpected token \"@\"") },

    { njs_str("require()"),
      njs_str("TypeError: missing path\n"
              "    at require (native)\n"
              "    at main (:1)\n") },

#if (NJS_HAVE_OPENSSL)
    { njs_str("require('crypto').createHash('sha')"),
      njs_str("TypeError: not supported algorithm: \"sha\"\n"
              "    at createHash (native)\n"
              "    at main (:1)\n") },

    { njs_str("var h = require('crypto').createHash('sha1');"
              "h.update([])"),
      njs_str("TypeError: data is not a string or Buffer-like object\n"
              "    at update (native)\n"
              "    at main (:1)\n") },

    { njs_str("require('crypto').createHmac('sha1', [])"),
      njs_str("TypeError: key is not a string or Buffer-like object\n"
              "    at createHmac (native)\n"
              "    at main (:1)\n") },

    { njs_str("var h = require('crypto').createHmac('sha1', 'secret');"
              "h.update([])"),
      njs_str("TypeError: data is not a string or Buffer-like object\n"
              "    at update (native)\n"
              "    at main (:1)\n") },
#endif

    { njs_str("function f(o) {function f_in(o) {return o.a.a};"
              "               return f_in(o)};"
              "f({})"),
      njs_str("TypeError: cannot get property \"a\" of undefined\n"
              "    at f_in (:1)\n"
              "    at f (:1)\n"
              "    at main (:1)\n") },

    { njs_str("function f(o) {var ff = function (o) {return o.a.a};"
              "               return ff(o)};"
              "f({})"),
      njs_str("TypeError: cannot get property \"a\" of undefined\n"
              "    at <anonymous> (:1)\n"
              "    at f (:1)\n"
              "    at main (:1)\n") },

    { njs_str("var fs = require('fs');"
              "["
              " 'access',"
              " 'accessSync',"
              " 'readFile',"
              " 'readFileSync',"
              " 'writeFile',"
              " 'writeFileSync',"
              " 'appendFile',"
              " 'appendFileSync',"
              " 'symlink',"
              " 'symlinkSync',"
              " 'unlink',"
              " 'unlinkSync',"
              " 'realpath',"
              " 'realpathSync',"
              "]"
              ".every(v=>{ try {fs[v]();} catch (e) { return e.stack.search(`at ${v} `) >= 0}})"),
      njs_str("true") },

    { njs_str("parseInt({ toString: function() { return [1] } })"),
      njs_str("TypeError: Cannot convert object to primitive value\n"
              "    at parseInt (native)\n"
              "    at main (:1)\n") },

    { njs_str("function f(n) { if (n == 0) { throw 'a'; } return f(n-1); }; f(2)"),
      njs_str("a") },

    { njs_str("Object.defineProperty(Function.__proto__, 'name', {get() { typeof 1;}});"
              "(new Uint8Array()).every()"),
      njs_str("TypeError: callback argument is not callable\n"
              "    at every (native)\n"
              "    at main (:1)\n") },

    { njs_str("var p = new Promise((_, reject) => { reject(new Error('oops'));});"
              "p.catch((e) => { $r.retval(e.stack) });"),
      njs_str("Error: oops\n"
              "    at <anonymous> (:1)\n"
              "    at Promise (native)\n"
              "    at main (:1)\n") },

    { njs_str("var e = new Error('oops'); e.stack = 123; e.stack"),
      njs_str("123") },

    { njs_str("function fa () {Function('aa','bb cc')};"
              "function fb () {fa()}"
              "fb()"),
      njs_str("SyntaxError: Unexpected token \"cc\"\n"
              "    at Function (native)\n"
              "    at fa (:1)\n"
              "    at fb (:1)\n"
              "    at main (:1)\n") },

    /* line numbers */

    { njs_str("/**/(function(){throw Error();})()"),
      njs_str("Error\n"
              "    at <anonymous> (:1)\n"
              "    at main (:1)\n") },

    { njs_str("/***/(function(){throw Error();})()"),
      njs_str("Error\n"
              "    at <anonymous> (:1)\n"
              "    at main (:1)\n") },

    { njs_str("/*\n**/(function(){throw Error();})()"),
      njs_str("Error\n"
              "    at <anonymous> (:2)\n"
              "    at main (:2)\n") },

    { njs_str("({})\n.a\n.a"),
      njs_str("TypeError: cannot get property \"a\" of undefined\n"
              "    at main (:3)\n") },

    { njs_str("1\n+a"),
      njs_str("ReferenceError: \"a\" is not defined\n"
              "    at main (:2)\n") },

    { njs_str("\n`\n${Object}\n${a}`"),
      njs_str("ReferenceError: \"a\" is not defined\n"
              "    at main (:4)\n") },

    { njs_str("function log(v) {}\nlog({}\n.a\n.a)"),
      njs_str("TypeError: cannot get property \"a\" of undefined\n"
              "    at main (:2)\n") },

    { njs_str("\nfor (var i = 0;\n i < a;\n i++) { }\n"),
      njs_str("ReferenceError: \"a\" is not defined\n"
              "    at main (:3)\n") },

    { njs_str("\nfor (var i = 0;\n i < 5;\n a) {\n }"),
      njs_str("ReferenceError: \"a\" is not defined\n"
              "    at main (:4)\n") },

    { njs_str("Math\n.min(1,\na)"),
      njs_str("ReferenceError: \"a\" is not defined\n"
              "    at main (:3)\n") },
};


typedef struct {
    njs_bool_t  disassemble;
    njs_str_t   filter;
    njs_bool_t  verbose;

    njs_uint_t  externals;
    njs_bool_t  module;
    njs_uint_t  repeat;
    njs_bool_t  unsafe;
    njs_bool_t  backtrace;
    njs_bool_t  handler;
    njs_bool_t  async;
    njs_bool_t  preload;
    unsigned    seed;
} njs_opts_t;


typedef struct {
    njs_uint_t  passed;
    njs_uint_t  failed;
} njs_stat_t;


typedef struct {
    njs_vm_t            *vm;
    njs_opaque_value_t  retval;

    njs_external_env_t  *env;
    njs_external_env_t  env0;

    enum {
        sw_start = 0,
        sw_handler,
        sw_loop,
        sw_done
    }                   state;
} njs_external_state_t;


typedef struct {
    njs_external_state_t  *states;
    njs_uint_t            size;
    njs_uint_t            current;
} njs_runtime_t;


static void
njs_unit_test_report(njs_str_t *name, njs_stat_t *prev, njs_stat_t *current)
{
    njs_stat_t  stat;

    stat.failed = current->failed - prev->failed;
    stat.passed = current->passed - prev->passed;

    njs_printf("%V tests: %s [%d/%d]\n", name,
               stat.failed ? "FAILED" : "PASSED", stat.passed,
               stat.passed + stat.failed);
}


static njs_int_t
njs_external_state_init(njs_vm_t *vm, njs_external_state_t *s, njs_opts_t *opts)
{
    njs_int_t  ret;

    if (opts->externals) {
        s->env = &s->env0;

        ret = njs_external_env_init(s->env);
        if (ret != NJS_OK) {
            njs_stderror("njs_external_env_init() failed\n");
            return NJS_ERROR;
        }

    } else {
        s->env = NULL;
    }

    s->vm = njs_vm_clone(vm, s->env);
    if (s->vm == NULL) {
        njs_stderror("njs_vm_clone() failed\n");
        return NJS_ERROR;
    }

    if (opts->externals) {
        ret = njs_externals_init(s->vm);
        if (ret != NJS_OK) {
            njs_stderror("njs_externals_init() failed\n");
            return NJS_ERROR;
        }
    }

    s->state = sw_start;

    return NJS_OK;
}


static njs_int_t
njs_external_retval(njs_external_state_t *state, njs_int_t ret, njs_str_t *s)
{
    if (state->env != NULL
        && ret == NJS_OK
        && njs_value_is_valid(njs_value_arg(&state->env->retval)))
    {
        return njs_vm_value_string(state->vm, s,
                                   njs_value_arg(&state->env->retval));
    }

    return njs_vm_value_string(state->vm, s, njs_value_arg(&state->retval));
}


static njs_runtime_t *
njs_runtime_init(njs_vm_t *vm, njs_opts_t *opts)
{
    njs_int_t      ret;
    njs_uint_t     i;
    njs_runtime_t  *rt;

    rt = njs_mp_alloc(njs_vm_memory_pool(vm), sizeof(njs_runtime_t));
    if (rt == NULL) {
        return NULL;
    }

    rt->size = opts->repeat;
    rt->states = njs_mp_alloc(njs_vm_memory_pool(vm),
                              sizeof(njs_external_state_t) * rt->size);
    if (rt->states == NULL) {
        return NULL;
    }

    rt->current = 0;
    srandom(opts->seed);

    for (i = 0; i < rt->size; i++) {
        ret = njs_external_state_init(vm, &rt->states[i], opts);
        if (ret != NJS_OK) {
            njs_stderror("njs_external_state_init() failed\n");
            return NULL;
        }
    }

    return rt;
}


static njs_external_state_t *
njs_runtime_next_state(njs_runtime_t *rt, njs_opts_t *opts)
{
    unsigned  next, n;

    n = 0;
    next = ((opts->async) ? (unsigned) random() : rt->current++) % rt->size;

    while (rt->states[next].state == sw_done) {
        next++;
        next = next % rt->size;

        n++;

        if (n == rt->size) {
            return NULL;
        }
    }

    return &rt->states[next];
}


static void
njs_runtime_destroy(njs_runtime_t *rt)
{
    njs_uint_t  i;

    for (i = 0; i < rt->size; i++) {
        if (rt->states[i].vm != NULL) {
            njs_vm_destroy(rt->states[i].vm);
        }
    }
}


static njs_mod_t *
njs_unit_test_module_loader(njs_vm_t *vm, njs_external_ptr_t external,
    njs_str_t *name)
{
    njs_vm_error(vm, "Cannot load module \"%V\"", name);

    return NULL;
}


static njs_int_t
njs_process_test(njs_external_state_t *state, njs_opts_t *opts,
    njs_unit_test_t *expected)
{
    njs_int_t           ret;
    njs_str_t           s;
    njs_bool_t          success;
    njs_opaque_value_t  request;

    static const njs_str_t  handler_str = njs_str("main.handler");
    static const njs_str_t  request_str = njs_str("$r");

    ret = NJS_OK;

    switch (state->state) {
    case sw_start:
        state->state = sw_handler;

        ret = njs_vm_start(state->vm, njs_value_arg(&state->retval));
        if (ret != NJS_OK) {
            goto done;
        }

        if (opts->async) {
            return NJS_OK;
        }

        /* Fall through. */
    case sw_handler:
        state->state = sw_loop;

        if (opts->handler) {
            ret = njs_vm_value(state->vm, &request_str,
                               njs_value_arg(&request));
            if (ret != NJS_OK) {
                njs_stderror("njs_vm_value(\"%V\") failed\n", &request_str);
                return NJS_ERROR;
            }

            ret = njs_external_call(state->vm, &handler_str,
                                    njs_value_arg(&request), 1);
            if (ret == NJS_ERROR) {
                goto done;
            }

            if (opts->async) {
                return NJS_OK;
            }
        }

        /* Fall through. */
    case sw_loop:
    default:
        for ( ;; ) {
            for ( ;; ) {
                ret = njs_vm_execute_pending_job(state->vm);
                if (ret <= NJS_OK) {
                    if (ret == NJS_ERROR) {
                        return NJS_ERROR;
                    }

                    break;
                }
            }

            ret = njs_external_process_events(state->vm, state->env);
            if (ret == NJS_ERROR) {
                njs_stderror("njs_external_process_events() failed\n");
                return NJS_ERROR;
            }

            if (ret == NJS_OK) {
                break;
            }

            if (opts->async) {
                return NJS_OK;
            }
        }
    }

done:

    state->state = sw_done;

    if (njs_external_retval(state, ret, &s) != NJS_OK) {
        njs_stderror("njs_external_retval() failed\n");
        return NJS_ERROR;
    }

    success = njs_strstr_starts_with(&s, &expected->ret);
    if (!success) {
        njs_stderror("njs(\"%V\")\nexpected: \"%V\"\n     got: \"%V\"\n",
                     &expected->script, &expected->ret, &s);

        return NJS_DECLINED;
    }

    njs_vm_destroy(state->vm);
    state->vm = NULL;

    return NJS_OK;
}


njs_module_t *njs_unit_test_addon_modules[] = {
    &njs_unit_test_262_module,
    NULL,
};


njs_module_t *njs_unit_test_addon_external_modules[] = {
    &njs_unit_test_262_module,
    &njs_unit_test_external_module,
    NULL,
};


static njs_int_t
njs_unit_test(njs_unit_test_t tests[], size_t num, njs_str_t *name,
    njs_opts_t *opts, njs_stat_t *stat)
{
    u_char                *start, *end;
    njs_vm_t              *vm;
    njs_int_t             ret;
    njs_str_t             s;
    njs_bool_t            success;
    njs_uint_t            i;
    njs_stat_t            prev;
    njs_vm_opt_t          options;
    njs_runtime_t         *rt;
    njs_opaque_value_t    retval;
    njs_external_state_t  *state;

    njs_str_t preload = njs_str(
        "globalThis.preload = JSON.parse("
            "'{\"a\": [1, {\"b\": 2, \"c\": 3}]}',"
            "function (k, v) {"
                "if (v instanceof Object) {"
                    "Object.freeze(Object.setPrototypeOf(v, null));"
                "}"
                "return v;"
            "}"
        ");"
    );

    vm = NULL;
    rt = NULL;

    prev = *stat;

    ret = NJS_ERROR;

    for (i = 0; i < num; i++) {

        if (opts->verbose) {
            njs_printf("\"%V\"\n", &tests[i].script);
        }

        njs_vm_opt_init(&options);

        options.init = opts->preload;
        options.module = opts->module;
        options.unsafe = opts->unsafe;
        options.backtrace = opts->backtrace;
        options.max_stack_size = 64 * 1024;
        options.addons = opts->externals ? njs_unit_test_addon_external_modules
                                         : njs_unit_test_addon_modules;

        vm = njs_vm_create(&options);
        if (vm == NULL) {
            njs_printf("njs_vm_create() failed\n");
            goto done;
        }

        njs_vm_set_module_loader(vm, njs_unit_test_module_loader, NULL);

        if (opts->preload) {
            start = preload.start;
            end = start + preload.length;

            ret = njs_vm_compile(vm, &start, end);
            if (ret != NJS_OK) {
                njs_printf("njs_vm_compile() preload failed\n");
                goto done;
            }

            ret = njs_vm_start(vm, njs_value_arg(&retval));
            if (ret != NJS_OK) {
                njs_printf("njs_vm_start() preload failed\n");
                goto done;
            }

            ret = njs_vm_reuse(vm);
            if (ret != NJS_OK) {
                njs_printf("njs_vm_reuse() failed\n");
                goto done;
            }
        }

        start = tests[i].script.start;
        end = start + tests[i].script.length;

        ret = njs_vm_compile(vm, &start, end);

        if (ret == NJS_OK && start == end) {
            if (opts->disassemble) {
                njs_disassembler(vm);
            }

            rt = njs_runtime_init(vm, opts);
            if (rt == NULL) {
                njs_stderror("njs_runtime_init() failed\n");
                goto done;
            }

            for ( ;; ) {
                state = njs_runtime_next_state(rt, opts);
                if (state == NULL) {
                    break;
                }

                ret = njs_process_test(state, opts, &tests[i]);
                if (ret != NJS_OK) {
                    if (ret == NJS_DECLINED) {
                        break;
                    }

                    njs_stderror("njs_process_test() failed\n");
                    goto done;
                }
            }

            success = (ret == NJS_OK);

            if (rt != NULL) {
                njs_runtime_destroy(rt);
                rt = NULL;
            }

        } else {
            if (ret != NJS_OK) {
                if (njs_vm_exception_string(vm, &s) != NJS_OK) {
                    njs_printf("njs_vm_exception_string() failed\n");
                    goto done;
                }

            } else {
                s = njs_str_value("Error: "
                                  "Extra characters at the end of the script");
            }

            success = njs_strstr_starts_with(&s, &tests[i].ret);
            if (!success) {
                njs_stderror("njs(\"%V\")\nexpected: \"%V\"\n"
                             "     got: \"%V\"\n",
                             &tests[i].script, &tests[i].ret, &s);
            }
        }

        if (success) {
            stat->passed++;

        } else {
            stat->failed++;
        }

        njs_vm_destroy(vm);
        vm = NULL;
    }

    ret = NJS_OK;

done:

    if (rt != NULL) {
        njs_runtime_destroy(rt);
    }

    if (vm != NULL) {
        njs_vm_destroy(vm);
    }

    njs_unit_test_report(name, &prev, stat);

    return ret;
}


static njs_int_t
njs_interactive_test(njs_unit_test_t tests[], size_t num, njs_str_t *name,
    njs_opts_t *opts, njs_stat_t *stat)
{
    u_char              *start, *last, *end;
    njs_vm_t            *vm;
    njs_int_t           ret;
    njs_str_t           s;
    njs_uint_t          i;
    njs_stat_t          prev;
    njs_bool_t          success;
    njs_vm_opt_t        options;
    njs_opaque_value_t  retval;

    vm = NULL;

    prev = *stat;

    ret = NJS_ERROR;

    for (i = 0; i < num; i++) {

        if (opts->verbose) {
            njs_printf("\"%V\"\n", &tests[i].script);
        }

        njs_vm_opt_init(&options);

        options.init = 1;
        options.interactive = 1;
        options.backtrace = 1;
        options.max_stack_size = 64 * 1024;
        options.addons = opts->externals ? njs_unit_test_addon_external_modules
                                         : njs_unit_test_addon_modules;

        vm = njs_vm_create(&options);
        if (vm == NULL) {
            njs_printf("njs_vm_create() failed\n");
            goto done;
        }

        if (opts->externals) {
            ret = njs_externals_init(vm);
            if (ret != NJS_OK) {
                goto done;
            }
        }

        start = tests[i].script.start;
        last = start + tests[i].script.length;
        end = NULL;

        for ( ;; ) {
            start = (end != NULL) ? end + njs_length(ENTER) : start;
            if (start >= last) {
                break;
            }

            end = (u_char *) strstr((char *) start, ENTER);

            ret = njs_vm_compile(vm, &start, end);
            if (ret == NJS_OK) {
                if (opts->disassemble) {
                    njs_disassembler(vm);
                }

                ret = njs_vm_start(vm, njs_value_arg(&retval));
            }
        }

        if (njs_vm_value_dump(vm, &s, njs_value_arg(&retval), 0, 1) != NJS_OK) {
            njs_printf("njs_vm_value_dump() failed\n");
            goto done;
        }

        success = njs_strstr_eq(&tests[i].ret, &s);

        if (!success) {
            njs_printf("njs(\"%V\")\nexpected: \"%V\"\n     got: \"%V\"\n",
                       &tests[i].script, &tests[i].ret, &s);

            stat->failed++;

        } else {
            stat->passed++;
        }

        njs_vm_destroy(vm);
        vm = NULL;
    }

    ret = NJS_OK;

done:

    if (vm != NULL) {
        njs_vm_destroy(vm);
    }

    njs_unit_test_report(name, &prev, stat);

    return ret;
}


static njs_int_t
njs_timezone_optional_test(njs_unit_test_t tests[], size_t num, njs_str_t *name,
    njs_opts_t *opts, njs_stat_t *stat)
{
    size_t     size;
    u_char     buf[16];
    time_t     clock;
    struct tm  tm;
    njs_int_t  ret;

    /*
     * Chatham Islands NZ-CHAT time zone.
     * Standard time: UTC+12:45, Daylight Saving time: UTC+13:45.
     */
    (void) putenv((char *) "TZ=Pacific/Chatham");
    tzset();

    clock = 0;
    localtime_r(&clock, &tm);

    size = strftime((char *) buf, sizeof(buf), "%z", &tm);

    if (memcmp(buf, "+1245", size) == 0) {
        ret = njs_unit_test(tests, num, name, opts, stat);
        if (ret != NJS_OK) {
            return ret;
        }

    } else {
        njs_printf("njs timezone tests skipped, timezone is unavailable\n");
    }

    return NJS_OK;
}


static njs_int_t
njs_regexp_optional_test(njs_unit_test_t tests[], size_t num, njs_str_t *name,
    njs_opts_t *opts, njs_stat_t *stat)
{
    njs_bool_t  safe;

#ifndef NJS_HAVE_PCRE2
    int         erroff;
    pcre        *re1, *re2;
    const char  *errstr;

    /*
     * pcre-8.21 crashes when it compiles unicode escape codes inside
     * square brackets when PCRE_UTF8 option is provided.
     * Catching it in runtime by compiling it without PCRE_UTF8. Normally it
     * should return NULL and "character value in \u.... sequence is too large"
     * error string.
     */
    re1 = pcre_compile("/[\\u0410]/", PCRE_JAVASCRIPT_COMPAT, &errstr, &erroff,
                      NULL);

    if (re1 != NULL) {
        pcre_free(re1);
    }

    /*
     * pcre-7.8 fails to compile unicode escape codes inside square brackets
     * even when PCRE_UTF8 option is provided.
     */
    re2 = pcre_compile("/[\\u0410]/", PCRE_JAVASCRIPT_COMPAT | PCRE_UTF8,
                       &errstr, &erroff, NULL);

    if (re2 != NULL) {
        pcre_free(re2);
    }

    safe = (re1 == NULL && re2 != NULL);

#else

    safe = 1;

#endif

    if (safe) {
        return njs_unit_test(tests, num, name, opts, stat);
    }

    njs_printf("regexp optional tests skipped\n");

    return NJS_OK;
}


static njs_int_t
njs_vm_json_test(njs_unit_test_t unused[], size_t num, njs_str_t *name,
    njs_opts_t *opts, njs_stat_t *stat)
{
    njs_vm_t            *vm;
    njs_int_t           ret;
    njs_str_t           s, *script;
    njs_uint_t          i;
    njs_bool_t          success;
    njs_stat_t          prev;
    njs_vm_opt_t        options;
    njs_opaque_value_t  args[3], retval;

    static const njs_str_t fname = njs_str("replacer");
    static const njs_str_t iname = njs_str("indent");

    static njs_unit_test_t tests[] = {
        { njs_str("'[1, true, \"x\", {\"a\": {}}]'"),
          njs_str("[1,true,\"x\",{\"a\":{}}]") },
        { njs_str("'{\"a\":{\"b\":1}}'"),
          njs_str("{\"a\":{\"b\":1}}") },
        { njs_str("'[[[],{}]]'"),
          njs_str("[[[],{}]]") },
        { njs_str("var indent = 1; '[]'"),
          njs_str("[\n \n]") },
        { njs_str("function replacer(k, v) {return v}; '{\"a\":{\"b\":1}}'"),
          njs_str("{\"a\":{\"b\":1}}") },
        { njs_str("function replacer(k, v) {"
                     "   return (typeof v === 'string') ? undefined : v};"
                     "'{\"a\":1, \"b\":\"x\"}'"),
          njs_str("{\"a\":1}") },
    };

    vm = NULL;

    prev = *stat;

    ret = NJS_ERROR;

    for (i = 0; i < njs_nitems(tests); i++) {

        njs_vm_opt_init(&options);
        options.init = 1;

        vm = njs_vm_create(&options);
        if (vm == NULL) {
            njs_printf("njs_vm_create() failed\n");
            goto done;
        }

        script = &tests[i].script;

        ret = njs_vm_compile(vm, &script->start,
                             script->start + script->length);

        if (ret != NJS_OK) {
            njs_printf("njs_vm_compile() failed\n");
            goto done;
        }

        ret = njs_vm_start(vm, njs_value_arg(&args[0]));
        if (ret != NJS_OK) {
            njs_printf("njs_vm_start() failed\n");
            goto done;
        }

        ret = njs_vm_json_parse(vm, njs_value_arg(args), 1,
                                njs_value_arg(&retval));
        if (ret != NJS_OK) {
            njs_printf("njs_vm_json_parse() failed\n");
            goto done;
        }

        njs_value_assign(&args[0], &retval);
        njs_vm_value(vm, &fname, njs_value_arg(&args[1]));
        njs_vm_value(vm, &iname, njs_value_arg(&args[2]));

        ret = njs_vm_json_stringify(vm, njs_value_arg(args), 3,
                                    njs_value_arg(&retval));
        if (ret != NJS_OK) {
            njs_printf("njs_vm_json_stringify() failed\n");
            goto done;
        }

        if (njs_vm_value_string(vm, &s, njs_value_arg(&retval)) != NJS_OK) {
            njs_printf("njs_vm_value_string() failed\n");
            goto done;
        }

        success = njs_strstr_eq(&tests[i].ret, &s);

        if (!success) {
            njs_printf("njs_vm_json_test(\"%V\")\n"
                       "expected: \"%V\"\n     got: \"%V\"\n", script,
                       &tests[i].ret, &s);

            stat->failed++;

        } else {
            stat->passed++;
        }

        njs_vm_destroy(vm);
        vm = NULL;

    }

    ret = NJS_OK;

done:

    if (ret != NJS_OK) {
        if (njs_vm_exception_string(vm, &s) != NJS_OK) {
            njs_printf("njs_vm_exception_string() failed\n");

        } else {
            njs_printf("%V\n", &s);
        }
    }

    njs_unit_test_report(name, &prev, stat);

    if (vm != NULL) {
        njs_vm_destroy(vm);
    }

    return ret;
}


static njs_int_t
njs_vm_value_test(njs_unit_test_t unused[], size_t num, njs_str_t *name,
    njs_opts_t *opts, njs_stat_t *stat)
{
    njs_vm_t            *vm;
    njs_int_t           ret;
    njs_str_t           s, *script, path;
    njs_uint_t          i;
    njs_bool_t          success;
    njs_stat_t          prev;
    njs_vm_opt_t        options;
    njs_opaque_value_t  retval;

    static struct {
        njs_str_t   script;
        njs_str_t   path;
        njs_str_t   ret;
    } tests[] = {
        {
          .script = njs_str("var o = {a:1}"),
          .path = njs_str("o.a"),
          .ret = njs_str("1"),
        },

        {
          .script = njs_str("var aaaaabbbbbcccccddddd = {e:2}"),
          .path = njs_str("aaaaabbbbbcccccddddd.e"),
          .ret = njs_str("2"),
        },

        {
          .script = njs_str("var o = {a:{b:3}}"),
          .path = njs_str("o.a.b"),
          .ret = njs_str("3"),
        },

        {
          .script = njs_str("var o = 1"),
          .path = njs_str("o.a"),
          .ret = njs_str("undefined"),
        },

        {
          .script = njs_str(""),
          .path = njs_str("o"),
          .ret = njs_str("undefined"),
        },

        {
          .script = njs_str("var o = {'':1}"),
          .path = njs_str("."),
          .ret = njs_str("TypeError: empty path element"),
        },

        {
          .script = njs_str("var o = {'':1}"),
          .path = njs_str("o."),
          .ret = njs_str("TypeError: empty path element"),
        },
        {
          .script = njs_str("var o = {'':1}"),
          .path = njs_str("o.."),
          .ret = njs_str("TypeError: empty path element"),
        },
    };

    vm = NULL;

    prev = *stat;

    ret = NJS_ERROR;

    for (i = 0; i < njs_nitems(tests); i++) {

        njs_vm_opt_init(&options);
        options.init = 1;

        vm = njs_vm_create(&options);
        if (vm == NULL) {
            njs_printf("njs_vm_create() failed\n");
            goto done;
        }

        script = &tests[i].script;

        ret = njs_vm_compile(vm, &script->start,
                             script->start + script->length);

        if (ret != NJS_OK) {
            njs_printf("njs_vm_compile() failed\n");
            goto done;
        }

        ret = njs_vm_start(vm, njs_value_arg(&retval));
        if (ret != NJS_OK) {
            njs_printf("njs_vm_run() failed\n");
            goto done;
        }

        path = tests[i].path;

        path.start = njs_mp_alloc(njs_vm_memory_pool(vm), path.length);
        if (path.start == NULL) {
            njs_printf("njs_mp_alloc() failed\n");
            goto done;
        }

        memcpy(path.start, tests[i].path.start, path.length);

        ret = njs_vm_value(vm, &path, njs_value_arg(&retval));

        if (ret == NJS_OK) {
            if (njs_vm_value_string(vm, &s, njs_value_arg(&retval))
                != NJS_OK)
            {
                njs_printf("njs_vm_value_string() failed\n");
                goto done;
            }

        } else {
            if (njs_vm_exception_string(vm, &s) != NJS_OK) {
                njs_printf("njs_vm_exception_string() failed\n");
                goto done;
            }
        }

        success = njs_strstr_eq(&tests[i].ret, &s);

        if (!success) {
            njs_printf("njs_vm_value_test(\"%V\")\n"
                       "expected: \"%V\"\n     got: \"%V\"\n", script,
                       &tests[i].ret, &s);

            stat->failed++;

        } else {
            stat->passed++;
        }

        njs_vm_destroy(vm);
        vm = NULL;

    }

    ret = NJS_OK;

done:

    if (ret != NJS_OK) {
        if (njs_vm_exception_string(vm, &s) != NJS_OK) {
            njs_printf("njs_vm_exception_string() failed\n");

        } else {
            njs_printf("%V\n", &s);
        }
    }

    njs_unit_test_report(name, &prev, stat);

    if (vm != NULL) {
        njs_vm_destroy(vm);
    }

    return ret;
}


static njs_int_t
njs_vm_object_alloc_test(njs_vm_t *vm, njs_opts_t *opts, njs_stat_t *stat)
{
    njs_int_t           ret;
    njs_opaque_value_t  args[2], obj, num_key, bool_key;

    njs_value_number_set(njs_value_arg(&args[0]), 1);
    njs_value_boolean_set(njs_value_arg(&args[0]), 0);

    (void) njs_vm_value_string_create(vm, njs_value_arg(&num_key),
                                     (u_char *) "num", 3);
    (void) njs_vm_value_string_create(vm, njs_value_arg(&bool_key),
                                     (u_char *) "bool", 4);

    ret = njs_vm_object_alloc(vm, njs_value_arg(&obj), NULL);
    if (ret != NJS_OK) {
        return NJS_ERROR;
    }

    ret = njs_vm_object_alloc(vm, njs_value_arg(&obj), njs_value_arg(&num_key),
                              NULL);
    if (ret == NJS_OK) {
        return NJS_ERROR;
    }

    ret = njs_vm_object_alloc(vm, njs_value_arg(&obj), njs_value_arg(&num_key),
                              njs_value_arg(&args[0]), NULL);
    if (ret != NJS_OK) {
        return NJS_ERROR;
    }

    ret = njs_vm_object_alloc(vm, njs_value_arg(&obj), njs_value_arg(&num_key),
                              njs_value_arg(&args[0]), njs_value_arg(&bool_key),
                              njs_value_arg(&args[1]), NULL);
    if (ret != NJS_OK) {
        stat->failed++;
        return NJS_OK;
    }

    stat->passed++;

    return NJS_OK;
}


static njs_int_t
njs_chb_test(njs_vm_t *vm, njs_opts_t *opts, njs_stat_t *stat)
{
    u_char     *p;
    njs_int_t  ret, i;
    njs_chb_t  chain;
    njs_str_t  string, arg;

    static const njs_str_t  expected = njs_str("arg: \"XYZ\" -5");

    NJS_CHB_MP_INIT(&chain, njs_vm_memory_pool(vm));

    p = njs_chb_reserve(&chain, 513);
    if (p == NULL) {
        ret = NJS_ERROR;
        njs_printf("njs_chb_reserve() failed\n");
        goto done;
    }

    njs_memset(p, 'Z', 256);

    njs_chb_written(&chain, 256);

    for (i = 0; i < 768; i++) {
        njs_chb_append(&chain, "X", 1);
    }

    ret = njs_chb_join(&chain, &string);
    if (ret != NJS_OK) {
        njs_printf("njs_chb_join() failed\n");
        goto done;
    }

    if (string.length != 1024 || njs_chb_size(&chain) != 1024) {
        ret = NJS_ERROR;
        njs_printf("njs_chb_join() corrupts "
                   "string.length:%z njs_chb_size(&chain):%z != 1024\n",
                   string.length, njs_chb_size(&chain));
        goto done;
    }

    for (i = 0; i < 1024; i++) {
        if (string.start[i] != ((i < 256) ? 'Z' : 'X')) {
            ret = NJS_ERROR;
            njs_printf("njs_chb_join() corrupts string[%i]:%c != '%c'\n",
                       i, string.start[i], (i < 256) ? 'Z' : 'X');
            goto done;
        }
    }

    njs_mp_free(njs_vm_memory_pool(vm), string.start);

    for (i = 0; i < 222; i++) {;
        njs_chb_drain(&chain, 3);
    }

    ret = njs_chb_join(&chain, &string);
    if (ret != NJS_OK) {
        njs_printf("njs_chb_join() failed\n");
        goto done;
    }

    if (string.length != 358 || njs_chb_size(&chain) != 358) {
        ret = NJS_ERROR;
        njs_printf("njs_chb_join() corrupts "
                   "string.length:%z njs_chb_size(&chain):%z != 358\n",
                   string.length, njs_chb_size(&chain));
        goto done;
    }

    for (i = 0; i < 358; i++) {
        if (string.start[i] != 'X') {
            ret = NJS_ERROR;
            njs_printf("njs_chb_join() corrupts string[%i]:%c != 'X'\n",
                       i, string.start[i]);
            goto done;
        }
    }

    for (i = 0; i < 512; i++) {
        njs_chb_append(&chain, "ABC", 3);
    }

    for (i = 0; i < 447; i++) {
        njs_chb_drop(&chain, 2);
    }

    ret = njs_chb_join(&chain, &string);
    if (ret != NJS_OK) {
        njs_printf("njs_chb_join() failed\n");
        goto done;
    }

    if (string.length != 1000 || njs_chb_size(&chain) != 1000) {
        ret = NJS_ERROR;
        njs_printf("njs_chb_join() corrupts "
                   "string.length:%z njs_chb_size(&chain):%z != 1000\n",
                   string.length, njs_chb_size(&chain));
        goto done;
    }

    njs_chb_drop(&chain, 500);
    njs_chb_drain(&chain, 501);

    if (njs_chb_size(&chain) != 0) {
        ret = NJS_ERROR;
        njs_printf("njs_chb_drop() corrupts "
                   "njs_chb_size(&chain):%z != 0\n", njs_chb_size(&chain));
        goto done;
    }

    arg = njs_str_value("XYZ");

    njs_chb_sprintf(&chain, 32, "arg: \"%V\" %d", &arg, -5);

    ret = njs_chb_join(&chain, &string);
    if (ret != NJS_OK) {
        njs_printf("njs_chb_join() failed\n");
        goto done;
    }

    if (!njs_strstr_eq(&string, &expected)) {
        ret = NJS_ERROR;
        njs_printf("njs_chb_sprintf() corrupts \"%V\" != \"%V\"\n", &string,
                   &expected);
        goto done;
    }

    njs_chb_destroy(&chain);
    njs_mp_free(njs_vm_memory_pool(vm), string.start);

    /*
     * Overflow: capped chain refuses appends beyond max_size and
     * reports NJS_CHB_ERR_OVERFLOW.
     */
    NJS_CHB_MP_INIT_MAX(&chain, njs_vm_memory_pool(vm), 100);

    njs_chb_append_literal(&chain, "0123456789");

    if (chain.error != NJS_CHB_ERR_NONE || njs_chb_size(&chain) != 10) {
        ret = NJS_ERROR;
        njs_printf("chb cap: pre-overflow state wrong, "
                   "error:%d size:%z\n",
                   (int) chain.error, (size_t) njs_chb_size(&chain));
        goto done;
    }

    for (i = 0; i < 20; i++) {
        njs_chb_append(&chain, "0123456789", 10);
    }

    if (chain.error != NJS_CHB_ERR_OVERFLOW) {
        ret = NJS_ERROR;
        njs_printf("chb cap: expected NJS_CHB_ERR_OVERFLOW, got %d\n",
                   (int) chain.error);
        goto done;
    }

    if (njs_chb_size(&chain) != -1) {
        ret = NJS_ERROR;
        njs_printf("chb cap: size after overflow should be -1, got %z\n",
                   (size_t) njs_chb_size(&chain));
        goto done;
    }

    njs_chb_destroy(&chain);

    /*
     * Full-chain drop preserves max_size.
     */
    NJS_CHB_MP_INIT_MAX(&chain, njs_vm_memory_pool(vm), 20);

    njs_chb_append_literal(&chain, "0123456789");
    njs_chb_drop(&chain, 100);

    if (chain.max_size != 20 || njs_chb_size(&chain) != 0) {
        ret = NJS_ERROR;
        njs_printf("chb drop: full reset lost cap or size, "
                   "max_size:%z size:%z\n",
                   (size_t) chain.max_size, (size_t) njs_chb_size(&chain));
        goto done;
    }

    /* Chain still enforces the cap after the reset. */
    for (i = 0; i < 5; i++) {
        njs_chb_append_literal(&chain, "0123456789");
    }

    if (chain.error != NJS_CHB_ERR_OVERFLOW) {
        ret = NJS_ERROR;
        njs_printf("chb drop: cap not enforced after full reset\n");
        goto done;
    }

    njs_chb_destroy(&chain);

done:

    if (ret != NJS_OK) {
        stat->failed++;
        return NJS_OK;
    }

    stat->passed++;

    return NJS_OK;
}


typedef struct {
    size_t      size;
    uint32_t    array[32];
    size_t      esize;
    uint32_t    expected[32];
} njs_sort_test_t;


static int
njs_sort_cmp(const void *a, const void *b, void *ctx)
{
    njs_sort_test_t  *c;

    c = ctx;

    switch (c->esize) {
    case 1:
        return *((uint8_t *) a) - *((uint8_t *) b);
    case 2:
        return *((uint16_t *) a) - *((uint16_t *) b);
    case 4:
    default:
        return *((uint32_t *) a) - *((uint32_t *) b);
    }
}


static njs_int_t
njs_sort_test(njs_vm_t *vm, njs_opts_t *opts, njs_stat_t *stat)
{
    u_char           *p;
    njs_uint_t        i, j, k;
    njs_sort_test_t  *t;
    u_char           array[sizeof(t->array)];
    uint32_t         sorted[sizeof(t->array) / sizeof(t->array[0])];

    static const njs_sort_test_t tests[] = {
        { 1, { 5 }, 1, { 5 } },
        { 3, { 3, 2, 1 }, 1, { 1, 2, 3 } },
        { 4, { 4, 3, 2, 1 }, 1, { 1, 2, 3, 4 } },
        { 5, { 5, 4, 3, 2, 1 }, 1, { 1, 2, 3, 4, 5 } },
        { 5, { 1, 0, 9, 1, 8 }, 1, { 0, 1, 1, 8, 9 } },
        { 8, { 0, 0, 0, 0, 0, 0, 0, 0 }, 1, { 0, 0, 0, 0, 0, 0, 0, 0 } },
        { 8, { 4, 5, 1, 4, 2, 5, 5, 6 }, 1, { 1, 2, 4, 4, 5, 5, 5, 6 } },
        { 4, { 512, 100, 65535, 0 }, 2, { 0, 100, 512, 65535 } },
        { 3, { 65536, 3, 262141 }, 4, { 3, 65536, 262141 } },
    };

    for (i = 0; i < njs_nitems(tests); i++) {
        t = (njs_sort_test_t *) &tests[i];

        p = array;
        for (k = 0; k < t->size; k++) {
            switch (t->esize) {
            case 1:
                *p = (uint8_t) t->array[k];
                break;
            case 2:
                *(uint16_t *) p = (uint16_t) t->array[k];
                break;
            case 4:
            default:
                *(uint32_t *) p = (uint32_t) t->array[k];
                break;
            }

            p += t->esize;
        }

        njs_qsort(array, t->size, t->esize, njs_sort_cmp, t);

        p = array;
        for (k = 0; k < t->size; k++) {
            switch (t->esize) {
            case 1:
                sorted[k] = *p;
                break;
            case 2:
                sorted[k] = *(uint16_t *) p;
                break;
            case 4:
            default:
                sorted[k] = *(uint32_t *) p;
                break;
            }

            p += t->esize;
        }


        for (k = 0; k < t->size; k++) {
            if (sorted[k] != t->expected[k]) {
                goto failed;
            }
        }

        stat->passed++;
        continue;

failed:

        njs_printf("njs_sort_test([");
        for (j = 0; j < t->size; j++) {
            njs_printf("%uD%s", t->array[j],
                       (j < t->size - 1) ? "," : "");
        }

        njs_printf("]):\nexpected: [");
        for (j = 0; j < t->size; j++) {
            njs_printf("%uD%s", t->expected[j],
                       (j < t->size - 1) ? "," : "");
        }

        njs_printf("]\n     got: [");
        for (j = 0; j < t->size; j++) {
            njs_printf("%uD%s", sorted[j],
                       (j < t->size - 1) ? "," : "");
        }

        njs_printf("]\n");

        stat->failed++;
    }

    return NJS_OK;
}


static njs_int_t
njs_string_to_index_test(njs_vm_t *vm, njs_opts_t *opts, njs_stat_t *stat)
{
    double              num;
    njs_str_t           s;
    njs_int_t           ret;
    njs_bool_t          success;
    njs_uint_t          i;
    njs_opaque_value_t  value, input;

    static const struct {
        njs_str_t    value;
        njs_str_t    expected;
    } tests[] = {
        { njs_str(" 1"), njs_str("NaN") },
        { njs_str(""), njs_str("NaN") },
        { njs_str("+0"), njs_str("NaN") },
        { njs_str("-"), njs_str("NaN") },
        { njs_str("-0"), njs_str("-0") },
        { njs_str("-1"), njs_str("-1") },
        { njs_str("0"), njs_str("0") },
        { njs_str("0."), njs_str("NaN") },
        { njs_str("0.0"), njs_str("NaN") },
        { njs_str("0x1"), njs_str("NaN") },
        { njs_str("1 "), njs_str("NaN") },
        { njs_str("1"), njs_str("1") },
        { njs_str("1."), njs_str("NaN") },
        { njs_str("1.1"), njs_str("1.1") },
        { njs_str("100"), njs_str("100") },
        { njs_str("1a"), njs_str("NaN") },
        { njs_str("1e+19"), njs_str("NaN") },
        { njs_str("1e+22"), njs_str("1e+22") },
        { njs_str("1e22"), njs_str("NaN") },
        { njs_str("4294967296"), njs_str("4294967296") },
    };

    for (i = 0; i < njs_nitems(tests); i++) {
            (void) njs_vm_value_string_create(vm, njs_value_arg(&input),
                                             tests[i].value.start,
                                             tests[i].value.length);

            num = njs_string_to_index(njs_value_arg(&input));
            njs_value_number_set(njs_value_arg(&value), num);

            ret = njs_vm_value_dump(vm, &s, njs_value_arg(&value), 0, 0);
            if (ret != NJS_OK) {
                njs_printf("njs_string_to_index_test: "
                           "njs_vm_value_dump() failed\n");
                return NJS_ERROR;
            }

            success = njs_strstr_eq(&tests[i].expected, &s);

            if (!success) {
                njs_printf("njs_string_to_index_test(\"%V\"):\n"
                           "expected: \"%V\"\n     got: \"%V\"\n",
                           &tests[i].value, &tests[i].expected, &s);

                stat->failed++;
                continue;
            }

        stat->passed++;
    }

    return NJS_OK;
}


#ifdef NJS_HAVE_ADDR2LINE
static njs_int_t
njs_addr2line_test(njs_vm_t *vm, njs_opts_t *opts, njs_stat_t *stat)
{
    njs_str_t   v;
    njs_uint_t  i;
    u_char      buf[512];

    static const struct {
        void         *fp;
        const char   *name;
    } tests[] = {
        { njs_addr2line_test, njs_stringify(njs_addr2line_test) },
        { njs_string_to_index_test, njs_stringify(njs_string_to_index_test) },
    };

    for (i = 0; i < njs_nitems(tests); i++) {
        v.start = buf;
        v.length = njs_sprintf(buf, &buf[512], "%P", tests[i].fp) - buf;

        if (memcmp(buf, tests[i].name, njs_strlen(tests[i].name))) {
            njs_printf("njs_addr2line_test(%p):\n"
                       "expected: %s\n     got: %V\n",
                       tests[i].fp, tests[i].name, &v);

            stat->failed++;
            continue;
        }

        stat->passed++;
    }

    return NJS_OK;
}
#endif


static njs_int_t
njs_vm_internal_api_test(njs_unit_test_t unused[], size_t num, njs_str_t *name,
    njs_opts_t *opts, njs_stat_t *stat)
{
    njs_vm_t      *vm;
    njs_int_t     ret;
    njs_uint_t    i;
    njs_stat_t    prev;
    njs_vm_opt_t  options;

    static const struct {
        njs_int_t  (*test)(njs_vm_t *, njs_opts_t *, njs_stat_t *stat);
        njs_str_t  name;
    } tests[] = {
        { njs_vm_object_alloc_test,
          njs_str("njs_vm_object_alloc_test") },
        { njs_chb_test,
          njs_str("njs_chb_test") },
        { njs_sort_test,
          njs_str("njs_sort_test") },
        { njs_string_to_index_test,
          njs_str("njs_string_to_index_test") },
#ifdef NJS_HAVE_ADDR2LINE
        { njs_addr2line_test,
          njs_str("njs_addr2line_test") },
#endif
    };

    vm = NULL;
    njs_vm_opt_init(&options);

    prev = *stat;

    ret = NJS_ERROR;

    for (i = 0; i < njs_nitems(tests); i++) {
        vm = njs_vm_create(&options);
        if (vm == NULL) {
            njs_printf("njs_vm_create() failed\n");
            goto done;
        }

        ret = tests[i].test(vm, opts, stat);
        if (njs_slow_path(ret != NJS_OK)) {
            njs_printf("njs_api_test: \"%V\" test failed\n", &tests[i].name);
            goto done;
        }

        njs_vm_destroy(vm);
        vm = NULL;
    }

    ret = NJS_OK;

done:

    njs_unit_test_report(name, &prev, stat);

    if (vm != NULL) {
        njs_vm_destroy(vm);
    }

    return ret;
}


static njs_int_t
njs_options_parse(njs_opts_t *opts, int argc, char **argv)
{
    char       *p;
    njs_int_t  i;

    static const char  help[] =
        "njs unit tests.\n"
        "\n"
        "njs_unit_test [options]"
        "\n"
        "Options:\n"
        "  -d                           print disassembled code.\n"
        "  -f PATTERN1[|PATTERN2..]     filter test suites to run.\n"
        "  -r count                     overrides repeat count for tests.\n"
        "  -s seed                      sets seed for async tests.\n"
        "  -v                           verbose mode.\n";

    for (i = 1; i < argc; i++) {

        p = argv[i];

        if (p[0] != '-') {
            goto help;
        }

        p++;

        switch (*p) {
        case '?':
        case 'h':
            njs_printf("%*s", njs_length(help), help);
            return NJS_DONE;

        case 'd':
            opts->disassemble = 1;
            break;

        case 'f':
            if (++i < argc) {
                opts->filter.start = (u_char *) argv[i];
                opts->filter.length = njs_strlen(argv[i]);
                break;
            }

            njs_stderror("option \"-f\" requires argument\n");
            return NJS_ERROR;

        case 'r':
            if (++i < argc) {
                opts->repeat = atoi(argv[i]);
                break;
            }

            njs_stderror("option \"-r\" requires argument\n");
            return NJS_ERROR;

        case 's':
            if (++i < argc) {
                opts->seed = atoi(argv[i]);
                break;
            }

            njs_stderror("option \"-s\" requires argument\n");
            return NJS_ERROR;

        case 'v':
            opts->verbose = 1;
            break;

        default:
            goto help;
        }
    }

    return NJS_OK;

help:

    njs_stderror("Unknown argument: \"%s\" "
                 "try \"%s -h\" for available options\n", argv[i],
                 argv[0]);

    return NJS_ERROR;
}


static njs_int_t
njs_match_test(njs_opts_t *opts, njs_str_t *name)
{
    u_char  *p, *start, *end;
    size_t  len;

    if (name->length == 0) {
        return 0;
    }

    if (opts->filter.length == 0) {
        return 1;
    }

    start = opts->filter.start;
    end = start + opts->filter.length;

    for ( ;; ) {
        p = njs_strlchr(start, end, '|');
        len = ((p != NULL) ? p : end) - start;
        len = njs_min(name->length, len);

        if (len != 0 && njs_strncmp(name->start, start, len) == 0) {
            return 1;
        }

        if (p == NULL) {
            break;
        }

        start = p + 1;
    }

    return 0;
}


typedef struct {
    njs_str_t        name;
    njs_opts_t       opts;
    njs_unit_test_t  *tests;
    size_t           n;
    njs_int_t        (*run)(njs_unit_test_t tests[], size_t num,
                            njs_str_t *name, njs_opts_t *opts,
                            njs_stat_t *stat);
} njs_test_suite_t;


static njs_test_suite_t  njs_suites[] =
{
    { njs_str("script"),
      { .repeat = 1, .unsafe = 1, .preload = 1 },
      njs_test,
      njs_nitems(njs_test),
      njs_unit_test },

    { njs_str("safe script"),
      { .repeat = 1},
      njs_safe_test,
      njs_nitems(njs_safe_test),
      njs_unit_test },

    { njs_str("denormals"),
      { .repeat = 1, .unsafe = 1 },
      njs_denormals_test,
      njs_nitems(njs_denormals_test),
      njs_unit_test },

    { njs_str("module"),
      { .repeat = 1, .module = 1, .unsafe = 1 },
      njs_module_test,
      njs_nitems(njs_module_test),
      njs_unit_test },

    { njs_str("fs module"),
      { .repeat = 1, .unsafe = 1 },
      njs_fs_module_test,
      njs_nitems(njs_fs_module_test),
      njs_unit_test },

    { njs_str("externals"),
      { .externals = 1, .repeat = 1, .unsafe = 1 },
      njs_externals_test,
      njs_nitems(njs_externals_test),
      njs_unit_test },

    { njs_str("async handler"),
      { .async = 1, .externals = 1, .handler = 1, .repeat = 4, .seed = 2, .unsafe = 1 },
      njs_async_handler_test,
      njs_nitems(njs_async_handler_test),
      njs_unit_test },

    { njs_str("shared"),
      { .externals = 1, .repeat = 128, .seed = 42, .unsafe = 1, .preload = 1, .backtrace = 1 },
      njs_shared_test,
      njs_nitems(njs_shared_test),
      njs_unit_test },

    { njs_str("interactive"),
      { .externals = 1, .repeat = 1, .unsafe = 1 },
      njs_shell_test,
      njs_nitems(njs_shell_test),
      njs_interactive_test },

    { njs_str("backtraces"),
      { .backtrace = 1, .externals = 1, .repeat = 1, .unsafe = 1 },
      njs_backtraces_test,
      njs_nitems(njs_backtraces_test),
      njs_unit_test },

    { njs_str("timezone"),
      { .repeat = 1, .unsafe = 1 },
      njs_tz_test,
      njs_nitems(njs_tz_test),
      njs_timezone_optional_test },

    { njs_str("regexp optional"),
      { .repeat = 1, .unsafe = 1 },
      njs_regexp_optional_tests,
      njs_nitems(njs_regexp_optional_tests),
      njs_regexp_optional_test },

    { njs_str("vm_json"),
      { .repeat = 1, .unsafe = 1 },
      NULL,
      0,
      njs_vm_json_test },

    { njs_str("vm_value"),
      { .repeat = 1, .unsafe = 1 },
      NULL,
      0,
      njs_vm_value_test },

    { njs_str("vm_internal_api"),
      { .repeat = 1, .unsafe = 1 },
      NULL,
      0,
      njs_vm_internal_api_test },
};


static const char  *restricted_environ[] = {
    "TZ=UTC",
    "DUP=bar",
    "dup=foo",
    NULL,
};


int njs_cdecl
main(int argc, char **argv)
{
    njs_int_t         ret;
    njs_uint_t        i;
    njs_opts_t        opts, op;
    njs_stat_t        stat;
    njs_test_suite_t  *suite;

    njs_memzero(&opts, sizeof(njs_opts_t));

    ret = njs_options_parse(&opts, argc, argv);
    if (ret != NJS_OK) {
        return (ret == NJS_DONE) ? EXIT_SUCCESS: EXIT_FAILURE;
    }

    environ = (char **) restricted_environ;

    tzset();

    njs_memzero(&stat, sizeof(njs_stat_t));

    for (i = 0; i < njs_nitems(njs_suites); i++) {
        suite = &njs_suites[i];

        if (!njs_match_test(&opts, &suite->name)) {
            continue;
        }

        op = suite->opts;

        op.disassemble = opts.disassemble;
        op.repeat = opts.repeat ? opts.repeat : op.repeat;
        op.seed = opts.seed ? opts.seed : op.seed;
        op.verbose = opts.verbose;

        ret = suite->run(suite->tests, suite->n, &suite->name, &op, &stat);
        if (ret != NJS_OK) {
            return ret;
        }
    }

    njs_printf("TOTAL: %s [%ui/%ui]\n", stat.failed ? "FAILED" : "PASSED",
               stat.passed, stat.passed + stat.failed);

    return stat.failed ? EXIT_FAILURE : EXIT_SUCCESS;
}
