§
    ˆ¿j,  ã                  óf  — d Z ddlmZ ddlZddlZddlZddlZddlmZ  ee	¦  «         
                    ¦   «         j        j        j        Zedz  dz  dz  Zedz  d	z  d
z  dz  dz  Zedz  d	z  d
z  dz  dz  Zedz  d	z  dz  Zdd„Z G d„ dej        ¦  «        Zedk    r ej        ¦   «          dS dS )ah  
FreeExile Milestone 2 Empirical Challenger Test Suite:
Adversarial Verification of Static Linter (tools/lint/check_i18n_hygiene.py).

Verifies Negative Baselines and Edge Cases:
- Test 1: Injected hardcoded Vietnamese string in UI file -> code 1 under --strict (RULE-1-HARDCODED-VI).
- Test 2: Injected missing key in 1 of 9 languages in catalog / mock catalog -> code 1 (RULE-2-DICT-PARITY).
- Test 3: Injected dangling data-i18n key in HTML -> code 1 (RULE-3-DANGLING-KEY).
- Test 4: Current production codebase -> code 0 (100% clean).
- Test 5: Allowlisted seed structures and fallback arguments do NOT trigger false positives.
- Test 6: Single-line and multi-line comments do NOT trigger false positives.
- Test 7: JSON audit report generation format and data integrity.
- Test 8-11: Deep empirical edge-case boundary challenges (path resolution, multiline, braces).
é    )ÚannotationsN)ÚPathÚtoolsÚlintzcheck_i18n_hygiene.pyÚclientÚwebappÚjsÚuiz
chat_ui.jsÚdatazchat_i18n_catalog.jsz
index.htmlÚ
extra_argsÚstrÚreturnú subprocess.CompletedProcess[str]c            	     óº   — t           j        t          t          ¦  «        gt	          | ¦  «        z   }t          j        |dddt          t          ¦  «        d¬¦  «        S )zBExecutes check_i18n_hygiene.py via subprocess with utf-8 encoding.Túutf-8g      .@)Úcapture_outputÚtextÚencodingÚcwdÚtimeout)ÚsysÚ
executabler   ÚLINTER_SCRIPTÚlistÚ
subprocessÚrunÚPROJECT_ROOT)r   Úcmds     úLC:\Projects\FreeExile\tests\unit\test_challenger_i18n_hygiene_adversarial.pyÚ
run_linterr       sV   € åŒ>�3�}Ñ-Ô-Ð
.µ°jÑ1AÔ1AÑ
A€CÝŒ>ØØØØÝ•ÑÔØðñ ô ð ó    c                  ób   — e Zd ZdZdd„Zdd„Zdd„Zdd„Zdd„Zdd	„Z	dd
„Z
dd„Zdd„Zdd„ZdS )Ú TestI18nHygieneLinterAdversarialzOEmpirical negative and positive baseline verification of check_i18n_hygiene.py.r   ÚNonec                ó8  — t           dz  dz  dz  dz  dz  }	 |                     dd¬¦  «         t          d	d
t          |¦  «        ¦  «        }|                      |j        dd|j        › �¦  «         |                      d|j        ¦  «         |                      d|j        ¦  «         |                      d|j        ¦  «         |                     ¦   «         r| 	                    ¦   «          dS dS # |                     ¦   «         r| 	                    ¦   «          w w xY w)zNTest 1: Injected hardcoded Vietnamese string in UI file MUST exit with code 1.r   r   r	   r
   ztemp_adversarial_vi.jsuE   export function renderAlert() { return "ThÃ´ng bÃ¡o kháº©n cáº¥p"; }
r   ©r   ú--strictú--target-filesé   úExpected code 1, got zRULE-1-HARDCODED-VIz$Hardcoded Vietnamese string detectedu   ThÃ´ng bÃ¡o kháº©n cáº¥pN)
r   Ú
write_textr    r   ÚassertEqualÚ
returncodeÚassertInÚstdoutÚexistsÚunlink)ÚselfÚ	temp_fileÚress      r   Ú>test_01_negative_baseline_hardcoded_vietnamese_ui_fails_strictz_TestI18nHygieneLinterAdversarial.test_01_negative_baseline_hardcoded_vietnamese_ui_fails_strict/   s4  € å  8Ñ+¨hÑ6¸Ñ=ÀÑDÐG_Ñ_ˆ	ð	#Ø× Ò ØXØ ð !ñ ô ð õ ˜ZÐ)9½3¸y¹>¼>ÑJÔJˆCØ×Ò˜Sœ^¨QÐ0XÈÌÐ0XÐ0XÑYÔYÐYØ�MŠMÐ/°´Ñ<Ô<Ð<Ø�MŠMÐ@À#Ä*ÑMÔMÐMØ�MŠMÐ4°c´jÑAÔAÐAà×ÒÑ!Ô!ð #Ø× Ò Ñ"Ô"Ð"Ð"Ð"ð#ð #øˆy×ÒÑ!Ô!ð #Ø× Ò Ñ"Ô"Ð"Ð"ð#øøøs   ˜B*C. Ã.+Dc                óX  — t                                d¬¦  «        }	 d}|                      ||d¦  «         |                     |dd¦  «        }t                                |d¬¦  «         t          d¦  «        }|                      |j        dd|j        › �¦  «         |                      d	|j        ¦  «         |                      d
|j        ¦  «         |                      d|j        ¦  «         t                                |d¬¦  «         dS # t                                |d¬¦  «         w xY w)zXTest 2: Injected missing key in 1 of 9 languages MUST trigger parity failure and code 1.r   r&   z"channel_world": "World",z!Target entry missing from catalogÚ r)   r'   r*   zRULE-2-DICT-PARITYzmissing 1 keysÚchannel_worldN)	ÚCHAT_CATALOG_JSÚ	read_textr.   Úreplacer+   r    r,   r-   r/   )r2   Úoriginal_contentÚtarget_entryÚmodifiedr4   s        r   Ú=test_02_negative_baseline_missing_key_in_catalog_fails_strictz^TestI18nHygieneLinterAdversarial.test_02_negative_baseline_missing_key_in_catalog_fails_strict@   s"  € å*×4Ò4¸gÐ4ÑFÔFÐð	Kà6ˆLØ�MŠM˜,Ð(8Ð:]Ñ^Ô^Ð^Ø'×/Ò/°¸bÀ!ÑDÔDˆHÝ×&Ò& x¸'Ð&ÑBÔBÐBå˜ZÑ(Ô(ˆCØ×Ò˜Sœ^¨QÐ0XÈÌÐ0XÐ0XÑYÔYÐYØ�MŠMÐ.°´
Ñ;Ô;Ð;Ø�MŠMÐ*¨C¬JÑ7Ô7Ð7Ø�MŠM˜/¨3¬:Ñ6Ô6Ð6å×&Ò&Ð'7À'Ð&ÑJÔJÐJÐJÐJø�O×&Ò&Ð'7À'Ð&ÑJÔJÐJÐJøøøs   �CD ÄD)c                óÌ  — t                                d¬¦  «        }d}	 t                                ||z   d¬¦  «         t          d¦  «        }|                      |j        dd|j        › �¦  «         |                      d|j        ¦  «         |                      d|j        ¦  «         t                                |d¬¦  «         d	S # t                                |d¬¦  «         w xY w)
zXTest 3: Injected dangling data-i18n key in HTML MUST detect missing key and exit code 1.r   r&   z<
<div data-i18n="adversarial_dangling_ghost_key_999"></div>
r'   r)   r*   zRULE-3-DANGLING-KEYÚ"adversarial_dangling_ghost_key_999N)Ú
INDEX_HTMLr:   r+   r    r,   r-   r.   r/   )r2   Úoriginal_htmlÚdangling_tagr4   s       r   ÚEtest_03_negative_baseline_dangling_data_i18n_key_in_html_fails_strictzfTestI18nHygieneLinterAdversarial.test_03_negative_baseline_dangling_data_i18n_key_in_html_fails_strictR   sß   € å"×,Ò,°gÐ,Ñ>Ô>ˆØWˆð	CÝ×!Ò! -°,Ñ">ÈÐ!ÑQÔQÐQÝ˜ZÑ(Ô(ˆCØ×Ò˜Sœ^¨QÐ0XÈÌÐ0XÐ0XÑYÔYÐYØ�MŠMÐ/°´Ñ<Ô<Ð<Ø�MŠMÐ>ÀÄ
ÑKÔKÐKå×!Ò! -¸'Ð!ÑBÔBÐBÐBÐBø�J×!Ò! -¸'Ð!ÑBÔBÐBÐBøøøs   ŸBC ÃC#c                óT  — t          d¦  «        }|                      |j        dd|j        › d|j        › �¦  «         |                      d|j        ¦  «         |                      d|j        ¦  «         |                      d|j        ¦  «         |                      d|j        ¦  «         d	S )
zBTest 4: Current production codebase MUST pass cleanly with code 0.r'   r   zProduction codebase failed:
ú
z%SUCCESS: 100% i18n hygiene compliancez4[*] Rule 1 (Zero Hardcoded VI Strings) Violations: 0z4[*] Rule 2 (9-Language Parity) Violations        : 0z4[*] Rule 3 (Missing / Dangling Keys) Violations  : 0N)r    r,   r-   r/   Ústderrr.   )r2   r4   s     r   Ú;test_04_positive_baseline_production_codebase_passes_strictz\TestI18nHygieneLinterAdversarial.test_04_positive_baseline_production_codebase_passes_strict_   s¢   € å˜Ñ$Ô$ˆØ×Ò˜œ¨Ð,fÈCÌJÐ,fÐ,fÐZ]ÔZdÐ,fÐ,fÑgÔgÐgØ�ŠÐ=¸s¼zÑJÔJÐJØ�ŠÐLÈcÌjÑYÔYÐYØ�ŠÐLÈcÌjÑYÔYÐYØ�ŠÐLÈcÌjÑYÔYÐYÐYÐYr!   c                óÐ  — t           dz  dz  dz  dz  dz  }d}	 |                     |d¬¦  «         t          d	d
t          |¦  «        ¦  «        }|                      |j        dd|j        › �¦  «         |                      d|j        ¦  «         |                     ¦   «         r| 	                    ¦   «          dS dS # |                     ¦   «         r| 	                    ¦   «          w w xY w)zBRule 1 MUST allow fallback string arguments and seed dictionaries.r   r   r	   r
   ztemp_allowlist_check.jsuý   
        export const CHANNELS = {
            world: { name: "Tháº¿ Giá»›i" }
        };
        export const RARITY_INFO = {
            1: { name: "PhÃ m Pháº©m" }
        };
        const text = t('my_key', null, 'Dá»¯ liá»‡u dá»± phÃ²ng');
        r   r&   r'   r(   r   z$False positive on allowlisted code:
zViolations: 0N)
r   r+   r    r   r,   r-   r/   r.   r0   r1   ©r2   r3   Úcoder4   s       r   Ú<test_05_allowlisted_seed_structures_and_fallback_params_passz]TestI18nHygieneLinterAdversarial.test_05_allowlisted_seed_structures_and_fallback_params_passh   s  € å  8Ñ+¨hÑ6¸Ñ=ÀÑDÐG`Ñ`ˆ	ðˆð	#Ø× Ò  °Ð Ñ8Ô8Ð8Ý˜ZÐ)9½3¸y¹>¼>ÑJÔJˆCØ×Ò˜Sœ^¨QÐ0dÐX[ÔXbÐ0dÐ0dÑeÔeÐeØ�MŠM˜/¨3¬:Ñ6Ô6Ð6à×ÒÑ!Ô!ð #Ø× Ò Ñ"Ô"Ð"Ð"Ð"ð#ð #øˆy×ÒÑ!Ô!ð #Ø× Ò Ñ"Ô"Ð"Ð"ð#øøøs   šA4B: Â:+C%c                óš  — t           dz  dz  dz  dz  dz  }d}	 |                     |d¬¦  «         t          d	d
t          |¦  «        ¦  «        }|                      |j        dd|j        › �¦  «         |                     ¦   «         r|                     ¦   «          dS dS # |                     ¦   «         r|                     ¦   «          w w xY w)zMRule 1 MUST ignore single-line and multi-line comments containing Vietnamese.r   r   r	   r
   ztemp_comment_check.jsué   
        // ChÃº thÃ­ch tiáº¿ng Viá»‡t má»™t dÃ²ng: Tháº¿ Giá»›i
        /*
         * ChÃº thÃ­ch tiáº¿ng Viá»‡t nhiá»�u dÃ²ng:
         * Bang Há»™i, Ä�á»™i NgÅ©, Máº­t ThÆ°
         */
        const key = "chat_btn_send";
        r   r&   r'   r(   r   zFalse positive on comments:
N)	r   r+   r    r   r,   r-   r/   r0   r1   rK   s       r   Ú6test_06_comments_with_vietnamese_do_not_trigger_rule_1zWTestI18nHygieneLinterAdversarial.test_06_comments_with_vietnamese_do_not_trigger_rule_1}   sì   € å  8Ñ+¨hÑ6¸Ñ=ÀÑDÐG^Ñ^ˆ	ðˆð	#Ø× Ò  °Ð Ñ8Ô8Ð8Ý˜ZÐ)9½3¸y¹>¼>ÑJÔJˆCØ×Ò˜Sœ^¨QÐ0\ÐPSÔPZÐ0\Ð0\Ñ]Ô]Ð]à×ÒÑ!Ô!ð #Ø× Ò Ñ"Ô"Ð"Ð"Ð"ð#ð #øˆy×ÒÑ!Ô!ð #Ø× Ò Ñ"Ô"Ð"Ð"ð#øøøs   šAB Â+C
c                óV  — t           j                             dt          t          ¦  «        ¦  «         ddlm} t          dz  dz  }d}	 |                     |d¬¦  «          ||d¦  «        }|                      t          |¦  «        d	¦  «         |  
                    d
|d         j        ¦  «         |  
                    d|d         j        ¦  «         |                     ¦   «         r|                     ¦   «          dS dS # |                     ¦   «         r|                     ¦   «          w w xY w)zQRule 2 isolated verification on a mock 9-language catalog with extra key in 'vi'.r   )Úcheck_rule2_dictionary_parityÚtestsztemp_mock_catalog.jsaÉ  
        export const MOCK_CATALOG = {
          vi: { "key_a": "A", "key_b": "B" },
          en: { "key_a": "A" },
          zh: { "key_a": "A", "key_b": "B" },
          ja: { "key_a": "A", "key_b": "B" },
          ko: { "key_a": "A", "key_b": "B" },
          th: { "key_a": "A", "key_b": "B" },
          de: { "key_a": "A", "key_b": "B" },
          ru: { "key_a": "A", "key_b": "B" },
          es: { "key_a": "A", "key_b": "B" }
        };
        r   r&   ÚMOCK_CATALOGr)   zLocale 'en' missing 1 keysÚkey_bN)r   ÚpathÚinsertr   r   Útools.lint.check_i18n_hygienerQ   r+   r,   Úlenr.   Úmessager0   r1   )r2   rQ   Úmock_catalogÚmock_contentÚ
violationss        r   Ú,test_07_mock_catalog_parity_checker_isolatedzMTestI18nHygieneLinterAdversarial.test_07_mock_catalog_parity_checker_isolated�   s3  € åŒ�Š˜�3�|Ñ,Ô,Ñ-Ô-Ð-ØOÐOÐOÐOÐOÐOå# gÑ-Ð0FÑFˆðˆð	&Ø×#Ò# L¸7Ð#ÑCÔCÐCØ6Ð6°|À^ÑTÔTˆJØ×Ò�S ™_œ_¨aÑ0Ô0Ð0Ø�MŠMÐ6¸
À1¼Ô8MÑNÔNÐNØ�MŠM˜' :¨a¤=Ô#8Ñ9Ô9Ð9à×"Ò"Ñ$Ô$ð &Ø×#Ò#Ñ%Ô%Ð%Ð%Ð%ð&ð &øˆ|×"Ò"Ñ$Ô$ð &Ø×#Ò#Ñ%Ô%Ð%Ð%ð&øøøs   Á	BC= Ã=+D(c                óø  — t           dz  dz  }	 t          ddt          |¦  «        ¦  «        }|                      |j        d¦  «         |                      |                     ¦   «         d¦  «         t          j        | 	                    d¬¦  «        ¦  «        }|  
                    d	|¦  «         |  
                    d
|¦  «         |  
                    d|¦  «         |  
                    d|¦  «         |  
                    d|¦  «         |                      |d
         d¦  «         |                     ¦   «         r|                     ¦   «          dS dS # |                     ¦   «         r|                     ¦   «          w w xY w)zDLinter with --json-out MUST write valid JSON matching report schema.rR   ztemp_i18n_report.jsonr'   z
--json-outr   z JSON report file was not createdr   r&   Útotal_files_scannedÚtotal_errorsÚrule1Úrule2Úrule3N)r   r    r   r,   r-   Ú
assertTruer0   ÚjsonÚloadsr:   r.   r1   )r2   Úout_jsonr4   r   s       r   Ú!test_08_json_report_export_schemazBTestI18nHygieneLinterAdversarial.test_08_json_report_export_schema­   sd  € å 'Ñ)Ð,CÑCˆð	"Ý˜Z¨µs¸8±}´}ÑEÔEˆCØ×Ò˜Sœ^¨QÑ/Ô/Ð/Ø�OŠO˜HŸOšOÑ-Ô-Ð/QÑRÔRÐRÝ”:˜h×0Ò0¸'Ð0ÑBÔBÑCÔCˆDØ�MŠMÐ/°Ñ6Ô6Ð6Ø�MŠM˜.¨$Ñ/Ô/Ð/Ø�MŠM˜' 4Ñ(Ô(Ð(Ø�MŠM˜' 4Ñ(Ô(Ð(Ø�MŠM˜' 4Ñ(Ô(Ð(Ø×Ò˜T .Ô1°1Ñ5Ô5Ð5à�ŠÑ Ô ð "Ø—’Ñ!Ô!Ð!Ð!Ð!ð"ð "øˆx�ŠÑ Ô ð "Ø—’Ñ!Ô!Ð!Ð!ð"øøøs   �DE Å+E9c                ó”  — t           dz  dz  dz  dz  dz  }d}	 |                     |d¬¦  «         t          d	d
t          |¦  «        ¦  «        }|j        dk    }|                      |d¦  «         |                     ¦   «         r|                     ¦   «          dS dS # |                     ¦   «         r|                     ¦   «          w w xY w)zQAdversarial stress: documents that multiline template literals bypass line regex.r   r   r	   r
   ztemp_multiline.jsu6   const unlocalized = `
Tiáº¿ng Viá»‡t nhiá»�u dÃ²ng
`;
r   r&   r'   r(   r   z5Empirical proof of multiline template literal evasionN)r   r+   r    r   r-   rd   r0   r1   )r2   r3   Úmultiline_coder4   Úbypasseds        r   Ú9test_09_multiline_template_string_blindspot_investigationzZTestI18nHygieneLinterAdversarial.test_09_multiline_template_string_blindspot_investigation¿   sä   € å  8Ñ+¨hÑ6¸Ñ=ÀÑDÐGZÑZˆ	àTˆð	#Ø× Ò  ¸'Ð ÑBÔBÐBÝ˜ZÐ)9½3¸y¹>¼>ÑJÔJˆCàœ¨!Ò+ˆHØ�OŠO˜HÐ&]Ñ^Ô^Ð^à×ÒÑ!Ô!ð #Ø× Ò Ñ"Ô"Ð"Ð"Ð"ð#ð #øˆy×ÒÑ!Ô!ð #Ø× Ò Ñ"Ô"Ð"Ð"ð#øøøs   šAB Â+Cc                ó(  — t           j                             dt          t          ¦  «        ¦  «         ddlm} t          dz  dz  }d}	 |                     |d¬¦  «          ||¦  «        }|                     dt          ¦   «         ¦  «        }|  
                    d	|¦  «         |                      d
|d¦  «         |                     ¦   «         r|                     ¦   «          dS dS # |                     ¦   «         r|                     ¦   «          w w xY w)zTAdversarial stress: documents that naive brace matching truncates on '}' in strings.r   )Úparse_catalog_keysrR   ztemp_brace_catalog.jszÂ
        export const MOCK = {
          vi: {
            "key1": "Value with closing } brace",
            "key2": "Second key",
            "key3": "Third key"
          }
        };
        r   r&   ÚviÚkey1Úkey2z.Empirical proof of brace truncation limitationN)r   rU   rV   r   r   rW   rn   r+   ÚgetÚsetr.   ÚassertNotInr0   r1   )r2   rn   rZ   r[   ÚkeysÚvi_keyss         r   Ú:test_10_catalog_brace_in_string_parser_limit_investigationz[TestI18nHygieneLinterAdversarial.test_10_catalog_brace_in_string_parser_limit_investigationÎ   s"  € åŒ�Š˜�3�|Ñ,Ô,Ñ-Ô-Ð-ØDÐDÐDÐDÐDÐDå# gÑ-Ð0GÑGˆðˆð		&Ø×#Ò# L¸7Ð#ÑCÔCÐCØ%Ð% lÑ3Ô3ˆDØ—h’h˜t¥S¡U¤UÑ+Ô+ˆGà�MŠM˜& 'Ñ*Ô*Ð*Ø×Ò˜V WÐ.^Ñ_Ô_Ð_à×"Ò"Ñ$Ô$ð &Ø×#Ò#Ñ%Ô%Ð%Ð%Ð%ð&ð &øˆ|×"Ò"Ñ$Ô$ð &Ø×#Ò#Ñ%Ô%Ð%Ð%ð&øøøs   Á	A1C& Ã&+DN)r   r$   )Ú__name__Ú
__module__Ú__qualname__Ú__doc__r5   r?   rE   rI   rM   rO   r]   rh   rl   rw   © r!   r   r#   r#   ,   sî   € € € € € ØYÐYð#ð #ð #ð #ð"Kð Kð Kð Kð$Cð Cð Cð CðZð Zð Zð Zð#ð #ð #ð #ð*#ð #ð #ð #ð&&ð &ð &ð &ð:"ð "ð "ð "ð$#ð #ð #ð #ð&ð &ð &ð &ð &ð &r!   r#   Ú__main__)r   r   r   r   )r{   Ú
__future__r   re   r   r   ÚunittestÚpathlibr   Ú__file__ÚresolveÚparentr   r   Ú
CHAT_UI_JSr9   rB   r    ÚTestCaser#   rx   Úmainr|   r!   r   ú<module>r‡      sT  ððð ð #Ð "Ð "Ð "Ð "Ð "à €€€Ø Ð Ð Ð Ø 
€
€
€
Ø €€€Ø Ð Ð Ð Ð Ð àˆt�H‰~Œ~×%Ò%Ñ'Ô'Ô.Ô5Ô<€Ø˜wÑ&¨Ñ/Ð2IÑI€Ø˜HÑ$ xÑ/°$Ñ6¸Ñ=ÀÑL€
Ø Ñ)¨HÑ4°tÑ;¸fÑDÐG]Ñ]€Ø˜HÑ$ xÑ/°,Ñ>€
ð
ð 
ð 
ð 
ðz&ð z&ð z&ð z&ð z& xÔ'8ñ z&ô z&ð z&ðz ˆzÒÐØ€H„M�O„O€O€O€Oð Ðr!   