from ctf.utils import suggest_patterns import pytest # ===================================================================== # 1. Test Strategy Summary # ===================================================================== # This suite verifies the `suggest_patterns` utility function which parses # a sample flag string and generates a prioritized, deduplicated list of # candidate regular expression patterns. # # Core scenarios tested: # A. Happy Path: # - Verifying pattern suggestion output for typical flags like 'SKY-1111-000' # and 'CTF{easy_flag_123}'. # - Verifying order and counts of specific vs. general patterns. # # B. Boundary Conditions: # - Handling single character inputs (e.g. 'A', '1', '{'). # - Handling strings containing only delimiter/special characters (e.g. '---'). # - Handling inputs with no numeric values or no alphabetic values. # # C. Edge Cases: # - Mixing case strings (e.g., 'AbCdEf') and verifying case-insensitive # or case-specific group behavior. # # D. Error Handling: # - Empty strings or strings containing only whitespace characters should # raise ValueError. # ===================================================================== # ===================================================================== # 2. Mocking/Setup Requirements # ===================================================================== # - No external database, network APIs, or filesystem mocks are needed # as `suggest_patterns` is a pure string-processing utility. # ===================================================================== def test_suggest_patterns_happy_path_sky(): """ Verifies that the suggestions for a hyphenated alpha-numeric flag like 'SKY-1111-000' include specific character group counts, variable length matches, and the literal match. """ patterns = suggest_patterns("SKY-1111-000") # Asserting we get a list of patterns assert isinstance(patterns, list) assert len(patterns) > 0 # Expected options: # 1. Specific count: ^[A-Z]{3}-\d{4}-\d{3}$ assert "^[A-Z]{3}-\\d{4}-\\d{3}$" in patterns # 2. Variable: ^[A-Z]+-\d+-\d+$ assert "^[A-Z]+-\\d+-\\d+$" in patterns # 3. Case-insensitive count: ^[A-Za-z]{3}-\d{4}-\d{3}$ assert "^[A-Za-z]{3}-\\d{4}-\\d{3}$" in patterns # 4. Alphanumeric + delimiter class: ^[A-Za-z0-9\-]+$ assert "^[A-Za-z0-9\\-]+$" in patterns # 5. Literal matching: ^SKY-1111-000$ assert "^SKY-1111-000$" in patterns def test_suggest_patterns_happy_path_ctf(): """ Verifies suggestions for flags with braces and underscores like 'CTF{easy_flag_123}'. Note that special regex characters like '{' and '}' are correctly escaped. """ patterns = suggest_patterns("CTF{easy_flag_123}") # 1. Specific count: ^[A-Z]{3}\{[a-z]{4}_[a-z]{4}_\d{3}\}$ assert "^[A-Z]{3}\\{[a-z]{4}_[a-z]{4}_\\d{3}\\}$" in patterns # 2. Variable: ^[A-Z]+\{[a-z]+_[a-z]+_\d+\}$ assert "^[A-Z]+\\{[a-z]+_[a-z]+_\\d+\\}$" in patterns # 3. Alphanumeric class: ^[A-Za-z0-9_{\}]+$ assert "^[A-Za-z0-9_\\{\\}]+$" in patterns # 4. Literal matching: ^CTF\{easy_flag_123\}$ assert "^CTF\\{easy_flag_123\\}$" in patterns def test_suggest_patterns_only_specials(): """ Verifies that a string with only special characters works and generates valid patterns. """ patterns = suggest_patterns("---") # All patterns should deduplicate to just the exact literal match or similar assert "^---$" in patterns def test_suggest_patterns_single_char(): """ Verifies pattern suggestion on single character flags. """ assert "^[A-Z]{1}$" in suggest_patterns("A") assert "^\\d{1}$" in suggest_patterns("5") def test_suggest_patterns_empty_and_whitespace(): """ Verifies that empty string or whitespace-only inputs trigger a ValueError. """ with pytest.raises(ValueError, match="Input string cannot be empty or whitespace only."): suggest_patterns("") with pytest.raises(ValueError, match="Input string cannot be empty or whitespace only."): suggest_patterns(" ") def test_suggest_patterns_with_competition_name_braced(): """ Verifies that when the competition name is matched in a braced flag, additional general wildcard patterns like '^CTF\\{.*\\}$' are generated. """ patterns = suggest_patterns("CTF{easy_flag_123}", comp_name="CTF") # Check that competition prefix is kept literal in specific/variable patterns assert "^CTF\\{[a-z]{4}_[a-z]{4}_\\d{3}\\}$" in patterns assert "^CTF\\{[a-z]+_[a-z]+_\\d+\\}$" in patterns # Check that braced wildcard options are suggested assert "^CTF\\{.*\\}$" in patterns assert "^CTF\\{[A-Za-z0-9_\\-]+\\}$" in patterns assert "^CTF\\{[a-z0-9_]+\\}$" in patterns def test_suggest_patterns_with_competition_name_non_braced(): """ Verifies that when the competition name is matched in a non-braced flag, suffix wildcards like '^SKY-.*$' or '^SKY.*$' are suggested. """ patterns = suggest_patterns("SKY-1111-000", comp_name="SKY") assert "^SKY-\\d{4}-\\d{3}$" in patterns assert "^SKY-.*$" in patterns def test_suggest_patterns_with_competition_name_mismatch(): """ Verifies that if the competition name is not in the example flag, it falls back to standard regex suggestion matching. """ patterns_mismatch = suggest_patterns("CTF{easy_flag_123}", comp_name="SKY") patterns_none = suggest_patterns("CTF{easy_flag_123}") assert patterns_mismatch == patterns_none