diff --git a/.github/workflows/gh-actions.yml b/.github/workflows/gh-actions.yml index 023d7e4822..9982bec23e 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-debugger/jerry_client.py b/jerry-debugger/jerry_client.py index ee735e5367..b531c6c704 100755 --- a/jerry-debugger/jerry_client.py +++ b/jerry-debugger/jerry_client.py @@ -326,6 +326,8 @@ def main(): break if res_type == result.PROMPT: prompt.cmdloop() + sys.stdout.flush() + sys.stderr.flush() elif res_type == result.TEXT: write(result.get_text()) continue 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..b4844ac26a 100755 --- a/tools/run-tests.py +++ b/tools/run-tests.py @@ -25,12 +25,16 @@ if sys.version_info.major >= 3: from runners import util + from runners.util import TERM_NORMAL, TERM_YELLOW, TERM_BLUE, TERM_RED else: sys.path.append(os.path.dirname(os.path.realpath(__file__)) + '/runners') import util OUTPUT_DIR = os.path.join(settings.PROJECT_DIR, 'build', 'tests') +# The saved result of get_arguments() for globally access +options = None + Options = collections.namedtuple('Options', ['name', 'build_args', 'test_args', 'skip']) Options.__new__.__defaults__ = ([], [], False) @@ -170,6 +174,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', action='store_const', const=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 +203,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,14 +211,17 @@ 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): +def create_binary(job): + global options build_args = job.build_args[:] build_dir_path = os.path.join(options.outdir, job.name) if options.build_debug: @@ -246,13 +250,17 @@ 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: subprocess.check_output(build_cmd) ret = 0 except subprocess.CalledProcessError as err: - print(err.output.decode("utf8")) + # As on Win32, the output encoding of 'cmd.exe' is 'native' such as 'gbk' not 'utf8'; + # For Linux, the output encoding of bash is 'utf8' by default, and native is 'utf8 in most case + # So it's better not specify the encoding when call native program with subprocess.check_output + print(err.output.decode(errors="ignore")) ret = err.returncode BINARY_CACHE[binary_key] = (ret, build_dir_path) @@ -272,17 +280,18 @@ def hash_binary(bin_path): buf = bin_file.read(blocksize) return hasher.hexdigest() -def iterate_test_runner_jobs(jobs, options): +def iterate_test_runner_jobs(jobs): tested_paths = set() tested_hashes = {} for job in jobs: - ret_build, build_dir_path = create_binary(job, options) + ret_build, build_dir_path = create_binary(job) if ret_build: yield job, ret_build, None 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 +300,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 @@ -300,6 +310,7 @@ def iterate_test_runner_jobs(jobs, options): yield job, ret_build, test_cmd def run_check(runnable, env=None): + global options report_command('Test command:', runnable, env=env) if env is not None: @@ -308,13 +319,13 @@ def run_check(runnable, env=None): env = full_env with subprocess.Popen(runnable, env=env) as proc: - proc.wait() + proc.wait(timeout=options.run_check_timeout) return proc.returncode -def run_jerry_debugger_tests(options): +def run_jerry_debugger_tests(): ret_build = ret_test = 0 for job in DEBUGGER_TEST_OPTIONS: - ret_build, build_dir_path = create_binary(job, options) + ret_build, build_dir_path = create_binary(job) if ret_build: print(f"\n{TERM_RED}Build failed{TERM_NORMAL}\n") break @@ -324,7 +335,7 @@ def run_jerry_debugger_tests(options): if test_file.endswith(".cmd"): test_case, _ = os.path.splitext(test_file) test_case_path = os.path.join(settings.DEBUGGER_TESTS_DIR, test_case) - test_cmd = [ + test_cmd = util.get_python_cmd_prefix() + [ settings.DEBUGGER_TEST_RUNNER_SCRIPT, get_binary_path(build_dir_path), channel, @@ -339,9 +350,10 @@ def run_jerry_debugger_tests(options): return ret_build | ret_test -def run_jerry_tests(options): +def run_jerry_tests(): + global options ret_build = ret_test = 0 - for job, ret_build, test_cmd in iterate_test_runner_jobs(JERRY_TESTS_OPTIONS, options): + for job, ret_build, test_cmd in iterate_test_runner_jobs(JERRY_TESTS_OPTIONS): if ret_build: break @@ -371,13 +383,14 @@ def run_jerry_tests(options): return ret_build | ret_test -def run_test262_test_suite(options): +def run_test262_test_suite(): + global options ret_build = ret_test = 0 jobs = TEST262_TEST_SUITE_OPTIONS for job in jobs: - ret_build, build_dir_path = create_binary(job, options) + ret_build, build_dir_path = create_binary(job) if ret_build: print(f"\n{TERM_RED}Build failed{TERM_NORMAL}\n") break @@ -401,13 +414,14 @@ def run_test262_test_suite(options): return ret_build | ret_test -def run_unittests(options): +def run_unittests(): + global options ret_build = ret_test = 0 for job in JERRY_UNITTESTS_OPTIONS: if job.skip: report_skip(job) continue - ret_build, build_dir_path = create_binary(job, options) + ret_build, build_dir_path = create_binary(job) if ret_build: print(f"\n{TERM_RED}Build failed{TERM_NORMAL}\n") break @@ -430,13 +444,13 @@ def run_unittests(options): return ret_build | ret_test -def run_buildoption_test(options): +def run_buildoption_test(): for job in JERRY_BUILDOPTIONS: if job.skip: report_skip(job) continue - ret, _ = create_binary(job, options) + ret, _ = create_binary(job) if ret: print(f"\n{TERM_RED}Build failed{TERM_NORMAL}\n") break @@ -445,7 +459,9 @@ def run_buildoption_test(options): Check = collections.namedtuple('Check', ['enabled', 'runner', 'arg']) -def main(options): +def main(): + global 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,18 +471,22 @@ 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() + else: + ret = check.runner(check.arg) if ret: sys.exit(ret) if __name__ == "__main__": - main(get_arguments()) + options = get_arguments() + main() diff --git a/tools/runners/run-debugger-test.py b/tools/runners/run-debugger-test.py new file mode 100644 index 0000000000..8719613783 --- /dev/null +++ b/tools/runners/run-debugger-test.py @@ -0,0 +1,99 @@ +#!/usr/bin/env python + +# Copyright JS Foundation and other contributors, http://js.foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os +import subprocess +import sys +import time + +import util +TempFile = __import__("test262-harness").TempFile # pylint: disable=invalid-name + +class DebuggerArgs: + def __init__(self): + self.jerry = sys.argv[1] + self.channel = sys.argv[2] + self.debugger_client = sys.argv[3] + self.test_case = sys.argv[4] + + +def check_output(command_args, stdin=None, encoding=None): + try: + out = subprocess.check_output(command_args, stdin=stdin, shell=False, stderr=subprocess.STDOUT) + except subprocess.CalledProcessError as check_error: + out = check_error.output + return out.decode(encoding or 'utf-8', 'ignore') + + +def execute_debug_client(out_tmp, cmd_file_name, debug_client_args): + print(f'input debug cmd: {cmd_file_name}') + with open(cmd_file_name, 'rb') as cmd_file: + out = check_output(debug_client_args, cmd_file) + out_tmp.write(out) + + +def main(args): + util.setup_stdio() + jerry_debug_server_cmd = [args.jerry] + client_args = [] + if 'client_source' in args.test_case: + jerry_debug_server_cmd += ['--start-debug-server', '--debug-channel', + args.channel, '--debugger-wait-source'] + client_args += ['--client-source'] + if 'client_source_multiple' in args.test_case: + client_args += [args.test_case + '_2.js', args.test_case + '_1.js'] + else: + client_args += [args.test_case + '.js'] + else: + jerry_debug_server_cmd += [args.test_case + '.js', '--start-debug-server', '--debug-channel', args.channel] + print(f'run debug server: {jerry_debug_server_cmd}') + with subprocess.Popen(jerry_debug_server_cmd, stdin=subprocess.PIPE, + stdout=subprocess.PIPE, stderr=subprocess.STDOUT) as proc: + time.sleep(1) + + out_tmp = TempFile(prefix=os.path.basename(args.test_case), suffix='out') + git_failed = False + try: + debug_client_args = util.get_python_cmd_prefix() + debug_client_args += [args.debugger_client, '--channel', args.channel, '--non-interactive'] + debug_client_args += client_args + print(f"run debug client: {' '.join(debug_client_args)}") + execute_debug_client(out_tmp, args.test_case + '.cmd', debug_client_args) + if 'restart' in args.test_case: + continue_case = args.test_case.replace('restart', 'continue') + execute_debug_client(out_tmp, continue_case + '.cmd', debug_client_args) + out_tmp.close() + git_diff_cmd = ['git', '--no-pager', 'diff', '--ignore-space-at-eol', + '--no-index', args.test_case + '.expected', out_tmp.name] + git_out = check_output(git_diff_cmd) + if '@@' in git_out: + git_failed = True + finally: + proc.wait() + print(f"jerry out:\n{proc.stdout.read().decode('utf-8')}\nEOF") + print(f"git diff cmd: {' '.join(git_diff_cmd)}") + if git_failed: + print(f'git diff result:\n{git_out}\nEOF') + print(f'{util.TERM_RED}FAIL: {args.test_case}{util.TERM_NORMAL}') + sys.exit(1) + else: + out_tmp.dispose() + print(f'{util.TERM_GREEN}PASS: {args.test_case}{util.TERM_NORMAL}') + sys.exit(0) + + +if __name__ == "__main__": + sys.exit(main(DebuggerArgs())) diff --git a/tools/runners/run-debugger-test.sh b/tools/runners/run-debugger-test.sh deleted file mode 100755 index a3c754c768..0000000000 --- a/tools/runners/run-debugger-test.sh +++ /dev/null @@ -1,66 +0,0 @@ -#!/bin/bash - -# Copyright JS Foundation and other contributors, http://js.foundation -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -JERRY=$1 -CHANNEL=$2 -DEBUGGER_CLIENT=$3 -TEST_CASE=$4 -CLIENT_ARGS="" - -TERM_NORMAL='\033[0m' -TERM_RED='\033[1;31m' -TERM_GREEN='\033[1;32m' - -if [[ $TEST_CASE == *"client_source"* ]]; then - START_DEBUG_SERVER="${JERRY} --start-debug-server --debug-channel ${CHANNEL} --debugger-wait-source &" - if [[ $TEST_CASE == *"client_source_multiple"* ]]; then - CLIENT_ARGS="--client-source ${TEST_CASE}_2.js ${TEST_CASE}_1.js" - else - CLIENT_ARGS="--client-source ${TEST_CASE}.js" - fi -else - START_DEBUG_SERVER="${JERRY} ${TEST_CASE}.js --start-debug-server --debug-channel ${CHANNEL} &" -fi - -echo "$START_DEBUG_SERVER" -eval "$START_DEBUG_SERVER" -JERRY_PID=$! -sleep 1s - -RESULT_TEMP=`mktemp ${TEST_CASE}.out.XXXXXXXXXX` - -(cat "${TEST_CASE}.cmd" | ${DEBUGGER_CLIENT} --channel ${CHANNEL} --non-interactive ${CLIENT_ARGS}) >${RESULT_TEMP} 2>&1 - -if [[ $TEST_CASE == *"restart"* ]]; then - CONTINUE_CASE=$(sed "s/restart/continue/g" <<< "$TEST_CASE") - (cat "${CONTINUE_CASE}.cmd" | ${DEBUGGER_CLIENT} --channel ${CHANNEL} --non-interactive ${CLIENT_ARGS}) >>${RESULT_TEMP} 2>&1 -fi - -diff -U0 ${TEST_CASE}.expected ${RESULT_TEMP} -STATUS_CODE=$? - -rm -f ${RESULT_TEMP} - -wait $JERRY_PID -JERRY_EXIT_CODE=$? -if [ ${STATUS_CODE} -ne 0 ] || [ ${JERRY_EXIT_CODE} -gt 1 ] -then - echo -e "${TERM_RED}FAIL: ${TEST_CASE}${TERM_NORMAL}\n" -else - echo -e "${TERM_GREEN}PASS: ${TEST_CASE}${TERM_NORMAL}\n" -fi - -exit ${STATUS_CODE} diff --git a/tools/runners/run-test-suite-test262.py b/tools/runners/run-test-suite-test262.py index a03c678627..6d14c52ba9 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,14 +85,14 @@ 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, 'rb+') as exclude_file: lines = exclude_file.readlines() exclude_file.seek(0) exclude_file.truncate() # Skip the last line "" to be able to insert new failing tests. for line in lines[:-1]: - match = re.match(r" ", line) + match = re.match(r" ", line.decode('utf-8', 'ignore')) if match: test = match.group(1) if test in failing_tests: @@ -114,11 +108,12 @@ def update_exclude_list(args): if failing_tests: print("New failing tests added to the excludelist") for test in sorted(failing_tests): - exclude_file.write(' \n') + line_added = ' \n' + exclude_file.write(line_added.encode('utf-8')) print(" " + test) print("") - exclude_file.write('\n') + exclude_file.write('\n'.encode('utf-8')) if new_passing_tests: print("New passing tests removed from the excludelist") @@ -135,6 +130,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 @@ -154,7 +150,7 @@ def main(args): 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..60a0f4d504 100755 --- a/tools/runners/run-test-suite.py +++ b/tools/runners/run-test-suite.py @@ -55,7 +55,7 @@ def get_tests(test_dir, test_list, skip_list): for root, _, files in os.walk(test_dir): for test_file in files: if test_file.endswith('.js') or test_file.endswith('.mjs'): - tests.extend([os.path.join(root, test_file)]) + tests.extend([os.path.normpath(os.path.join(root, test_file))]) if test_list: dirname = os.path.dirname(test_list) @@ -64,6 +64,7 @@ def get_tests(test_dir, test_list, skip_list): tests.append(os.path.normpath(os.path.join(dirname, test.rstrip()))) tests.sort() + skip_list = [os.path.normpath(skip) for skip in skip_list] def filter_tests(test): for skipped in skip_list: @@ -78,6 +79,7 @@ def execute_test_command(test_cmd): kwargs = {} if sys.version_info.major >= 3: 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 +87,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 404e20fc20..d1ecef1bc1 100755 --- a/tools/runners/test262-harness.py +++ b/tools/runners/test262-harness.py @@ -40,6 +40,7 @@ # This code is governed by the BSD license found in the LICENSE file. +import codecs import logging import argparse import os @@ -55,6 +56,8 @@ import signal import multiprocessing +import util + ####################################################################### # based on _monkeyYaml.py ####################################################################### @@ -400,11 +403,12 @@ 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: - return file_desc.read() + with open(self.name, 'rb') as file_desc: + result = file_desc.read() + return result.decode('utf8', 'ignore') def close(self): if not self.is_closed: @@ -490,7 +494,7 @@ def __init__(self, suite, name, full_path, strict_mode, command_template, module self.name = name self.full_path = full_path self.strict_mode = strict_mode - 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: self.contents = file_desc.read() test_record = parse_test_record(self.contents, name) self.test = test_record["test"] @@ -742,7 +746,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 @@ -750,8 +754,8 @@ 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: - contents = file_desc.read() + with open(static, 'rb') as file_desc: + contents = file_desc.read().decode('utf8', 'ignore') contents = re.sub(r'\r\n', '\n', contents) self.include_cache[name] = contents + "\n" else: @@ -839,7 +843,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 = codecs.open(logname, "w", encoding='utf8', errors='ignore') # pylint: disable=consider-using-with if job_count == 1: for case in cases: @@ -901,6 +905,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..b4b23540d0 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): @@ -41,6 +51,20 @@ def set_sighdl_to_reset_timezone(timezone): assert sys.platform == 'win32', "install_signal_handler_to_restore_timezone is Windows only function" 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(): + (out_stream, err_stream) = (sys.stdout, sys.stderr) + if sys.version_info.major >= 3: + (out_stream, err_stream) = (sys.stdout.buffer, sys.stderr.buffer) + # 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)(out_stream, 'xmlcharrefreplace') + sys.stderr = codecs.getwriter(encoding)(err_stream, 'xmlcharrefreplace') + def print_test_summary(summary_string, total, passed, failed): print(f"\n[summary] {summary_string}\n") @@ -72,4 +96,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'] diff --git a/tools/settings.py b/tools/settings.py index 4b062c4d3c..d94c786d0c 100755 --- a/tools/settings.py +++ b/tools/settings.py @@ -24,7 +24,7 @@ BUILD_SCRIPT = path.join(TOOLS_DIR, 'build.py') CPPCHECK_SCRIPT = path.join(TOOLS_DIR, 'check-cppcheck.sh') DEBUGGER_CLIENT_SCRIPT = path.join(PROJECT_DIR, 'jerry-debugger/jerry_client.py') -DEBUGGER_TEST_RUNNER_SCRIPT = path.join(TOOLS_DIR, 'runners/run-debugger-test.sh') +DEBUGGER_TEST_RUNNER_SCRIPT = path.join(TOOLS_DIR, 'runners/run-debugger-test.py') DOXYGEN_SCRIPT = path.join(TOOLS_DIR, 'check-doxygen.sh') LICENSE_SCRIPT = path.join(TOOLS_DIR, 'check-license.py') STRINGS_SCRIPT = path.join(TOOLS_DIR, 'check-strings.sh')