Source code for stix2generator.test.test_pattern_generator

import pytest
import re
import stix2generator
from stix2generator.generation.pattern_generator import PatternGenerator, Config
import stix2patterns.inspector
from stix2patterns.validator import validate
from stix2patterns.v21.pattern import Pattern


_REPEATS_RE = re.compile(r"REPEATS (\d+) TIMES")
_WITHIN_RE = re.compile(r"WITHIN (\d+) SECONDS")


[docs]@pytest.fixture(scope="session") def default_object_generator(): return stix2generator.create_object_generator(stix_version="2.1")
[docs]def test_patterns_valid(num_trials, default_object_generator): generator = PatternGenerator(default_object_generator, "2.1") for _ in range(num_trials): pattern = generator.generate() # Turn on error printing so that we can see what the errors are # just by changing how we invoke pytest. assert validate(pattern, stix_version="2.1", print_errs=True)
[docs]def test_config_pattern_size(num_trials, default_object_generator): pattern_config = Config(min_pattern_size=3, max_pattern_size=7) generator = PatternGenerator( default_object_generator, "2.1", pattern_config ) for _ in range(num_trials): pattern_str = generator.generate() pattern_obj = Pattern(pattern_str) pattern_data = pattern_obj.inspect() comparison_data = pattern_data.comparisons pattern_size = sum( len(comparisons) for comparisons in comparison_data.values() ) assert 3 <= pattern_size <= 7
[docs]def test_config_repeat_count(num_trials, default_object_generator): pattern_config = Config( min_repeat_count=3, max_repeat_count=7, # Ensure there are lots of qualifiers, to increase the probability we # will actually see some REPEATS qualifiers to test. There's not # actually any guarantee any will show up in the pattern! # ("probability_qualifier=1" below guarantees some qualifiers will be # included, but not which type of qualifiers they are.) min_pattern_size=5, max_pattern_size=10, probability_qualifier=1, ) generator = PatternGenerator( default_object_generator, "2.1", pattern_config ) for _ in range(num_trials): pattern_str = generator.generate() pattern_obj = Pattern(pattern_str) pattern_data = pattern_obj.inspect() for qualifier in pattern_data.qualifiers: m = _REPEATS_RE.match(qualifier) if m: repeat_count = int(m.group(1)) assert 3 <= repeat_count <= 7
[docs]def test_config_within_count(num_trials, default_object_generator): pattern_config = Config( min_within_count=3, max_within_count=7, min_pattern_size=5, max_pattern_size=10, probability_qualifier=1, ) generator = PatternGenerator( default_object_generator, "2.1", pattern_config ) for _ in range(num_trials): pattern_str = generator.generate() pattern_obj = Pattern(pattern_str) pattern_data = pattern_obj.inspect() for qualifier in pattern_data.qualifiers: m = _WITHIN_RE.match(qualifier) if m: within_count = int(m.group(1)) assert 3 <= within_count <= 7
[docs]def test_config_continue_path_through_ref_always( num_trials, default_object_generator ): pattern_config = Config( min_pattern_size=5, max_pattern_size=10, probability_continue_path_through_ref=1, ) generator = PatternGenerator( default_object_generator, "2.1", pattern_config ) for _ in range(num_trials): pattern_str = generator.generate() pattern_obj = Pattern(pattern_str) pattern_data = pattern_obj.inspect() for comparisons in pattern_data.comparisons.values(): for path, _, _ in comparisons: # If all paths continue through refs, a ref prop can't be last, # and a refs prop can't be second-to-last. path_len = len(path) for i, path_elt in enumerate(path): if isinstance(path_elt, str): assert not path_elt.endswith("_ref") or i < path_len-1 assert not path_elt.endswith("_refs") or i < path_len-2
[docs]def test_config_continue_path_through_ref_never( num_trials, default_object_generator ): pattern_config = Config( min_pattern_size=5, max_pattern_size=10, probability_continue_path_through_ref=0, ) generator = PatternGenerator( default_object_generator, "2.1", pattern_config ) for _ in range(num_trials): pattern_str = generator.generate() pattern_obj = Pattern(pattern_str) pattern_data = pattern_obj.inspect() for comparisons in pattern_data.comparisons.values(): for path, _, _ in comparisons: # If no paths continue through refs, a ref prop must be last, # and a refs prop must be second-to-last. path_len = len(path) for i, path_elt in enumerate(path): if isinstance(path_elt, str): if path_elt.endswith("_ref"): assert i == path_len-1 elif path_elt.endswith("_refs"): assert i == path_len-2
[docs]def test_config_probability_index_star_step_always( num_trials, default_object_generator ): pattern_config = Config( min_pattern_size=5, max_pattern_size=10, probability_index_star_step=1, ) generator = PatternGenerator( default_object_generator, "2.1", pattern_config ) for _ in range(num_trials): pattern_str = generator.generate() pattern_obj = Pattern(pattern_str) pattern_data = pattern_obj.inspect() for comparisons in pattern_data.comparisons.values(): for path, _, _ in comparisons: # If always using index star steps, there should never be any # integer steps. assert not any( isinstance(path_elt, int) for path_elt in path )
[docs]def test_config_probability_index_star_step_never( num_trials, default_object_generator ): pattern_config = Config( min_pattern_size=5, max_pattern_size=10, probability_index_star_step=0, ) generator = PatternGenerator( default_object_generator, "2.1", pattern_config ) for _ in range(num_trials): pattern_str = generator.generate() pattern_obj = Pattern(pattern_str) pattern_data = pattern_obj.inspect() for comparisons in pattern_data.comparisons.values(): for path, _, _ in comparisons: # If always using integer steps into lists, there should never # be any star steps. assert not any( path_elt is stix2patterns.inspector.INDEX_STAR for path_elt in path )