|
605 | 605 | " key : The feature key (e.g., the chosen alternative or rule itself).\n", |
606 | 606 | " '''\n", |
607 | 607 | "\n", |
608 | | - " def __init__(self, name: str, rule: str, key: str) -> None:\n", |
| 608 | + " def __init__(self, name: str, rule: str, key: str, /,\n", |
| 609 | + " friendly_name: str = None) -> None:\n", |
609 | 610 | " self.name = name\n", |
610 | 611 | " self.rule = rule\n", |
611 | 612 | " self.key = key\n", |
| 613 | + " self._friendly_name = friendly_name or name\n", |
612 | 614 | " super().__init__()\n", |
613 | 615 | "\n", |
614 | 616 | " def __repr__(self) -> str:\n", |
|
619 | 621 | " def name_rep(self) -> str:\n", |
620 | 622 | " pass\n", |
621 | 623 | "\n", |
| 624 | + " def friendly_name(self) -> str:\n", |
| 625 | + " return self._friendly_name\n", |
| 626 | + "\n", |
622 | 627 | " @abstractmethod\n", |
623 | 628 | " def get_feature_value(self, derivation_tree) -> float:\n", |
624 | 629 | " '''Returns the feature value for a given derivation tree of an input.'''\n", |
|
648 | 653 | " key : The feature key, equal to the rule attribute for production features,\n", |
649 | 654 | " or equal to the corresponding alternative for alternative features.\n", |
650 | 655 | " '''\n", |
651 | | - " def __init__(self, name: str, rule: str, key: str) -> None:\n", |
652 | | - " super().__init__(name, rule, key)\n", |
| 656 | + " def __init__(self, name: str, rule: str, key: str,\n", |
| 657 | + " friendly_name: str = None) -> None:\n", |
| 658 | + " super().__init__(name, rule, key, friendly_name=friendly_name)\n", |
653 | 659 | "\n", |
654 | 660 | " def name_rep(self) -> str:\n", |
655 | 661 | " if self.rule == self.key:\n", |
|
709 | 715 | " e.g., 'num(<integer>)'\n", |
710 | 716 | " rule : The production rule.\n", |
711 | 717 | " '''\n", |
712 | | - " def __init__(self, name: str, rule: str) -> None:\n", |
713 | | - " super().__init__(name, rule, rule)\n", |
| 718 | + " def __init__(self, name: str, rule: str, friendly_name: str = None) -> None:\n", |
| 719 | + " super().__init__(name, rule, rule, friendly_name=friendly_name)\n", |
714 | 720 | "\n", |
715 | 721 | " def name_rep(self) -> str:\n", |
716 | 722 | " return f\"num({self.key})\"\n", |
|
766 | 772 | " features.append(ExistenceFeature(f\"exists({rule})\", rule, rule))\n", |
767 | 773 | " # add all alternatives\n", |
768 | 774 | " for count, expansion in enumerate(grammar[rule]):\n", |
769 | | - " features.append(ExistenceFeature(f\"exists({rule}@{count})\", rule, expansion))\n", |
| 775 | + " name = f\"exists({rule}@{count})\"\n", |
| 776 | + " friendly_name = f\"{rule} == {repr(expansion)}\"\n", |
| 777 | + " feature = ExistenceFeature(name, rule, expansion,\n", |
| 778 | + " friendly_name=friendly_name)\n", |
| 779 | + " features.append(feature)\n", |
770 | 780 | "\n", |
771 | 781 | " return features" |
772 | 782 | ] |
|
825 | 835 | " for key in derivable_chars:\n", |
826 | 836 | " # Check if derivable chars contain only numeric chars\n", |
827 | 837 | " if len(derivable_chars[key] - numeric_chars) == 0:\n", |
828 | | - " features.append(NumericInterpretation(f\"num({key})\", key))\n", |
| 838 | + " name = f\"num({key})\"\n", |
| 839 | + " friendly_name = f\"{key}\"\n", |
| 840 | + "\n", |
| 841 | + " features.append(NumericInterpretation(f\"num({key})\", key,\n", |
| 842 | + " friendly_name=friendly_name))\n", |
829 | 843 | "\n", |
830 | 844 | " return features" |
831 | 845 | ] |
|
849 | 863 | "get_all_features(CALC_GRAMMAR)" |
850 | 864 | ] |
851 | 865 | }, |
| 866 | + { |
| 867 | + "cell_type": "code", |
| 868 | + "execution_count": null, |
| 869 | + "metadata": {}, |
| 870 | + "outputs": [], |
| 871 | + "source": [ |
| 872 | + "[f.friendly_name() for f in get_all_features(CALC_GRAMMAR)] " |
| 873 | + ] |
| 874 | + }, |
852 | 875 | { |
853 | 876 | "cell_type": "markdown", |
854 | 877 | "metadata": {}, |
|
2161 | 2184 | " self.value = value\n", |
2162 | 2185 | "\n", |
2163 | 2186 | " def __str__(self):\n", |
2164 | | - " return f\"Requirement({self.feature.name} {self.quant} {self.value})\"" |
| 2187 | + " return f\"Requirement({self.feature.name} {self.quant} {self.value})\"\n", |
| 2188 | + "\n", |
| 2189 | + " def __repr__(self):\n", |
| 2190 | + " return f\"Requirement({self.feature.name}, {self.quant}, {self.value})\"\n", |
| 2191 | + "\n", |
| 2192 | + " def friendly(self):\n", |
| 2193 | + " def value(x):\n", |
| 2194 | + " try:\n", |
| 2195 | + " return float(x)\n", |
| 2196 | + " except Exception:\n", |
| 2197 | + " return None\n", |
| 2198 | + "\n", |
| 2199 | + " if isinstance(self.feature, ExistenceFeature):\n", |
| 2200 | + " if value(self.value) > 0:\n", |
| 2201 | + " return f\"{self.feature.friendly_name()}\"\n", |
| 2202 | + " elif value(self.value) < 0:\n", |
| 2203 | + " return f\"not {self.feature.friendly_name()}\"\n", |
| 2204 | + "\n", |
| 2205 | + " return f\"{self.feature.friendly_name()} {self.quant} {self.value}\"" |
2165 | 2206 | ] |
2166 | 2207 | }, |
2167 | 2208 | { |
|
2181 | 2222 | " self.requirements: List[SpecRequirement] = requirements\n", |
2182 | 2223 | "\n", |
2183 | 2224 | " def __str__(self):\n", |
2184 | | - " # Handle first element\n", |
2185 | | - " s = f\"{str(self.requirements[0])}\"\n", |
2186 | | - " for count in range(1, len(self.requirements)):\n", |
2187 | | - " s += (\", \" + str(self.requirements[count]))\n", |
| 2225 | + " s = \", \".join(str(r) for r in self.requirements)\n", |
| 2226 | + " return f\"InputSpecification({s})\"\n", |
2188 | 2227 | "\n", |
2189 | | - " return f\"InputSpecification({s})\"" |
| 2228 | + " def friendly(self):\n", |
| 2229 | + " return \" and \".join(r.friendly() for r in self.requirements)\n", |
| 2230 | + "\n", |
| 2231 | + " def __repr__(self):\n", |
| 2232 | + " return self.__str__()" |
2190 | 2233 | ] |
2191 | 2234 | }, |
2192 | 2235 | { |
|
2339 | 2382 | "metadata": {}, |
2340 | 2383 | "source": [ |
2341 | 2384 | "We implement a _Grammar-Based Input Generator_ that generates new input samples from a List of `Input Specifications`.\n", |
2342 | | - "The Input Specifications are extracted from the decision tree boundaries in the previous Activity 3: _RequirementExtraction_\n", |
| 2385 | + "The Input Specifications are extracted from the decision tree boundaries in the previous Activity 3: _RequirementExtraction_.\n", |
| 2386 | + "\n", |
2343 | 2387 | "An Input Specification consists of **1 to n** many predicates or requirements (e.g. feature '>=' value, or 'num(term) <= 13').\n", |
2344 | | - "We generate a new input for each InputSpecification.\n", |
2345 | | - "The new input fulfills all the given requirements of an IputSpecification." |
| 2388 | + "We generate a new input for each `InputSpecification`.\n", |
| 2389 | + "The new input fulfills all the given requirements of an InputSpecification." |
2346 | 2390 | ] |
2347 | 2391 | }, |
2348 | 2392 | { |
2349 | 2393 | "cell_type": "markdown", |
2350 | 2394 | "metadata": {}, |
2351 | 2395 | "source": [ |
2352 | | - "**Info:** For furter details, please refer to <b>Section 4.4 and 4.5</b> of the <a href=\"https://publications.cispa.saarland/3107/7/fse2020-alhazen.pdf\">paper</a> and the Chapter <b><a href=\"https://www.fuzzingbook.org/html/GrammarFuzzer.html\">Efficient Grammar Fuzzing</a></b> in the fuzzingbook." |
| 2396 | + "**Info:** For further details, please refer to <b>Section 4.4 and 4.5</b> of the <a href=\"https://publications.cispa.saarland/3107/7/fse2020-alhazen.pdf\">paper</a> and the Chapter <b><a href=\"https://www.fuzzingbook.org/html/GrammarFuzzer.html\">Efficient Grammar Fuzzing</a></b> in the fuzzingbook." |
2353 | 2397 | ] |
2354 | 2398 | }, |
2355 | 2399 | { |
|
2679 | 2723 | " self._data.drop(['oracle'], axis=1))\n", |
2680 | 2724 | " print(f\" New input specifications:\")\n", |
2681 | 2725 | " for spec in new_input_specifications:\n", |
2682 | | - " print(f\" {str(spec)}\")\n", |
| 2726 | + " print(f\" {spec.friendly()}\")\n", |
2683 | 2727 | "\n", |
2684 | 2728 | " # generate new inputs according to the new input specifications\n", |
2685 | 2729 | " new_samples = generate_samples(self._grammar,\n", |
2686 | 2730 | " new_input_specifications,\n", |
2687 | 2731 | " self._generator_timeout)\n", |
2688 | 2732 | " print(f\" New samples:\")\n", |
2689 | | - " for sample in new_samples:\n", |
2690 | | - " print(f\" {str(sample)}\")\n", |
| 2733 | + " print(f\" {\", \".join(new_samples)}\")\n", |
2691 | 2734 | " self._previous_samples = new_samples" |
2692 | 2735 | ] |
2693 | 2736 | }, |
|
2749 | 2792 | "metadata": {}, |
2750 | 2793 | "outputs": [], |
2751 | 2794 | "source": [ |
2752 | | - "all_features = extract_existence(CALC_GRAMMAR) + extract_numeric(CALC_GRAMMAR)\n", |
2753 | | - "all_feature_names = [f.name for f in all_features]" |
| 2795 | + "all_features = get_all_features(CALC_GRAMMAR)\n", |
| 2796 | + "all_feature_names = [f.friendly_name() for f in all_features]" |
2754 | 2797 | ] |
2755 | 2798 | }, |
2756 | 2799 | { |
|
0 commit comments