<commit_before>//! Support for mock HTTP servers that verify pacts.

use std::{
  env,
  fmt::Write as FmtWrite,
  io::{self, prelude::*},
  thread,
};
use std::sync::{Arc, Mutex};

use async_trait::async_trait;
use log::{debug, warn};
use url::Url;

use pact_mock_server::*;
use pact_mock_server::matching::MatchResult;
use pact_mock_server::mock_server::{MockServerConfig, MockServerMetrics};
use pact_models::pact::Pact;
use pact_models::sync_pact::RequestResponsePact;
use std::path::PathBuf;
use uuid::Uuid;
use pact_matching::metrics::{MetricEvent, send_metrics};

/// This trait is implemented by types which allow us to start a mock server.
#[async_trait]
pub trait StartMockServer {
  /// Start a mock server running in a background thread.
  fn start_mock_server(&self) -> ValidatingMockServer;

  /// Start a mock server running in a task (requires a Tokio runtime to be already setup)
  async fn start_mock_server_async(&self) -> ValidatingMockServer;
}

#[async_trait]
impl StartMockServer for RequestResponsePact {
  fn start_mock_server(&self) -> ValidatingMockServer {
    ValidatingMockServer::start(self.boxed(), None)
  }

  async fn start_mock_server_async(&self) -> ValidatingMockServer {
    ValidatingMockServer::start_async(self.boxed(), None).await
  }
}

/// A mock HTTP server that handles the requests described in a `Pact`, intended
/// for use in tests, and validates that the requests made to that server are
/// correct.
///
/// Because this is intended for use in tests, it will panic if something goes
/// wrong.
pub struct ValidatingMockServer {
    // A description of our mock server, for use in error messages.
    description: String,
    // The URL of our mock server.
    url: Url,
    // The mock server instance
    mock_server: Arc<Mutex<mock_server::MockServer>>,
    // Signal received when the server thread is done executing
    done_rx: std::sync::mpsc::Receiver<()>,
    // Output directory to write pact files
    output_dir: Option<PathBuf>,
}

impl ValidatingMockServer {
  /// Create a new mock server which handles requests as described in the
  /// pact, and runs in a background thread
  ///
  /// Panics:
  /// Will panic if the provided Pact can not be sent to the background thread.
  pub fn start(pact: Box<dyn Pact + Send + Sync>, output_dir: Option<PathBuf>) -> ValidatingMockServer {
    debug!("Starting mock server from pact {:?}", pact);
    // Spawn new runtime in thread to prevent reactor execution context conflict
    let (pact_tx, pact_rx) = std::sync::mpsc::channel::<Box<dyn Pact + Send + Sync>>();
    pact_tx.send(pact).expect("INTERNAL ERROR: Could not pass pact into mock server thread");
    let (mock_server, done_rx) = std::thread::spawn(|| {
      let runtime = tokio::runtime::Builder::new_current_thread()
        .enable_all()
        .build()
        .expect("new runtime");

      let (mock_server, server_future) = runtime.block_on(async move {
        mock_server::MockServer::new(
          Uuid::new_v4().to_string(),
          pact_rx.recv().unwrap(),
          ([0, 0, 0, 0], 0).into(),
          MockServerConfig::default()
        )
          .await
          .unwrap()
      });

      // Start the actual thread the runtime will run on
      let (done_tx, done_rx) = std::sync::mpsc::channel::<()>();
      let tname = format!(
        "test({})-pact-mock-server",
        thread::current().name().unwrap_or("<unknown>")
      );
      std::thread::Builder::new()
        .name(tname)
        .spawn(move || {
          runtime.block_on(server_future);
          let _ = done_tx.send(());
        })
        .expect("thread spawn");

      (mock_server, done_rx)
    })
    .join()
    .unwrap();

    let (description, url_str) = {
      let ms = mock_server.lock().unwrap();
      let pact = ms.pact.lock().unwrap();
      let description = format!(
        "{}/{}", pact.consumer().name, pact.provider().name
      );
      (description, ms.url())
    };
    ValidatingMockServer {
      description,
      url: url_str.parse().expect("invalid mock server URL"),
      mock_server,
      done_rx,
      output_dir
    }
  }

  /// Create a new mock server which handles requests as described in the
  /// pact, and runs in a background task in the current Tokio runtime.
  ///
  /// Panics:
  /// Will panic if unable to get the URL to the spawned mock server
  pub async fn start_async(pact: Box<dyn Pact + Send + Sync>, output_dir: Option<PathBuf>) -> ValidatingMockServer {
    debug!("Starting mock server from pact {:?}", pact);

    let (mock_server, server_future) = mock_server::MockServer::new(
      Uuid::new_v4().to_string(),
      pact,
      ([0, 0, 0, 0], 0 as u16).into(),
      MockServerConfig::default()
    )
      .await
      .unwrap();

    let (done_tx, done_rx) = std::sync::mpsc::channel::<()>();
    tokio::spawn(async move {
      dbg!(server_future.await);
      let _ = done_tx.send(());
    });

    let (description, url_str) = {
      let ms = mock_server.lock().unwrap();
      let pact = ms.pact.lock().unwrap();
      let description = format!(
        "{}/{}", pact.consumer().name, pact.provider().name
      );
      (description, ms.url())
    };
    ValidatingMockServer {
      description,
      url: url_str.parse().expect("invalid mock server URL"),
      mock_server,
      done_rx,
      output_dir
    }
  }

    /// The URL of our mock server. You can make normal HTTP requests using this
    /// as the base URL.
    pub fn url(&self) -> &Url {
        &self.url
    }

    /// Given a path string, return a URL pointing to that path on the mock
    /// server. If the `path` cannot be parsed as URL, **this function will
    /// panic**. For a non-panicking version, call `.url()` instead and build
    /// this path yourself.
    pub fn path<P: AsRef<str>>(&self, path: P) -> Url {
        // We panic here because this a _test_ library, the `?` operator is
        // useless in tests, and filling up our test code with piles of `unwrap`
        // calls is ugly.
        self.url.join(path.as_ref()).expect("could not parse URL")
    }

    /// Returns the current status of the mock server
    pub fn status(&self) -> Vec<MatchResult> {
      self.mock_server.lock().unwrap().mismatches()
    }

    /// Helper function called by our `drop` implementation. This basically exists
    /// so that it can return `Err(message)` whenever needed without making the
    /// flow control in `drop` ultra-complex.
    fn drop_helper(&mut self) -> Result<(), String> {
        // Kill the server
        let mut ms = self.mock_server.lock().unwrap();
        ms.shutdown()?;

        if ::std::thread::panicking() {
            return Ok(());
        }

        // Wait for the server thread to finish
        if let Err(_) = self.done_rx.recv_timeout(std::time::Duration::from_secs(3)) {
          warn!("Timed out waiting for mock server to finish");
        }

      let interactions = {
        let pact = ms.pact.lock().unwrap();
        pact.interactions().len()
      };
      send_metrics(MetricEvent::ConsumerTestRun {
        interactions,
        test_framework: "pact_consumer".to_string(),
        app_name: "pact_consumer".to_string(),
        app_version: env!("CARGO_PKG_VERSION").to_string()
      });

        // Look up any mismatches which occurred.
        let mismatches = ms.mismatches();

        if mismatches.is_empty() {
          // Success! Write out the generated pact file.
          let output_dir = self.output_dir.as_ref().map(|dir| dir.to_string_lossy().to_string())
            .unwrap_or_else(|| {
              let val = env::var("PACT_OUTPUT_DIR");
              debug!("env:PACT_OUTPUT_DIR = {:?}", val);
              val.unwrap_or_else(|_| "target/pacts".to_owned())
            });
          let overwrite = env::var("PACT_OVERWRITE");
          debug!("env:PACT_OVERWRITE = {:?}", overwrite);
          ms.write_pact(
            &Some(output_dir),
            overwrite.unwrap_or_else(|_| "false".to_owned()) == "true")
            .map_err(|err| format!("error writing pact: {}", err))?;
            Ok(())
        } else {
            // Failure. Format our errors.
            let mut msg = format!("mock server {} failed verification:\n", self.description,);
            for mismatch in mismatches {
                match mismatch {
                    MatchResult::RequestMatch(..) => {
                        unreachable!("list of mismatches contains a match");
                    }
                    MatchResult::RequestMismatch(request, mismatches) => {
                        let _ = writeln!(&mut msg, "- request {}:", request);
                        for m in mismatches {
                            let _ = writeln!(&mut msg, "  - {}", m.description());
                        }
                    }
                    MatchResult::RequestNotFound(request) => {
                        let _ = writeln!(&mut msg, "- received unexpected request:");
                        let _ = writeln!(&mut msg, "{:#?}", request);
                    }
                    MatchResult::MissingRequest(request) => {
                        let _ = writeln!(
                            &mut msg,
                            "- request {} expected, but never occurred", request,
                        );
                        let _ = writeln!(&mut msg, "{:#?}", request);
                    }
                }
            }
            Err(msg)
        }
    }

  /// Returns the metrics collected by the mock server
  pub fn metrics(&self) -> MockServerMetrics {
    self.mock_server.lock().unwrap().metrics.clone()
  }
}

/// Either panic with `msg`, or if we're already in the middle of a panic,
/// just print `msg` to standard error.
fn panic_or_print_error(msg: &str) {
    if thread::panicking() {
        // The current thread is panicking, so don't try to panic again, because
        // double panics don't print useful explanations of why the test failed.
        // Instead, just print to `stderr`. Ignore any errors, because there's
        // not much we can do if we can't panic and we can't write to `stderr`.
        let _ = writeln!(io::stderr(), "{}", msg);
    } else {
        panic!("{}", msg);
    }
}

impl Drop for ValidatingMockServer {
    fn drop(&mut self) {
        let result = self.drop_helper();
        if let Err(msg) = result {
            panic_or_print_error(&msg);
        }
    }
}
<commit_msg>chore: remove accidental debug statement<commit_after>//! Support for mock HTTP servers that verify pacts.

use std::{
  env,
  fmt::Write as FmtWrite,
  io::{self, prelude::*},
  thread,
};
use std::sync::{Arc, Mutex};

use async_trait::async_trait;
use log::{debug, warn};
use url::Url;

use pact_mock_server::*;
use pact_mock_server::matching::MatchResult;
use pact_mock_server::mock_server::{MockServerConfig, MockServerMetrics};
use pact_models::pact::Pact;
use pact_models::sync_pact::RequestResponsePact;
use std::path::PathBuf;
use uuid::Uuid;
use pact_matching::metrics::{MetricEvent, send_metrics};

/// This trait is implemented by types which allow us to start a mock server.
#[async_trait]
pub trait StartMockServer {
  /// Start a mock server running in a background thread.
  fn start_mock_server(&self) -> ValidatingMockServer;

  /// Start a mock server running in a task (requires a Tokio runtime to be already setup)
  async fn start_mock_server_async(&self) -> ValidatingMockServer;
}

#[async_trait]
impl StartMockServer for RequestResponsePact {
  fn start_mock_server(&self) -> ValidatingMockServer {
    ValidatingMockServer::start(self.boxed(), None)
  }

  async fn start_mock_server_async(&self) -> ValidatingMockServer {
    ValidatingMockServer::start_async(self.boxed(), None).await
  }
}

/// A mock HTTP server that handles the requests described in a `Pact`, intended
/// for use in tests, and validates that the requests made to that server are
/// correct.
///
/// Because this is intended for use in tests, it will panic if something goes
/// wrong.
pub struct ValidatingMockServer {
    // A description of our mock server, for use in error messages.
    description: String,
    // The URL of our mock server.
    url: Url,
    // The mock server instance
    mock_server: Arc<Mutex<mock_server::MockServer>>,
    // Signal received when the server thread is done executing
    done_rx: std::sync::mpsc::Receiver<()>,
    // Output directory to write pact files
    output_dir: Option<PathBuf>,
}

impl ValidatingMockServer {
  /// Create a new mock server which handles requests as described in the
  /// pact, and runs in a background thread
  ///
  /// Panics:
  /// Will panic if the provided Pact can not be sent to the background thread.
  pub fn start(pact: Box<dyn Pact + Send + Sync>, output_dir: Option<PathBuf>) -> ValidatingMockServer {
    debug!("Starting mock server from pact {:?}", pact);
    // Spawn new runtime in thread to prevent reactor execution context conflict
    let (pact_tx, pact_rx) = std::sync::mpsc::channel::<Box<dyn Pact + Send + Sync>>();
    pact_tx.send(pact).expect("INTERNAL ERROR: Could not pass pact into mock server thread");
    let (mock_server, done_rx) = std::thread::spawn(|| {
      let runtime = tokio::runtime::Builder::new_current_thread()
        .enable_all()
        .build()
        .expect("new runtime");

      let (mock_server, server_future) = runtime.block_on(async move {
        mock_server::MockServer::new(
          Uuid::new_v4().to_string(),
          pact_rx.recv().unwrap(),
          ([0, 0, 0, 0], 0).into(),
          MockServerConfig::default()
        )
          .await
          .unwrap()
      });

      // Start the actual thread the runtime will run on
      let (done_tx, done_rx) = std::sync::mpsc::channel::<()>();
      let tname = format!(
        "test({})-pact-mock-server",
        thread::current().name().unwrap_or("<unknown>")
      );
      std::thread::Builder::new()
        .name(tname)
        .spawn(move || {
          runtime.block_on(server_future);
          let _ = done_tx.send(());
        })
        .expect("thread spawn");

      (mock_server, done_rx)
    })
    .join()
    .unwrap();

    let (description, url_str) = {
      let ms = mock_server.lock().unwrap();
      let pact = ms.pact.lock().unwrap();
      let description = format!(
        "{}/{}", pact.consumer().name, pact.provider().name
      );
      (description, ms.url())
    };
    ValidatingMockServer {
      description,
      url: url_str.parse().expect("invalid mock server URL"),
      mock_server,
      done_rx,
      output_dir
    }
  }

  /// Create a new mock server which handles requests as described in the
  /// pact, and runs in a background task in the current Tokio runtime.
  ///
  /// Panics:
  /// Will panic if unable to get the URL to the spawned mock server
  pub async fn start_async(pact: Box<dyn Pact + Send + Sync>, output_dir: Option<PathBuf>) -> ValidatingMockServer {
    debug!("Starting mock server from pact {:?}", pact);

    let (mock_server, server_future) = mock_server::MockServer::new(
      Uuid::new_v4().to_string(),
      pact,
      ([0, 0, 0, 0], 0 as u16).into(),
      MockServerConfig::default()
    )
      .await
      .unwrap();

    let (done_tx, done_rx) = std::sync::mpsc::channel::<()>();
    tokio::spawn(async move {
      server_future.await;
      let _ = done_tx.send(());
    });

    let (description, url_str) = {
      let ms = mock_server.lock().unwrap();
      let pact = ms.pact.lock().unwrap();
      let description = format!(
        "{}/{}", pact.consumer().name, pact.provider().name
      );
      (description, ms.url())
    };
    ValidatingMockServer {
      description,
      url: url_str.parse().expect("invalid mock server URL"),
      mock_server,
      done_rx,
      output_dir
    }
  }

    /// The URL of our mock server. You can make normal HTTP requests using this
    /// as the base URL.
    pub fn url(&self) -> &Url {
        &self.url
    }

    /// Given a path string, return a URL pointing to that path on the mock
    /// server. If the `path` cannot be parsed as URL, **this function will
    /// panic**. For a non-panicking version, call `.url()` instead and build
    /// this path yourself.
    pub fn path<P: AsRef<str>>(&self, path: P) -> Url {
        // We panic here because this a _test_ library, the `?` operator is
        // useless in tests, and filling up our test code with piles of `unwrap`
        // calls is ugly.
        self.url.join(path.as_ref()).expect("could not parse URL")
    }

    /// Returns the current status of the mock server
    pub fn status(&self) -> Vec<MatchResult> {
      self.mock_server.lock().unwrap().mismatches()
    }

    /// Helper function called by our `drop` implementation. This basically exists
    /// so that it can return `Err(message)` whenever needed without making the
    /// flow control in `drop` ultra-complex.
    fn drop_helper(&mut self) -> Result<(), String> {
        // Kill the server
        let mut ms = self.mock_server.lock().unwrap();
        ms.shutdown()?;

        if ::std::thread::panicking() {
            return Ok(());
        }

        // Wait for the server thread to finish
        if let Err(_) = self.done_rx.recv_timeout(std::time::Duration::from_secs(3)) {
          warn!("Timed out waiting for mock server to finish");
        }

      let interactions = {
        let pact = ms.pact.lock().unwrap();
        pact.interactions().len()
      };
      send_metrics(MetricEvent::ConsumerTestRun {
        interactions,
        test_framework: "pact_consumer".to_string(),
        app_name: "pact_consumer".to_string(),
        app_version: env!("CARGO_PKG_VERSION").to_string()
      });

        // Look up any mismatches which occurred.
        let mismatches = ms.mismatches();

        if mismatches.is_empty() {
          // Success! Write out the generated pact file.
          let output_dir = self.output_dir.as_ref().map(|dir| dir.to_string_lossy().to_string())
            .unwrap_or_else(|| {
              let val = env::var("PACT_OUTPUT_DIR");
              debug!("env:PACT_OUTPUT_DIR = {:?}", val);
              val.unwrap_or_else(|_| "target/pacts".to_owned())
            });
          let overwrite = env::var("PACT_OVERWRITE");
          debug!("env:PACT_OVERWRITE = {:?}", overwrite);
          ms.write_pact(
            &Some(output_dir),
            overwrite.unwrap_or_else(|_| "false".to_owned()) == "true")
            .map_err(|err| format!("error writing pact: {}", err))?;
            Ok(())
        } else {
            // Failure. Format our errors.
            let mut msg = format!("mock server {} failed verification:\n", self.description,);
            for mismatch in mismatches {
                match mismatch {
                    MatchResult::RequestMatch(..) => {
                        unreachable!("list of mismatches contains a match");
                    }
                    MatchResult::RequestMismatch(request, mismatches) => {
                        let _ = writeln!(&mut msg, "- request {}:", request);
                        for m in mismatches {
                            let _ = writeln!(&mut msg, "  - {}", m.description());
                        }
                    }
                    MatchResult::RequestNotFound(request) => {
                        let _ = writeln!(&mut msg, "- received unexpected request:");
                        let _ = writeln!(&mut msg, "{:#?}", request);
                    }
                    MatchResult::MissingRequest(request) => {
                        let _ = writeln!(
                            &mut msg,
                            "- request {} expected, but never occurred", request,
                        );
                        let _ = writeln!(&mut msg, "{:#?}", request);
                    }
                }
            }
            Err(msg)
        }
    }

  /// Returns the metrics collected by the mock server
  pub fn metrics(&self) -> MockServerMetrics {
    self.mock_server.lock().unwrap().metrics.clone()
  }
}

/// Either panic with `msg`, or if we're already in the middle of a panic,
/// just print `msg` to standard error.
fn panic_or_print_error(msg: &str) {
    if thread::panicking() {
        // The current thread is panicking, so don't try to panic again, because
        // double panics don't print useful explanations of why the test failed.
        // Instead, just print to `stderr`. Ignore any errors, because there's
        // not much we can do if we can't panic and we can't write to `stderr`.
        let _ = writeln!(io::stderr(), "{}", msg);
    } else {
        panic!("{}", msg);
    }
}

impl Drop for ValidatingMockServer {
    fn drop(&mut self) {
        let result = self.drop_helper();
        if let Err(msg) = result {
            panic_or_print_error(&msg);
        }
    }
}
<|endoftext|>


<commit_before>use pact_matching::models::Pact;
use rustc_serialize::json::Json;
use itertools::Itertools;
use std::collections::BTreeMap;
use hyper::client::*;
use std::error::Error;
use super::provider_client::join_paths;
use hyper::header::{Accept, qitem};
use hyper::mime::{Mime, TopLevel, SubLevel, Attr, Value};

fn is_true(object: &BTreeMap<String, Json>, field: &String) -> bool {
    match object.get(field) {
        Some(json) => match json {
            &Json::Boolean(b) => b,
            _e => false
        },
        None => false
    }
}

fn as_string(json: &Json) -> String {
    match json {
        &Json::String(ref s) => s.clone(),
        _ => format!("{}", json)
    }
}

pub struct HALClient {
    url: String,
    provider: String,
    path_info: Option<Json>
}

impl HALClient {

    fn default() -> HALClient {
        HALClient{ url: s!(""), provider: s!(""), path_info: None }
    }

    fn navigate(&mut self, link: &str) -> Result<(), String> {
        if self.path_info.is_none() {
            self.path_info = Some(try!(self.fetch("/")));
        }
        self.path_info = Some(try!(self.fetch_link(link)));
        Ok(())
    }

    fn fetch_link(&self, link: &str) -> Result<Json, String> {
        let link_data = try!(match self.path_info {
            None => Err(format!("Expected a HAL+JSON response from the pact broker, but got a non-JSON response. URL: '{}', LINK: '{}'",
                self.url, link)),
            Some(ref json) => match json.find("_links") {
                Some(json) => match json.find(link) {
                    Some(link_data) => link_data.as_object()
                        .ok_or(format!("Link is malformed, expcted an object but got {}. URL: '{}', LINK: '{}'",
                            link_data, self.url, link)),
                    None => Err(format!("Link '{}' was not found in the response, only the following links where found: {:?}. URL: '{}', LINK: '{}'",
                        link, json.as_object().unwrap().keys().join(", "), self.url, link))
                },
                None => Err(format!("Expected a HAL+JSON response from the pact broker, but got a response with no '_links'. URL: '{}', LINK: '{}'",
                    self.url, link))
            }
        });

        let link_url = try!(if is_true(link_data, &s!("templated")) {
            self.parse_link_url(link_data)
        } else {
            link_data.get("href").map(|href| as_string(href)).ok_or(format!("Link is malformed, there is no href. URL: '{}', LINK: '{}'",
                self.url, link))
        });
        self.fetch(&link_url)
    }

    fn fetch(&self, path: &str) -> Result<Json, String> {
        debug!("Fetching path '{}' from pact broker", path);
        let client = Client::new();
        let res = client.get(&join_paths(self.url.clone(), s!(path)))
            .header(Accept(vec![
                qitem(Mime(TopLevel::Application, SubLevel::Ext(s!("hal+json")),
                   vec![(Attr::Charset, Value::Utf8)])),
               qitem(Mime(TopLevel::Application, SubLevel::Json,
                  vec![(Attr::Charset, Value::Utf8)]))
            ]))
            .send();
        match res {
            Ok(response) => {
                debug!("Got response {:?}", response);
                if response.status.is_success() {
                    Err(s!(""))
                } else {
                    Err(format!("Request to pact broker path '{}' failed: {}", path,
                        response.status))
                }
            },
            Err(err) => Err(format!("Failed to access pact broker path '{}' - {:?}. URL: '{}'",
                path, err.description(), self.url))
        }
    }

    fn parse_link_url(&self, link_data: &BTreeMap<String, Json>) -> Result<String, String> {
        Err(s!(""))
    }
}

pub fn fetch_pacts_from_broker(broker_url: &String, provider_name: &String) -> Result<Vec<Result<Pact, String>>, String> {
    let mut client = HALClient{ url: broker_url.clone(), provider: provider_name.clone(), .. HALClient::default() };
    client.navigate("pb:latest-provider-pacts");
    Err(s!("Boom"))
}

#[cfg(test)]
mod tests {
    use expectest::prelude::*;
    use super::*;
    use pact_consumer::*;
    use env_logger::*;

    #[test]
    fn fetch_returns_an_error_if_there_is_no_pact_broker() {
        let client = HALClient{ url: s!("http://idont.exist:6666"), provider: s!("sad_provider"), .. HALClient::default() };
        expect!(client.fetch(&s!("/"))).to(be_err().value(s!("Failed to access pact broker path \'/\' - \"failed to lookup address information: Name or service not known\". URL: \'http://idont.exist:6666\'")));
    }

    #[test]
    fn fetch_returns_an_error_if_it_does_not_get_a_success_response() {
        init().unwrap_or(());

        let pact_runner = ConsumerPactBuilder::consumer(s!("RustPactVerifier"))
            .has_pact_with(s!("PactBroker"))
            .given(s!("the pact broker has a valid pact"))
            .upon_receiving(s!("a request to a non-existant path"))
                .path(s!("/hello"))
            .will_respond_with()
                .status(404)
            .build();

        let result = pact_runner.run(&|broker_url| {
            debug!("Broker URL is {}, Running test ...", broker_url);
            let client = HALClient{ url: broker_url, provider: s!("sad_provider"), .. HALClient::default() };
            let result = client.fetch(&s!("/hello"));
            expect!(result).to(be_err().value(s!("Request to pact broker path \'/hello\' failed: 404 Not Found")));
            Ok(())
        });
        expect!(result).to(be_equal_to(VerificationResult::PactVerified));
    }

    #[test]
    fn fetch_returns_an_error_if_it_does_not_get_a_hal_response() {
        let client = HALClient{ url: s!("http://idont.exist:6666"), provider: s!("sad_provider"), .. HALClient::default() };
        expect!(client.fetch(&s!("/"))).to(be_err().value(s!("Failed to access pact broker path \'/\' - \"failed to lookup address information: Name or service not known\". URL: \'http://idont.exist:6666\'")));
    }
}
<commit_msg>Fix for failing tests on OSX<commit_after>use pact_matching::models::Pact;
use rustc_serialize::json::Json;
use itertools::Itertools;
use std::collections::BTreeMap;
use hyper::client::*;
use std::error::Error;
use super::provider_client::join_paths;
use hyper::header::{Accept, qitem};
use hyper::mime::{Mime, TopLevel, SubLevel, Attr, Value};

fn is_true(object: &BTreeMap<String, Json>, field: &String) -> bool {
    match object.get(field) {
        Some(json) => match json {
            &Json::Boolean(b) => b,
            _e => false
        },
        None => false
    }
}

fn as_string(json: &Json) -> String {
    match json {
        &Json::String(ref s) => s.clone(),
        _ => format!("{}", json)
    }
}

pub struct HALClient {
    url: String,
    provider: String,
    path_info: Option<Json>
}

impl HALClient {

    fn default() -> HALClient {
        HALClient{ url: s!(""), provider: s!(""), path_info: None }
    }

    fn navigate(&mut self, link: &str) -> Result<(), String> {
        if self.path_info.is_none() {
            self.path_info = Some(try!(self.fetch("/")));
        }
        self.path_info = Some(try!(self.fetch_link(link)));
        Ok(())
    }

    fn fetch_link(&self, link: &str) -> Result<Json, String> {
        let link_data = try!(match self.path_info {
            None => Err(format!("Expected a HAL+JSON response from the pact broker, but got a non-JSON response. URL: '{}', LINK: '{}'",
                self.url, link)),
            Some(ref json) => match json.find("_links") {
                Some(json) => match json.find(link) {
                    Some(link_data) => link_data.as_object()
                        .ok_or(format!("Link is malformed, expcted an object but got {}. URL: '{}', LINK: '{}'",
                            link_data, self.url, link)),
                    None => Err(format!("Link '{}' was not found in the response, only the following links where found: {:?}. URL: '{}', LINK: '{}'",
                        link, json.as_object().unwrap().keys().join(", "), self.url, link))
                },
                None => Err(format!("Expected a HAL+JSON response from the pact broker, but got a response with no '_links'. URL: '{}', LINK: '{}'",
                    self.url, link))
            }
        });

        let link_url = try!(if is_true(link_data, &s!("templated")) {
            self.parse_link_url(link_data)
        } else {
            link_data.get("href").map(|href| as_string(href)).ok_or(format!("Link is malformed, there is no href. URL: '{}', LINK: '{}'",
                self.url, link))
        });
        self.fetch(&link_url)
    }

    fn fetch(&self, path: &str) -> Result<Json, String> {
        debug!("Fetching path '{}' from pact broker", path);
        let client = Client::new();
        let res = client.get(&join_paths(self.url.clone(), s!(path)))
            .header(Accept(vec![
                qitem(Mime(TopLevel::Application, SubLevel::Ext(s!("hal+json")),
                   vec![(Attr::Charset, Value::Utf8)])),
               qitem(Mime(TopLevel::Application, SubLevel::Json,
                  vec![(Attr::Charset, Value::Utf8)]))
            ]))
            .send();
        match res {
            Ok(response) => {
                debug!("Got response {:?}", response);
                if response.status.is_success() {
                    Err(s!(""))
                } else {
                    Err(format!("Request to pact broker path '{}' failed: {}", path,
                        response.status))
                }
            },
            Err(err) => Err(format!("Failed to access pact broker path '{}' - {:?}. URL: '{}'",
                path, err.description(), self.url))
        }
    }

    fn parse_link_url(&self, link_data: &BTreeMap<String, Json>) -> Result<String, String> {
        Err(s!(""))
    }
}

pub fn fetch_pacts_from_broker(broker_url: &String, provider_name: &String) -> Result<Vec<Result<Pact, String>>, String> {
    let mut client = HALClient{ url: broker_url.clone(), provider: provider_name.clone(), .. HALClient::default() };
    client.navigate("pb:latest-provider-pacts");
    Err(s!("Boom"))
}

#[cfg(test)]
mod tests {
    use expectest::prelude::*;
    use super::*;
    use pact_consumer::*;
    use env_logger::*;

    #[test]
    fn fetch_returns_an_error_if_there_is_no_pact_broker() {
        let client = HALClient{ url: s!("http://idont.exist:6666"), provider: s!("sad_provider"), .. HALClient::default() };
        expect!(client.fetch(&s!("/"))).to(be_err());
    }

    #[test]
    fn fetch_returns_an_error_if_it_does_not_get_a_success_response() {
        init().unwrap_or(());

        let pact_runner = ConsumerPactBuilder::consumer(s!("RustPactVerifier"))
            .has_pact_with(s!("PactBroker"))
            .given(s!("the pact broker has a valid pact"))
            .upon_receiving(s!("a request to a non-existant path"))
                .path(s!("/hello"))
            .will_respond_with()
                .status(404)
            .build();

        let result = pact_runner.run(&|broker_url| {
            debug!("Broker URL is {}, Running test ...", broker_url);
            let client = HALClient{ url: broker_url, provider: s!("sad_provider"), .. HALClient::default() };
            let result = client.fetch(&s!("/hello"));
            expect!(result).to(be_err().value(s!("Request to pact broker path \'/hello\' failed: 404 Not Found")));
            Ok(())
        });
        expect!(result).to(be_equal_to(VerificationResult::PactVerified));
    }

    #[test]
    fn fetch_returns_an_error_if_it_does_not_get_a_hal_response() {
        let client = HALClient{ url: s!("http://idont.exist:6666"), provider: s!("sad_provider"), .. HALClient::default() };
        expect!(client.fetch(&s!("/"))).to(be_err());
    }
}
<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::collections::hash_map::{Entry, HashMap};
use std::collections::hash_set::HashSet;
use std::rc::Rc;

use uuid::Uuid;

use js_types::js_type::JsPtrEnum;

pub mod scope;

pub type Alloc<T> = Rc<RefCell<T>>;

pub struct AllocBox {
    black_set: HashMap<Uuid, Alloc<JsPtrEnum>>,
    grey_set: HashMap<Uuid, Alloc<JsPtrEnum>>,
    white_set: HashMap<Uuid, Alloc<JsPtrEnum>>,
}

impl AllocBox {
    pub fn new() -> AllocBox {
        AllocBox {
            black_set: HashMap::new(),
            grey_set: HashMap::new(),
            white_set: HashMap::new(),
        }
    }

    pub fn alloc(&mut self, uuid: Uuid, ptr: JsPtrEnum) -> Uuid {
        self.white_set.insert(uuid, Rc::new(RefCell::new(ptr)));
        uuid
    }

    pub fn dealloc(&mut self, uuid: &Uuid) -> bool {
        if let Some(_) = self.white_set.remove(uuid) { true } else { false }
    }

    pub fn mark_roots(&mut self, marks: HashSet<Uuid>) {
        for mark in marks {
            // FIXME? Could a root be grey already?
            if let Some(ptr) = self.white_set.remove(&mark) {
                // Get all child references
                let child_ids = AllocBox::get_ptr_children(&ptr);
                // Mark current ref as black
                self.black_set.insert(mark, ptr);
                // Mark child references as grey
                self.grey_children(child_ids);
            }
        }
    }

    pub fn mark_ptrs(&mut self) {
        // Mark any grey object as black, and mark all white objs it refs as grey
        let mut new_grey_set = HashMap::new();
        for (uuid, var) in self.grey_set.drain() {
            let child_ids = AllocBox::get_ptr_children(&var);
            self.black_set.insert(uuid, var);
            for child_id in child_ids {
                if let Some(var) = self.white_set.remove(&child_id) {
                    new_grey_set.insert(child_id, var);
                }
            }
        }
        self.grey_set = new_grey_set;
    }

    pub fn sweep_ptrs(&mut self) {
        // Delete all white pointers and reset the GC state.
        self.white_set = self.black_set.clone();
        self.grey_set = HashMap::new();
        self.black_set = HashMap::new();
    }

    pub fn find_id(&self, uuid: &Uuid) -> Option<&Alloc<JsPtrEnum>> {
        self.white_set.get(uuid).or(
            self.grey_set.get(uuid).or(
                self.black_set.get(uuid)))
    }

    pub fn update_ptr(&mut self, uuid: &Uuid, ptr: JsPtrEnum) -> bool {
        if let Entry::Occupied(mut view) = self.find_id_mut(&uuid) {
            let inner = view.get_mut();
            *inner.borrow_mut() = ptr;
            true
        } else { false }
    }

    fn grey_children(&mut self, child_ids: HashSet<Uuid>) {
        for child_id in child_ids.iter() {
            if let Some(var) = self.white_set.remove(child_id) {
                self.grey_set.insert(*child_id, var);
            }
        }
    }

    fn get_ptr_children(ptr: &Alloc<JsPtrEnum>) -> HashSet<Uuid> {
        if let JsPtrEnum::JsObj(ref obj) = *ptr.borrow() {
            obj.get_children()
        } else { HashSet::new() }
    }

    fn find_id_mut(&mut self, uuid: &Uuid) -> Entry<Uuid, Alloc<JsPtrEnum>> {
        if let e @ Entry::Occupied(_) = self.white_set.entry(*uuid) {
            e
        } else if let e @ Entry::Occupied(_) = self.grey_set.entry(*uuid) {
            e
        } else { self.black_set.entry(*uuid) }
    }
}
<commit_msg>Add len method to AllocBox<commit_after>use std::cell::RefCell;
use std::collections::hash_map::{Entry, HashMap};
use std::collections::hash_set::HashSet;
use std::rc::Rc;

use uuid::Uuid;

use js_types::js_type::JsPtrEnum;

pub mod scope;

pub type Alloc<T> = Rc<RefCell<T>>;

pub struct AllocBox {
    black_set: HashMap<Uuid, Alloc<JsPtrEnum>>,
    grey_set: HashMap<Uuid, Alloc<JsPtrEnum>>,
    white_set: HashMap<Uuid, Alloc<JsPtrEnum>>,
}

impl AllocBox {
    pub fn new() -> AllocBox {
        AllocBox {
            black_set: HashMap::new(),
            grey_set: HashMap::new(),
            white_set: HashMap::new(),
        }
    }

    pub fn len(&self) -> usize {
        self.black_set.len() + self.grey_set.len() + self.white_set.len()
    }

    pub fn alloc(&mut self, uuid: Uuid, ptr: JsPtrEnum) -> Uuid {
        self.white_set.insert(uuid, Rc::new(RefCell::new(ptr)));
        uuid
    }

    pub fn dealloc(&mut self, uuid: &Uuid) -> bool {
        if let Some(_) = self.white_set.remove(uuid) { true } else { false }
    }

    pub fn mark_roots(&mut self, marks: HashSet<Uuid>) {
        for mark in marks {
            // FIXME? Could a root be grey already?
            if let Some(ptr) = self.white_set.remove(&mark) {
                // Get all child references
                let child_ids = AllocBox::get_ptr_children(&ptr);
                // Mark current ref as black
                self.black_set.insert(mark, ptr);
                // Mark child references as grey
                self.grey_children(child_ids);
            }
        }
    }

    pub fn mark_ptrs(&mut self) {
        // Mark any grey object as black, and mark all white objs it refs as grey
        let mut new_grey_set = HashMap::new();
        for (uuid, var) in self.grey_set.drain() {
            let child_ids = AllocBox::get_ptr_children(&var);
            self.black_set.insert(uuid, var);
            for child_id in child_ids {
                if let Some(var) = self.white_set.remove(&child_id) {
                    new_grey_set.insert(child_id, var);
                }
            }
        }
        self.grey_set = new_grey_set;
    }

    pub fn sweep_ptrs(&mut self) {
        // Delete all white pointers and reset the GC state.
        self.white_set = self.black_set.clone();
        self.grey_set = HashMap::new();
        self.black_set = HashMap::new();
    }

    pub fn find_id(&self, uuid: &Uuid) -> Option<&Alloc<JsPtrEnum>> {
        self.white_set.get(uuid).or(
            self.grey_set.get(uuid).or(
                self.black_set.get(uuid)))
    }

    pub fn update_ptr(&mut self, uuid: &Uuid, ptr: JsPtrEnum) -> bool {
        if let Entry::Occupied(mut view) = self.find_id_mut(&uuid) {
            let inner = view.get_mut();
            *inner.borrow_mut() = ptr;
            true
        } else { false }
    }

    fn grey_children(&mut self, child_ids: HashSet<Uuid>) {
        for child_id in child_ids.iter() {
            if let Some(var) = self.white_set.remove(child_id) {
                self.grey_set.insert(*child_id, var);
            }
        }
    }

    fn get_ptr_children(ptr: &Alloc<JsPtrEnum>) -> HashSet<Uuid> {
        if let JsPtrEnum::JsObj(ref obj) = *ptr.borrow() {
            obj.get_children()
        } else { HashSet::new() }
    }

    fn find_id_mut(&mut self, uuid: &Uuid) -> Entry<Uuid, Alloc<JsPtrEnum>> {
        if let e @ Entry::Occupied(_) = self.white_set.entry(*uuid) {
            e
        } else if let e @ Entry::Occupied(_) = self.grey_set.entry(*uuid) {
            e
        } else { self.black_set.entry(*uuid) }
    }
}
<|endoftext|>


<commit_before>//! Allocator shim
// Adapted from rustc

use crate::prelude::*;

use cranelift_codegen::binemit::{NullStackMapSink, NullTrapSink};
use rustc_ast::expand::allocator::{AllocatorKind, AllocatorTy, ALLOCATOR_METHODS};
use rustc_span::symbol::sym;

/// Returns whether an allocator shim was created
pub(crate) fn codegen(
    tcx: TyCtxt<'_>,
    module: &mut impl Module,
    unwind_context: &mut UnwindContext,
) -> bool {
    let any_dynamic_crate = tcx.dependency_formats(()).iter().any(|(_, list)| {
        use rustc_middle::middle::dependency_format::Linkage;
        list.iter().any(|&linkage| linkage == Linkage::Dynamic)
    });
    if any_dynamic_crate {
        false
    } else if let Some(kind) = tcx.allocator_kind() {
        codegen_inner(module, unwind_context, kind);
        true
    } else {
        false
    }
}

fn codegen_inner(
    module: &mut impl Module,
    unwind_context: &mut UnwindContext,
    kind: AllocatorKind,
) {
    let usize_ty = module.target_config().pointer_type();

    for method in ALLOCATOR_METHODS {
        let mut arg_tys = Vec::with_capacity(method.inputs.len());
        for ty in method.inputs.iter() {
            match *ty {
                AllocatorTy::Layout => {
                    arg_tys.push(usize_ty); // size
                    arg_tys.push(usize_ty); // align
                }
                AllocatorTy::Ptr => arg_tys.push(usize_ty),
                AllocatorTy::Usize => arg_tys.push(usize_ty),

                AllocatorTy::ResultPtr | AllocatorTy::Unit => panic!("invalid allocator arg"),
            }
        }
        let output = match method.output {
            AllocatorTy::ResultPtr => Some(usize_ty),
            AllocatorTy::Unit => None,

            AllocatorTy::Layout | AllocatorTy::Usize | AllocatorTy::Ptr => {
                panic!("invalid allocator output")
            }
        };

        let sig = Signature {
            call_conv: CallConv::triple_default(module.isa().triple()),
            params: arg_tys.iter().cloned().map(AbiParam::new).collect(),
            returns: output.into_iter().map(AbiParam::new).collect(),
        };

        let caller_name = format!("__rust_{}", method.name);
        let callee_name = kind.fn_name(method.name);
        //eprintln!("Codegen allocator shim {} -> {} ({:?} -> {:?})", caller_name, callee_name, sig.params, sig.returns);

        let func_id = module.declare_function(&caller_name, Linkage::Export, &sig).unwrap();

        let callee_func_id = module.declare_function(&callee_name, Linkage::Import, &sig).unwrap();

        let mut ctx = Context::new();
        ctx.func = Function::with_name_signature(ExternalName::user(0, 0), sig.clone());
        {
            let mut func_ctx = FunctionBuilderContext::new();
            let mut bcx = FunctionBuilder::new(&mut ctx.func, &mut func_ctx);

            let block = bcx.create_block();
            bcx.switch_to_block(block);
            let args = arg_tys
                .into_iter()
                .map(|ty| bcx.append_block_param(block, ty))
                .collect::<Vec<Value>>();

            let callee_func_ref = module.declare_func_in_func(callee_func_id, &mut bcx.func);
            let call_inst = bcx.ins().call(callee_func_ref, &args);
            let results = bcx.inst_results(call_inst).to_vec(); // Clone to prevent borrow error

            bcx.ins().return_(&results);
            bcx.seal_all_blocks();
            bcx.finalize();
        }
        module
            .define_function(func_id, &mut ctx, &mut NullTrapSink {}, &mut NullStackMapSink {})
            .unwrap();
        unwind_context.add_function(func_id, &ctx, module.isa());
    }

    let sig = Signature {
        call_conv: CallConv::triple_default(module.isa().triple()),
        params: vec![AbiParam::new(usize_ty), AbiParam::new(usize_ty)],
        returns: vec![],
    };

    let callee_name = kind.fn_name(sym::oom);
    //eprintln!("Codegen allocator shim {} -> {} ({:?} -> {:?})", caller_name, callee_name, sig.params, sig.returns);

    let func_id =
        module.declare_function("__rust_alloc_error_handler", Linkage::Export, &sig).unwrap();

    let callee_func_id = module.declare_function(&callee_name, Linkage::Import, &sig).unwrap();

    let mut ctx = Context::new();
    ctx.func = Function::with_name_signature(ExternalName::user(0, 0), sig);
    {
        let mut func_ctx = FunctionBuilderContext::new();
        let mut bcx = FunctionBuilder::new(&mut ctx.func, &mut func_ctx);

        let block = bcx.create_block();
        bcx.switch_to_block(block);
        let args = (&[usize_ty, usize_ty])
            .iter()
            .map(|&ty| bcx.append_block_param(block, ty))
            .collect::<Vec<Value>>();

        let callee_func_ref = module.declare_func_in_func(callee_func_id, &mut bcx.func);
        bcx.ins().call(callee_func_ref, &args);

        bcx.ins().trap(TrapCode::UnreachableCodeReached);
        bcx.seal_all_blocks();
        bcx.finalize();
    }
    module
        .define_function(func_id, &mut ctx, &mut NullTrapSink {}, &mut NullStackMapSink {})
        .unwrap();
    unwind_context.add_function(func_id, &ctx, module.isa());
}
<commit_msg>Make allocator_kind a query.<commit_after>//! Allocator shim
// Adapted from rustc

use crate::prelude::*;

use cranelift_codegen::binemit::{NullStackMapSink, NullTrapSink};
use rustc_ast::expand::allocator::{AllocatorKind, AllocatorTy, ALLOCATOR_METHODS};
use rustc_span::symbol::sym;

/// Returns whether an allocator shim was created
pub(crate) fn codegen(
    tcx: TyCtxt<'_>,
    module: &mut impl Module,
    unwind_context: &mut UnwindContext,
) -> bool {
    let any_dynamic_crate = tcx.dependency_formats(()).iter().any(|(_, list)| {
        use rustc_middle::middle::dependency_format::Linkage;
        list.iter().any(|&linkage| linkage == Linkage::Dynamic)
    });
    if any_dynamic_crate {
        false
    } else if let Some(kind) = tcx.allocator_kind(()) {
        codegen_inner(module, unwind_context, kind);
        true
    } else {
        false
    }
}

fn codegen_inner(
    module: &mut impl Module,
    unwind_context: &mut UnwindContext,
    kind: AllocatorKind,
) {
    let usize_ty = module.target_config().pointer_type();

    for method in ALLOCATOR_METHODS {
        let mut arg_tys = Vec::with_capacity(method.inputs.len());
        for ty in method.inputs.iter() {
            match *ty {
                AllocatorTy::Layout => {
                    arg_tys.push(usize_ty); // size
                    arg_tys.push(usize_ty); // align
                }
                AllocatorTy::Ptr => arg_tys.push(usize_ty),
                AllocatorTy::Usize => arg_tys.push(usize_ty),

                AllocatorTy::ResultPtr | AllocatorTy::Unit => panic!("invalid allocator arg"),
            }
        }
        let output = match method.output {
            AllocatorTy::ResultPtr => Some(usize_ty),
            AllocatorTy::Unit => None,

            AllocatorTy::Layout | AllocatorTy::Usize | AllocatorTy::Ptr => {
                panic!("invalid allocator output")
            }
        };

        let sig = Signature {
            call_conv: CallConv::triple_default(module.isa().triple()),
            params: arg_tys.iter().cloned().map(AbiParam::new).collect(),
            returns: output.into_iter().map(AbiParam::new).collect(),
        };

        let caller_name = format!("__rust_{}", method.name);
        let callee_name = kind.fn_name(method.name);
        //eprintln!("Codegen allocator shim {} -> {} ({:?} -> {:?})", caller_name, callee_name, sig.params, sig.returns);

        let func_id = module.declare_function(&caller_name, Linkage::Export, &sig).unwrap();

        let callee_func_id = module.declare_function(&callee_name, Linkage::Import, &sig).unwrap();

        let mut ctx = Context::new();
        ctx.func = Function::with_name_signature(ExternalName::user(0, 0), sig.clone());
        {
            let mut func_ctx = FunctionBuilderContext::new();
            let mut bcx = FunctionBuilder::new(&mut ctx.func, &mut func_ctx);

            let block = bcx.create_block();
            bcx.switch_to_block(block);
            let args = arg_tys
                .into_iter()
                .map(|ty| bcx.append_block_param(block, ty))
                .collect::<Vec<Value>>();

            let callee_func_ref = module.declare_func_in_func(callee_func_id, &mut bcx.func);
            let call_inst = bcx.ins().call(callee_func_ref, &args);
            let results = bcx.inst_results(call_inst).to_vec(); // Clone to prevent borrow error

            bcx.ins().return_(&results);
            bcx.seal_all_blocks();
            bcx.finalize();
        }
        module
            .define_function(func_id, &mut ctx, &mut NullTrapSink {}, &mut NullStackMapSink {})
            .unwrap();
        unwind_context.add_function(func_id, &ctx, module.isa());
    }

    let sig = Signature {
        call_conv: CallConv::triple_default(module.isa().triple()),
        params: vec![AbiParam::new(usize_ty), AbiParam::new(usize_ty)],
        returns: vec![],
    };

    let callee_name = kind.fn_name(sym::oom);
    //eprintln!("Codegen allocator shim {} -> {} ({:?} -> {:?})", caller_name, callee_name, sig.params, sig.returns);

    let func_id =
        module.declare_function("__rust_alloc_error_handler", Linkage::Export, &sig).unwrap();

    let callee_func_id = module.declare_function(&callee_name, Linkage::Import, &sig).unwrap();

    let mut ctx = Context::new();
    ctx.func = Function::with_name_signature(ExternalName::user(0, 0), sig);
    {
        let mut func_ctx = FunctionBuilderContext::new();
        let mut bcx = FunctionBuilder::new(&mut ctx.func, &mut func_ctx);

        let block = bcx.create_block();
        bcx.switch_to_block(block);
        let args = (&[usize_ty, usize_ty])
            .iter()
            .map(|&ty| bcx.append_block_param(block, ty))
            .collect::<Vec<Value>>();

        let callee_func_ref = module.declare_func_in_func(callee_func_id, &mut bcx.func);
        bcx.ins().call(callee_func_ref, &args);

        bcx.ins().trap(TrapCode::UnreachableCodeReached);
        bcx.seal_all_blocks();
        bcx.finalize();
    }
    module
        .define_function(func_id, &mut ctx, &mut NullTrapSink {}, &mut NullStackMapSink {})
        .unwrap();
    unwind_context.add_function(func_id, &ctx, module.isa());
}
<|endoftext|>


<commit_before>#![feature(phase)]

extern crate serialize;
#[phase(plugin, link)] extern crate log;

extern crate cargo;
extern crate docopt;
#[phase(plugin)] extern crate docopt_macros;

use std::collections::TreeSet;
use std::os;
use std::io;
use std::io::fs;
use std::io::process::{Command,InheritFd,ExitStatus,ExitSignal};
use serialize::Encodable;
use docopt::FlagParser;

use cargo::{execute_main_without_stdin, handle_error, shell};
use cargo::core::MultiShell;
use cargo::util::important_paths::find_project;
use cargo::util::{CliError, CliResult, Require, config, human};

fn main() {
    execute_main_without_stdin(execute, true)
}

docopt!(Flags, "
Rust's package manager

Usage:
    cargo <command> [<args>...]
    cargo [options]

Options:
    -h, --help       Display this message
    -V, --version    Print version info and exit
    --list           List installed commands
    -v, --verbose    Use verbose output

Some common cargo commands are:
    build       Compile the current project
    clean       Remove the target directory
    doc         Build this project's and its dependencies' documentation
    new         Create a new cargo project
    run         Build and execute src/main.rs
    test        Run the tests
    bench       Run the benchmarks
    update      Update dependencies listed in Cargo.lock

See 'cargo help <command>' for more information on a specific command.
")

/**
  The top-level `cargo` command handles configuration and project location
  because they are fundamental (and intertwined). Other commands can rely
  on this top-level information.
*/
fn execute(flags: Flags, shell: &mut MultiShell) -> CliResult<Option<()>> {
    debug!("executing; cmd=cargo; args={}", os::args());
    shell.set_verbose(flags.flag_verbose);
    if flags.flag_list {
        println!("Installed Commands:");
        for command in list_commands().iter() {
            println!("    {}", command);
            // TODO: it might be helpful to add result of -h to each command.
        };
        return Ok(None)
    }
    let mut args = flags.arg_args.clone();
    args.insert(0, flags.arg_command.clone());
    match flags.arg_command.as_slice() {
        "config-for-key" => {
            log!(4, "cmd == config-for-key");
            let r = cargo::call_main_without_stdin(config_for_key, shell,
                                                   args.as_slice(), false);
            cargo::process_executed(r, shell)
        },
        "config-list" => {
            log!(4, "cmd == config-list");
            let r = cargo::call_main_without_stdin(config_list, shell,
                                                   args.as_slice(), false);
            cargo::process_executed(r, shell)
        },
        "locate-project" => {
            log!(4, "cmd == locate-project");
            let r = cargo::call_main_without_stdin(locate_project, shell,
                                                   args.as_slice(), false);
            cargo::process_executed(r, shell)
        },
        // If we have `help` with no arguments, re-invoke ourself with `-h` to
        // get the help message printed
        "help" if flags.arg_args.len() == 0 => {
            shell.set_verbose(true);
            let r = cargo::call_main_without_stdin(execute, shell,
                                                   ["-h".to_string()], false);
            cargo::process_executed(r, shell)
        },
        orig_cmd => {
            let is_help = orig_cmd == "help";
            let cmd = if is_help {
                flags.arg_args[0].as_slice()
            } else {
                orig_cmd
            };
            execute_subcommand(cmd, is_help, &flags, shell)
        }
    }
    Ok(None)
}

fn execute_subcommand(cmd: &str, is_help: bool, flags: &Flags, shell: &mut MultiShell) -> () {
    match find_command(cmd) {
        Some(command) => {
            let mut command = Command::new(command);
            let command = if is_help {
                command.arg("-h")
            } else {
                command.args(flags.arg_args.as_slice())
            };
            let status = command
                .stdin(InheritFd(0))
                .stdout(InheritFd(1))
                .stderr(InheritFd(2))
                .status();

            match status {
                Ok(ExitStatus(0)) => (),
                Ok(ExitStatus(i)) => {
                    handle_error(CliError::new("", i as uint), shell)
                }
                Ok(ExitSignal(i)) => {
                    let msg = format!("subcommand failed with signal: {}", i);
                    handle_error(CliError::new(msg, i as uint), shell)
                }
                Err(io::IoError{kind, ..}) if kind == io::FileNotFound =>
                    handle_error(CliError::new("No such subcommand", 127), shell),
                Err(err) => handle_error(
                    CliError::new(
                        format!("Subcommand failed to run: {}", err), 127),
                    shell)
            }
        },
        None => handle_error(CliError::new("No such subcommand", 127), shell)
    }
}

/// List all runnable commands. find_command should always succeed
/// if given one of returned command.
fn list_commands() -> TreeSet<String> {
    let command_prefix = "cargo-";
    let mut commands = TreeSet::new();
    for dir in list_command_directory().iter() {
        let entries = match fs::readdir(dir) {
            Ok(entries) => entries,
            _ => continue
        };
        for entry in entries.iter() {
            let filename = match entry.filename_str() {
                Some(filename) => filename,
                _ => continue
            };
            if filename.starts_with(command_prefix) &&
                    filename.ends_with(os::consts::EXE_SUFFIX) &&
                    is_executable(entry) {
                let command = filename.slice(
                    command_prefix.len(),
                    filename.len() - os::consts::EXE_SUFFIX.len());
                commands.insert(String::from_str(command));
            }
        }
    }
    commands
}

fn is_executable(path: &Path) -> bool {
    match fs::stat(path) {
        Ok(io::FileStat{kind, perm, ..}) =>
            (kind == io::TypeFile) && perm.contains(io::OtherExecute),
        _ => false
    }
}

/// Get `Command` to run given command.
fn find_command(cmd: &str) -> Option<Path> {
    let command_exe = format!("cargo-{}{}", cmd, os::consts::EXE_SUFFIX);
    let dirs = list_command_directory();
    let mut command_paths = dirs.iter().map(|dir| dir.join(command_exe.as_slice()));
    command_paths.find(|path| path.exists())
}

/// List candidate locations where subcommands might be installed.
fn list_command_directory() -> Vec<Path> {
    let mut dirs = vec![];
    match os::self_exe_path() {
        Some(path) => {
            dirs.push(path.join("../lib/cargo"));
            dirs.push(path);
        },
        None => {}
    };
    match std::os::getenv("PATH") {
        Some(val) => {
            for dir in os::split_paths(val).iter() {
                dirs.push(Path::new(dir))
            }
        },
        None => {}
    };
    dirs
}

#[deriving(Encodable)]
struct ConfigOut {
    values: std::collections::HashMap<String, config::ConfigValue>
}

docopt!(ConfigForKeyFlags, "
Usage: cargo config-for-key --human --key=<key>
")

fn config_for_key(args: ConfigForKeyFlags,
                  _: &mut MultiShell) -> CliResult<Option<ConfigOut>> {
    let value = try!(config::get_config(os::getcwd(),
                                        args.flag_key.as_slice()).map_err(|_| {
        CliError::new("Couldn't load configuration",  1)
    }));

    if args.flag_human {
        println!("{}", value);
        Ok(None)
    } else {
        let mut map = std::collections::HashMap::new();
        map.insert(args.flag_key.clone(), value);
        Ok(Some(ConfigOut { values: map }))
    }
}

docopt!(ConfigListFlags, "
Usage: cargo config-list --human
")

fn config_list(args: ConfigListFlags, _: &mut MultiShell) -> CliResult<Option<ConfigOut>> {
    let configs = try!(config::all_configs(os::getcwd()).map_err(|_|
        CliError::new("Couldn't load configuration", 1)));

    if args.flag_human {
        for (key, value) in configs.iter() {
            println!("{} = {}", key, value);
        }
        Ok(None)
    } else {
        Ok(Some(ConfigOut { values: configs }))
    }
}

docopt!(LocateProjectFlags, "
Usage: cargo locate-project
")

#[deriving(Encodable)]
struct ProjectLocation {
    root: String
}

fn locate_project(_: LocateProjectFlags,
                  _: &mut MultiShell) -> CliResult<Option<ProjectLocation>> {
    let root = try!(find_project(&os::getcwd(), "Cargo.toml").map_err(|e| {
        CliError::from_boxed(e, 1)
    }));

    let string = try!(root.as_str()
                      .require(|| human("Your project path contains characters \
                                         not representable in Unicode"))
                      .map_err(|e| CliError::from_boxed(e, 1)));

    Ok(Some(ProjectLocation { root: string.to_string() }))
}
<commit_msg>auto merge of #412 : ScriptDevil/cargo/default-help, r=alexcrichton<commit_after>#![feature(phase)]

extern crate serialize;
#[phase(plugin, link)] extern crate log;

extern crate cargo;
extern crate docopt;
#[phase(plugin)] extern crate docopt_macros;

use std::collections::TreeSet;
use std::os;
use std::io;
use std::io::fs;
use std::io::process::{Command,InheritFd,ExitStatus,ExitSignal};
use serialize::Encodable;
use docopt::FlagParser;

use cargo::{execute_main_without_stdin, handle_error, shell};
use cargo::core::MultiShell;
use cargo::util::important_paths::find_project;
use cargo::util::{CliError, CliResult, Require, config, human};

fn main() {
    execute_main_without_stdin(execute, true)
}

docopt!(Flags, "
Rust's package manager

Usage:
    cargo <command> [<args>...]
    cargo [options]

Options:
    -h, --help       Display this message
    -V, --version    Print version info and exit
    --list           List installed commands
    -v, --verbose    Use verbose output

Some common cargo commands are:
    build       Compile the current project
    clean       Remove the target directory
    doc         Build this project's and its dependencies' documentation
    new         Create a new cargo project
    run         Build and execute src/main.rs
    test        Run the tests
    bench       Run the benchmarks
    update      Update dependencies listed in Cargo.lock

See 'cargo help <command>' for more information on a specific command.
")

/**
  The top-level `cargo` command handles configuration and project location
  because they are fundamental (and intertwined). Other commands can rely
  on this top-level information.
*/
fn execute(flags: Flags, shell: &mut MultiShell) -> CliResult<Option<()>> {
    debug!("executing; cmd=cargo; args={}", os::args());
    shell.set_verbose(flags.flag_verbose);
    if flags.flag_list {
        println!("Installed Commands:");
        for command in list_commands().iter() {
            println!("    {}", command);
            // TODO: it might be helpful to add result of -h to each command.
        };
        return Ok(None)
    }
    let mut args = flags.arg_args.clone();
    args.insert(0, flags.arg_command.clone());
    match flags.arg_command.as_slice() {
        "config-for-key" => {
            log!(4, "cmd == config-for-key");
            let r = cargo::call_main_without_stdin(config_for_key, shell,
                                                   args.as_slice(), false);
            cargo::process_executed(r, shell)
        },
        "config-list" => {
            log!(4, "cmd == config-list");
            let r = cargo::call_main_without_stdin(config_list, shell,
                                                   args.as_slice(), false);
            cargo::process_executed(r, shell)
        },
        "locate-project" => {
            log!(4, "cmd == locate-project");
            let r = cargo::call_main_without_stdin(locate_project, shell,
                                                   args.as_slice(), false);
            cargo::process_executed(r, shell)
        },
        // If we are invoked with no arguments or with `help` with no
        // arguments, re-invoke ourself with `-h` to get the help
        // message printed
        "" | "help" if flags.arg_args.len() == 0 => {
            shell.set_verbose(true);
            let r = cargo::call_main_without_stdin(execute, shell,
                                                   ["-h".to_string()], false);
            cargo::process_executed(r, shell)
        },
        orig_cmd => {
            let is_help = orig_cmd == "help";
            let cmd = if is_help {
                flags.arg_args[0].as_slice()
            } else {
                orig_cmd
            };
            execute_subcommand(cmd, is_help, &flags, shell)
        }
    }
    Ok(None)
}

fn execute_subcommand(cmd: &str, is_help: bool, flags: &Flags, shell: &mut MultiShell) -> () {
    match find_command(cmd) {
        Some(command) => {
            let mut command = Command::new(command);
            let command = if is_help {
                command.arg("-h")
            } else {
                command.args(flags.arg_args.as_slice())
            };
            let status = command
                .stdin(InheritFd(0))
                .stdout(InheritFd(1))
                .stderr(InheritFd(2))
                .status();

            match status {
                Ok(ExitStatus(0)) => (),
                Ok(ExitStatus(i)) => {
                    handle_error(CliError::new("", i as uint), shell)
                }
                Ok(ExitSignal(i)) => {
                    let msg = format!("subcommand failed with signal: {}", i);
                    handle_error(CliError::new(msg, i as uint), shell)
                }
                Err(io::IoError{kind, ..}) if kind == io::FileNotFound =>
                    handle_error(CliError::new("No such subcommand", 127), shell),
                Err(err) => handle_error(
                    CliError::new(
                        format!("Subcommand failed to run: {}", err), 127),
                    shell)
            }
        },
        None => handle_error(CliError::new("No such subcommand", 127), shell)
    }
}

/// List all runnable commands. find_command should always succeed
/// if given one of returned command.
fn list_commands() -> TreeSet<String> {
    let command_prefix = "cargo-";
    let mut commands = TreeSet::new();
    for dir in list_command_directory().iter() {
        let entries = match fs::readdir(dir) {
            Ok(entries) => entries,
            _ => continue
        };
        for entry in entries.iter() {
            let filename = match entry.filename_str() {
                Some(filename) => filename,
                _ => continue
            };
            if filename.starts_with(command_prefix) &&
                    filename.ends_with(os::consts::EXE_SUFFIX) &&
                    is_executable(entry) {
                let command = filename.slice(
                    command_prefix.len(),
                    filename.len() - os::consts::EXE_SUFFIX.len());
                commands.insert(String::from_str(command));
            }
        }
    }
    commands
}

fn is_executable(path: &Path) -> bool {
    match fs::stat(path) {
        Ok(io::FileStat{kind, perm, ..}) =>
            (kind == io::TypeFile) && perm.contains(io::OtherExecute),
        _ => false
    }
}

/// Get `Command` to run given command.
fn find_command(cmd: &str) -> Option<Path> {
    let command_exe = format!("cargo-{}{}", cmd, os::consts::EXE_SUFFIX);
    let dirs = list_command_directory();
    let mut command_paths = dirs.iter().map(|dir| dir.join(command_exe.as_slice()));
    command_paths.find(|path| path.exists())
}

/// List candidate locations where subcommands might be installed.
fn list_command_directory() -> Vec<Path> {
    let mut dirs = vec![];
    match os::self_exe_path() {
        Some(path) => {
            dirs.push(path.join("../lib/cargo"));
            dirs.push(path);
        },
        None => {}
    };
    match std::os::getenv("PATH") {
        Some(val) => {
            for dir in os::split_paths(val).iter() {
                dirs.push(Path::new(dir))
            }
        },
        None => {}
    };
    dirs
}

#[deriving(Encodable)]
struct ConfigOut {
    values: std::collections::HashMap<String, config::ConfigValue>
}

docopt!(ConfigForKeyFlags, "
Usage: cargo config-for-key --human --key=<key>
")

fn config_for_key(args: ConfigForKeyFlags,
                  _: &mut MultiShell) -> CliResult<Option<ConfigOut>> {
    let value = try!(config::get_config(os::getcwd(),
                                        args.flag_key.as_slice()).map_err(|_| {
        CliError::new("Couldn't load configuration",  1)
    }));

    if args.flag_human {
        println!("{}", value);
        Ok(None)
    } else {
        let mut map = std::collections::HashMap::new();
        map.insert(args.flag_key.clone(), value);
        Ok(Some(ConfigOut { values: map }))
    }
}

docopt!(ConfigListFlags, "
Usage: cargo config-list --human
")

fn config_list(args: ConfigListFlags, _: &mut MultiShell) -> CliResult<Option<ConfigOut>> {
    let configs = try!(config::all_configs(os::getcwd()).map_err(|_|
        CliError::new("Couldn't load configuration", 1)));

    if args.flag_human {
        for (key, value) in configs.iter() {
            println!("{} = {}", key, value);
        }
        Ok(None)
    } else {
        Ok(Some(ConfigOut { values: configs }))
    }
}

docopt!(LocateProjectFlags, "
Usage: cargo locate-project
")

#[deriving(Encodable)]
struct ProjectLocation {
    root: String
}

fn locate_project(_: LocateProjectFlags,
                  _: &mut MultiShell) -> CliResult<Option<ProjectLocation>> {
    let root = try!(find_project(&os::getcwd(), "Cargo.toml").map_err(|e| {
        CliError::from_boxed(e, 1)
    }));

    let string = try!(root.as_str()
                      .require(|| human("Your project path contains characters \
                                         not representable in Unicode"))
                      .map_err(|e| CliError::from_boxed(e, 1)));

    Ok(Some(ProjectLocation { root: string.to_string() }))
}
<|endoftext|>


<commit_before>use std::env;

use cargo::core::Workspace;
use cargo::ops::{CompileOptions, CompileMode};
use cargo::ops;
use cargo::util::important_paths::{find_root_manifest_for_wd};
use cargo::util::{CliResult, CliError, Config, human};

#[derive(RustcDecodable)]
pub struct Options {
    arg_opts: Option<Vec<String>>,
    flag_package: Option<String>,
    flag_jobs: Option<u32>,
    flag_features: Vec<String>,
    flag_no_default_features: bool,
    flag_target: Option<String>,
    flag_manifest_path: Option<String>,
    flag_verbose: u32,
    flag_quiet: Option<bool>,
    flag_color: Option<String>,
    flag_release: bool,
    flag_lib: bool,
    flag_bin: Vec<String>,
    flag_example: Vec<String>,
    flag_test: Vec<String>,
    flag_bench: Vec<String>,
    flag_profile: Option<String>,
}

pub const USAGE: &'static str = "
Compile a package and all of its dependencies

Usage:
    cargo rustc [options] [--] [<opts>...]

Options:
    -h, --help               Print this message
    -p SPEC, --package SPEC  The profile to compile for
    -j N, --jobs N           Number of parallel jobs, defaults to # of CPUs
    --lib                    Build only this package's library
    --bin NAME               Build only the specified binary
    --example NAME           Build only the specified example
    --test NAME              Build only the specified test target
    --bench NAME             Build only the specified benchmark target
    --release                Build artifacts in release mode, with optimizations
    --profile PROFILE        Profile to build the selected target for
    --features FEATURES      Features to compile for the package
    --no-default-features    Do not compile default features for the package
    --target TRIPLE          Target triple which compiles will be for
    --manifest-path PATH     Path to the manifest to fetch dependencies for
    -v, --verbose ...        Use verbose output
    -q, --quiet              No output printed to stdout
    --color WHEN             Coloring: auto, always, never

The specified target for the current package (or package specified by SPEC if
provided) will be compiled along with all of its dependencies. The specified
<opts>... will all be passed to the final compiler invocation, not any of the
dependencies. Note that the compiler will still unconditionally receive
arguments such as -L, --extern, and --crate-type, and the specified <opts>...
will simply be added to the compiler invocation.

This command requires that only one target is being compiled. If more than one
target is available for the current package the filters of --lib, --bin, etc,
must be used to select which target is compiled. To pass flags to all compiler
processes spawned by Cargo, use the $RUSTFLAGS environment variable or the
`build.rustflags` configuration option.
";

pub fn execute(options: Options, config: &Config) -> CliResult<Option<()>> {
    debug!("executing; cmd=cargo-rustc; args={:?}",
           env::args().collect::<Vec<_>>());
    try!(config.configure_shell(options.flag_verbose,
                                options.flag_quiet,
                                &options.flag_color));

    let root = try!(find_root_manifest_for_wd(options.flag_manifest_path,
                                              config.cwd()));
    let mode = match options.flag_profile.as_ref().map(|t| &t[..]) {
        Some("dev") | None => CompileMode::Build,
        Some("test") => CompileMode::Test,
        Some("bench") => CompileMode::Bench,
        Some(mode) => {
            let err = human(format!("unknown profile: `{}`, use dev,
                                     test, or bench", mode));
            return Err(CliError::new(err, 101))
        }
    };

    let opts = CompileOptions {
        config: config,
        jobs: options.flag_jobs,
        target: options.flag_target.as_ref().map(|t| &t[..]),
        features: &options.flag_features,
        no_default_features: options.flag_no_default_features,
        spec: &options.flag_package.map_or(Vec::new(), |s| vec![s]),
        exec_engine: None,
        mode: mode,
        release: options.flag_release,
        filter: ops::CompileFilter::new(options.flag_lib,
                                        &options.flag_bin,
                                        &options.flag_test,
                                        &options.flag_example,
                                        &options.flag_bench),
        target_rustdoc_args: None,
        target_rustc_args: options.arg_opts.as_ref().map(|a| &a[..]),
    };

    let ws = try!(Workspace::new(&root, config));
    try!(ops::compile(&ws, &opts));
    Ok(None)
}

<commit_msg>Auto merge of #2889 - bennofs:fix-cargo-rustc-help, r=alexcrichton<commit_after>use std::env;

use cargo::core::Workspace;
use cargo::ops::{CompileOptions, CompileMode};
use cargo::ops;
use cargo::util::important_paths::{find_root_manifest_for_wd};
use cargo::util::{CliResult, CliError, Config, human};

#[derive(RustcDecodable)]
pub struct Options {
    arg_opts: Option<Vec<String>>,
    flag_package: Option<String>,
    flag_jobs: Option<u32>,
    flag_features: Vec<String>,
    flag_no_default_features: bool,
    flag_target: Option<String>,
    flag_manifest_path: Option<String>,
    flag_verbose: u32,
    flag_quiet: Option<bool>,
    flag_color: Option<String>,
    flag_release: bool,
    flag_lib: bool,
    flag_bin: Vec<String>,
    flag_example: Vec<String>,
    flag_test: Vec<String>,
    flag_bench: Vec<String>,
    flag_profile: Option<String>,
}

pub const USAGE: &'static str = "
Compile a package and all of its dependencies

Usage:
    cargo rustc [options] [--] [<opts>...]

Options:
    -h, --help               Print this message
    -p SPEC, --package SPEC  Package to build
    -j N, --jobs N           Number of parallel jobs, defaults to # of CPUs
    --lib                    Build only this package's library
    --bin NAME               Build only the specified binary
    --example NAME           Build only the specified example
    --test NAME              Build only the specified test target
    --bench NAME             Build only the specified benchmark target
    --release                Build artifacts in release mode, with optimizations
    --profile PROFILE        Profile to build the selected target for
    --features FEATURES      Features to compile for the package
    --no-default-features    Do not compile default features for the package
    --target TRIPLE          Target triple which compiles will be for
    --manifest-path PATH     Path to the manifest to fetch dependencies for
    -v, --verbose ...        Use verbose output
    -q, --quiet              No output printed to stdout
    --color WHEN             Coloring: auto, always, never

The specified target for the current package (or package specified by SPEC if
provided) will be compiled along with all of its dependencies. The specified
<opts>... will all be passed to the final compiler invocation, not any of the
dependencies. Note that the compiler will still unconditionally receive
arguments such as -L, --extern, and --crate-type, and the specified <opts>...
will simply be added to the compiler invocation.

This command requires that only one target is being compiled. If more than one
target is available for the current package the filters of --lib, --bin, etc,
must be used to select which target is compiled. To pass flags to all compiler
processes spawned by Cargo, use the $RUSTFLAGS environment variable or the
`build.rustflags` configuration option.
";

pub fn execute(options: Options, config: &Config) -> CliResult<Option<()>> {
    debug!("executing; cmd=cargo-rustc; args={:?}",
           env::args().collect::<Vec<_>>());
    try!(config.configure_shell(options.flag_verbose,
                                options.flag_quiet,
                                &options.flag_color));

    let root = try!(find_root_manifest_for_wd(options.flag_manifest_path,
                                              config.cwd()));
    let mode = match options.flag_profile.as_ref().map(|t| &t[..]) {
        Some("dev") | None => CompileMode::Build,
        Some("test") => CompileMode::Test,
        Some("bench") => CompileMode::Bench,
        Some(mode) => {
            let err = human(format!("unknown profile: `{}`, use dev,
                                     test, or bench", mode));
            return Err(CliError::new(err, 101))
        }
    };

    let opts = CompileOptions {
        config: config,
        jobs: options.flag_jobs,
        target: options.flag_target.as_ref().map(|t| &t[..]),
        features: &options.flag_features,
        no_default_features: options.flag_no_default_features,
        spec: &options.flag_package.map_or(Vec::new(), |s| vec![s]),
        exec_engine: None,
        mode: mode,
        release: options.flag_release,
        filter: ops::CompileFilter::new(options.flag_lib,
                                        &options.flag_bin,
                                        &options.flag_test,
                                        &options.flag_example,
                                        &options.flag_bench),
        target_rustdoc_args: None,
        target_rustc_args: options.arg_opts.as_ref().map(|a| &a[..]),
    };

    let ws = try!(Workspace::new(&root, config));
    try!(ops::compile(&ws, &opts));
    Ok(None)
}

<|endoftext|>


<commit_before>use std::str::FromStr;

#[derive(Debug, PartialEq, PartialOrd, Eq, Ord, Clone, Copy)]
pub enum Suit {
    Club,
    Diamond,
    Heart,
    Spade,
}

impl From<Suit> for &'static str {
    fn from(suit: Suit) -> &'static str {
        match suit {
            Suit::Heart => "Heart",
            Suit::Diamond => "Diamond",
            Suit::Spade => "Spade",
            Suit::Club => "Club"
        }
    }
}

impl From<Suit> for String {
    fn from(suit: Suit) -> String {
        let suit_str: &str = suit.into();
        suit_str.to_owned()
    }
}

impl FromStr for Suit {
    type Err = String;

    fn from_str(string: &str) -> Result<Suit, String> {
        match string {
            "Heart" => Ok(Suit::Heart),
            "Diamond" => Ok(Suit::Diamond),
            "Spade" => Ok(Suit::Spade),
            "Club" => Ok(Suit::Club),
            other => Err(format!("Not a valid suit: {}", other))
        }
    }
}
<commit_msg>reverse suit ordering<commit_after>use std::str::FromStr;

#[derive(Debug, PartialEq, PartialOrd, Eq, Ord, Clone, Copy)]
pub enum Suit {
    Spade,
    Heart,
    Diamond,
    Club,
}

impl From<Suit> for &'static str {
    fn from(suit: Suit) -> &'static str {
        match suit {
            Suit::Heart => "Heart",
            Suit::Diamond => "Diamond",
            Suit::Spade => "Spade",
            Suit::Club => "Club"
        }
    }
}

impl From<Suit> for String {
    fn from(suit: Suit) -> String {
        let suit_str: &str = suit.into();
        suit_str.to_owned()
    }
}

impl FromStr for Suit {
    type Err = String;

    fn from_str(string: &str) -> Result<Suit, String> {
        match string {
            "Heart" => Ok(Suit::Heart),
            "Diamond" => Ok(Suit::Diamond),
            "Spade" => Ok(Suit::Spade),
            "Club" => Ok(Suit::Club),
            other => Err(format!("Not a valid suit: {}", other))
        }
    }
}
<|endoftext|>


<commit_before>//! Traits, helpers, and type definitions for Card functionality.
//!
//! The `libterminal_cribbage::cards` module contains a number of common things you will need when
//! using cards during the game.
//!
//! ## Card, Rank, and Suit
//!
//! With all card games, using the standard playing cards, each [`Card`] references a [`Rank`] and a
//! [`Suit`]. `libterminal_cribbage::cards` provides the struct [`Card`], and two enums, [`Rank`]
//! and [`Suit`], in order to ease the use of organization and comparrisons.
//!
//! For example, in Cribbage, when scoring, each [`Card`] must be evaluated based on it's [`Rank`]
//! and [`Suit`]:
//!
//! ```
//! use libterminal_cribbage::cards::{Card, Rank, Suit};
//!
//! let playing_card = Card::new(Rank::Ace, Suit::Clubs);
//! let other_playing_card = Card::new(Rank::Eight, Suit::Clubs);
//!
//! assert_eq!(playing_card.suit, other_playing_card.suit);
//!
//! let score = match playing_card.rank {
//!     Rank::Ace => 1,
//!     Rank::Two => 2,
//!     Rank::Three => 3,
//!     Rank::Four => 4,
//!     Rank::Five => 5,
//!     Rank::Six => 6,
//!     Rank::Seven => 7,
//!     Rank::Eight => 8,
//!     Rank::Nine => 9,
//!     Rank::Ten => 10,
//!     Rank::Jack => 10,
//!     Rank::Queen => 10,
//!     Rank::King => 10,
//! };
//!
//! assert_eq!(score, 1);
//! ```
//!
//! ## Deck and Hand
//!
//! In Cribbage there are two different types of [`Card`] piles. These are used through out the
//! game, and to help with this `libterminal_cribbage::cards` comes with two handy structs, [`Deck`]
//! and `Hand`, which wrap these piles. The wrappers provide a way to reduce the number of calls
//! and collections for compiling and manipulating [`Card`] piles.
//!
//! For example, [`Deck`] provides a way to create a new deck of [`Card`]s, and shuffle them:
//!
//! ```
//! use libterminal_cribbage::cards::{Deck, Hand};
//!
//! let mut deck = Deck::new();
//! let mut hand = Hand::new();
//!
//! println!("Unshuffled deck of cards: {}", deck);
//!
//! deck.shuffle();
//!
//! println!("Shuffled deck of cards: {}", deck);
//! ```
//!
//! `Hand` provides an easy way to keep the cards in order, and discard:
//! `Hand` example:
//!
//! ```
//! ```
//!
//! ## Dealing and Discarding
//!
//! Since Cribbage involves a lot of dealing and discarding, you may see this functions appear all
//! over the crate. For example, after dealing out a hand, a player must discard two [`Card`]s:
//!
//! ```
//! ```
//!
//! [`Card`]: struct.Card.html
//! [`Deck`]: struct.Deck.html
//! [`Rank`]: enum.Rank.html
//! [`Suit`]: enum.Suit.html

pub use self::deck::Deck;
pub use self::hand::Hand;
pub use self::card::{Card, Rank, Suit};

mod card;
mod deck;
mod hand;<commit_msg>Finish docs for cards mod.<commit_after>//! Traits, helpers, and type definitions for Card functionality.
//!
//! The `libterminal_cribbage::cards` module contains a number of common things you will need when
//! using cards during the game.
//!
//! ## Card, Rank, and Suit
//!
//! With all card games, using the standard playing cards, each [`Card`] references a [`Rank`] and a
//! [`Suit`]. `libterminal_cribbage::cards` provides the struct [`Card`], and two enums, [`Rank`]
//! and [`Suit`], in order to ease the use of organization and comparrisons.
//!
//! For example, in Cribbage, when scoring, each [`Card`] must be evaluated based on it's [`Rank`]
//! and [`Suit`]:
//!
//! ```
//! use libterminal_cribbage::cards::{Card, Rank, Suit};
//!
//! let playing_card = Card::new(Rank::Ace, Suit::Clubs);
//! let other_playing_card = Card::new(Rank::Eight, Suit::Clubs);
//!
//! assert_eq!(playing_card.suit, other_playing_card.suit);
//!
//! let score = match playing_card.rank {
//!     Rank::Ace => 1,
//!     Rank::Two => 2,
//!     Rank::Three => 3,
//!     Rank::Four => 4,
//!     Rank::Five => 5,
//!     Rank::Six => 6,
//!     Rank::Seven => 7,
//!     Rank::Eight => 8,
//!     Rank::Nine => 9,
//!     Rank::Ten => 10,
//!     Rank::Jack => 10,
//!     Rank::Queen => 10,
//!     Rank::King => 10,
//! };
//!
//! assert_eq!(score, 1);
//! ```
//!
//! ## Deck and Hand
//!
//! In Cribbage there are two different types of [`Card`] piles. These are used through out the
//! game, and to help with this `libterminal_cribbage::cards` comes with two handy structs, [`Deck`]
//! and `Hand`, which wrap these piles. The wrappers provide a way to reduce the number of calls
//! and collections for compiling and manipulating [`Card`] piles.
//!
//! For example, [`Deck`] provides a way to create a new deck of [`Card`]s, and shuffle them:
//!
//! ```
//! use libterminal_cribbage::cards::{Deck, Hand};
//!
//! let mut deck = Deck::new();
//!
//! println!("Unshuffled deck of cards: {}", deck);
//!
//! deck.shuffle();
//!
//! println!("Shuffled deck of cards: {}", deck);
//! ```
//!
//! `Hand` provides an easy way to keep the cards in order, and discard:
//! `Hand` example:
//!
//! ```
//! use libterminal_cribbage::cards::{Deck, Card, Hand, Rank, Suit};
//!
//! let mut hand = Hand::new();
//!
//! hand.add_card(Card::new(Rank::Ace, Suit::Clubs));
//! hand.add_card(Card::new(Rank::Four, Suit::Spades));
//! hand.add_card(Card::new(Rank::Three, Suit::Hearts));
//! hand.add_card(Card::new(Rank::Two, Suit::Spades));
//! hand.add_card(Card::new(Rank::Queen, Suit::Diamonds));
//! hand.add_card(Card::new(Rank::Two, Suit::Hearts));
//! hand.add_card(Card::new(Rank::Ten, Suit::Clubs));
//!
//! assert_eq!(
//!     hand.0,
//!     vec![Card::new(Rank::Ace, Suit::Clubs),
//!          Card::new(Rank::Two, Suit::Hearts),
//!          Card::new(Rank::Two, Suit::Spades),
//!          Card::new(Rank::Three, Suit::Hearts),
//!          Card::new(Rank::Four, Suit::Spades),
//!          Card::new(Rank::Ten, Suit::Clubs),
//!          Card::new(Rank::Queen, Suit::Diamonds)]);
//!
//! assert_eq!(hand.discard(4), Ok(Card::new(Rank::Four, Suit::Spades)));
//! assert_eq!(hand.discard(4), Ok(Card::new(Rank::Ten, Suit::Clubs)));
//! ```
//!
//! ## Dealing and Discarding
//!
//! Since Cribbage involves a lot of dealing and discarding, you may see this functions appear all
//! over the crate. For example, after dealing out a hand, a player must discard two [`Card`]s:
//!
//! ```
//! use libterminal_cribbage::cards::{Deck, Hand};
//!
//! let mut deck = Deck::new();
//! let mut hand = Hand::new();
//!
//! deck.shuffle();

//! for _ in 0..6 {
//!     hand.add_card(deck.deal().unwrap());
//! }
//!
//! println!("Hand of cards: {}", hand);
//! println!("Discarded Card: {}", hand.discard(0).unwrap());
//!
//! ```
//!
//! [`Card`]: struct.Card.html
//! [`Deck`]: struct.Deck.html
//! [`Rank`]: enum.Rank.html
//! [`Suit`]: enum.Suit.html

pub use self::deck::Deck;
pub use self::hand::Hand;
pub use self::card::{Card, Rank, Suit};

mod card;
mod deck;
mod hand;<|endoftext|>


<commit_before>/// Character level parsers

use internal::{IResult,Needed};
use util::ErrorKind;
use std::ops::{Range,RangeFrom,RangeTo};
use traits::{AsChar,Compare,CompareResult,IterIndices,Slice};

/// matches one of the provided characters
#[macro_export]
macro_rules! one_of (
  ($i:expr, $inp: expr) => (
    {
      if $i.is_empty() {
        $crate::IResult::Incomplete::<_, _>($crate::Needed::Size(1))
      } else {
        #[inline(always)]
        fn as_bytes<T: $crate::AsBytes>(b: &T) -> &[u8] {
          b.as_bytes()
        }

        let expected = $inp;
        let bytes = as_bytes(&expected);
        one_of_bytes!($i, bytes)
      }
    }
  );
);

#[doc(hidden)]
#[macro_export]
macro_rules! one_of_bytes (
  ($i:expr, $bytes: expr) => (
    {
      if $i.is_empty() {
        $crate::IResult::Incomplete::<_, _>($crate::Needed::Size(1))
      } else {
        let mut found = false;

        for &i in $bytes {
          if i == $i[0] {
            found = true;
            break;
          }
        }

        if found {
          $crate::IResult::Done(&$i[1..], $i[0] as char)
        } else {
          //$crate::IResult::Error($crate::Err::Position($crate::ErrorKind::OneOf, $i))
          $crate::IResult::Error(error_position!($crate::ErrorKind::OneOf, $i))
        }
      }
    }
  );
);

/// matches anything but the provided characters
#[macro_export]
macro_rules! none_of (
  ($i:expr, $inp: expr) => (
    {
      if $i.is_empty() {
        $crate::IResult::Incomplete::<_, _>($crate::Needed::Size(1))
      } else {
        #[inline(always)]
        fn as_bytes<T: $crate::AsBytes>(b: &T) -> &[u8] {
          b.as_bytes()
        }

        let expected = $inp;
        let bytes = as_bytes(&expected);
        none_of_bytes!($i, bytes)
      }
    }
  );
);

#[doc(hidden)]
#[macro_export]
macro_rules! none_of_bytes (
  ($i:expr, $bytes: expr) => (
    {
      if $i.is_empty() {
        $crate::IResult::Incomplete::<_, _>($crate::Needed::Size(1))
      } else {
        let mut found = false;

        for &i in $bytes {
          if i == $i[0] {
            found = true;
            break;
          }
        }

        if !found {
          $crate::IResult::Done(&$i[1..], $i[0] as char)
        } else {
          $crate::IResult::Error(error_position!($crate::ErrorKind::NoneOf, $i))
        }
      }
    }
  );
);

/// matches one character: `char!(char) => &[u8] -> IResult<&[u8], char>
#[macro_export]
macro_rules! char (
  ($i:expr, $c: expr) => (
    {
      if $i.is_empty() {
        let res: $crate::IResult<&[u8], char> = $crate::IResult::Incomplete($crate::Needed::Size(1));
        res
      } else {
        if $i[0] == $c as u8 {
          $crate::IResult::Done(&$i[1..], $i[0] as char)
        } else {
          $crate::IResult::Error(error_position!($crate::ErrorKind::Char, $i))
        }
      }
    }
  );
);

named!(pub newline<char>, char!('\n'));

named!(pub tab<char>, char!('\t'));

pub fn anychar(input:&[u8]) -> IResult<&[u8], char> {
  if input.is_empty() {
    IResult::Incomplete(Needed::Size(1))
  } else {
    IResult::Done(&input[1..], input[0] as char)
  }
}

#[cfg(test)]
mod tests {
  use super::*;
  use internal::IResult::*;
  use internal::Needed;
  use util::ErrorKind;

  #[test]
  fn one_of() {
    named!(f<char>, one_of!("ab"));

    let a = &b"abcd"[..];
    assert_eq!(f(a), Done(&b"bcd"[..], 'a'));

    let b = &b"cde"[..];
    assert_eq!(f(b), Error(error_position!(ErrorKind::OneOf, b)));
  }

  #[test]
  fn none_of() {
    named!(f<char>, none_of!("ab"));

    let a = &b"abcd"[..];
    assert_eq!(f(a), Error(error_position!(ErrorKind::NoneOf, a)));

    let b = &b"cde"[..];
    assert_eq!(f(b), Done(&b"de"[..], 'c'));
  }

  #[test]
  fn char() {
    named!(f<char>, char!('c'));

    let a = &b"abcd"[..];
    assert_eq!(f(a), Error(error_position!(ErrorKind::Char, a)));

    let b = &b"cde"[..];
    assert_eq!(f(b), Done(&b"de"[..], 'c'));
  }

}
<commit_msg>Remove warnings<commit_after>/// Character level parsers

use internal::{IResult,Needed};

/// matches one of the provided characters
#[macro_export]
macro_rules! one_of (
  ($i:expr, $inp: expr) => (
    {
      if $i.is_empty() {
        $crate::IResult::Incomplete::<_, _>($crate::Needed::Size(1))
      } else {
        #[inline(always)]
        fn as_bytes<T: $crate::AsBytes>(b: &T) -> &[u8] {
          b.as_bytes()
        }

        let expected = $inp;
        let bytes = as_bytes(&expected);
        one_of_bytes!($i, bytes)
      }
    }
  );
);

#[doc(hidden)]
#[macro_export]
macro_rules! one_of_bytes (
  ($i:expr, $bytes: expr) => (
    {
      if $i.is_empty() {
        $crate::IResult::Incomplete::<_, _>($crate::Needed::Size(1))
      } else {
        let mut found = false;

        for &i in $bytes {
          if i == $i[0] {
            found = true;
            break;
          }
        }

        if found {
          $crate::IResult::Done(&$i[1..], $i[0] as char)
        } else {
          $crate::IResult::Error(error_position!($crate::ErrorKind::OneOf, $i))
        }
      }
    }
  );
);

/// matches anything but the provided characters
#[macro_export]
macro_rules! none_of (
  ($i:expr, $inp: expr) => (
    {
      if $i.is_empty() {
        $crate::IResult::Incomplete::<_, _>($crate::Needed::Size(1))
      } else {
        #[inline(always)]
        fn as_bytes<T: $crate::AsBytes>(b: &T) -> &[u8] {
          b.as_bytes()
        }

        let expected = $inp;
        let bytes = as_bytes(&expected);
        none_of_bytes!($i, bytes)
      }
    }
  );
);

#[doc(hidden)]
#[macro_export]
macro_rules! none_of_bytes (
  ($i:expr, $bytes: expr) => (
    {
      if $i.is_empty() {
        $crate::IResult::Incomplete::<_, _>($crate::Needed::Size(1))
      } else {
        let mut found = false;

        for &i in $bytes {
          if i == $i[0] {
            found = true;
            break;
          }
        }

        if !found {
          $crate::IResult::Done(&$i[1..], $i[0] as char)
        } else {
          $crate::IResult::Error(error_position!($crate::ErrorKind::NoneOf, $i))
        }
      }
    }
  );
);

/// matches one character: `char!(char) => &[u8] -> IResult<&[u8], char>
#[macro_export]
macro_rules! char (
  ($i:expr, $c: expr) => (
    {
      if $i.is_empty() {
        let res: $crate::IResult<&[u8], char> = $crate::IResult::Incomplete($crate::Needed::Size(1));
        res
      } else {
        if $i[0] == $c as u8 {
          $crate::IResult::Done(&$i[1..], $i[0] as char)
        } else {
          $crate::IResult::Error(error_position!($crate::ErrorKind::Char, $i))
        }
      }
    }
  );
);

named!(pub newline<char>, char!('\n'));

named!(pub tab<char>, char!('\t'));

pub fn anychar(input:&[u8]) -> IResult<&[u8], char> {
  if input.is_empty() {
    IResult::Incomplete(Needed::Size(1))
  } else {
    IResult::Done(&input[1..], input[0] as char)
  }
}

#[cfg(test)]
mod tests {
  use super::*;
  use internal::IResult::*;
  use internal::Needed;
  use util::ErrorKind;

  #[test]
  fn one_of() {
    named!(f<char>, one_of!("ab"));

    let a = &b"abcd"[..];
    assert_eq!(f(a), Done(&b"bcd"[..], 'a'));

    let b = &b"cde"[..];
    assert_eq!(f(b), Error(error_position!(ErrorKind::OneOf, b)));
  }

  #[test]
  fn none_of() {
    named!(f<char>, none_of!("ab"));

    let a = &b"abcd"[..];
    assert_eq!(f(a), Error(error_position!(ErrorKind::NoneOf, a)));

    let b = &b"cde"[..];
    assert_eq!(f(b), Done(&b"de"[..], 'c'));
  }

  #[test]
  fn char() {
    named!(f<char>, char!('c'));

    let a = &b"abcd"[..];
    assert_eq!(f(a), Error(error_position!(ErrorKind::Char, a)));

    let b = &b"cde"[..];
    assert_eq!(f(b), Done(&b"de"[..], 'c'));
  }

}
<|endoftext|>