def test_inter_library_dependencies_ordering(): lib1 = Library('lib1', '') lib2 = Library('lib2', '') lib3 = Library('lib3', '') lib4 = Library('lib4', '') js1 = Resource(lib1, 'js1.js') js2 = Resource(lib2, 'js2.js', depends=[js1]) js3 = Resource(lib3, 'js3.js', depends=[js2]) style1 = Resource(lib3, 'style1.css') style2 = Resource(lib4, 'style2.css', depends=[style1]) needed = init_needed(resources=[js3, style2]) assert sort_resources(needed.resources()) == \ [style1, style2, js1, js2, js3]
def test_cannot_add_dependency_loop(): foo = Library('foo', '') a1 = Resource(foo, 'a1.js') b1 = Resource(foo, 'b1.js', depends=[a1]) with pytest.raises(ValueError): a1.add_dependency(b1)
def test_sort_resources_library_sorting_by_name(): # these libraries are all at the same level so should be sorted by name X = Library('X', '') Y = Library('Y', '') Z = Library('Z', '') a = Resource(X, 'a.js') b = Resource(Y, 'b.js') c = Resource(Z, 'c.js') needed = init_needed() needed.need(a) needed.need(b) needed.need(c) assert sort_resources(needed.resources()) == [a, b, c]
def test_bundle_single_entry(): # we can successfully bundle a single resource (it's not bundled though) foo = Library('foo', '') a = Resource(foo, 'a.js') resources = bundle_resources([a]) assert resources == [a]
def test_rendering_base_url(): foo = Library('foo', '') x1 = Resource(foo, 'a.js') x2 = Resource(foo, 'b.css') y1 = Resource(foo, 'c.js', depends=[x1, x2]) needed = init_needed(resources=[y1]) incl = Inclusion(needed) assert incl.render() == '''\ <link rel="stylesheet" type="text/css" href="/fanstatic/foo/b.css" /> <script type="text/javascript" src="/fanstatic/foo/a.js"></script> <script type="text/javascript" src="/fanstatic/foo/c.js"></script>''' needed = init_needed(base_url='http://localhost/static', resources=[y1]) incl = Inclusion(needed) assert incl.render() == '''\ <link rel="stylesheet" type="text/css" href="http://localhost/static/fanstatic/foo/b.css" /> <script type="text/javascript" src="http://localhost/static/fanstatic/foo/a.js"></script> <script type="text/javascript" src="http://localhost/static/fanstatic/foo/c.js"></script>''' # The base_url has been set. assert needed.has_base_url() needed.set_base_url('foo') # The base_url can only be set once. assert needed._base_url == 'http://localhost/static'
def test_delegator(tmpdir): foo_library_dir = tmpdir.mkdir('foo') resource = tmpdir.join('foo').join('test.js') resource.write('/* a test */') libraries = LibraryRegistry([Library('foo', foo_library_dir.strpath)]) publisher = Publisher(libraries) def real_app(environ, start_response): start_response('200 OK', []) return ['Hello world!'] delegator = Delegator(real_app, publisher) request = webob.Request.blank('/fanstatic/foo/test.js') response = request.get_response(delegator) assert response.body == '/* a test */' # A deeper fanstatic. request = webob.Request.blank('/foo/bar/fanstatic/foo/test.js') response = request.get_response(delegator) assert response.body == '/* a test */' request = webob.Request.blank('/somethingelse') response = request.get_response(delegator) assert response.body == 'Hello world!'
def test_delegator(tmpdir): foo_library_dir = tmpdir.mkdir('foo') resource = tmpdir.join('foo').join('test.js') resource.write('/* a test */') libraries = LibraryRegistry([Library('foo', foo_library_dir.strpath)]) publisher = Publisher(libraries) def real_app(environ, start_response): start_response('200 OK', [('Content-Type', 'text/html')]) return ['Hello world!'] delegator = Delegator(real_app, publisher) request = webob.Request.blank('/fanstatic/foo/test.js') response = request.get_response(delegator) assert response.body == b'/* a test */' assert response.content_type == 'text/javascript' # A deeper fanstatic. request = webob.Request.blank('/foo/bar/fanstatic/foo/test.js') response = request.get_response(delegator) assert response.body == b'/* a test */' assert response.content_type == 'text/javascript' request = webob.Request.blank('/somethingelse') response = request.get_response(delegator) assert response.body == 'Hello world!' # Default content type from WebOb assert response.content_type == 'text/html'
def test_rollup(): foo = Library('foo', '') b1 = Resource(foo, 'b1.js') b2 = Resource(foo, 'b2.js') giant = Resource(foo, 'giant.js', supersedes=[b1, b2]) assert rollup_resources([b1, b2]) == set([giant])
def test_logging_when_compiling(tmpdir, compilers, caplog): caplog.set_level(logging.INFO, logger='fanstatic') class WhiteSpaceRemover(fanstatic.compiler.Compiler): """A silly minifier, to showcase logging.""" name = 'whitespace' source_extension = '.frop' def process(self, source, target): with open(target, 'wb') as output: output.write( compat.as_bytestring( open(source, 'r').read().replace(' ', ''))) compilers.add_compiler(WhiteSpaceRemover()) lib = Library('lib', str(tmpdir)) tmpdir.join('a.frop').write(' foo bar baz ') a = Resource(lib, 'a.js', compiler='whitespace') assert len(caplog.records) == 0 a.compile() assert len(caplog.records) == 1 assert "Compiling <Resource 'a.js' in library 'lib'> in" in caplog.text # The 'compiler' really worked! assert tmpdir.join('a.js').read() == 'foobarbaz'
def test_resource_name_conflict_raises_error(compilers): compilers.add_minifier(MockMinifier()) lib = Library('lib', '', minifiers={'.js': 'mock'}) a = Resource(lib, 'a.js') with pytest.raises(fanstatic.ConfigurationError) as exc: Resource(lib, 'a.min.js') assert str(exc.value) == 'Resource path a.min.js is already defined.'
def test_add_dependency_resource_to_group(): foo = Library('foo', '') a1 = Resource(foo, 'a1.js') b1 = Group([a1]) c1 = Resource(foo, 'c1.js', depends=[b1]) assert a1.depends == set([]) assert a1.resources == set([a1]) assert b1.depends == set([a1]) assert b1.resources == set([a1]) assert c1.depends == set([b1]) assert c1.resources == set([a1, c1]) a2 = Resource(foo, 'a2.js') b1.add_dependency(a2) assert b1.depends == set([a1, a2]) assert b1.resources == set([a1, a2]) assert c1.depends == set([b1]) assert c1.resources == set([a1, a2, c1]) # Adding it twice does not change anything. b1.add_dependency(a2) assert b1.depends == set([a1, a2]) assert b1.resources == set([a1, a2]) assert c1.depends == set([b1]) assert c1.resources == set([a1, a2, c1])
def test_mode_fully_specified(): foo = Library('foo', '') k_debug = Resource(foo, 'k-debug.js') k = Resource(foo, 'k.js', debug=k_debug) x = Resource(foo, 'x.js', minified='x-min.js') needed = init_needed() needed.need(k) incl = Inclusion(needed) assert incl.resources == [k] incl = Inclusion(needed, mode='debug') assert incl.resources == [k_debug] # If no minified can be found, the 'raw' resource is taken. incl = Inclusion(needed, mode='minified') assert incl.resources == [k] # If only a minified resource is defined, debug returns the raw version. needed = init_needed() needed.need(x) incl = Inclusion(needed, mode='debug') assert incl.resources == [x] incl = Inclusion(needed, mode='minified') assert incl.resources == [x.modes['minified']]
def test_slot_with_default_uses_default_if_nothing_given_in_need(): lib = Library('lib', '') default_resource_for_slot = Resource(lib, 'b.js') slot = Slot(lib, '.js', default=default_resource_for_slot) a = Resource(lib, 'a.js', depends=[slot]) needed = init_needed(resources=[a]) relpaths = [r.relpath for r in sort_resources(needed.resources())] assert relpaths == ['b.js', 'a.js']
def test_no_need_to_fill_in_not_required(): lib = Library('lib', '') slot = Slot(lib, '.js', required=False) a = Resource(lib, 'a.js', depends=[slot]) needed = init_needed(resources=[a]) # slot wasn't required and not filled in, so filled slot doesn't show up assert needed.resources() == set([a])
def test_compile_only_for_libraries_under_development(compilers): compilers.add_compiler(MockCompiler()) lib = Library('lib', '') a = Resource(lib, 'a.js', compiler='mock') needed = init_needed(resources=[a]) incl = Inclusion(needed, compile=True) assert len(compilers.compiler('mock').calls) == 1 # Gathering all resources again will add a call. incl = Inclusion(needed, compile=True) assert len(compilers.compiler('mock').calls) == 2 lib.version = 1 incl = Inclusion(needed, compile=True) assert len(compilers.compiler('mock').calls) == 2
def test_minifier_available_and_minified_file_not_present_should_not_raise( tmpdir, compilers): open(str(tmpdir / 'a.js'), 'w').close() compilers.add_minifier(MockMinifier()) set_resource_file_existence_checking(True) lib = Library('lib', str(tmpdir)) # assert_nothing_raised a = Resource(lib, 'a.js', minifier='mock')
def test_do_add_library_after_register(): set_auto_register_library(False) library_registry = get_library_registry() bar = Library('bar', '') assert 'bar' not in library_registry library_registry.add(bar) assert 'bar' in library_registry library_registry.prepare() foo = Library('foo', '') with pytest.raises(ValueError): library_registry.add(foo)
def test_compiler_available_and_source_not_present_should_raise( tmpdir, compilers): compilers.add_compiler(MockCompiler()) set_resource_file_existence_checking(True) lib = Library('lib', str(tmpdir)) with pytest.raises(fanstatic.UnknownResourceError) as exc: a = Resource(lib, 'a.js', compiler='mock') assert 'a.source' in str(exc.value)
def test_html_insert_head_with_attributes(): # ticket 72: .need() broken when <head> tag has attributes foo = Library('foo', '') x1 = Resource(foo, 'a.js') needed = NeededResources(resources=[x1]) html = '<html><head profile="http://example.org">something</head></html>' assert needed.render_into_html(html) == '''\
def test_generate_source(): foo = Library('foo', '') i1 = Resource(foo, 'i1.js') i2 = Resource(foo, 'i2.js', depends=[i1]) i3 = Resource(foo, 'i3.js', depends=[i2]) i5 = Resource(foo, 'i5.js', depends=[i3]) assert generate_code(i1=i1, i2=i2, i3=i3, i5=i5) == '''\
def test_empty_base_url_and_publisher_signature(): ''' When the base_url is not set and the publisher_signature is an empty string, render a URL without them. ''' foo = Library('foo', '') x1 = Resource(foo, 'a.js') needed = init_needed(publisher_signature='', resources=[x1]) incl = Inclusion(needed) assert incl.render() == '''\
def test_library_url_script_name_base_url(): foo = Library('foo', '') needed = NeededResources(script_name='/root', base_url="http://example.com/something") # base_url is set so script_name should be ignored assert (needed.library_url(foo) == 'http://example.com/something/fanstatic/foo')
def test_bundle_resources(): foo = Library('foo', '') x1 = Resource(foo, 'a.css') x2 = Resource(foo, 'b.css') bundle = bundle_resources([x1, x2]) assert len(bundle) == 1 assert isinstance(bundle[0], Bundle) x3 = Resource(foo, 'c.css', dont_bundle=True) # x3 is not bundle safe. bundle = bundle_resources([x1, x3]) assert len(bundle) == 2 # We don't create bundles of one element. assert bundle[0] == x1 assert bundle[1] == x3 # x2 and x1 are not bundled because x3 is in the way. # (sort_resources in NeededResources fixes the sorting) bundle = bundle_resources([x1, x3, x2]) assert bundle == [x1, x3, x2] # XXX sort_resources does not take care of this for us: needed = NeededResources(bundle=True) needed.need(x1) needed.need(x3) needed.need(x2) # The resources are sorted by renderer order, library dependencies # and resource dependencies. bundle = bundle_resources(needed.resources()) assert len(bundle) == 2 assert isinstance(bundle[0], Bundle) assert bundle[1] == x3 bar = Library('bar', '') y1 = Resource(bar, 'y1.css') y2 = Resource(bar, 'y2.css') bundle = bundle_resources([x1, x2, y1, y2]) assert len(bundle) == 2 y3 = Resource(bar, 'subdir/y3.css') y4 = Resource(bar, 'subdir/y4.css') bundle = bundle_resources([y1, y2, y3, y4]) assert len(bundle) == 2
def test_compile_only_for_libraries_under_development( compilers): compilers.add_compiler(MockCompiler()) lib = Library('lib', '') a = Resource(lib, 'a.js', compiler='mock') needed = NeededResources(resources=[a]) incl = Inclusion(needed, compile=True) assert len(compilers.compiler('mock').calls) == 1 # Gathering all resources again will add a call. incl = Inclusion(needed, compile=True) assert len(compilers.compiler('mock').calls) == 2 lib.version = 1 incl = Inclusion(needed, compile=True) assert len(compilers.compiler('mock').calls) == 2
def test_html_insert_head_with_attributes(): # ticket 72: .need() broken when <head> tag has attributes foo = Library('foo', '') x1 = Resource(foo, 'a.js') needed = init_needed(resources=[x1]) injector = TopBottomInjector({}) html = b'<html><head profile="http://example.org">something</head></html>' assert injector(html, needed) == b'''\
def test_sort_group_per_library(): foo = Library('foo', '') bar = Library('bar', '') e = Resource(foo, 'e.js') d = Resource(foo, 'd.js', depends=[e]) c = Resource(bar, 'c.js', depends=[e]) b = Resource(bar, 'b.js') a = Resource(bar, 'a.js', depends=[c]) needed = NeededResources() needed.need(a) needed.need(b) needed.need(c) needed.need(d) needed.need(e) assert needed.resources() == [e, d, b, c, a]
def test_empty_base_url_and_publisher_signature(): ''' When the base_url is not set and the publisher_signature is an empty string, render a URL without them. ''' foo = Library('foo', '') x1 = Resource(foo, 'a.js') needed = NeededResources(publisher_signature='') needed.need(x1) assert needed.render() == '''\
def test_rollup_without_mode(): foo = Library('foo', '') h1 = Resource(foo, 'h1.js', debug='h1-debug.js') h2 = Resource(foo, 'h2.js', debug='h2-debug.js') gianth = Resource(foo, 'gianth.js', supersedes=[h1, h2]) needed = NeededResources(resources=[h1, h2], rollup=True, debug=True) # no mode available for rollup, use the rollup. assert needed.resources() == [gianth]
def test_bundle_single_dont_bundle_entry(): foo = Library('foo', '') a = Resource(foo, 'a.js', dont_bundle=True) needed = NeededResources(bundle=True) needed.need(a) resources = needed.resources() assert resources == [a]
def test_sort_resources_topological(): foo = Library('foo', '') a1 = Resource(foo, 'a1.js') a2 = Resource(foo, 'a2.js', depends=[a1]) a3 = Resource(foo, 'a3.js', depends=[a2]) a5 = Resource(foo, 'a5.js', depends=[a3]) assert sort_resources_topological([a5, a3, a1, a2]) == [a1, a2, a3, a5]
def test_rollup_size_competing(): foo = Library('foo', '') d1 = Resource(foo, 'd1.js') d2 = Resource(foo, 'd2.js') d3 = Resource(foo, 'd3.js') giant = Resource(foo, 'giant.js', supersedes=[d1, d2]) giant_bigger = Resource(foo, 'giant-bigger.js', supersedes=[d1, d2, d3]) assert rollup_resources([d1, d2, d3]) == set([giant_bigger])
def test_library_nr(): X = Library('X', '') Y = Library('Y', '') Z = Library('Z', '') # only X and Z will be at the same level now a = Resource(X, 'a.js') c = Resource(Z, 'c.js') b = Resource(Y, 'b.js', depends=[a, c]) X.init_library_nr() Y.init_library_nr() Z.init_library_nr() assert a.library.library_nr == 0 assert c.library.library_nr == 0 assert b.library.library_nr == 1
from fanstatic import Resource, Group, Library library = Library('dummy', '.') library.need = lambda: 'No, sorry, that is a Library.' resource = Resource(library, 'fanstatic_dummy_resource.css') resource.need = lambda: 'needed resource' group = Group([resource]) group.need = lambda: 'needed group'