diff --git a/.github/workflows/gh-actions.yml b/.github/workflows/gh-actions.yml index d8db661351..d4db89902f 100644 --- a/.github/workflows/gh-actions.yml +++ b/.github/workflows/gh-actions.yml @@ -56,6 +56,34 @@ jobs: - run: $RUNNER -q --jerry-tests --buildoptions=--compile-flag=-m32,--cpointer-32bit=on - run: $RUNNER -q --jerry-tests --buildoptions=--compile-flag=-m32,--cpointer-32bit=on --build-debug + Win_x86-64_Conformance_Tests_ESNext: + runs-on: windows-latest + steps: + - uses: actions/checkout@v2 + - run: python $env:RUNNER --test262 update + + Win_x86-64_Conformance_Tests_ESNext_Debug: + runs-on: windows-latest + steps: + - uses: actions/checkout@v2 + - run: python $env:RUNNER --test262 update --build-debug + + Win_x86-64_Tests: + runs-on: windows-latest + steps: + - uses: actions/checkout@v2 + - run: python $env:RUNNER -q --jerry-tests + - run: python $env:RUNNER -q --unittests + - run: python $env:RUNNER -q --buildoption-test + + Win_x86-64_Tests_Debug: + runs-on: windows-latest + steps: + - uses: actions/checkout@v2 + - run: python $env:RUNNER -q --jerry-tests --build-debug + - run: python $env:RUNNER -q --unittests --build-debug + - run: python $env:RUNNER -q --buildoption-test --build-debug + OSX_x86-64_Build_Correctness_Unit_Tests: runs-on: macos-13 steps: diff --git a/README.md b/README.md index eac8ef0c45..ebe84d3f96 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,6 @@ # JerryScript: JavaScript engine for the Internet of Things [![License](https://img.shields.io/badge/licence-Apache%202.0-brightgreen.svg?style=flat)](LICENSE) [![GitHub Actions Status](https://github.com/jerryscript-project/jerryscript/workflows/JerryScript%20CI/badge.svg)](https://github.com/jerryscript-project/jerryscript/actions) -[![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/ct8reap35u2vooa5/branch/master?svg=true)](https://ci.appveyor.com/project/jerryscript-project/jerryscript/branch/master) [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Fjerryscript-project%2Fjerryscript.svg?type=shield)](https://app.fossa.io/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Fjerryscript-project%2Fjerryscript?ref=badge_shield) [![IRC Channel](https://img.shields.io/badge/chat-on%20freenode-brightgreen.svg)](https://kiwiirc.com/client/irc.freenode.net/#jerryscript) diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index cc215ac00d..0000000000 --- a/appveyor.yml +++ /dev/null @@ -1,27 +0,0 @@ -version: "{build}" -branches: - except: - - coverity_scan - - gh_pages -skip_tags: true - -# Build matrix setup. -image: - - Visual Studio 2017 -configuration: - - Debug - - Release -platform: - - x64 - - Win32 - -# Steps of a job. -init: - - cmake -version -before_build: - - if "%PLATFORM%"=="Win32" cmake -G"Visual Studio 15 2017" -Bbuild -H. -DJERRY_DEBUGGER=ON - - if "%PLATFORM%"=="x64" cmake -G"Visual Studio 15 2017 Win64" -Bbuild -H. -DJERRY_DEBUGGER=ON -build: - project: build\Jerry.sln - parallel: false # FIXME: This should not be needed but right now it is: msbuild generates all amalgamated files twice, at the same time in parallel builds, leading to I/O errors. - verbosity: minimal diff --git a/jerry-port/win/jerry-port-win-date.c b/jerry-port/win/jerry-port-win-date.c index 91aee32646..ea3823eabe 100644 --- a/jerry-port/win/jerry-port-win-date.c +++ b/jerry-port/win/jerry-port-win-date.c @@ -23,8 +23,8 @@ #include #include -#define UNIX_EPOCH_IN_TICKS 116444736000000000ull /* difference between 1970 and 1601 */ -#define TICKS_PER_MS 10000ull /* 1 tick is 100 nanoseconds */ +#define UNIX_EPOCH_IN_TICKS 116444736000000000LL /* difference between 1970 and 1601 */ +#define TICKS_PER_MS 10000LL /* 1 tick is 100 nanoseconds */ /* * If you take the limit of SYSTEMTIME (last millisecond in 30827) then you end up with @@ -44,15 +44,9 @@ * https://support.microsoft.com/en-us/help/167296/how-to-convert-a-unix-time-t-to-a-win32-filetime-or-systemtime */ static void -unix_time_to_filetime (double t, LPFILETIME ft_p) +unix_time_to_filetime (LONGLONG t, LPFILETIME ft_p) { - LONGLONG ll = (LONGLONG) t * TICKS_PER_MS + UNIX_EPOCH_IN_TICKS; - - /* FILETIME values before the epoch are invalid. */ - if (ll < 0) - { - ll = 0; - } + LONGLONG ll = t * TICKS_PER_MS + UNIX_EPOCH_IN_TICKS; ft_p->dwLowDateTime = (DWORD) ll; ft_p->dwHighDateTime = (DWORD) (ll >> 32); @@ -63,13 +57,15 @@ unix_time_to_filetime (double t, LPFILETIME ft_p) * * @return unix time */ -static double +static LONGLONG filetime_to_unix_time (LPFILETIME ft_p) { ULARGE_INTEGER date; + LONGLONG ll; date.HighPart = ft_p->dwHighDateTime; date.LowPart = ft_p->dwLowDateTime; - return (double) (((LONGLONG) date.QuadPart - UNIX_EPOCH_IN_TICKS) / TICKS_PER_MS); + ll = date.QuadPart - UNIX_EPOCH_IN_TICKS; + return ll / TICKS_PER_MS; } /* filetime_to_unix_time */ /** @@ -85,6 +81,7 @@ jerry_port_local_tza (double unix_ms) FILETIME local; SYSTEMTIME utc_sys; SYSTEMTIME local_sys; + LONGLONG t = (LONGLONG) (unix_ms); /* * If the time is earlier than the date 1601-01-02, then always using date 1601-01-02 to @@ -93,23 +90,23 @@ jerry_port_local_tza (double unix_ms) * after converting between local time and utc time, the time may be earlier than 1601-01-01 * in UTC time, that exceeds the FILETIME representation range. */ - if (unix_ms < (double) UNIX_EPOCH_DATE_1601_01_02) + if (t < UNIX_EPOCH_DATE_1601_01_02) { - unix_ms = (double) UNIX_EPOCH_DATE_1601_01_02; + t = UNIX_EPOCH_DATE_1601_01_02; } /* Like above, do not use the last supported day */ - if (unix_ms > (double) UNIX_EPOCH_DATE_30827_12_29) + if (t > UNIX_EPOCH_DATE_30827_12_29) { - unix_ms = (double) UNIX_EPOCH_DATE_30827_12_29; + t = UNIX_EPOCH_DATE_30827_12_29; } - unix_time_to_filetime (unix_ms, &utc); + unix_time_to_filetime (t, &utc); if (FileTimeToSystemTime (&utc, &utc_sys) && SystemTimeToTzSpecificLocalTime (NULL, &utc_sys, &local_sys) && SystemTimeToFileTime (&local_sys, &local)) { - double unix_local = filetime_to_unix_time (&local); - return (int32_t) (unix_local - unix_ms); + LONGLONG unix_local = filetime_to_unix_time (&local); + return (int32_t) (unix_local - t); } return 0; @@ -125,7 +122,7 @@ jerry_port_current_time (void) { FILETIME ft; GetSystemTimeAsFileTime (&ft); - return filetime_to_unix_time (&ft); + return (double) filetime_to_unix_time (&ft); } /* jerry_port_current_time */ #endif /* defined(_WIN32) */ diff --git a/tests/jerry/date-getters.js b/tests/jerry/date-getters.js index 77cd9042b1..0a2061fd38 100644 --- a/tests/jerry/date-getters.js +++ b/tests/jerry/date-getters.js @@ -110,8 +110,16 @@ assert (new Date(-1, -1, -1, -1, -1, -1, -1, -1).getMilliseconds() === 999); assert (isNaN(new Date(20000000, 0).getFullYear())); assert (new Date(0, 0).getFullYear() === 1900); assert (new Date(1.2, 0).getFullYear() === 1901); + +/* 7. test case */ +/* A Number can exactly represent all integers from -9,007,199,254,740,992 to 9,007,199,254,740,992 (21.1.2.8 and 21.1.2.6). + A time value supports a slightly smaller range of -8,640,000,000,000,000 to 8,640,000,000,000,000 milliseconds. */ assert((new Date(8640000000000000).getFullYear()) == 275760); assert(isNaN(new Date(8640000000000001).getFullYear())); +assert((new Date(-8640000000000000).getFullYear()) == -271821); +assert(isNaN(new Date(-8640000000000001).getFullYear())); + +/* 8. test case */ assert((new Date(-271821, 3, 21).getFullYear()) == -271821); assert(isNaN(new Date(1970, 0, -100000000).getFullYear())); assert(new Date(1970, 0, -100000000 + 1).getFullYear() == -271821); diff --git a/tools/run-tests.py b/tools/run-tests.py index 64bc1ed827..b58b5ff439 100755 --- a/tools/run-tests.py +++ b/tools/run-tests.py @@ -23,11 +23,8 @@ import sys import settings -if sys.version_info.major >= 3: - from runners import util -else: - sys.path.append(os.path.dirname(os.path.realpath(__file__)) + '/runners') - import util +from runners import util +from runners.util import TERM_NORMAL, TERM_YELLOW, TERM_BLUE, TERM_RED OUTPUT_DIR = os.path.join(settings.PROJECT_DIR, 'build', 'tests') @@ -170,6 +167,8 @@ def get_arguments(): help='Run "magic string source code generator should be executed" check') parser.add_argument('--build-debug', action='store_true', help='Build debug version jerryscript') + parser.add_argument('--run-check-timeout', type=int, default=30 * 60, + help='Specify run_check timeout, default to 30 minutes, unit: second') parser.add_argument('--jerry-debugger', action='store_true', help='Run jerry-debugger tests') parser.add_argument('--jerry-tests', action='store_true', @@ -197,11 +196,6 @@ def get_arguments(): BINARY_CACHE = {} -TERM_NORMAL = '\033[0m' -TERM_YELLOW = '\033[1;33m' -TERM_BLUE = '\033[1;34m' -TERM_RED = '\033[1;31m' - def report_command(cmd_type, cmd, env=None): sys.stderr.write(f'{TERM_BLUE}{cmd_type}{TERM_NORMAL}\n') if env is not None: @@ -210,12 +204,14 @@ def report_command(cmd_type, cmd, env=None): sys.stderr.write(f"{TERM_BLUE}" + f" \\{TERM_NORMAL}\n\t{TERM_BLUE}".join(cmd) + f"{TERM_NORMAL}\n") + sys.stderr.flush() def report_skip(job): sys.stderr.write(f'{TERM_YELLOW}Skipping: {job.name}') if job.skip: sys.stderr.write(f' ({job.skip})') sys.stderr.write(f'{TERM_NORMAL}\n') + sys.stderr.flush() def create_binary(job, options): build_args = job.build_args[:] @@ -246,6 +242,7 @@ def create_binary(job, options): if binary_key in BINARY_CACHE: ret, build_dir_path = BINARY_CACHE[binary_key] sys.stderr.write(f'(skipping: already built at {build_dir_path} with returncode {ret})\n') + sys.stderr.flush() return ret, build_dir_path try: @@ -283,6 +280,7 @@ def iterate_test_runner_jobs(jobs, options): if build_dir_path in tested_paths: sys.stderr.write(f'(skipping: already tested with {build_dir_path})\n') + sys.stderr.flush() continue tested_paths.add(build_dir_path) @@ -291,6 +289,7 @@ def iterate_test_runner_jobs(jobs, options): if bin_hash in tested_hashes: sys.stderr.write(f'(skipping: already tested with equivalent {tested_hashes[bin_hash]})\n') + sys.stderr.flush() continue tested_hashes[bin_hash] = build_dir_path @@ -299,7 +298,7 @@ def iterate_test_runner_jobs(jobs, options): yield job, ret_build, test_cmd -def run_check(runnable, env=None): +def run_check(options, runnable, env=None): report_command('Test command:', runnable, env=env) if env is not None: @@ -308,7 +307,11 @@ def run_check(runnable, env=None): env = full_env with subprocess.Popen(runnable, env=env) as proc: - proc.wait() + try: + proc.wait(timeout=options.run_check_timeout) + except subprocess.TimeoutExpired: + proc.kill() + return -1 return proc.returncode def run_jerry_debugger_tests(options): @@ -335,7 +338,7 @@ def run_jerry_debugger_tests(options): if job.test_args: test_cmd.extend(job.test_args) - ret_test |= run_check(test_cmd) + ret_test |= run_check(options, test_cmd) return ret_build | ret_test @@ -367,7 +370,7 @@ def run_jerry_tests(options): if job.test_args: test_cmd.extend(job.test_args) - ret_test |= run_check(test_cmd, env=dict(TZ='UTC')) + ret_test |= run_check(options, test_cmd, env=dict(TZ='UTC')) return ret_build | ret_test @@ -397,7 +400,7 @@ def run_test262_test_suite(options): test_cmd.append('--test262-test-list') test_cmd.append(options.test262_test_list) - ret_test |= run_check(test_cmd, env=dict(TZ='America/Los_Angeles')) + ret_test |= run_check(options, test_cmd, env=dict(TZ='America/Los_Angeles')) return ret_build | ret_test @@ -422,6 +425,7 @@ def run_unittests(options): ret_test |= run_check( + options, util.get_python_cmd_prefix() + [settings.UNITTEST_RUNNER_SCRIPT] + [os.path.join(build_dir_path, 'tests', build_config)] + @@ -446,6 +450,7 @@ def run_buildoption_test(options): Check = collections.namedtuple('Check', ['enabled', 'runner', 'arg']) def main(options): + util.setup_stdio() checks = [ Check(options.check_signed_off, run_check, [settings.SIGNED_OFF_SCRIPT] + {'tolerant': ['--tolerant'], 'gh-actions': ['--gh-actions']}.get(options.check_signed_off, [])), @@ -455,16 +460,19 @@ def main(options): Check(options.check_format, run_check, [settings.FORMAT_SCRIPT]), Check(options.check_license, run_check, [settings.LICENSE_SCRIPT]), Check(options.check_strings, run_check, [settings.STRINGS_SCRIPT]), - Check(options.jerry_debugger, run_jerry_debugger_tests, options), - Check(options.jerry_tests, run_jerry_tests, options), - Check(options.test262, run_test262_test_suite, options), - Check(options.unittests, run_unittests, options), - Check(options.buildoption_test, run_buildoption_test, options), + Check(options.jerry_debugger, run_jerry_debugger_tests, None), + Check(options.jerry_tests, run_jerry_tests, None), + Check(options.test262, run_test262_test_suite, None), + Check(options.unittests, run_unittests, None), + Check(options.buildoption_test, run_buildoption_test, None), ] for check in checks: if check.enabled or options.all: - ret = check.runner(check.arg) + if check.arg is None: + ret = check.runner(options) + else: + ret = check.runner(options, check.arg) if ret: sys.exit(ret) diff --git a/tools/runners/run-test-suite-test262.py b/tools/runners/run-test-suite-test262.py index a03c678627..08e665ef2a 100755 --- a/tools/runners/run-test-suite-test262.py +++ b/tools/runners/run-test-suite-test262.py @@ -22,12 +22,6 @@ import util -def get_platform_cmd_prefix(): - if sys.platform == 'win32': - return ['cmd', '/S', '/C'] - return ['python3'] - - def get_arguments(): execution_runtime = os.environ.get('RUNTIME', '') parser = argparse.ArgumentParser() @@ -91,7 +85,7 @@ def update_exclude_list(args): # Tests pass in strict-mode but fail in non-strict-mode (or vice versa) should be considered as failures passing_tests = passing_tests - failing_tests - with open(args.excludelist_path, 'r+', encoding='utf8') as exclude_file: + with open(args.excludelist_path, 'r+', encoding='utf8', errors='ignore') as exclude_file: lines = exclude_file.readlines() exclude_file.seek(0) exclude_file.truncate() @@ -135,6 +129,7 @@ def update_exclude_list(args): def main(args): + util.setup_stdio() return_code = prepare_test262_test_suite(args) if return_code: return return_code @@ -149,12 +144,11 @@ def main(args): command += ' --test262-object' kwargs = {} - if sys.version_info.major >= 3: - kwargs['errors'] = 'ignore' + kwargs['errors'] = 'ignore' test262_harness_path = os.path.join(args.test262_harness_dir, 'test262-harness.py') - test262_command = get_platform_cmd_prefix() + \ + test262_command = util.get_python_cmd_prefix() + \ [test262_harness_path, '--command', command, '--tests', args.test_dir, diff --git a/tools/runners/run-test-suite.py b/tools/runners/run-test-suite.py index afd4477f77..fb3c341dda 100755 --- a/tools/runners/run-test-suite.py +++ b/tools/runners/run-test-suite.py @@ -61,13 +61,13 @@ def get_tests(test_dir, test_list, skip_list): dirname = os.path.dirname(test_list) with open(test_list, "r", encoding='utf8') as test_list_fd: for test in test_list_fd: - tests.append(os.path.normpath(os.path.join(dirname, test.rstrip()))) + tests.append(os.path.join(dirname, test.rstrip())) tests.sort() def filter_tests(test): for skipped in skip_list: - if skipped in test: + if os.path.normpath(skipped) in os.path.normpath(test): return False return True @@ -76,8 +76,8 @@ def filter_tests(test): def execute_test_command(test_cmd): kwargs = {} - if sys.version_info.major >= 3: - kwargs['encoding'] = 'unicode_escape' + kwargs['encoding'] = 'unicode_escape' + kwargs['errors'] = 'ignore' with subprocess.Popen(test_cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True, **kwargs) as process: stdout, _ = process.communicate() @@ -85,6 +85,7 @@ def execute_test_command(test_cmd): def main(args): + util.setup_stdio() tests = get_tests(args.test_dir, args.test_list, args.skip_list) total = len(tests) if total == 0: diff --git a/tools/runners/run-unittests.py b/tools/runners/run-unittests.py index d54f643692..ef07d41f14 100755 --- a/tools/runners/run-unittests.py +++ b/tools/runners/run-unittests.py @@ -49,6 +49,7 @@ def get_unittests(path): def main(args): + util.setup_stdio() unittests = get_unittests(args.path) total = len(unittests) if total == 0: diff --git a/tools/runners/test262-harness.py b/tools/runners/test262-harness.py index d4389db752..a368d0bd5d 100755 --- a/tools/runners/test262-harness.py +++ b/tools/runners/test262-harness.py @@ -46,6 +46,7 @@ import signal import multiprocessing +import util # The timeout of each test case TEST262_CASE_TIMEOUT = 180 @@ -130,10 +131,10 @@ def open_file(self): text=self.text) def write(self, string): - os.write(self.file_desc, string.encode('utf8')) + os.write(self.file_desc, string.encode('utf8', 'ignore')) def read(self): - with open(self.name, "r", newline='', encoding='utf8') as file_desc: + with open(self.name, "r", newline='', encoding='utf8', errors='ignore') as file_desc: return file_desc.read() def close(self): @@ -227,7 +228,7 @@ def __init__(self, suite, name, full_path, strict_mode, command_template, module self.validate() def parse_test_record(self): - with open(self.full_path, "r", newline='', encoding='utf8') as file_desc: + with open(self.full_path, "r", newline='', encoding='utf8', errors='ignore') as file_desc: full_test = file_desc.read() match = TEST_RE.search(full_test) @@ -488,7 +489,7 @@ def should_run(rel_path, tests): if not tests: return True for test in tests: - if test in rel_path: + if os.path.normpath(test) in os.path.normpath(rel_path): return True return False @@ -496,7 +497,7 @@ def get_include(self, name): if not name in self.include_cache: static = path.join(self.lib_root, name) if path.exists(static): - with open(static, encoding='utf8') as file_desc: + with open(static, encoding='utf8', errors='ignore') as file_desc: contents = file_desc.read() contents = re.sub(r'\r\n', '\n', contents) self.include_cache[name] = contents + "\n" @@ -585,7 +586,7 @@ def run(self, command_template, tests, print_summary, full_summary, logname, job report_error("No tests to run") progress = ProgressIndicator(len(cases)) if logname: - self.logf = open(logname, "w", encoding='utf8') # pylint: disable=consider-using-with + self.logf = open(logname, "w", encoding='utf8', errors='ignore') # pylint: disable=consider-using-with if job_count == 1: for case in cases: @@ -647,6 +648,7 @@ def list_includes(self, tests): def main(): + util.setup_stdio() code = 0 parser = build_options() options = parser.parse_args() diff --git a/tools/runners/util.py b/tools/runners/util.py index 90e920491b..f4225da62a 100755 --- a/tools/runners/util.py +++ b/tools/runners/util.py @@ -12,13 +12,23 @@ # See the License for the specific language governing permissions and # limitations under the License. +import codecs import signal import subprocess import sys -TERM_NORMAL = '\033[0m' -TERM_RED = '\033[1;31m' -TERM_GREEN = '\033[1;32m' +if sys.platform == 'win32': + TERM_NORMAL = '' + TERM_RED = '' + TERM_GREEN = '' + TERM_YELLOW = '' + TERM_BLUE = '' +else: + TERM_NORMAL = '\033[0m' + TERM_RED = '\033[1;31m' + TERM_GREEN = '\033[1;32m' + TERM_YELLOW = '\033[1;33m' + TERM_BLUE = '\033[1;34m' def set_timezone(timezone): @@ -42,6 +52,18 @@ def set_sighdl_to_reset_timezone(timezone): signal.signal(signal.SIGINT, lambda signal, frame: set_timezone_and_exit(timezone)) +# This is for not lost data on 'win32' with python 'print'. +# When use python subprocess call another script on win32, output with +# 'utf-8' encoding, that's the same like linux platform; but when +# call the python script in 'cmd.exe' shell, we have to output in 'native' encoding. +def setup_stdio(): + # For tty using native encoding, otherwise (pipe) use 'utf-8' + encoding = sys.stdout.encoding if sys.stdout.isatty() else 'utf-8' + # Always override it to avoid encode error + sys.stdout = codecs.getwriter(encoding)(sys.stdout.buffer, 'xmlcharrefreplace') + sys.stderr = codecs.getwriter(encoding)(sys.stderr.buffer, 'xmlcharrefreplace') + + def print_test_summary(summary_string, total, passed, failed): print(f"\n[summary] {summary_string}\n") print(f"TOTAL: {total}") @@ -72,4 +94,4 @@ def get_platform_cmd_prefix(): def get_python_cmd_prefix(): # python script doesn't have execute permission on github actions windows runner - return get_platform_cmd_prefix() + [sys.executable or 'python'] + return [sys.executable or 'python']