普通文本  |  307行  |  9.91 KB

#!/usr/bin/env python
# Copyright (c) 2012 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 unittest

import parse_deps
import os

srcdir = os.path.join(os.path.dirname(__file__), '../src')

class JSStripTests(unittest.TestCase):
  def test_tokenize_0(self):
    tokens = list(parse_deps._tokenize_js(''))
    self.assertEquals([], tokens)

  def test_tokenize_nl(self):
    tokens = list(parse_deps._tokenize_js('\n'))
    self.assertEquals(['\n'], tokens)

  def test_tokenize_slashslash_comment(self):
    tokens = list(parse_deps._tokenize_js('A // foo'))
    self.assertEquals(['A ', '//', ' foo'], tokens)

  def test_tokenize_slashslash_comment_then_newline2(self):
    tokens = list(parse_deps._tokenize_js("""A // foo
bar"""
))
    self.assertEquals(['A ', '//', ' foo', '\n', 'bar'], tokens)

  def test_tokenize_cstyle_comment(self):
    tokens = list(parse_deps._tokenize_js("""A /* foo */"""))
    self.assertEquals(['A ', '/*', ' foo ', '*/'], tokens)

  def test_tokenize_cstyle_comment(self):
    tokens = list(parse_deps._tokenize_js("""A /* foo
*bar
*/"""))
    self.assertEquals(['A ', '/*', ' foo', '\n', '*bar', '\n', '*/'], tokens)

  def test_strip_comments(self):
    self.assertEquals('A ', parse_deps._strip_js_comments('A // foo'))

    self.assertEquals('A  b', parse_deps._strip_js_comments('A /* foo */ b'))
    self.assertEquals('A  b', parse_deps._strip_js_comments("""A /* foo
 */ b"""))


class ValidateTests(unittest.TestCase):
  def test_validate_1(self):
    text = """// blahblahblah

'use strict';

base.require('dependency1');
"""
    module = parse_deps.Module('myModule')
    stripped_text = parse_deps._strip_js_comments(text)
    module.validate_uses_strict_mode_(stripped_text)

  def test_validate_2(self):
    text = """// blahblahblah

base.require('dependency1');
"""
    module = parse_deps.Module('myModule')
    stripped_text = parse_deps._strip_js_comments(text)
    self.assertRaises(lambda: module.validate_uses_strict_mode_(stripped_text))

class ParseTests(unittest.TestCase):
  def test_parse_definition_1(self):
    text = """// blahblahblah
'use strict';
base.require('dependency1');
base.require('dependency2');
base.requireStylesheet('myStylesheet');
"""
    module = parse_deps.Module('myModule')
    stripped_text = parse_deps._strip_js_comments(text)
    module.parse_definition_(stripped_text)
    self.assertEquals(['myStylesheet'], module.style_sheet_names);
    self.assertEquals(['dependency1', 'dependency2'],
                      module.dependent_module_names);

  def test_parse_definition_missing_semis(self):
    text = """// blahblahblah
'use strict';
base.require('dependency1')
base.require('dependency2');
base.requireStylesheet('myStylesheet')
"""
    module = parse_deps.Module('myModule')
    stripped_text = parse_deps._strip_js_comments(text)
    module.parse_definition_(stripped_text)
    self.assertEquals(['myStylesheet'], module.style_sheet_names);
    self.assertEquals(['dependency1', 'dependency2'],
                      module.dependent_module_names);

  def test_parse_definition_with_deps_and_stylesheet_swapped(self):
    text = """// blahblahblah
'use strict';
base.require('dependency1');
base.requireStylesheet('myStylesheet');
base.require('dependency2');
"""
    module = parse_deps.Module('myModule')
    stripped_text = parse_deps._strip_js_comments(text)
    module.parse_definition_(stripped_text)
    self.assertEquals(['myStylesheet'], module.style_sheet_names);
    self.assertEquals(['dependency1', 'dependency2'],
                      module.dependent_module_names);

  def test_parse_empty_definition(self):
    text = """// blahblahblah
'use strict';
"""
    module = parse_deps.Module('myModule')
    stripped_text = parse_deps._strip_js_comments(text)
    module.parse_definition_(stripped_text, decl_required=False)
    self.assertEquals([], module.style_sheet_names);
    self.assertEquals([], module.dependent_module_names);

  def test_parse_definition_3(self):
    text = """// blahblahblah
'use strict';
base.require('dependency1');
//base.require('dependency2');
"""
    module = parse_deps.Module('myModule')
    stripped_text = parse_deps._strip_js_comments(text)
    module.parse_definition_(stripped_text)
    self.assertEquals([], module.style_sheet_names);
    self.assertEquals(['dependency1'], module.dependent_module_names);

  def test_parse_definition_4(self):
    text = """// Copyright (c) 2012 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.

'use strict';

/**
 * @fileoverview TimelineView visualizes TRACE_EVENT events using the
 * tracing.TimelineTrackView component and adds in selection summary and
 * control buttons.
 */
base.requireStylesheet('timeline_view')
base.require('timeline_track_view');
base.require('timeline_analysis');
base.require('overlay');
base.require('trace_event_importer');
base.require('linux_perf_importer');
base.exportsTo('tracing', function() {"""

    module = parse_deps.Module('timeline_view')
    stripped_text = parse_deps._strip_js_comments(text)
    module.parse_definition_(stripped_text)
    self.assertEquals(['timeline_view'], module.style_sheet_names);
    self.assertEquals(['timeline_track_view',
                       'timeline_analysis',
                       'overlay',
                       'trace_event_importer',
                       'linux_perf_importer'], module.dependent_module_names);

  def test_parse_definition_with_definition_in_comments(self):
    text = """// SomeComment
/*
 * All subclasses should depend on linux_perf_parser, e.g.
 *
 * base.require('linux_perf_parser');
 * base.exportTo('tracing', function() { });
 *
 */
'use strict';
base.require('dependency1');
base.require('dependency2');
"""
    module = parse_deps.Module('myModule')
    stripped_text = parse_deps._strip_js_comments(text)
    module.parse_definition_(stripped_text)
    self.assertEquals([], module.style_sheet_names);
    self.assertEquals(['dependency1', 'dependency2'],
                      module.dependent_module_names);

  def test_parse_dependency_with_slashes(self):
    text = """base.require('foo/dependency1')
"""
    module = parse_deps.Module('myModule')
    self.assertRaises(parse_deps.DepsException,
                      lambda: module.parse_definition_(text))

  def test_parse_dependency_with_dots(self):
    text = """base.require('foo.dependency1')
"""
    module = parse_deps.Module('myModule')
    stripped_text = parse_deps._strip_js_comments(text)
    module.parse_definition_(stripped_text)
    self.assertEquals([], module.style_sheet_names);
    self.assertEquals(['foo.dependency1'],
                      module.dependent_module_names);


class ResourceFinderStub(object):
  def __init__(self):
    self.modules = {}

  def add_module(self, name, filename, contents):
    module = {'filename': filename,
              'contents': contents}
    self.modules[name] = module

  def find_and_load_module(self, current_module, requested_module_name):
    if requested_module_name not in self.modules:
      return None
    return (self.modules[requested_module_name]['filename'],
            self.modules[requested_module_name]['contents'])


x_contents = """
'use strict';
base.require('y');
base.require('z');
base.exportTo('xyz', function() { });
"""

y_contents = """
'use strict';
base.require('z');
base.exportsTo('xyz', function() { });
"""

z_contents = """
'use strict';
base.exportsTo('xyz', function() { });
"""

class FlattenTests(unittest.TestCase):
  def test_module(self):
    resource_finder = ResourceFinderStub()
    resource_finder.add_module('y', 'y.js', y_contents);
    resource_finder.add_module('z', 'z.js', z_contents);

    x_module = parse_deps.Module('x')
    x_module.load_and_parse('x.js', x_contents)

    all_resources = {}
    x_module.resolve(all_resources, resource_finder)

    self.assertEquals([all_resources['scripts']['y'],
                       all_resources['scripts']['z']],
                      x_module.dependent_modules)

    already_loaded_set = set()
    load_sequence = []
    x_module.compute_load_sequence_recursive(load_sequence, already_loaded_set)

    self.assertEquals([all_resources['scripts']['z'],
                       all_resources['scripts']['y'],
                       x_module],
                      load_sequence)


class ResourceFinderTest(unittest.TestCase):
  def test_basic(self):

    resource_finder = parse_deps.ResourceFinder(srcdir)
    module = parse_deps.Module('guid')
    module.load_and_parse(os.path.join(srcdir, 'base', 'guid.js'))
    filename, contents = resource_finder.find_and_load_module(module, 'base')

    self.assertTrue(os.path.samefile(filename, os.path.join(srcdir, 'base.js')))
    expected_contents = ''
    with open(os.path.join(srcdir, 'base.js')) as f:
      expected_contents = f.read()
    self.assertEquals(contents, expected_contents)

  def test_dependency_in_subdir(self):
    resource_finder = parse_deps.ResourceFinder(srcdir)
    module = parse_deps.Module('base.guid')
    module.load_and_parse(os.path.join(srcdir, 'base', 'guid.js'))
    filename, contents = resource_finder.find_and_load_module(
        module, 'tracing.tracks.track')

    assert filename

    self.assertTrue(os.path.samefile(filename, os.path.join(
      srcdir, 'tracing', 'tracks', 'track.js')))
    expected_contents = ''
    with open(os.path.join(srcdir, 'tracing', 'tracks', 'track.js')) as f:
      expected_contents = f.read()
    self.assertEquals(contents, expected_contents)


class CalcLoadSequenceTest(unittest.TestCase):
  def test_one_toplevel_nodeps(self):
    load_sequence = parse_deps.calc_load_sequence(
      [os.path.join(srcdir, 'base', 'guid.js')], srcdir)
    name_sequence = [x.name for x in load_sequence]
    self.assertEquals(['base.guid'], name_sequence)

  # Tests that we resolve deps between toplevels.
  def test_calc_load_sequence_two_toplevels(self):
    pass

if __name__ == '__main__':
  unittest.main()