from datetime import timedelta
from unittest.mock import patch

import pytest
from requests import PreparedRequest, Request
from requests.cookies import RequestsCookieJar

from requests_cache.cache_keys import create_key
from requests_cache.models import CachedRequest, CachedResponse
from requests_cache.policy import EXPIRE_IMMEDIATELY, CacheActions, CacheSettings, utcnow
from tests.conftest import ETAG, HTTPDATE_STR, LAST_MODIFIED, MOCKED_URL, get_mock_response

IGNORED_DIRECTIVES = [
    'no-transform',
    'private',
    'proxy-revalidate',
    'public',
    's-maxage=<seconds>',
]
BASIC_REQUEST = Request(method='GET', url='https://site.com/img.jpg', headers={})
EXPIRED_RESPONSE = CachedResponse(expires=utcnow() - timedelta(1))


@pytest.mark.parametrize(
    'request_expire_after, url_expire_after, expected_expiration',
    [
        (2, 3, 2),
        (None, 3, 3),
        (2, None, 2),
        (None, None, 1),
    ],
)
@patch('requests_cache.policy.actions.get_url_expiration')
def test_init(
    get_url_expiration,
    request_expire_after,
    url_expire_after,
    expected_expiration,
):
    """Test precedence with various combinations or per-request, per-session, per-URL, and
    Cache-Control expiration
    """
    request = PreparedRequest()
    request.url = 'https://img.site.com/base/img.jpg'
    if request_expire_after:
        request.headers = {'Cache-Control': f'max-age={request_expire_after}'}
    get_url_expiration.return_value = url_expire_after

    settings = CacheSettings(cache_control=True, expire_after=1)
    actions = CacheActions.from_request(cache_key='key', request=request, settings=settings)
    assert actions.expire_after == expected_expiration


@pytest.mark.parametrize(
    'headers, expected_expiration',
    [
        ({}, None),
        ({'Expires': HTTPDATE_STR}, None),  # Only valid for response headers
        ({'Cache-Control': 'max-age=60'}, 60),
        ({'Cache-Control': 'public, max-age=60'}, 60),
        ({'Cache-Control': b'public, max-age=60'}, 60),  # requests-oauthlib casts headers to bytes
        ({'Cache-Control': 'max-age=0'}, EXPIRE_IMMEDIATELY),
    ],
)
def test_init_from_headers(headers, expected_expiration):
    """Test with Cache-Control request headers"""
    settings = CacheSettings(cache_control=True)
    request = Request(method='GET', url=MOCKED_URL, headers=headers).prepare()
    actions = CacheActions.from_request('key', request, settings)

    assert actions.cache_key == 'key'
    if expected_expiration != EXPIRE_IMMEDIATELY:
        assert actions.expire_after == expected_expiration
        assert actions.skip_read is False
        assert actions.skip_write is False


def test_init_from_headers__no_store():
    """Test with Cache-Control request headers"""
    settings = CacheSettings(cache_control=True)
    request = Request(method='GET', url=MOCKED_URL, headers={'Cache-Control': 'no-store'}).prepare()
    actions = CacheActions.from_request('key', request, settings)

    assert actions.skip_read is True
    assert actions.skip_write is True


@pytest.mark.parametrize(
    'url, request_expire_after, expected_expiration',
    [
        ('https://img.site_1.com', None, timedelta(hours=12)),
        ('https://img.site_1.com', 60, 60),
        ('https://img.site.com/base/', None, 1),
        ('https://img.site.com/base/img.jpg', None, 1),
        ('http://site_2.com/resource_1', None, timedelta(hours=20)),
        ('ftp://site_2.com/resource_1/index.html', None, timedelta(hours=20)),
        ('http://site_2.com/resource_2/', None, timedelta(days=7)),
        ('http://site_2.com/static/', None, -1),
        ('http://site_2.com/static/img.jpg', None, -1),
        ('http://site_2.com', None, 1),
        ('http://site_2.com', 60, 60),
        ('https://some_other_site.com', None, 1),
        ('https://some_other_site.com', 60, 60),
    ],
)
def test_init_from_settings(url, request_expire_after, expected_expiration):
    """Test with per-session, per-request, and per-URL expiration"""
    settings = CacheSettings(
        expire_after=1,
        urls_expire_after={
            '*.site_1.com': timedelta(hours=12),
            'site_2.com/resource_1': timedelta(hours=20),
            'site_2.com/resource_2': timedelta(days=7),
            'site_2.com/static': -1,
        },
    )
    request = Request(method='GET', url=url)
    if request_expire_after:
        request.headers = {'Cache-Control': f'max-age={request_expire_after}'}

    actions = CacheActions.from_request('key', request.prepare(), settings)
    assert actions.expire_after == expected_expiration


@pytest.mark.parametrize(
    'headers, expire_after, expected_expiration, expected_skip_read',
    [
        ({'Cache-Control': 'max-age=60'}, 1, 60, False),
        ({}, 1, 1, False),
        ({}, 0, 0, False),
        ({'Cache-Control': 'max-age=60'}, 1, 60, False),
        ({'Cache-Control': 'max-age=0'}, 1, 0, False),
        ({'Cache-Control': 'no-store'}, 1, 1, True),
        ({'Cache-Control': 'no-cache'}, 1, 1, True),
    ],
)
def test_init_from_settings_and_headers(
    headers, expire_after, expected_expiration, expected_skip_read
):
    """Test behavior with both cache settings and request headers."""
    request = Request(method='GET', url=MOCKED_URL, headers=headers)
    settings = CacheSettings(expire_after=expire_after)
    actions = CacheActions.from_request('key', request, settings)

    assert actions.expire_after == expected_expiration
    assert actions.skip_read == expected_skip_read


def test_update_from_cached_response__new_request():
    actions = CacheActions.from_request('key', BASIC_REQUEST)
    actions.update_from_cached_response(None)
    assert actions.send_request is True


def test_update_from_cached_response__resend_request():
    actions = CacheActions.from_request('key', BASIC_REQUEST)

    actions.update_from_cached_response(EXPIRED_RESPONSE)
    assert actions.resend_request is True


@pytest.mark.parametrize(
    'response_headers, expected_validation_headers',
    [
        ({}, {}),
        ({'ETag': ETAG}, {'If-None-Match': ETAG}),
        ({'Last-Modified': LAST_MODIFIED}, {'If-Modified-Since': LAST_MODIFIED}),
        (
            {'ETag': ETAG, 'Last-Modified': LAST_MODIFIED},
            {'If-None-Match': ETAG, 'If-Modified-Since': LAST_MODIFIED},
        ),
    ],
)
def test_update_from_cached_response__revalidate(response_headers, expected_validation_headers):
    """Conditional request headers should be added if the cached response is expired"""
    actions = CacheActions.from_request('key', BASIC_REQUEST)
    cached_response = CachedResponse(headers=response_headers, expires=utcnow() - timedelta(1))

    actions.update_from_cached_response(cached_response)
    assert actions.send_request is False
    assert actions.resend_request is True
    assert actions._validation_headers == expected_validation_headers


@pytest.mark.parametrize(
    'response_headers',
    [
        {'Cache-Control': 'no-cache'},
        {'Cache-Control': 'max-age=0,must-revalidate'},
    ],
)
@pytest.mark.parametrize('cache_control', [True, False])
def test_update_from_cached_response__force_revalidate(cache_control, response_headers):
    """Conditional request headers should be added if requested by response headers, even if the
    response is not expired
    """
    actions = CacheActions.from_request(
        'key',
        request=Request(url='https://img.site.com/base/img.jpg', headers={}),
        settings=CacheSettings(cache_control=cache_control),
    )
    cached_response = CachedResponse(headers={'ETag': ETAG, **response_headers}, expires=None)

    actions.update_from_cached_response(cached_response)

    # cache_control=False overrides revalidation in this case
    if cache_control is False:
        assert actions.resend_request is False
        assert not actions._validation_headers
    else:
        assert actions.resend_request is True
        assert actions._validation_headers == {'If-None-Match': ETAG}


def test_update_from_cached_response__no_revalidation():
    """Conditional request headers should NOT be added if the cached response is not expired and
    revalidation is otherwise not requested"""
    actions = CacheActions.from_request('key', BASIC_REQUEST)
    cached_response = CachedResponse(
        headers={'ETag': ETAG, 'Last-Modified': LAST_MODIFIED}, expires=None
    )

    actions.update_from_cached_response(cached_response)
    assert actions._validation_headers == {}


def test_update_from_cached_response__504():
    settings = CacheSettings(only_if_cached=True)
    actions = CacheActions.from_request('key', BASIC_REQUEST, settings=settings)
    actions.update_from_cached_response(EXPIRED_RESPONSE)
    assert actions.error_504 is True


def test_update_from_cached_response__stale_if_error():
    settings = CacheSettings(only_if_cached=True, stale_if_error=True)
    actions = CacheActions.from_request('key', BASIC_REQUEST, settings=settings)
    actions.update_from_cached_response(EXPIRED_RESPONSE)
    assert actions.error_504 is False and actions.resend_request is False


def test_update_from_cached_response__stale_while_revalidate():
    settings = CacheSettings(only_if_cached=True, stale_while_revalidate=True)
    actions = CacheActions.from_request('key', BASIC_REQUEST, settings=settings)
    actions.update_from_cached_response(EXPIRED_RESPONSE)
    assert actions.resend_async is True


@pytest.mark.parametrize(
    'vary, cached_headers, new_headers, expected_match',
    [
        ({}, {}, {}, True),
        ({'Vary': 'Accept'}, {'Accept': 'application/json'}, {'Accept': 'application/json'}, True),
        ({'Vary': 'Accept'}, {'Accept': 'application/json'}, {}, False),
        (
            {'Vary': 'Accept'},
            {'Accept': 'application/json'},
            {'Accept': 'application/json', 'Accept-Language': 'en'},
            True,
        ),
        (
            {'Vary': 'Accept-Encoding'},
            {'Accept': 'application/json'},
            {'Accept': 'text/html'},
            True,
        ),
        ({'Vary': 'Accept'}, {'Accept': 'application/json'}, {'Accept': 'text/html'}, False),
        (
            {'Vary': 'Accept-Encoding'},
            {'Accept-Encoding': 'gzip,deflate'},
            {'Accept-Encoding': 'gzip,deflate'},
            True,
        ),
        # Only basic header normalization is done in create_key() (whitespace, case, order)
        (
            {'Vary': 'Accept-Encoding'},
            {'Accept-Encoding': 'gzip,deflate'},
            {'Accept-Encoding': 'dEfLaTe,  GZIP, '},
            True,
        ),
        (
            {'Vary': 'Accept-Encoding'},
            {'Accept-Encoding': 'gzip,deflate'},
            {'Accept-Encoding': 'gzip,br'},
            False,
        ),
        (
            {'Vary': 'Accept, Accept-Encoding'},
            {'Accept': 'application/json', 'Accept-Encoding': 'gzip,deflate'},
            {'Accept': 'application/json', 'Accept-Encoding': 'gzip,deflate'},
            True,
        ),
        (
            {'Vary': 'Accept, Accept-Encoding'},
            {'Accept': 'application/json', 'Accept-Encoding': 'gzip,deflate'},
            {'Accept': 'application/json', 'Accept-Encoding': 'br'},
            False,
        ),
        (
            {'Vary': 'Accept, Accept-Encoding'},
            {'Accept': 'application/json', 'Accept-Encoding': 'gzip,deflate'},
            {'Accept': 'text/html', 'Accept-Encoding': 'gzip,deflate'},
            False,
        ),
        (
            {'Vary': 'Accept, Accept-Encoding'},
            {'Accept': 'application/json', 'Accept-Encoding': 'gzip,deflate'},
            {'Accept-Encoding': 'gzip,deflate'},
            False,
        ),
        ({'Vary': '*'}, {}, {}, False),
        ({'Vary': '*'}, {'Accept': 'application/json'}, {'Accept': 'application/json'}, False),
    ],
)
def test_update_from_cached_response__vary_headers(
    vary, cached_headers, new_headers, expected_match
):
    cached_response = CachedResponse(
        headers=vary,
        request=Request(method='GET', url='https://site.com/img.jpg', headers=cached_headers),
    )
    request = Request(method='GET', url='https://site.com/img.jpg', headers=new_headers)
    actions = CacheActions.from_request('key', request)
    actions.update_from_cached_response(cached_response, create_key=create_key)

    # If the headers don't match wrt. Vary, expect a new request to be sent (cache miss)
    assert actions.send_request is not expected_match


@pytest.mark.parametrize(
    'vary, cached_headers, new_headers, expect_vary_key_set',
    [
        # Vary mismatch: secondary key should be set (and differ from base key)
        ({'Vary': 'Accept'}, {'Accept': 'application/json'}, {'Accept': 'text/html'}, True),
        # Vary match: no secondary key needed
        ({'Vary': 'Accept'}, {'Accept': 'application/json'}, {'Accept': 'application/json'}, False),
        # Vary: * always misses, but no secondary lookup is possible
        ({'Vary': '*'}, {'Accept': 'application/json'}, {'Accept': 'application/json'}, False),
        # No Vary header: no secondary key
        ({}, {}, {}, False),
        # Vary: Cookie with matching cookies: no secondary key (cookies match, so cache hit)
        ({'Vary': 'Cookie'}, {}, {}, False),
    ],
)
def test_vary_cache_key(vary, cached_headers, new_headers, expect_vary_key_set):
    cached_response = CachedResponse(
        headers=vary,
        request=Request(method='GET', url='https://site.com/img.jpg', headers=cached_headers),
    )
    request = Request(method='GET', url='https://site.com/img.jpg', headers=new_headers)
    actions = CacheActions.from_request('key', request)
    actions.update_from_cached_response(cached_response, create_key=create_key)

    if expect_vary_key_set:
        assert actions.vary_cache_key is not None
        assert actions.vary_cache_key != actions.cache_key
    else:
        assert actions.vary_cache_key is None


def test_vary_cache_key__merges_user_match_headers():
    """vary_cache_key should incorporate user match_headers along with Vary headers"""
    cached_response = CachedResponse(
        headers={'Vary': 'Accept'},
        request=Request(
            method='GET',
            url='https://site.com/img.jpg',
            headers={'Accept': 'application/json', 'Authorization': 'Bearer token1'},
        ),
    )
    request = Request(
        method='GET',
        url='https://site.com/img.jpg',
        headers={'Accept': 'text/html', 'Authorization': 'Bearer token2'},
    )
    settings = CacheSettings(match_headers=['Authorization'])
    actions = CacheActions.from_request('key', request, settings=settings)
    actions.update_from_cached_response(cached_response, create_key=create_key)

    assert actions.vary_cache_key is not None

    # The secondary key should differ from a key built with only Vary headers
    request_2 = Request(
        method='GET',
        url='https://site.com/img.jpg',
        headers={'Accept': 'text/html', 'Authorization': 'Bearer token_different'},
    )
    actions_2 = CacheActions.from_request('key', request_2, settings=settings)
    actions_2.update_from_cached_response(cached_response, create_key=create_key)
    assert actions_2.vary_cache_key != actions.vary_cache_key


def test_vary_cache_key__match_all():
    """vary_cache_key should be set when match_headers=True (match all headers)"""
    cached_response = CachedResponse(
        headers={'Vary': 'Accept'},
        request=Request(
            method='GET',
            url='https://site.com/img.jpg',
            headers={'Accept': 'application/json'},
        ),
    )
    request = Request(
        method='GET',
        url='https://site.com/img.jpg',
        headers={'Accept': 'text/html'},
    )
    settings = CacheSettings(match_headers=True)
    actions = CacheActions.from_request('key', request, settings=settings)
    actions.update_from_cached_response(cached_response, create_key=create_key)

    assert actions.vary_cache_key is not None
    assert actions.vary_cache_key != actions.cache_key


@pytest.mark.parametrize(
    'cached_cookies, new_cookies, expected_match',
    [
        ({'session': 'abc123'}, {'session': 'abc123'}, True),
        ({'session': 'abc123'}, {'session': 'xyz789'}, False),
        ({'session': 'abc', 'user': 'bob'}, {'session': 'abc', 'user': 'bob'}, True),
        ({'user': 'bob', 'session': 'abc'}, {'session': 'abc', 'user': 'bob'}, True),
        ({'session': 'abc', 'user': 'bob'}, {'session': 'abc', 'user': 'alice'}, False),
        ({}, {}, True),
        ({'session': 'abc123'}, {}, False),
        ({}, {'session': 'abc123'}, False),
    ],
)
def test_update_from_cached_response__vary_cookie(cached_cookies, new_cookies, expected_match):
    cached_cookiejar = RequestsCookieJar()
    cached_cookiejar.update(cached_cookies)
    new_cookiejar = RequestsCookieJar()
    new_cookiejar.update(new_cookies)

    # Cached response with cookies
    cached_request = CachedRequest(
        method='GET',
        url='https://site.com/page',
        cookies=cached_cookiejar,
    )
    cached_response = CachedResponse(
        headers={'Vary': 'Cookie'},
        request=cached_request,
    )

    # New request with cookies
    new_request = PreparedRequest()
    new_request.prepare(method='GET', url='https://site.com/page', cookies=new_cookiejar)

    actions = CacheActions.from_request('key', new_request)
    actions.update_from_cached_response(cached_response, create_key=create_key)

    # If cookies don't match, expect a new request (cache miss)
    assert actions.send_request is not expected_match


def test_update_from_cached_response__vary_cookie_and_headers():
    cached_cookiejar = RequestsCookieJar()
    cached_cookiejar.set('session', 'abc123')
    new_cookiejar = RequestsCookieJar()
    new_cookiejar.set('session', 'abc123')

    # Cached response with Vary: Cookie, Accept
    cached_request = CachedRequest(
        method='GET',
        url='https://site.com/page',
        headers={'Accept': 'application/json'},
        cookies=cached_cookiejar,
    )
    cached_response = CachedResponse(
        headers={'Vary': 'Cookie, Accept'},
        request=cached_request,
    )

    # New request with matching cookies but different Accept header
    new_request = PreparedRequest()
    new_request.prepare(
        method='GET',
        url='https://site.com/page',
        headers={'Accept': 'text/html'},
        cookies=new_cookiejar,
    )

    actions = CacheActions.from_request('key', new_request)
    actions.update_from_cached_response(cached_response, create_key=create_key)

    # Should be a cache miss because Accept header differs
    assert actions.send_request is True
    # Cookies match, so secondary key is set for the differing Accept header
    assert actions.vary_cache_key is not None


@pytest.mark.parametrize('max_stale, usable', [(5, False), (15, True)])
def test_is_usable__max_stale(max_stale, usable):
    """For a response that expired 10 seconds ago, it may be either accepted or rejected based on
    max-stale
    """
    request = Request(
        url='https://img.site.com/base/img.jpg',
        headers={'Cache-Control': f'max-stale={max_stale}'},
    )
    actions = CacheActions.from_request('key', request)
    cached_response = CachedResponse(expires=utcnow() - timedelta(seconds=10))
    assert actions.is_usable(cached_response) is usable


@pytest.mark.parametrize('min_fresh, usable', [(5, True), (15, False)])
def test_is_usable__min_fresh(min_fresh, usable):
    """For a response that expires in 10 seconds, it may be either accepted or rejected based on
    min-fresh
    """
    request = Request(
        url='https://img.site.com/base/img.jpg',
        headers={'Cache-Control': f'min-fresh={min_fresh}'},
    )
    actions = CacheActions.from_request('key', request)
    cached_response = CachedResponse(expires=utcnow() + timedelta(seconds=10))
    assert actions.is_usable(cached_response) is usable


@pytest.mark.parametrize(
    'stale_if_error, error, usable',
    [
        (5, True, False),
        (15, True, True),
        (15, False, False),
    ],
)
def test_is_usable__stale_if_error(stale_if_error, error, usable):
    """For a response that expired 10 seconds ago, if an error occurred while refreshing, it may be
    either accepted or rejected based on stale-if-error
    """
    request = Request(
        url='https://img.site.com/base/img.jpg',
        headers={'Cache-Control': f'stale-if-error={stale_if_error}'},
    )
    actions = CacheActions.from_request('key', request)
    cached_response = CachedResponse(expires=utcnow() - timedelta(seconds=10))
    assert actions.is_usable(cached_response, error=error) is usable


@pytest.mark.parametrize(
    'stale_while_revalidate, usable',
    [
        (5, False),
        (15, True),
    ],
)
def test_is_usable__stale_while_revalidate(stale_while_revalidate, usable):
    """For a response that expired 10 seconds ago, if an error occurred while refreshing, it may be
    either accepted or rejected based on stale-while-revalidate
    """
    request = Request(
        url='https://img.site.com/base/img.jpg',
        headers={'Cache-Control': f'stale-while-revalidate={stale_while_revalidate}'},
    )
    actions = CacheActions.from_request('key', request)
    cached_response = CachedResponse(expires=utcnow() - timedelta(seconds=10))
    assert actions.is_usable(cached_response=cached_response) is usable


@pytest.mark.parametrize(
    'headers, expected_expiration',
    [
        ({}, None),
        ({'Cache-Control': 'no-cache'}, None),  # Forces revalidation, but no effect on expiration
        ({'Cache-Control': 'max-age=0'}, 0),
        ({'Cache-Control': 'max-age=60'}, 60),
        ({'Cache-Control': 'public, max-age=60'}, 60),
        ({'Cache-Control': 'max-age=0'}, 0),
        ({'Cache-Control': 'immutable'}, -1),
        ({'Cache-Control': 'immutable, max-age=60'}, -1),  # Immutable should take precedence
        ({'Expires': HTTPDATE_STR}, HTTPDATE_STR),
        ({'Expires': HTTPDATE_STR, 'Cache-Control': 'max-age=60'}, 60),
    ],
)
def test_update_from_response(headers, expected_expiration):
    """Test with Cache-Control response headers"""
    actions = CacheActions.from_request('key', BASIC_REQUEST, CacheSettings(cache_control=True))
    actions.update_from_response(get_mock_response(headers=headers))

    assert actions.expire_after == expected_expiration
    assert actions.skip_write is (expected_expiration == EXPIRE_IMMEDIATELY)


def test_update_from_response__no_store():
    actions = CacheActions.from_request('key', BASIC_REQUEST, CacheSettings(cache_control=True))
    actions.update_from_response(get_mock_response(headers={'Cache-Control': 'no-store'}))
    assert actions.skip_write is True


def test_update_from_response__ignored():
    actions = CacheActions.from_request('key', BASIC_REQUEST, CacheSettings(cache_control=False))
    actions.update_from_response(get_mock_response(headers={'Cache-Control': 'max-age=5'}))
    assert actions.expire_after is None


@pytest.mark.parametrize('validator_headers', [{'ETag': ETAG}, {'Last-Modified': LAST_MODIFIED}])
@pytest.mark.parametrize('cache_headers', [{'Cache-Control': 'max-age=0'}, {'Expires': '0'}])
@patch('requests_cache.expiration.utcnow')
def test_update_from_response__revalidate(mock_utcnow, cache_headers, validator_headers):
    """If expiration is 0 and there's a validator, the response should be cached, but with immediate
    expiration
    """
    actions = CacheActions.from_request('key', BASIC_REQUEST, CacheSettings(cache_control=True))
    response = get_mock_response(headers={**cache_headers, **validator_headers})
    actions.update_from_response(response)

    assert actions.expires == mock_utcnow()
    assert actions.skip_write is False


@pytest.mark.parametrize(
    'read_only, headers_changed, expected_skip_write',
    [
        (False, False, True),  # Nothing changed: skip_write should be True (optimization)
        (False, True, False),  # Headers changed, not read_only: should write
        (True, False, True),  # read_only: should remain True even if nothing changed
        (True, True, True),  # read_only + headers changed: skip_write must remain True
    ],
)
def test_update_revalidated_response__skip_write(read_only, headers_changed, expected_skip_write):
    """skip_write should be True when read_only=True or when nothing changed,
    and False when headers/expiration changed and read_only=False
    """
    actions = CacheActions.from_request(
        'key', BASIC_REQUEST, CacheSettings(cache_control=True, read_only=read_only)
    )
    cached_response = get_mock_response(headers={'ETag': ETAG})
    cached_response.expires = None
    new_headers = {'ETag': ETAG, 'X-Custom-Header': 'new'} if headers_changed else {'ETag': ETAG}
    new_response = get_mock_response(status_code=304, headers=new_headers)
    actions.update_revalidated_response(new_response, cached_response)
    assert actions.skip_write is expected_skip_write


def test_update_revalidated_response__transfer_encoding():
    """When updating response headers after revalidating a cached response,
    don't set both `Content-Length` and `Transfer-Encoding`
    """
    actions = CacheActions.from_request('key', BASIC_REQUEST, CacheSettings(cache_control=True))
    cached_response = get_mock_response(headers={'ETag': ETAG, 'Transfer-Encoding': 'chunked'})
    new_response = get_mock_response(status_code=304, headers={'ETag': ETAG, 'Content-Length': 0})
    cached_response = actions.update_revalidated_response(new_response, cached_response)
    assert cached_response.headers['Transfer-Encoding'] == 'chunked'
    assert 'Content-Length' not in cached_response.headers


@pytest.mark.parametrize('directive', IGNORED_DIRECTIVES)
def test_ignored_headers(directive):
    """Ensure that currently unimplemented Cache-Control headers do not affect behavior"""
    request = Request(
        method='GET', url='https://img.site.com/base/img.jpg', headers={'Cache-Control': directive}
    ).prepare()
    settings = CacheSettings(expire_after=1, cache_control=True)
    actions = CacheActions.from_request('key', request, settings)

    assert actions.expire_after == 1
    assert actions.skip_read is False
    assert actions.skip_write is False
