public function run_plan_features()
 {
     // Execute each feature file 1 by one to show the proper progress...
     $testplanconfig = util::get_feature_config();
     if (empty($testplanconfig)) {
         util::performance_exception("Check generator config file testplan.json");
     }
     $status = $this->execute_behat_generator();
     // Don't proceed if it fails.
     if ($status) {
         echo "Error: Failed generating test plan" . PHP_EOL . PHP_EOL;
         $cmd = "vendor/bin/behat --config " . util::get_tool_dir() . DIRECTORY_SEPARATOR . 'behat.yml ';
         echo "Run " . PHP_EOL . '  - ' . $cmd . PHP_EOL . PHP_EOL;
         die;
     } else {
         echo PHP_EOL . "Test plan has been generated under:" . PHP_EOL;
         echo " - " . util::get_final_testplan_path() . PHP_EOL;
     }
 }
 /**
  * Return request index which is defined in config with updated query data, leaving global values untouched.
  *
  * @param $getrequests
  * @param $postrequests
  * @param $postdata
  * @param $requestsfromconfig
  * @return array requestindex, method and path.
  */
 private function is_request_in_config($capturelabel, $requests)
 {
     $requestsfromconfig = $this->get_capture_request_from_config($capturelabel, \behat_hooks::$featurefile);
     $requestfromhar = null;
     // Check if request is already set by user in config.
     if (!empty($requestsfromconfig)) {
         // Loop though each request from har and find the appropriate one.
         // We need this to replace query values except the global set by user.
         foreach ($requests as $index => $request) {
             if ($requestsfromconfig['method'] == $request['method'] && $requestsfromconfig['path'] == $request['path']) {
                 break;
             }
         }
         if (empty($request)) {
             util::performance_exception("Request from har is not found in config. Check: " . \behat_hooks::$featurefile . " : " . $capturelabel);
         }
         // Replace global values in query array with config values.
         foreach ($requestsfromconfig['query'] as $key => $value) {
             if (preg_match('/^\\$\\{.*\\}/', $value)) {
                 $request['query'][$key] = $value;
             }
         }
         return $request;
     }
     return array();
 }
 /**
  * Return proxy used by the test plan generator.
  *
  * @return array.
  */
 public static function get_option($option)
 {
     $optionfile = self::get_tool_dir() . DIRECTORY_SEPARATOR . 'testplanoptions.json';
     if (!file_exists($optionfile)) {
         util::performance_exception("Option " . $option . " is not set.");
     } else {
         $contents = json_decode(file_get_contents($optionfile), true);
         if (!empty($contents[$option])) {
             return $contents[$option];
         } else {
             util::performance_exception("Option " . $option . " is not set.");
         }
     }
 }
 /**
  * Return xml for the given tag.
  *
  * @param string $tag name of the tag
  * @param array $replacements search=> replace in xml. with #!search!# => replace
  * @return string xml for the testplan tag.
  * @throws \moodle_exception
  */
 public static function get_testplan_tag_xml($tag, $replacements = array())
 {
     $xmlfilepath = __DIR__ . "/../fixtures/" . $tag . ".xml";
     if (!file_exists($xmlfilepath)) {
         util::performance_exception("Xml for tag " . $tag . " not found");
     }
     $tagxml = file_get_contents($xmlfilepath);
     // Replace all required values.
     foreach ($replacements as $search => $replace) {
         $tagxml = str_replace('#!' . $search . '!#', $replace, $tagxml);
     }
     return $tagxml;
 }