"""V8.20 offline CMS compatibility tests, independent of the public network.""" import io import json import pytest from app import wordpress_compat from app.wp_complex_v820 import inspect_wxr, extract_acf from app.wp_migration_v82 import _media_urls, _rewrite_media_html from test_factory_v2 import factory,site def wxr(records): return (''''''+records+'').encode() def entry(wp_id,link,custom='',body='',kind='page'): return f'''Page {wp_id}{link.replace('&','&')} {kind}{wp_id} publish{custom}''' def meta(key,value): return f'{key}' def test_wxr_duplicate_route_and_dynamic_query_blocked(): data=wxr(entry(1,'https://old.example/products/a/')+entry(2,'https://old.example/products/a/')+entry(3,'https://old.example/?p=5')) out=inspect_wxr(data) assert out['unique_published_routes']==1 assert out['blocking_issues']==2 assert {x['code'] for x in out['issues']}=={'duplicate_route','invalid_permalink'} assert out['ready_for_automatic_publish'] is False def test_wxr_counts_attachments_and_custom_types(): data=wxr(entry(1,'https://old.example/a/',kind='attachment')+entry(2,'https://old.example/b/',kind='portfolio')) out=inspect_wxr(data) assert out['counts']['attachments']==1 assert out['features']['custom_post_types']==1 assert out['sample_routes'][0]['route']=='/b/' def test_wxr_dynamic_shortcode_not_claimed_as_static(): data=wxr(entry(1,'https://old.example/contact/',body='[contact-form-7 id="4"]')) out=inspect_wxr(data) assert out['blocking_issues']==1 assert out['issues'][0]['code']=='dynamic_shortcode' def test_acf_simple_repeater_explicit_field_references(): values={'_features':'field_parent','features':'2','features_0_title':'First','_features_0_title':'field_child', 'features_1_title':'Second','_features_1_title':'field_child','headline':'About','_headline':'field_header'} parsed=extract_acf(values) assert parsed['repeaters']['features']==[{'title':'First'},{'title':'Second'}] assert parsed['fields']['headline']=='About' assert any('核对' in s for s in parsed['warnings']) def test_acf_serialized_does_not_execute_or_decode(): parsed=extract_acf({'_links':'field_test','links':'a:1:{i:0;s:4:"evil";}'}) assert 'links' not in parsed['fields'] assert any('序列化' in s for s in parsed['warnings']) def test_acf_incomplete_repeater_kept_raw_only(): meta_values={'_list':'field_list','list':'2','_list_0_title':'field_title','list_0_title':'First'} parsed=extract_acf(meta_values) assert 'list' not in parsed['repeaters'] assert any('不连续' in x for x in parsed['warnings']) def test_elementor_unknown_widget_reported(): data=json.dumps([{'elType':'widget','widgetType':'unknown_gallery','settings':{}}, {'elType':'widget','widgetType':'heading','settings':{'title':'A & B'}}]) out=wordpress_compat.elementor_to_html(data) assert out['widgets']==2 assert 'A & B' in out['html'] assert any('unknown_gallery' in x for x in out['warnings']) def test_css_remote_image_inventory_and_rewrite(): source={'body':'''
'''} assert _media_urls(source)==['https://old.example/bg.webp','https://old.example/lazy.png'] converted={'https://old.example/bg.webp':'/media/a.webp','https://old.example/lazy.png':'/media/b.png'} result,changed=_rewrite_media_html(source['body'],converted) assert changed and '/media/a.webp' in result and '/media/b.png' in result assert not _media_urls({'body':result}) def test_xxe_and_invalid_input_are_rejected(): with pytest.raises(ValueError):inspect_wxr(b'') with pytest.raises(Exception):inspect_wxr(b']>&x;') with pytest.raises(ValueError):inspect_wxr(b'') def test_wxr_api_enforces_auth_and_csrf(factory): sid=site(factory,mode='migration') payload=wxr(entry(1,'https://old.example/about/')) response=factory.post(f'/api/migrations/sites/{sid}/wordpress/wxr-preflight',files={'file':('site.xml',payload)}) assert response.status_code==200,response.text assert response.json()['unique_published_routes']==1 assert response.json()['ready_for_automatic_publish'] is False bad=factory.post(f'/api/migrations/sites/{sid}/wordpress/wxr-preflight',files={'file':('site.xml',b'')}) assert bad.status_code==400 def test_import_wxr_rejects_dynamic_path_before_writing(factory): sid=site(factory,mode='migration') payload=wxr(entry(1,'https://old.example/?p=13')) response=factory.post(f'/api/sites/{sid}/import',files={'file':('site.xml',payload)}) assert response.status_code in (400,422) assert not any(x['route']=='/' and x['title']=='Page 1' for x in factory.get(f'/api/sites/{sid}/entries').json()) def test_wxr_acf_repeater_survives_import(factory): sid=site(factory,mode='migration') custom=''.join(meta(k,v) for k,v in {'_features':'field_parent','features':'2', '_features_0_name':'field_child','features_0_name':'SUV', '_features_1_name':'field_child','features_1_name':'Pickup'}.items()) payload=wxr(entry(1,'https://old.example/products/a/',custom=custom)) response=factory.post(f'/api/sites/{sid}/import',files={'file':('site.xml',payload)}) assert response.status_code==200,response.text item=next(x for x in factory.get(f'/api/sites/{sid}/entries').json() if x['route']=='/products/a/') assert item['meta']['fields']['features']==[{'name':'SUV'},{'name':'Pickup'}] assert item['meta']['acf_repeaters']=={'features':[{'name':'SUV'},{'name':'Pickup'}]}