示例#1
0
def test_lock_one_change(mocker, tmpworkdir):
    yml = """\
    download_root: droot
    download:
      'http://wherever.com/file.js': file.js
      'http://wherever.com/file2.js': file2.js"""
    mktree(tmpworkdir, {'grablib.yml': yml})
    mock_requests_get = mocker.patch('grablib.download.requests.Session.get')
    mock_requests_get.return_value = MockResponse()
    Grab().download()
    assert mock_requests_get.call_count == 2
    assert gettree(tmpworkdir, max_len=None) == {
        'grablib.yml': yml,
        'droot': {'file.js': 'response text', 'file2.js': 'response text'},
        '.grablib.lock': """\
b5a3344a4b3651ebd60a1e15309d737c http://wherever.com/file.js file.js
b5a3344a4b3651ebd60a1e15309d737c http://wherever.com/file2.js file2.js\n"""
    }
    tmpworkdir.join('droot/file.js').remove()
    print('##################')
    Grab().download()
    assert mock_requests_get.call_count == 3
    assert gettree(tmpworkdir, max_len=None) == {
        'grablib.yml': yml,
        'droot': {'file.js': 'response text', 'file2.js': 'response text'},
        '.grablib.lock': """\
b5a3344a4b3651ebd60a1e15309d737c http://wherever.com/file.js file.js
b5a3344a4b3651ebd60a1e15309d737c http://wherever.com/file2.js file2.js\n"""
    }
示例#2
0
def test_lock_local_file_changes(mocker, tmpworkdir):
    mktree(tmpworkdir, {
        'grablib.yml': "download:\n  'http://wherever.com/file.js': x"
    })
    mock_requests_get = mocker.patch('grablib.download.requests.Session.get')
    mock_requests_get.return_value = MockResponse()
    Grab(download_root='test-download-dir').download()
    assert mock_requests_get.call_count == 1
    assert gettree(tmpworkdir) == {
        'grablib.yml': "download:\n  'http://wherever.com/file.js': x",
        'test-download-dir': {'x': 'response text'},
        '.grablib.lock': 'b5a3344a4b3651ebd60a1e15309d737c http://wherever.com/file.js x\n'
    }
    mktree(tmpworkdir, {
        'grablib.yml': "download:\n  'http://wherever.com/file.js': x2"
    })
    Grab(download_root='test-download-dir').download()
    assert mock_requests_get.call_count == 2
    assert gettree(tmpworkdir, max_len=0) == {
        'grablib.yml': "download:\n  'http://wherever.com/file.js': x2",
        'test-download-dir': {'x2': 'response text'},
        '.grablib.lock': 'b5a3344a4b3651ebd60a1e15309d737c http://wherever.com/file.js x2\n'
                         '# "stale" files which grablib should delete where found, '
                         'you can delete these once everyone has run grablib\n'
                         'b5a3344a4b3651ebd60a1e15309d737c :stale x\n'
    }
示例#3
0
def test_simple_render(tmpdir):
    foo_page = '# hello\n\nthis is a test foo: {{ foo }}'
    mktree(
        tmpdir, {
            'pages': {
                'foobar.md': foo_page,
                'spam.html': '# SPAM',
                'favicon.ico': '*',
            },
            'theme/templates/main.jinja': 'main, content:\n\n{{ content }}',
            'tmp/content/foobar.md': foo_page,
        })
    config = Config(
        source_dir=str(tmpdir),
        tmp_dir=str(tmpdir.join('tmp')),
        foo='bar',
    )

    som = {
        'pages': {
            'foobar.md': {
                'uri': '/foobar.html',
                'infile': config.pages_dir / 'foobar.md',
                'template': 'main.jinja',
                'content_template': Path('content') / 'foobar.md',
            },
            'favicon.ico': {
                'uri': '/favicon.ico',
                'infile': config.pages_dir / 'favicon.ico',
            },
        }
    }
    expected_tree = {
        'foobar.html': ('main, content:\n\n'
                        '<h1 id="1-hello">hello</h1>\n\n'
                        '<p>this is a test foo: </p>\n'),
        'favicon.ico':
        '*',
    }
    assert not tmpdir.join('dist').check()

    assert render_pages(config, som) is None
    assert gettree(tmpdir.join('dist')) == expected_tree

    tmpdir.join('dist').remove(rec=1)
    assert not tmpdir.join('dist').check()

    cache = render_pages(config, som, {})
    assert gettree(tmpdir.join('dist')) == expected_tree
    assert len(cache) == 2

    tmpdir.join('dist').remove(rec=1)
    assert not tmpdir.join('dist').check()

    render_pages(config, som, cache)
    assert gettree(tmpdir.join('dist')) != expected_tree
示例#4
0
def test_copy_assets_prod(tmpdir):
    mktree(
        tmpdir, {
            'pages/foobar.md': '# hello',
            'theme': {
                'templates': {
                    'main.jinja': 'main:\n {{ content }}'
                },
                'assets': {
                    'image.png': '*',
                    'favicon.ico': '*',
                    'move': {
                        'foobar.svg': 'x'
                    }
                }
            },
        })

    config = get_config(str(tmpdir))
    config.mode = Mode.production
    copy_assets(config)
    assert gettree(tmpdir.join('dist')) == {
        'image.3389dae.png': '*',
        'favicon.ico': '*',
        'move': {
            'foobar.9dd4e46.svg': 'x'
        }
    }
示例#5
0
def test_dev_simple(tmpdir, mocker, loop):
    async def awatch_alt(*args, **kwargs):
        yield {(Change.modified, str(tmpdir.join('pages/foobar.md')))}
        yield {(Change.modified, str(tmpdir.join('pages/features/whatever.md')))}
        yield {(Change.modified, str(tmpdir.join('harrier.yml')))}
        yield {(Change.added, str(tmpdir.join('theme/sass/main.scss')))}
        tmpdir.join('harrier.yml').write('foo: 2')
        yield {(Change.modified, str(tmpdir.join('harrier.yml')))}

    asyncio.set_event_loop(loop)
    mktree(tmpdir, {
        'pages': {
            'foobar.md': '# hello\n {{ config.foo }}',
            'features/whatever.md': '## Foo',
        },
        'harrier.yml': 'foo: 1'
    })
    mocker.patch('harrier.dev.awatch', side_effect=awatch_alt)

    assert not tmpdir.join('dist').check()

    dev(str(tmpdir), 25698)

    # debug(gettree(tmpdir.join('dist')))
    assert gettree(tmpdir.join('dist')) == {
        'foobar': {
            'index.html': '<h1 id="1-hello">hello</h1>\n\n<p>2</p>\n',
        },
        'features': {
            'whatever': {
                'index.html': '<h2 id="2-foo">Foo</h2>\n',
            },
        },
    }
示例#6
0
def test_resolve_sass_path_dev(tmpdir):
    mktree(
        tmpdir, {
            'pages/foobar.md': '# hello',
            'theme': {
                'assets/assets/image.png':
                '*',
                'sass/main.scss':
                'body {content: resolve_path("/assets/image.png")}',
            },
        })

    config = get_config(str(tmpdir))
    config.mode = Mode.development
    assets_grablib(config)
    mtime = tmpdir.join('theme/sass/main.scss').stat().mtime
    assert gettree(tmpdir.join('dist')) == {
        'assets': {
            'image.png': '*',
        },
        'theme': {
            'main.css.map':
            RegexStr('{.*'),
            'main.css': ("body {\n"
                         "  content: '/assets/image.png?t=%0.0f'; }\n"
                         "\n"
                         "/*# sourceMappingURL=main.css.map */") % mtime,
            '.src': {
                'main.scss':
                'body {content: resolve_path("/assets/image.png")}',
            },
        },
    }
示例#7
0
def test_dev_data(tmpdir, mocker, loop):
    async def awatch_alt(*args, **kwargs):
        tmpdir.join('data/foobar.yml').write('a: 2')
        yield {(Change.modified, str(tmpdir.join('data/foobar.yml')))}

    asyncio.set_event_loop(loop)
    mktree(tmpdir, {
        'pages': {
            'foobar.html': '{{ data.foobar.a }}',
        },
        'data/foobar.yml': 'a: 1'
    })
    mocker.patch('harrier.dev.awatch', side_effect=awatch_alt)
    mocker.patch('harrier.dev.Server', return_value=MockServer())

    assert not tmpdir.join('dist').check()

    dev(str(tmpdir), 8000)

    # debug(gettree(tmpdir.join('dist')))
    assert gettree(tmpdir.join('dist')) == {
        'foobar': {
            'index.html': '2\n',
        },
    }
示例#8
0
def test_ignored_directory(tmpdir, mocker, loop):
    async def awatch_alt(*args, **kwargs):
        yield {(Change.modified, str(tmpdir.join('pages/ignored.html')))}

    asyncio.set_event_loop(loop)
    mktree(tmpdir, {
        'pages': {
            'foobar.html': '1',
            'ignored.html': '2'
        },
        'harrier.yaml': (
            'ignore:\n'
            '- /ignored.html'
        )
    })
    mocker.patch('harrier.dev.awatch', side_effect=awatch_alt)
    mocker.patch('harrier.dev.Server', return_value=MockServer())

    assert not tmpdir.join('dist').check()

    dev(str(tmpdir), 8000)

    # debug(gettree(tmpdir.join('dist')))
    assert gettree(tmpdir.join('dist')) == {
        'foobar': {
            'index.html': '1\n',
        },
    }
示例#9
0
def test_grablib(tmpdir):
    mktree(
        tmpdir, {
            'pages/foobar.md':
            '# hello',
            'theme': {
                'templates': {
                    'main.jinja': 'main:\n {{ content }}'
                },
                'sass/main.scss': ('@import "DL/demo";'
                                   'body {background: $foo}'),
            },
            'harrier.yml':
            (f'download:\n'
             f"  'https://gist.githubusercontent.com/samuelcolvin/ae6d04dadbb4d552d365f440d3ac8015/"
             f"raw/cda04f66c71e4a5f418e78d111d651ae3a2e3784/demo.scss': '_demo.scss'"
             )
        })

    config = get_config(str(tmpdir))
    run_grablib(config)
    assert gettree(tmpdir.join('dist')) == {
        'theme': {
            'main.7cc3e19.css': 'body{background:#BAD}\n',
        },
    }
示例#10
0
def test_ignore_no_template(tmpdir):
    mktree(
        tmpdir, {
            'pages': {
                'ignore_this.md':
                'this file is ignored',
                'normal.md':
                'hello this is normal',
                'no_template.md':
                'this should be passed through as-is',
                'normal_but_no_output.md': ('---\n'
                                            'output: false\n'
                                            '---\n'
                                            'hello this is normal\n')
            },
            'theme': {
                'templates/foobar.jinja': 'rendered {{ content }}',
            },
            'harrier.yml': ('default_template: "foobar.jinja"\n'
                            'ignore:\n'
                            '- "**/ignore*"\n'
                            'defaults:\n'
                            '  "/no_temp*":\n'
                            '    pass_through: true\n')
        })
    build(tmpdir, mode=Mode.production)
    assert gettree(tmpdir.join('dist')) == {
        'no_template': {
            'index.html': 'this should be passed through as-is',
        },
        'normal': {
            'index.html': 'rendered <p>hello this is normal</p>\n',
        },
    }
示例#11
0
def test_dev_delete(tmpdir, mocker, loop):
    async def awatch_alt(*args, **kwargs):
        yield {(Change.deleted, str(tmpdir.join('pages/features/whatever.md')))}

    asyncio.set_event_loop(loop)
    mktree(tmpdir, {
        'pages': {
            'foobar.md': 'hello',
            'features/whatever.md': 'Foo',
        },
    })
    mocker.patch('harrier.dev.awatch', side_effect=awatch_alt)
    mocker.patch('harrier.dev.Server', return_value=MockServer())

    assert not tmpdir.join('dist').check()

    assert dev(str(tmpdir), 8000) == 0

    # debug(gettree(tmpdir.join('dist')))
    assert gettree(tmpdir.join('dist')) == {
        'foobar': {
            'index.html': '<p>hello</p>\n',
        },
        'features': {
            'whatever': {},
        },
    }
示例#12
0
def test_inline_css_dev(tmpdir):
    mktree(
        tmpdir, {
            'pages': {
                'foo.html': '{{inline_css("theme/main.css")}}',
                'bar.html': "{{ url('theme/main.css') }}",
            },
            'theme': {
                'sass/main.scss': 'body {width: 10px + 10px;}',
            },
        })
    build(tmpdir, mode=Mode.development)
    assert gettree(tmpdir.join('dist')) == {
        'foo': {
            'index.html': ('body {\n'
                           '  width: 20px; }\n'
                           '\n'
                           '/*# sourceMappingURL=/theme/main.css.map */\n'),
        },
        'bar': {
            'index.html': RegexStr(r'/theme/main.css\?t=\d+\n'),
        },
        'theme': {
            'main.css.map':
            RegexStr('{.*'),
            'main.css': ('body {\n'
                         '  width: 20px; }\n'
                         '\n'
                         '/*# sourceMappingURL=main.css.map */'),
            '.src': {
                'main.scss': 'body {width: 10px + 10px;}',
            },
        },
    }
示例#13
0
def test_full_build(tmpdir):
    mktree(
        tmpdir, {
            'pages': {
                'foobar.html': ('{{ url("foobar.png") }}\n'
                                '{{ resolve_url("theme/main.css") }}\n'
                                '{{ resolve_url("another") }}\n'),
                'another.md':
                '# Hello',
                'third.yaml':
                'content: "hello there"',
            },
            'theme': {
                'sass/main.scss': 'body {width: 10px + 10px;}',
                'assets/foobar.png': '*',
            },
        })
    build(tmpdir, mode=Mode.production)
    assert gettree(tmpdir.join('dist')) == {
        'foobar': {
            'index.html': ('/foobar.3389dae.png\n'
                           '/theme/main.a1ac3a7.css\n'
                           '/another/\n'),
        },
        'another': {
            'index.html': '<h1 id="1-hello">Hello</h1>\n'
        },
        'theme': {
            'main.a1ac3a7.css': 'body{width:20px}\n',
        },
        'third': {
            'index.html': 'hello there\n'
        },
        'foobar.3389dae.png': '*',
    }
示例#14
0
def test_sass_clever_import_node_modules(tmpworkdir):
    mktree(tmpworkdir, {
        'grablib.yml': """
        build_root: built_at
        debug: true
        build:
          sass:
            css: sass_dir
        """,
        'sass_dir': {
            'foo.scss': "@import 'NM/foobar/bar';",
        },
        'node_modules': {
            'foobar/_bar.scss': 'a {color: black;}'
        }
    })
    Grab().build()
    tree = gettree(tmpworkdir.join('built_at/css'))
    assert {
        'foo.css': 'a {\n'
                   '  color: black; }\n\n'
                   '/*# sourceMappingURL=foo.css.map */',
        'foo.css.map': RegexStr('{.*'),
        '.src': {
            'foo.scss': "@import 'NM/foobar/bar';"
        }
    } == tree
示例#15
0
def test_extensions_error(tmpdir, mocker, loop):
    async def awatch_alt(*args, **kwargs):
        tmpdir.join('extensions.py').write('print(xxx)')
        yield {(Change.modified, str(tmpdir.join('extensions.py')))}

    asyncio.set_event_loop(loop)
    mktree(tmpdir, {
        'pages': {
            'foobar.md': '**hello**',
        },
        'theme/templates/main.jinja': 'main:\n {{ content }}',
        'harrier.yml': 'default_template: main.jinja',
        'extensions.py': 'x = 1'
    })
    mocker.patch('harrier.dev.awatch', side_effect=awatch_alt)
    mocker.patch('harrier.dev.Server', return_value=MockServer())

    assert not tmpdir.join('dist').check()

    assert dev(str(tmpdir), 8000) == 1

    assert gettree(tmpdir.join('dist')) == {
        'foobar': {
            'index.html': 'main:\n <p><strong>hello</strong></p>\n',
        },
    }
示例#16
0
def test_sass(tmpworkdir):
    mktree(tmpworkdir, {
        'grablib.yml': """
        build_root: "built_at"
        build:
          sass:
            "css": "sass_dir"
        """,
        'sass_dir': {
            'not_css.txt': 'not included',
            'adir/_mixin.scss': 'a { color: red};',
            'foo.scss': """
            @import 'adir/mixin';
            .foo {
              .bar {
                color: black;
                width: (60px / 6);
              }
            }
            """
        }
    })
    Grab().build()
    assert gettree(tmpworkdir.join('built_at')) == {
        'css': {
            'foo.css': 'a{color:red}.foo .bar{color:black;width:10px}\n'
        }
    }
示例#17
0
def test_sass_custom_functions(tmpdir):
    mktree(tmpdir, {
        'sass': {
            'foo.scss': (
                ".foo {color: waffle(100px, 'foobar.png')}"
            )
        },
        'downloads': {}
    })
    args = None

    def waffle(a, b):
        nonlocal args
        args = f'{a.value:0.0f}{a.unit}', b
        return '#G00D'

    sass_gen = SassGenerator(
        input_dir=Path(tmpdir.join('sass')),
        output_dir=Path(tmpdir.join('output')),
        download_root=Path(tmpdir.join('downloads')),
        custom_functions={waffle},
    )
    sass_gen()
    assert gettree(tmpdir.join('output')) == {
        'foo.css': '.foo{color:#G00D}\n'
    }
    assert args == ('100px', 'foobar.png')
示例#18
0
def test_rm_some(tmpworkdir):
    mktree(tmpworkdir, {
        'grablib.yml': """
        build_root: "built_at"
        build:
          wipe:
          - boom.txt
          - another_dir.*
        """,
        'built_at': {
            'foo/bar.js': 'x',
            'boom.txt': 'x',
            'another_dir': {
                'a.txt': 'x',
                'b.txt': 'x',
            },
            'remain.txt': 'y',
        }
    })
    setup_logging('DEBUG')
    Grab().build()
    assert {
        'foo': {
            'bar.js': 'x'
        },
        'remain.txt': 'y',
    } == gettree(tmpworkdir.join('built_at'))
示例#19
0
def test_stale_lock(mocker, tmpworkdir):
    gl = """\
    download:
      'http://wherever.com/file.js': foo
    """
    lock = (
        '# this is a comment\n'
        'b5a3344a4b3651ebd60a1e15309d737c http://wherever.com/file.js foo\n'
        ' #so is this\n'
        'b5a3344a4b3651ebd60a1e15309d737c :stale to_delete\n'
    )
    mktree(tmpworkdir, {
        'grablib.yml': gl,
        '.grablib.lock': lock,
        'test-download-dir': {'foo': 'response text', 'to_delete': 'response text'},
    })
    mock_requests_get = mocker.patch('grablib.download.requests.Session.get')
    mock_requests_get.return_value = MockResponse()
    grab = Grab(download_root='test-download-dir')
    grab.download()
    assert gettree(tmpworkdir, max_len=0) == {
        'grablib.yml': gl,
        '.grablib.lock': 'b5a3344a4b3651ebd60a1e15309d737c http://wherever.com/file.js foo\n'
                         '# "stale" files which grablib should delete where found, '
                         'you can delete these once everyone has run grablib\n'
                         'b5a3344a4b3651ebd60a1e15309d737c :stale to_delete\n',
        'test-download-dir': {'foo': 'response text'},
    }
示例#20
0
def test_lock_zip(mocker, tmpworkdir):
    mktree(tmpworkdir, {'grablib.yml': zip_dowload_yml})
    mock_requests_get = mocker.patch('grablib.download.requests.Session.get')
    mock_requests_get.side_effect = request_fixture
    Grab().download()
    assert mock_requests_get.call_count == 1
    assert zip_downloaded_directory == gettree(tmpworkdir, max_len=None)
    Grab().download()
    assert mock_requests_get.call_count == 1
    assert zip_downloaded_directory == gettree(tmpworkdir, max_len=None)
    Grab().download()
    assert mock_requests_get.call_count == 1
    assert zip_downloaded_directory == gettree(tmpworkdir, max_len=None)
    tmpworkdir.join('droot/subdirectory/a.txt').remove()

    Grab().download()
    assert mock_requests_get.call_count == 2
    assert zip_downloaded_directory == gettree(tmpworkdir, max_len=None)
示例#21
0
def test_extensions_ok(tmpdir):
    mktree(
        tmpdir, {
            'pages': {
                'foo.md': '# foo',
                'bar.html': '{{ 4|add_one }} {{ dynamic }}',
                'spam.html': 'before',
                'splat.html': '{{ 3 is two }} {{ 2 is two }}',
            },
            'theme/templates/main.jinja':
            '{{ content }}',
            'extensions.py':
            """
from harrier.extensions import modify, template

@modify.pages('/foo.*')
def modify_foo(page, config):
    page['content'] += ' changed by extension'
    return page

@modify.som
def add_var(site):
    site['dynamic'] = 42
    return site

@modify.som
def change_pages(site):
    site['pages']['/spam.html']['content'] = 'after'
    return site

@template.filter
def add_one(v):
    return v + 1

@template.test
def two(v):
    return v == 2
        """
        })

    build(str(tmpdir))
    assert gettree(tmpdir.join('dist')) == {
        'foo': {
            'index.html':
            '<h1 id="1-foo-changed-by-extension">foo changed by extension</h1>\n',
        },
        'bar': {
            'index.html': '5 42\n',
        },
        'spam': {
            'index.html': 'after\n',
        },
        'splat': {
            'index.html': 'False True\n',
        },
    }
示例#22
0
def test_no_lock(mocker, tmpworkdir):
    mktree(tmpworkdir, {
        'grablib.yml': "lock: null\ndownload:\n  'http://wherever.com/file.js': x"
    })
    mock_requests_get = mocker.patch('grablib.download.requests.Session.get')
    mock_requests_get.return_value = MockResponse()
    grab = Grab(download_root='s')
    grab.download()
    assert gettree(tmpworkdir) == {
        'grablib.yml': "lock: null\ndownload:\n  'http://wherever.com/file.js': x",
        's': {'x': 'response text'},
    }
示例#23
0
def test_zip_null(mocker, tmpworkdir):
    mock_requests_get = mocker.patch('grablib.download.requests.Session.get')
    mock_requests_get.side_effect = request_fixture
    mktree(tmpworkdir, {
        'grablib.yaml': """
      "download":
        "https://any-old-url.com/test_assets.zip":
           "test_assets/assets/a.txt": null
           "test_assets/assets/(.+)": "subdirectory/{filename}"
    """})
    Grab(download_root='test-download-dir').download()
    assert gettree(tmpworkdir.join('test-download-dir')) == {'subdirectory': {'b.txt': 'b\n'}}
示例#24
0
def test_build_no_templates(tmpdir):
    mktree(tmpdir, {
        'pages': {
            'foobar.md': ('### Whatever'),
        },
    })
    build(tmpdir, mode=Mode.production)
    assert gettree(tmpdir.join('dist')) == {
        'foobar': {
            'index.html': ('<h3 id="3-whatever">Whatever</h3>\n'),
        },
    }
示例#25
0
def test_xml_no_front_matter(tmpdir):
    mktree(
        tmpdir, {
            'pages': {
                'foobar.xml': ('<x><y>{{ config.whatever }}</y></x>'),
            },
            'harrier.yml': 'whatever: 123'
        })
    build(tmpdir, mode=Mode.production)
    assert gettree(tmpdir.join('dist')) == {
        'foobar.xml': '<x><y>{{ config.whatever }}</y></x>'
    }
示例#26
0
def test_zip_double(mocker, tmpworkdir):
    mock_requests_get = mocker.patch('grablib.download.requests.Session.get')
    mock_requests_get.side_effect = request_fixture
    mktree(tmpworkdir, {
        'grablib.yaml': """
      'download':
        'https://any-old-url.com/test_assets.zip':
           'test_assets/assets/a.txt':
             - a.txt
             - a_again.txt
           'test_assets/assets/(.+)': '{filename}'
    """})
    Grab(download_root='test-download-dir').download()
    assert gettree(tmpworkdir.join('test-download-dir')) == {'b.txt': 'b\n', 'a.txt': 'a\n', 'a_again.txt': 'a\n'}
示例#27
0
def test_lock_unchanged(mocker, tmpworkdir):
    mktree(tmpworkdir, {
        'grablib.yml': "download:\n  'http://wherever.com/file.js': x",
        '.grablib.lock': 'b5a3344a4b3651ebd60a1e15309d737c http://wherever.com/file.js x\n',
    })
    mock_requests_get = mocker.patch('grablib.download.requests.Session.get')
    mock_requests_get.return_value = MockResponse()
    grab = Grab(download_root='test-download-dir')
    grab.download()
    assert gettree(tmpworkdir) == {
        'grablib.yml': "download:\n  'http://wherever.com/file.js': x",
        'test-download-dir': {'x': 'response text'},
        '.grablib.lock': 'b5a3344a4b3651ebd60a1e15309d737c http://wherever.com/file.js x\n'
    }
示例#28
0
def test_rm_all(tmpworkdir):
    mktree(tmpworkdir, {
        'grablib.yml': """
        build_root: "built_at"
        build:
          wipe: '.*'
        """,
        'built_at': {
            'foo/bar.js': 'x',
            'boom.txt': 'x',
        }
    })
    Grab().build()
    assert gettree(tmpworkdir.join('built_at')) == {}
示例#29
0
def test_jinja_format(tmpdir):
    mktree(
        tmpdir, {
            'pages': {
                'index.html':
                '{{"{:0.2f}"|format(3.1415)}}',
                '2032-06-02-date.txt':
                '---\nx: 1\n---\n{{ "{:%b %d, %Y}"|format(page.created) }}',
            },
        })
    build(tmpdir, mode=Mode.production)
    assert gettree(tmpdir.join('dist')) == {
        'index.html': '3.14\n',
        'date.txt': 'Jun 02, 2032\n'
    }
示例#30
0
def test_simple_lock(mocker, tmpworkdir):
    mktree(tmpworkdir, {
        'grablib.yml': "lock: the.lock\ndownload:\n  'http://wherever.com/file.js': x"
    })
    mock_requests_get = mocker.patch('grablib.download.requests.Session.get')
    mock_requests_get.return_value = MockResponse()
    Grab(download_root='static').download()
    assert mock_requests_get.call_count == 1
    assert gettree(tmpworkdir) == {
        'grablib.yml': "lock: the.lock\ndownload:\n  'http://wherever.com/file.js': x",
        'static': {'x': 'response text'},
        'the.lock': 'b5a3344a4b3651ebd60a1e15309d737c http://wherever.com/file.js x\n'
    }
    Grab(download_root='static').download()
    assert mock_requests_get.call_count == 1
示例#31
0
def test_no_trailing_slash(tmpdir):
    mktree(
        tmpdir, {
            'pages': {
                'index.html': '<a href="{{ url("other") }}">link to other</a>',
                'other.html': 'xxx'
            },
            'harrier.yml': 'apply_trailing_slash: false'
        })
    build(tmpdir, mode=Mode.production)
    assert gettree(tmpdir.join('dist')) == {
        'other': {
            'index.html': 'xxx\n',
        },
        'index.html': '<a href="/other">link to other</a>\n',
    }
示例#32
0
def test_lock_zip_remote_changed(mocker, tmpworkdir):
    mktree(tmpworkdir, {'grablib.yml': zip_dowload_yml})
    mock_requests_get = mocker.patch('grablib.download.requests.Session.get')
    zip_r = request_fixture('https://any-old-url.com/test_assets.zip')
    mock_requests_get.side_effect = [
        MockResponse(content=zip_r.content, headers={'content-type': 'application/zip'}),
        MockResponse(content=zip_r.content + b'x', headers={'content-type': 'application/zip'}),
    ]
    Grab().download()
    assert mock_requests_get.call_count == 1
    assert zip_downloaded_directory == gettree(tmpworkdir, max_len=None)
    tmpworkdir.join('droot/subdirectory/a.txt').remove()

    with pytest.raises(GrablibError):
        Grab().download()
    assert mock_requests_get.call_count == 2
示例#33
0
def test_generate_pages(tmpdir):
    mktree(
        tmpdir, {
            'pages': {
                'index.html': 'hello',
            },
            'extensions.py':
            """
from pathlib import Path
from harrier.extensions import modify
THIS_DIR = Path(__file__).parent.resolve()

@modify.generate_pages
def add_extra_pages(som):
    config: Config = som['config']
    yield {
        'path': Path('extra/index.md'),
        'content': '# this is a test\\n\\nwith of generating pages dynamically',
    }
    yield {
        'path': Path('more/index.html'),
        'content': 'testing {{ page.x }}',
        'data': {
            'uri': '/foo-bar-whatever',
            'x': 123,
        }
    }
    (THIS_DIR / 'pages' / 'binary_file').write_bytes(b'xxx')
    yield {
        'path': 'binary_file',
        'content': None,
    }
    """
        })
    build(str(tmpdir))
    assert gettree(tmpdir.join('dist')) == {
        'extra': {
            'index.html': ('<h1 id="1-this-is-a-test">this is a test</h1>\n'
                           '\n'
                           '<p>with of generating pages dynamically</p>\n'),
        },
        'foo-bar-whatever': {
            'index.html': 'testing 123\n'
        },
        'index.html': 'hello\n',
        'binary_file': 'xxx',
    }
示例#34
0
def test_just_build(tmpworkdir):
    mktree(tmpworkdir, {
        'grablib.yml': """
        build_root: "built_at"
        build:
          cat:
            "libraries.js":
              - "./foo.js"
        """,
        'foo.js': 'var v = "foo js";',
    })
    result = CliRunner().invoke(cli, ['download'])
    assert result.exit_code == 0
    assert tmpworkdir.join('built_at').check() is False
    result = CliRunner().invoke(cli, ['build'])
    assert result.exit_code == 0
    assert gettree(tmpworkdir.join('built_at')) == {'libraries.js': '/* === foo.js === */\nvar v="foo js";\n'}
示例#35
0
def test_already_deleted(mocker, tmpworkdir):
    mktree(tmpworkdir, {
        'grablib.yml': 'download: {}',
        '.grablib.lock': 'b5a3344a4b3651ebd60a1e15309d737c http://wherever.com/file.js path/to/x\n',
        'test-download-dir': {'foo': 'bar'},
    })
    mock_requests_get = mocker.patch('grablib.download.requests.Session.get')
    mock_requests_get.return_value = MockResponse()
    grab = Grab(download_root='test-download-dir')
    grab.download()
    assert gettree(tmpworkdir, max_len=0) == {
        'grablib.yml': 'download: {}',
        'test-download-dir': {'foo': 'bar'},
        '.grablib.lock': '# "stale" files which grablib should delete where found, '
                         'you can delete these once everyone has run grablib\n'
                         'b5a3344a4b3651ebd60a1e15309d737c :stale path/to/x\n'
    }
示例#36
0
def test_yaml_render(tmpdir):
    mktree(
        tmpdir, {
            'pages': {
                'test.yml': ('template: foobar.jinja\n'
                             'foo:\n'
                             '  bar: 42\n'),
            },
            'theme': {
                'templates/foobar.jinja': 'foo bar: {{ page.foo.bar }}',
            },
        })
    build(tmpdir, mode=Mode.production)
    assert gettree(tmpdir.join('dist')) == {
        'test': {
            'index.html': 'foo bar: 42\n'
        }
    }
示例#37
0
def test_lock_remote_file_changes(mocker, tmpworkdir):
    mktree(tmpworkdir, {
        'grablib.yml': "download:\n  'http://wherever.com/file.js': x"
    })
    mock_requests_get = mocker.patch('grablib.download.requests.Session.get')
    mock_requests_get.side_effect = [
        MockResponse(),
        MockResponse(content=b'changed')
    ]
    Grab(download_root='s').download()
    assert mock_requests_get.call_count == 1
    assert gettree(tmpworkdir) == {
        'grablib.yml': "download:\n  'http://wherever.com/file.js': x",
        's': {'x': 'response text'},
        '.grablib.lock': 'b5a3344a4b3651ebd60a1e15309d737c http://wherever.com/file.js x\n'
    }
    tmpworkdir.join('s/x').remove()
    with pytest.raises(GrablibError):
        Grab(download_root='s').download()
示例#38
0
def test_changed_file_url(mocker, tmpworkdir):
    gl = """\
    download:
      'http://wherever.com/file_different.js': x
    """
    mktree(tmpworkdir, {
        'grablib.yml': gl,
        '.grablib.lock': 'b5a3344a4b3651ebd60a1e15309d737c http://wherever.com/file.js x\n',
        'test-download-dir': {'x': 'response text'},
    })
    mock_requests_get = mocker.patch('grablib.download.requests.Session.get')
    mock_requests_get.return_value = MockResponse()
    grab = Grab(download_root='test-download-dir')
    grab.download()
    assert gettree(tmpworkdir, max_len=0) == {
        'grablib.yml': gl,
        'test-download-dir': {'x': 'response text'},
        '.grablib.lock': 'b5a3344a4b3651ebd60a1e15309d737c http://wherever.com/file_different.js x\n'
    }
示例#39
0
def test_cat_regex(tmpworkdir):
    mktree(tmpworkdir, {
        'grablib.yml': """
        build_root: "built_at"
        build:
          cat:
            "f.min.js":
              - src: "./foo.js"
                replace:
                  "change": "!new_value"
        """,
        'foo.js': 'var v = "change js";',
    })
    Grab().build()
    assert gettree(tmpworkdir.join('built_at')) == {
        'f.min.js':
            '/* === foo.js === */\n'
            'var v="!new_value js";\n'
    }
示例#40
0
def test_with_aliases(mocker, tmpworkdir):
    mktree(tmpworkdir, {
        'grablib.yml': """\
        download_root: download_to
        aliases:
          WHATEVER: https://www.whatever.com
        download:
          "WHATEVER/foo.js": "js/"
        """
    })
    mock_requests_get = mocker.patch('grablib.download.requests.Session.get')
    mock_requests_get.return_value = MockResponse()
    Grab().download()
    mock_requests_get.assert_called_with('https://www.whatever.com/foo.js')
    assert gettree(tmpworkdir.join('download_to')) == {
        'js': {
            'foo.js': 'response text'
        }
    }
示例#41
0
def test_inline_css_prod(tmpdir):
    mktree(
        tmpdir, {
            'pages': {
                'foobar.html': '{{inline_css("theme/main.css")}}'
            },
            'theme': {
                'sass/main.scss': 'body {width: 10px + 10px;}',
            },
        })
    build(tmpdir, mode=Mode.production)
    assert gettree(tmpdir.join('dist')) == {
        'foobar': {
            'index.html': ('body{width:20px}\n'),
        },
        'theme': {
            'main.a1ac3a7.css': 'body{width:20px}\n',
        },
    }
示例#42
0
def test_raw_sass_prod(tmpdir):
    mktree(tmpdir, {
        'sass': {
            'adir/_mixin.scss': '$my_colour: #G00D;',
            'foo.scss': (
                "@import 'adir/mixin';\n"
                ".foo {color: $my_colour}"
            )
        },
        'downloads': {}
    })
    sass_gen = SassGenerator(
        input_dir=Path(tmpdir.join('sass')),
        output_dir=Path(tmpdir.join('output')),
        download_root=Path(tmpdir.join('downloads')),
    )
    sass_gen()
    assert gettree(tmpdir.join('output')) == {
        'foo.css': '.foo{color:#G00D}\n'
    }
示例#43
0
def test_stale_changed(mocker, tmpworkdir):
    gl = """\
    download:
      'http://wherever.com/file.js': x
    """
    mktree(tmpworkdir, {
        'grablib.yml': gl,
        '.grablib.lock': 'b5a3344a4b3651ebd60a1e15309d737c http://wherever.com/file.js old\n',
        'test-download-dir': {'old': 'response text - different'},
    })
    mock_requests_get = mocker.patch('grablib.download.requests.Session.get')
    mock_requests_get.return_value = MockResponse()
    grab = Grab(download_root='test-download-dir')
    with pytest.raises(GrablibError):
        grab.download()
    assert gettree(tmpworkdir) == {
        'grablib.yml': gl,
        '.grablib.lock': 'b5a3344a4b3651ebd60a1e15309d737c http://wherever.com/file.js old\n',
        'test-download-dir': {'old': 'response text - different', 'x': 'response text'},
    }
示例#44
0
def test_frontmatter_maybe(tmpdir):
    mktree(
        tmpdir, {
            'pages': {
                'foobar.xml': ('---\n'
                               'foo: bar\n'
                               '---\n'
                               '<x><y>{{ config.whatever }}</y></x>'),
                'foobar.txt': ('---\n'
                               'x: 1\n'
                               '---\n'
                               '{{ page.x }}'),
            },
            'harrier.yml': 'whatever: 123'
        })
    build(tmpdir, mode=Mode.production)
    assert gettree(tmpdir.join('dist')) == {
        'foobar.xml': '<x><y>123</y></x>\n',
        'foobar.txt': '1\n',
    }
示例#45
0
def test_sass_exclude(tmpworkdir):
    mktree(tmpworkdir, {
        'grablib.yml': """
        build_root: 'built_at'
        build:
          sass:
            css:
              src: sass_dir
              exclude: 'adir/.*$'
        """,
        'sass_dir': {
            'adir/bar.scss': '.bar { color: red};',
            'foo.scss': '.foo { color: black;}'
        }
    })
    Grab().build()
    assert gettree(tmpworkdir.join('built_at')) == {
        'css': {
            'foo.css': '.foo{color:black}\n'
        }
    }
示例#46
0
def test_grablib_pygments(tmpdir):
    mktree(
        tmpdir, {
            'pages/foobar.md': '# hello',
            'theme': {
                'sass': {
                    '_other.scss':
                    'div {colour: red}',
                    'main.scss': ('@import "other";\n'
                                  '@import "pygments/default";\n'),
                },
            }
        })

    config = get_config(str(tmpdir))
    run_grablib(config)
    assert gettree(tmpdir.join('dist')) == {
        'theme': {
            'main.9a9caa6.css': RegexStr('div{colour:red}\.hi \.hll.*'),
        },
    }
示例#47
0
def test_cat_download_root(tmpworkdir):
    mktree(tmpworkdir, {
        'grablib.yml': """
        download_root: downloaded2
        build_root: "built_at"
        build:
          cat:
            "f.min.js":
              - "./foo.js"
              - "DL/bar.js"
        """,
        'foo.js': 'var v = "foo js";',
        'downloaded2/bar.js': 'var v = "bar js";',
    })
    Grab().build()
    assert gettree(tmpworkdir.join('built_at')) == {
        'f.min.js':
            '/* === foo.js === */\n'
            'var v="foo js";\n'
            '/* === bar.js === */\n'
            'var v="bar js";\n'
    }
示例#48
0
def test_sass_debug(tmpworkdir):
    mktree(tmpworkdir, {
        'grablib.yml': """
        build_root: "built_at"
        debug: true
        build:
          sass:
            "css": "sass_dir"
        """,
        'sass_dir': {
            'foo.scss': '.foo { .bar {color: black;}}'
        }
    })
    Grab().build()
    tree = gettree(tmpworkdir.join('built_at/css'))
    assert {
        'foo.css': '.foo .bar {\n  color: black; }\n\n/*# sourceMappingURL=foo.css.map */',
        'foo.css.map': RegexStr('{\n\t"version": 3,\n\t"file": "\.src/foo.css".*'),
        '.src': {
            'foo.scss': '.foo { .bar {color: black;}}'
        }
    } == tree
示例#49
0
def test_cat_debug(tmpworkdir):
    mktree(tmpworkdir, {
        'grablib.yml': """
        build_root: "built_at"
        build:
          cat:
            "libraries.js":
              - "./foo.js"
              - "./bar.js"
        """,
        'foo.js': 'var v = "foo js";\n    vindent = true;',
        'bar.js': 'var v = "bar js";',
    })
    Grab(debug=True).build()
    assert {
        'libraries.js':
            '/* === foo.js === */\n'
            'var v = "foo js";\n'
            '    vindent = true;\n'
            '/* === bar.js === */\n'
            'var v = "bar js";\n'
    } == gettree(tmpworkdir.join('built_at'))
示例#50
0
def test_resolve_sass_path(tmpdir):
    mktree(
        tmpdir, {
            'pages/foobar.md': '# hello',
            'theme': {
                'assets/assets/image.png':
                '*',
                'sass/main.scss':
                'body {content: resolve_path("/assets/image.png")}',
            },
        })

    config = get_config(str(tmpdir))
    assets_grablib(config)
    assert gettree(tmpdir.join('dist')) == {
        'theme': {
            'main.d024f29.css': "body{content:'/assets/image.3389dae.png'}\n",
        },
        'assets': {
            'image.3389dae.png': '*',
        },
    }
示例#51
0
def test_sass_clever_import(tmpworkdir):
    mktree(tmpworkdir, {
        'grablib.yml': """
        download_root: downloaded2
        build_root: built_at
        debug: false
        build:
          sass:
            css: sass_dir
        """,
        'downloaded2': {
            'x.css': '.x {width:100px}'
        },
        'sass_dir': {
            'foo.scss': "@import 'SRC/path/to/bar';\n@import 'DL/x';",
            'path/to/_bar.scss': 'a {color: black;}'
        }
    })
    Grab().build()
    assert {
        'foo.css': 'a{color:black}.x{width:100px}\n',
    } == gettree(tmpworkdir.join('built_at/css'))
示例#52
0
def test_sass_log_repeat(tmpworkdir, smart_caplog):
    mktree(tmpworkdir, {
        'grablib.yml': """
        build_root: "built_at"
        build:
          sass:
            "css": "sass_dir"
        """,
        'sass_dir': {
            'foo.scss': 'span {color: white}'
        }
    })
    Grab().build()
    assert gettree(tmpworkdir.join('built_at')) == {'css': {'foo.css': 'span{color:white}\n'}}
    assert '18B' in smart_caplog
    assert '%' not in smart_caplog
    Grab().build()
    assert '%' not in smart_caplog
    tmpworkdir.join('sass_dir/foo.scss').write('span {color: white};\ndiv {color: red}')
    Grab().build()
    assert '32B' in smart_caplog
    assert '+78%' in smart_caplog
示例#53
0
def test_dev_extensions(tmpdir, mocker, loop):
    async def awatch_alt(*args, **kwargs):
        yield {(Change.modified, str(tmpdir.join('pages/foobar.html')))}
        yield {(Change.modified, str(tmpdir.join('pages/foobar.html')))}

    asyncio.set_event_loop(loop)
    mktree(tmpdir, {
        'pages': {
            'foobar.html': 'before',
        },
        'call': '0',
        'extensions.py': """
from pathlib import Path
from harrier.extensions import modify, template
p = Path(__file__).parent / 'call'

@modify.som
def change_pages(site):
    v = int(p.read_text())
    v += 1
    p.write_text(str(v))
    site['pages']['/foobar.html']['content'] = str(v)
    return site
        """
    })
    mocker.patch('harrier.dev.awatch', side_effect=awatch_alt)
    mocker.patch('harrier.dev.Server', return_value=MockServer())

    assert not tmpdir.join('dist').check()

    dev(str(tmpdir), 8000)

    # debug(gettree(tmpdir.join('dist')))
    assert gettree(tmpdir.join('dist')) == {
        'foobar': {
            'index.html': '3\n',
        },
    }
示例#54
0
def test_smart_sass_url(tmpdir):
    mktree(
        tmpdir, {
            'pages/foobar.md': '# hello',
            'theme': {
                'assets/assets/image.png':
                '*',
                'sass/main.scss':
                'body {background: smart_url("assets/image.png")}',
            },
        })

    config = get_config(str(tmpdir))
    assets_grablib(config)
    assert gettree(tmpdir.join('dist')) == {
        'theme': {
            'main.28d2724.css':
            "body{background:url('/assets/image.3389dae.png')}\n",
        },
        'assets': {
            'image.3389dae.png': '*',
        },
    }
示例#55
0
def test_cat(tmpworkdir):
    mktree(tmpworkdir, {
        'grablib.yml': """
        download:
          http://whatever.com/file: file.txt
        build_root: "built_at"
        build:
          cat:
            "libs.min.js":
              - "./foo.js"
              - "./bar.js"
        """,
        'foo.js': 'var v = "foo js";\n    vindent = true;',
        'bar.js': 'var v = "bar js";',
    })
    Grab().build()
    assert gettree(tmpworkdir.join('built_at')) == {
        'libs.min.js':
            '/* === foo.js === */\n'
            'var v="foo js";vindent=true;\n'
            '/* === bar.js === */\n'
            'var v="bar js";\n'
    }
示例#56
0
def test_copy_extensions(tmpdir):
    mktree(
        tmpdir, {
            'pages': {
                'index.html': 'hello',
            },
            'theme/assets': {
                'image1.png': 'a',
                'image2.png': 'c',
                'foo/bar.svg': 'c',
            },
            'extensions.py':
            """
from harrier.extensions import modify, template

@modify.copy('/foo/*')
def modify_foo(in_path, out_path, config):
    out_path.write_text(f'{in_path.name} {in_path.read_text()} custom')
    return 1  # prevent default copy

@modify.copy('/image2.png')
def print_in_path(in_path, out_path, config):
    out_path.with_name(out_path.name + '.alt').write_bytes(in_path.read_bytes() + b'2')
    # return nothing so normal copy also happens
    """
        })

    build(str(tmpdir))
    assert gettree(tmpdir.join('dist')) == {
        'index.html': 'hello\n',
        'foo': {
            'bar.4a8a08f.svg': 'bar.svg c custom',
        },
        'image1.0cc175b.png': 'a',
        'image2.4a8a08f.png': 'c',
        'image2.4a8a08f.png.alt': 'c2',
    }
示例#57
0
def test_gettree(tmpdir):
    tmpdir.join('foo').write_text('bar', 'utf8')
    assert {'foo': 'bar'} == gettree(tmpdir)
示例#58
0
def test_gettree_truncate(tmpdir):
    tmpdir.join('foo').write_text('123456789', 'utf8')
    assert {'foo': '12...'} == gettree(tmpdir, max_len=5)
示例#59
0
def test_build_multi_part(tmpdir):
    mktree(
        tmpdir, {
            'pages': {
                'multipart_list.md': ('---\n'
                                      'uri: /list_md.html\n'
                                      'template: list.jinja\n'
                                      '---\n'
                                      'part 1\n'
                                      '--- . ---\n'
                                      'part **2**\n'
                                      '---.---\n'
                                      'this is part *3*\n'),
                'multipart_dict.md': ('---\n'
                                      'uri: /dict_md.html\n'
                                      'template: dict.jinja\n'
                                      '---\n'
                                      'the main **section**\n'
                                      '--- other ---\n'
                                      'part *2*\n'),
                'multipart_list.html': ('---\n'
                                        'uri: /list_html.html\n'
                                        'template: list.jinja\n'
                                        '---\n'
                                        'part 1\n'
                                        '--- . ---\n'
                                        'part 2\n'
                                        '---.---\n'
                                        'this is part 3\n'),
                'multipart_dict.html': ('---\n'
                                        'uri: /dict_html.html\n'
                                        'template: dict.jinja\n'
                                        '---\n'
                                        'the main section\n'
                                        '--- other ---\n'
                                        'part 2\n'),
            },
            'theme': {
                'templates/': {
                    'list.jinja': ('{% for v in content %}\n'
                                   '  {{ v.content }}\n'
                                   '{% endfor %}\n'),
                    'dict.jinja': ('{{ content.main.content }}\n'
                                   '{{ content.other.content }}\n'),
                },
            },
        })
    build(tmpdir, mode=Mode.production)
    assert gettree(tmpdir.join('dist')) == {
        'list_md.html': ('\n'
                         '  <p>part 1</p>\n'
                         '\n\n'
                         '  <p>part <strong>2</strong></p>\n'
                         '\n\n'
                         '  <p>this is part <em>3</em></p>\n'),
        'dict_md.html': ('<p>the main <strong>section</strong></p>\n'
                         '\n'
                         '<p>part <em>2</em></p>\n'),
        'list_html.html': ('\n'
                           '  part 1\n'
                           '\n'
                           '  part 2\n'
                           '\n'
                           '  this is part 3\n'),
        'dict_html.html': ('the main section\n'
                           'part 2\n'),
    }
示例#60
0
def test_mock_executor(tmpdir, mocker):
    foobar_path = str(tmpdir.join('pages/foobar.md'))

    async def awatch_alt(*args, **kwargs):
        yield {(Change.modified, str(tmpdir.join('harrier.yml')))}
        yield {(Change.modified, foobar_path)}
        yield {(Change.modified, str(tmpdir.join('theme/assets/main.png')))}
        yield {(Change.modified, str(tmpdir.join('theme/sass/main.scss')))}
        yield {(Change.modified, str(tmpdir.join('theme/templates/main.jinja')))}
        yield {(Change.modified, str(tmpdir.join('extensions.py')))}
        yield {(Change.modified, str(tmpdir.join('data/foobar.yml')))}

    mktree(tmpdir, {
        'pages/foobar.md': '# hello',
        'theme/templates/main.jinja': 'main:\n {{ content }}',
        'harrier.yml': 'foo: bar',
    })
    mocker.patch('harrier.dev.awatch', side_effect=awatch_alt)
    mocker.patch('harrier.dev.Server', return_value=MockServer())

    loop = asyncio.new_event_loop()
    f = asyncio.Future(loop=loop)
    f.set_result(None)
    mock_run_in_executor = mocker.patch.object(loop, 'run_in_executor', return_value=f)
    asyncio.set_event_loop(loop)

    assert not tmpdir.join('dist').check()

    dev(str(tmpdir), 8000)

    assert gettree(tmpdir.join('dist')) == {}

    assert [c[0][2].dict(exclude={'config_path'}) for c in mock_run_in_executor.call_args_list] == [
        {
            'pages': '__FB__',
            'assets': False,
            'sass': False,
            'templates': False,
            'data': False,
            'extensions': False,
            'update_config': False,
        },
        {
            'pages': set(),
            'assets': False,
            'sass': False,
            'templates': False,
            'data': False,
            'extensions': False,
            'update_config': True,
        },
        {
            'pages': {(Change.modified, Path(foobar_path))},
            'assets': False,
            'sass': False,
            'templates': False,
            'data': False,
            'extensions': False,
            'update_config': False,
        },
        {
            'pages': set(),
            'assets': True,
            'sass': False,
            'templates': False,
            'data': False,
            'extensions': False,
            'update_config': False,
        },
        {
            'pages': set(),
            'assets': False,
            'sass': True,
            'templates': False,
            'data': False,
            'extensions': False,
            'update_config': False,
        },
        {
            'pages': set(),
            'assets': False,
            'sass': False,
            'templates': True,
            'data': False,
            'extensions': False,
            'update_config': False,
        },
        {
            'pages': set(),
            'assets': False,
            'sass': False,
            'templates': False,
            'data': False,
            'extensions': True,
            'update_config': False,
        },
        {
            'pages': set(),
            'assets': False,
            'sass': False,
            'templates': False,
            'data': True,
            'extensions': False,
            'update_config': False,
        },
    ]