# Copyright (c) 2014 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import json
import os
import re
import sys
import shutil
import tempfile
import unittest
sys.path.append(
os.path.join(os.path.dirname(__file__), '..', '..', 'mock'))
import mock
import vinn
def _EscapeJsString(s):
return json.dumps(s)
class VinnUnittest(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.test_data_dir = os.path.abspath(
os.path.join(os.path.dirname(__file__), 'test_data'))
def GetTestFilePath(self, file_name):
return os.path.join(self.test_data_dir, file_name)
def AssertHasNamedFrame(self, func_name, file_and_linum, exception_message):
m = re.search('at %s.+\(.*%s.*\)' % (func_name, file_and_linum),
exception_message)
if not m:
sys.stderr.write('\n=============================================\n')
msg = "Expected to find %s and %s" % (func_name, file_and_linum)
sys.stderr.write('%s\n' % msg)
sys.stderr.write('=========== Begin Exception Message =========\n')
sys.stderr.write(exception_message)
sys.stderr.write('=========== End Exception Message =========\n\n')
self.fail(msg)
def AssertHasFrame(self, file_and_linum, exception_message):
m = re.search('at .*%s.*' % file_and_linum, exception_message)
if not m:
sys.stderr.write('\n=============================================\n')
msg = "Expected to find %s" % file_and_linum
sys.stderr.write('%s\n' % msg)
sys.stderr.write('=========== Begin Exception Message =========\n')
sys.stderr.write(exception_message)
sys.stderr.write('=========== End Exception Message =========\n\n')
self.fail(msg)
def testExecuteJsStringStdoutPiping(self):
tmp_dir = tempfile.mkdtemp()
try:
temp_file_name = os.path.join(tmp_dir, 'out_file')
with open(temp_file_name, 'w') as f:
vinn.ExecuteJsString(
'print("Hello w0rld");\n', stdout=f)
with open(temp_file_name, 'r') as f:
self.assertEquals(f.read(), 'Hello w0rld\n')
finally:
shutil.rmtree(tmp_dir)
def testRunJsStringStdoutPiping(self):
tmp_dir = tempfile.mkdtemp()
try:
temp_file_name = os.path.join(tmp_dir, 'out_file')
with open(temp_file_name, 'w') as f:
vinn.RunJsString(
'print("Hello w0rld");\n', stdout=f)
with open(temp_file_name, 'r') as f:
self.assertEquals(f.read(), 'Hello w0rld\n')
finally:
shutil.rmtree(tmp_dir)
def testExecuteFileStdoutPiping(self):
file_path = self.GetTestFilePath('simple.js')
tmp_dir = tempfile.mkdtemp()
try:
temp_file_name = os.path.join(tmp_dir, 'out_file')
with open(temp_file_name, 'w') as f:
vinn.ExecuteFile(file_path, stdout=f)
with open(temp_file_name, 'r') as f:
self.assertEquals(f.read(), 'Hello W0rld from simple.js\n')
finally:
shutil.rmtree(tmp_dir)
def testRunFileStdoutPiping(self):
file_path = self.GetTestFilePath('simple.js')
tmp_dir = tempfile.mkdtemp()
try:
temp_file_name = os.path.join(tmp_dir, 'out_file')
with open(temp_file_name, 'w') as f:
vinn.RunFile(file_path, stdout=f)
with open(temp_file_name, 'r') as f:
self.assertEquals(f.read(), 'Hello W0rld from simple.js\n')
finally:
shutil.rmtree(tmp_dir)
def testSimpleJsExecution(self):
file_path = self.GetTestFilePath('print_file_content.js')
dummy_test_path = self.GetTestFilePath('dummy_test_file')
output = vinn.ExecuteFile(file_path, source_paths=[self.test_data_dir],
js_args=[dummy_test_path])
self.assertIn(
'This is file contains only data for testing.\n1 2 3 4', output)
def testDuplicateSourcePaths(self):
output = vinn.ExecuteJsString(
"HTMLImportsLoader.loadHTML('/load_simple_html.html');",
source_paths=[self.test_data_dir]*100)
self.assertIn(
'load_simple_html.html is loaded', output)
def testJsFileLoadHtmlFile(self):
file_path = self.GetTestFilePath('load_simple_html.js')
output = vinn.ExecuteFile(file_path, source_paths=[self.test_data_dir])
expected_output = ('File foo.html is loaded\n'
'x = 1\n'
"File foo.html's second script is loaded\n"
'x = 2\n'
'load_simple_html.js is loaded\n')
self.assertEquals(output, expected_output)
def testJsFileLoadJsFile(self):
file_path = self.GetTestFilePath('load_simple_js.js')
output = vinn.ExecuteFile(file_path, source_paths=[self.test_data_dir])
expected_output = ('bar.js is loaded\n'
'load_simple_js.js is loaded\n')
self.assertEquals(output, expected_output)
def testHTMLFileLoadHTMLFile(self):
file_path = self.GetTestFilePath('load_simple_html.html')
output = vinn.ExecuteFile(
file_path, source_paths=[self.test_data_dir])
expected_output = ('File foo.html is loaded\n'
'x = 1\n'
"File foo.html's second script is loaded\n"
'x = 2\n'
'bar.js is loaded\n'
'File load_simple_html.html is loaded\n')
self.assertEquals(output, expected_output)
def testQuit0Handling(self):
file_path = self.GetTestFilePath('quit_0_test.js')
res = vinn.RunFile(file_path, source_paths=[self.test_data_dir])
self.assertEquals(res.returncode, 0)
def testQuit1Handling(self):
file_path = self.GetTestFilePath('quit_1_test.js')
res = vinn.RunFile(file_path, source_paths=[self.test_data_dir])
self.assertEquals(res.returncode, 1)
def testQuit42Handling(self):
file_path = self.GetTestFilePath('quit_42_test.js')
res = vinn.RunFile(file_path, source_paths=[self.test_data_dir])
self.assertEquals(res.returncode, 42)
def testQuit274Handling(self):
file_path = self.GetTestFilePath('quit_274_test.js')
res = vinn.RunFile(file_path, source_paths=[self.test_data_dir])
self.assertEquals(res.returncode, 238)
def testErrorStackTraceJs(self):
file_path = self.GetTestFilePath('error_stack_test.js')
# error_stack_test.js imports load_simple_html.html
# load_simple_html.html imports foo.html
# foo.html imports error.js
# error.js defines maybeRaiseException() method that can raise exception
# foo.html defines maybeRaiseExceptionInFoo() method that calls
# maybeRaiseException()
# Finally, we call maybeRaiseExceptionInFoo() error_stack_test.js
# Exception log should capture these method calls' stack trace.
with self.assertRaises(RuntimeError) as context:
vinn.ExecuteFile(file_path, source_paths=[self.test_data_dir])
# Assert error stack trace contain src files' info.
exception_message = context.exception.message
self.assertIn(
('error.js:7: Error: Throw ERROR\n'
" throw new Error('Throw ERROR');"), exception_message)
self.AssertHasNamedFrame('maybeRaiseException', 'error.js:7',
exception_message)
self.AssertHasNamedFrame('global.maybeRaiseExceptionInFoo', 'foo.html:34',
exception_message)
self.AssertHasFrame('error_stack_test.js:14', exception_message)
def testErrorStackTraceHTML(self):
file_path = self.GetTestFilePath('error_stack_test.html')
# error_stack_test.html imports error_stack_test.js
# error_stack_test.js imports load_simple_html.html
# load_simple_html.html imports foo.html
# foo.html imports error.js
# error.js defines maybeRaiseException() method that can raise exception
# foo.html defines maybeRaiseExceptionInFoo() method that calls
# maybeRaiseException()
# Finally, we call maybeRaiseExceptionInFoo() error_stack_test.js
# Exception log should capture these method calls' stack trace.
with self.assertRaises(RuntimeError) as context:
vinn.ExecuteFile(file_path, source_paths=[self.test_data_dir])
# Assert error stack trace contain src files' info.
exception_message = context.exception.message
self.assertIn(
('error.js:7: Error: Throw ERROR\n'
" throw new Error('Throw ERROR');"), exception_message)
self.AssertHasNamedFrame('maybeRaiseException', 'error.js:7',
exception_message)
self.AssertHasNamedFrame('global.maybeRaiseExceptionInFoo', 'foo.html:34',
exception_message)
self.AssertHasFrame('error_stack_test.js:14', exception_message)
self.AssertHasNamedFrame('eval', 'error_stack_test.html:22',
exception_message)
def testStackTraceOfErroWhenLoadingHTML(self):
file_path = self.GetTestFilePath('load_error.html')
with self.assertRaises(RuntimeError) as context:
vinn.ExecuteFile(file_path, source_paths=[self.test_data_dir])
# Assert error stack trace contain src files' info.
exception_message = context.exception.message
self.assertIn('Error: /does_not_exist.html not found', exception_message)
self.AssertHasNamedFrame('eval', 'load_error_2.html:21', exception_message)
self.AssertHasNamedFrame('eval', 'load_error.html:23', exception_message)
def testStackTraceOfErroWhenSyntaxErrorOccurs(self):
file_path = self.GetTestFilePath('syntax_error.html')
with self.assertRaises(RuntimeError) as context:
vinn.ExecuteFile(file_path, source_paths=[self.test_data_dir])
# Assert error stack trace contain src files' info.
exception_message = context.exception.message
self.assertIn('syntax_error.html:23: SyntaxError: Unexpected identifier',
exception_message)
def testStackTraceOfErroWhenLoadingJS(self):
file_path = self.GetTestFilePath('load_js_error.html')
with self.assertRaises(RuntimeError) as context:
vinn.ExecuteFile(file_path, source_paths=[self.test_data_dir])
# Assert error stack trace contain src files' info.
exception_message = context.exception.message
self.assertIn('Error: /does_not_exist.js not found', exception_message)
self.AssertHasNamedFrame('eval', 'load_js_error_2.html:20',
exception_message)
self.AssertHasNamedFrame('eval', 'load_js_error.html:22',
exception_message)
def testStrictError(self):
file_path = self.GetTestFilePath('non_strict_error.html')
with self.assertRaises(RuntimeError) as context:
vinn.ExecuteFile(file_path, source_paths=[self.test_data_dir])
# Assert error stack trace contain src files' info.
exception_message = context.exception.message
self.assertIn('non_defined_variable is not defined', exception_message)
self.AssertHasNamedFrame('eval', 'non_strict_error.html:17',
exception_message)
def testConsolePolyfill(self):
self.assertEquals(
vinn.ExecuteJsString('console.log("hello", "world");'),
'hello world\n')
self.assertEquals(
vinn.ExecuteJsString('console.info("hello", "world");'),
'Info: hello world\n')
self.assertEquals(
vinn.ExecuteJsString('console.warn("hello", "world");'),
'Warning: hello world\n')
self.assertEquals(
vinn.ExecuteJsString('console.error("hello", "world");'),
'Error: hello world\n')
def testConsoleTimeEndAssertion(self):
file_path = self.GetTestFilePath('console_time_test.js')
try:
vinn.ExecuteFile(file_path)
except RuntimeError:
self.fail()
def testConsoleTime(self):
self.assertEquals(
vinn.ExecuteJsString('console.time("AA")'),
'')
def testConsoleTimeEndOutput(self):
output = vinn.ExecuteJsString('console.time("AA");console.timeEnd("AA")')
m = re.search('\d+\.\d+', output)
if not m:
sys.stderr.write('\nExpected to find output of timer AA')
self.fail()
a_duration = float(m.group())
self.assertTrue(a_duration > 0.0)
output = vinn.ExecuteJsString("""console.time("BB");
console.time("CC");
console.timeEnd("CC");
console.timeEnd("BB")""")
m = re.findall('(\d+\.\d+)', output)
if not m:
sys.stderr.write('\nExpected to find output of timer\n')
self.fail()
c_duration = float(m[0])
b_duration = float(m[1])
self.assertTrue(b_duration > c_duration)
class PathUtilUnittest(unittest.TestCase):
def testPathUtil(self):
path_util_js_test = os.path.abspath(os.path.join(
os.path.dirname(__file__), 'path_utils_test.js'))
path_utils_js_dir = os.path.abspath(
os.path.join(os.path.dirname(__file__), 'path_utils.js'))
test_loading_js = """
load(%s);
load(%s);
runTests();
""" % (_EscapeJsString(path_utils_js_dir),
_EscapeJsString(path_util_js_test))
res = vinn.RunJsString(test_loading_js)
self.assertEquals(res.returncode, 0)
def _GetLineNumberOfSubstring(content, substring):
""" Return the line number of |substring| in |content|."""
index = content.index(substring)
return content[:index].count('\n') + 1
def _GenerateLineByLineDiff(actual, expected):
results = []
expected_lines = expected.split('\n')
actual_lines = actual.split('\n')
max_num_lines = max(len(expected_lines), len(actual_lines))
results.append('**Actual : num lines = %i' % len(actual_lines))
results.append('**Expected : num lines = %i' % len(expected_lines))
for i in xrange(0, max_num_lines):
expected_current_line = expected_lines[i] if i < len(expected_lines) else ''
actual_current_line = actual_lines[i] if i < len(actual_lines) else ''
if actual_current_line == expected_current_line:
continue
results.append('================= Line %s ======================' % (i + 1))
results.append('**Actual : %s' % repr(actual_current_line))
results.append('**Expected : %s' % repr(expected_current_line))
return '\n'.join(results)
class HTMLGeneratorTest(unittest.TestCase):
def AssertStringEquals(self, actual, expected):
if actual != expected:
message = 'Expected %s but got %s.\n' % (repr(expected), repr(actual))
message += _GenerateLineByLineDiff(actual, expected)
self.fail(message)
def GetGeneratedJs(self, html_text):
tmp_dir = tempfile.mkdtemp()
try:
temp_file_name = os.path.join(tmp_dir, 'test.html')
with open(temp_file_name, 'w') as f:
f.write(html_text)
return vinn.ExecuteJsString(
'write(generateJsFromHTML(read(%s)));' %
_EscapeJsString(temp_file_name))
finally:
shutil.rmtree(tmp_dir)
def testGenerateJsForD8RunnerSimpleHTMLImport(self):
html = ''
expected_js = "global.HTMLImportsLoader.loadHTML('/base/math.html');"
self.AssertStringEquals(self.GetGeneratedJs(html), expected_js)
def testGenerateJSForD8RunnerImportMultilineHTMLImport(self):
html = """
"""
expected_js = "\nglobal.HTMLImportsLoader.loadHTML('/base/math.html');"
self.AssertStringEquals(self.GetGeneratedJs(html),
expected_js)
def testGenerateJsForD8RunnerImportSimpleScriptWithSrc(self):
html = ''
expected_js = "global.HTMLImportsLoader.loadScript('/base/math.js');"
self.AssertStringEquals(self.GetGeneratedJs(html),
expected_js)
def testGenerateJsForD8RunnerImportMultilineScriptWithSrc(self):
html = """"""
expected_js = """global.HTMLImportsLoader.loadScript('/base/math.js');
"""
self.AssertStringEquals(self.GetGeneratedJs(html),
expected_js)
def testGenerateJsForD8RunnerWithMixedMultipleImport(self):
html = """
"""
expected_js = ("""
global.HTMLImportsLoader.loadHTML('/base.html');global.HTMLImportsLoader.loadHTML('/base64.html');
global.HTMLImportsLoader.loadHTML('/base/math.html');
global.HTMLImportsLoader.loadScript('/base/3d.js');
""" + """
global.HTMLImportsLoader.loadScript('/base/math.js');
global.HTMLImportsLoader.loadHTML('/base/random.html');""")
self.AssertStringEquals(self.GetGeneratedJs(html),
expected_js)
def testGenerateJsForD8RunnerImportWithSimpleContent(self):
html = """
"""
expected_js = """
var html_lines = [
'
"""
expected_js = """
var s = ("<") + "<\/script>";
var x = 100;
"""
self.AssertStringEquals(self.GetGeneratedJs(html),
expected_js)
def testGenerateJsForD8RunnerImportWithSrcAndSimpleContent(self):
html = """
"""
expected_js = """global.HTMLImportsLoader.loadScript('/base.js');
var html_lines = [
'
"""
expected_js = """
global.HTMLImportsLoader.loadHTML('/base/math.html');var x = 1;
global.HTMLImportsLoader.loadScript('/base/computer.js');
var linux = os.system; // line number of this is 9
""" + """
global.HTMLImportsLoader.loadHTML('/base/physics.html');
var html_lines = [
'