<commit_before>/// Helpers for code generation that don't need macro expansion.

use aster;
use ir::layout::Layout;
use syntax::ast;
use syntax::ptr::P;

pub mod attributes {
    use aster;
    use syntax::ast;

    pub fn repr(which: &str) -> ast::Attribute {
        aster::AstBuilder::new().attr().list("repr").words(&[which]).build()
    }

    pub fn repr_list(which_ones: &[&str]) -> ast::Attribute {
        aster::AstBuilder::new().attr().list("repr").words(which_ones).build()
    }

    pub fn derives(which_ones: &[&str]) -> ast::Attribute {
        aster::AstBuilder::new().attr().list("derive").words(which_ones).build()
    }

    pub fn inline() -> ast::Attribute {
        aster::AstBuilder::new().attr().word("inline")
    }

    pub fn doc(comment: &str) -> ast::Attribute {
        aster::AstBuilder::new().attr().doc(comment)
    }

    pub fn link_name(name: &str) -> ast::Attribute {
        aster::AstBuilder::new().attr().name_value("link_name").str(name)
    }
}

/// Generates a proper type for a field or type with a given `Layout`, that is,
/// a type with the correct size and alignment restrictions.
pub struct BlobTyBuilder {
    layout: Layout,
}

impl BlobTyBuilder {
    pub fn new(layout: Layout) -> Self {
        BlobTyBuilder {
            layout: layout,
        }
    }

    pub fn build(self) -> P<ast::Ty> {
        use std::cmp;

        let ty_name = match self.layout.align {
            8 => "u64",
            4 => "u32",
            2 => "u16",
            1 | _ => "u8",
        };
        let data_len = if ty_name == "u8" {
            self.layout.size
        } else {
            self.layout.size / cmp::max(self.layout.align, 1)
        };

        let inner_ty = aster::AstBuilder::new().ty().path().id(ty_name).build();
        if data_len == 1 {
            inner_ty
        } else {
            aster::ty::TyBuilder::new().array(data_len).build(inner_ty)
        }
    }
}
<commit_msg>Convert mod comment to a proper comment to avoid hitting https://github.com/rust-lang-nursery/rustfmt/issues/1184<commit_after>//! Helpers for code generation that don't need macro expansion.

use aster;
use ir::layout::Layout;
use syntax::ast;
use syntax::ptr::P;

pub mod attributes {
    use aster;
    use syntax::ast;

    pub fn repr(which: &str) -> ast::Attribute {
        aster::AstBuilder::new().attr().list("repr").words(&[which]).build()
    }

    pub fn repr_list(which_ones: &[&str]) -> ast::Attribute {
        aster::AstBuilder::new().attr().list("repr").words(which_ones).build()
    }

    pub fn derives(which_ones: &[&str]) -> ast::Attribute {
        aster::AstBuilder::new().attr().list("derive").words(which_ones).build()
    }

    pub fn inline() -> ast::Attribute {
        aster::AstBuilder::new().attr().word("inline")
    }

    pub fn doc(comment: &str) -> ast::Attribute {
        aster::AstBuilder::new().attr().doc(comment)
    }

    pub fn link_name(name: &str) -> ast::Attribute {
        aster::AstBuilder::new().attr().name_value("link_name").str(name)
    }
}

/// Generates a proper type for a field or type with a given `Layout`, that is,
/// a type with the correct size and alignment restrictions.
pub struct BlobTyBuilder {
    layout: Layout,
}

impl BlobTyBuilder {
    pub fn new(layout: Layout) -> Self {
        BlobTyBuilder {
            layout: layout,
        }
    }

    pub fn build(self) -> P<ast::Ty> {
        use std::cmp;

        let ty_name = match self.layout.align {
            8 => "u64",
            4 => "u32",
            2 => "u16",
            1 | _ => "u8",
        };
        let data_len = if ty_name == "u8" {
            self.layout.size
        } else {
            self.layout.size / cmp::max(self.layout.align, 1)
        };

        let inner_ty = aster::AstBuilder::new().ty().path().id(ty_name).build();
        if data_len == 1 {
            inner_ty
        } else {
            aster::ty::TyBuilder::new().array(data_len).build(inner_ty)
        }
    }
}
<|endoftext|>


<commit_before>//
// Copyright 2020 The Project Oak Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

use super::*;
use maplit::hashmap;
use oak_abi::{label::Label, proto::oak::application::ApplicationConfiguration};
use std::{fs, option::Option, thread::JoinHandle};

static LOCAL_CA: &str = "../examples/certs/local/ca.pem";
static GCP_CA: &str = "../examples/certs/gcp/ca.pem";

struct HttpServerTester {
    runtime: RuntimeProxy,
    server_node_thread_handle: Option<JoinHandle<()>>,
    oak_node_simulator_thread_handle: Option<JoinHandle<()>>,
    notify_sender: Option<tokio::sync::oneshot::Sender<()>>,
}

impl HttpServerTester {
    /// Create a new runtime and test server.
    /// port: The port on which the server is started
    /// number_of_requests: the number of requests the server expects to receive. This parameter is
    /// passed to `oak_node_simulator` to set up the Oak node that servers the requests.
    fn new(port: u32, number_of_requests: i32) -> HttpServerTester {
        let runtime = create_runtime();
        let server_node = create_server_node(port);
        let (init_receiver, invocation_receiver) = create_communication_channel(&runtime);

        // Start the server node
        let (notify_sender, notify_receiver) = tokio::sync::oneshot::channel::<()>();
        let runtime_proxy = runtime.clone();
        // TODO(#1186): Use tokio instead of spawning a thread.
        let server_node_thread = std::thread::spawn(move || {
            server_node.run(runtime_proxy, init_receiver, notify_receiver)
        });

        // Simulate an Oak node that responds with 200 (OK) to every request it receives
        // TODO(#1186): Use tokio instead of spawning a thread.
        let runtime_proxy = runtime.clone();
        let oak_node_simulator_thread = Some(std::thread::spawn(move || {
            oak_node_simulator(number_of_requests, &runtime_proxy, invocation_receiver);
        }));

        HttpServerTester {
            runtime,
            server_node_thread_handle: Some(server_node_thread),
            oak_node_simulator_thread_handle: oak_node_simulator_thread,
            notify_sender: Some(notify_sender),
        }
    }

    fn cleanup(&mut self) {
        if let Some(sender) = self.notify_sender.take() {
            sender.send(()).unwrap_or_else(|()| {
                debug!("Test node already dropped `notify_receiver`.");
            })
        }
        if let Some(handle) = self.server_node_thread_handle.take() {
            let _ = handle.join();
        };
        if let Some(handle) = self.oak_node_simulator_thread_handle.take() {
            let _ = handle.join();
        };

        // stop the runtime and any servers it is running
        self.runtime.runtime.stop();
    }
}

fn init_logger() {
    // Ignore the result. We don't want to panic if the logger cannot be initialized, or is being
    // initialized more than once. Also, if the logger is not initialized, we cannot log an
    // error!
    let _res = env_logger::builder().is_test(true).try_init();
}

#[tokio::test]
async fn test_https_server_can_serve_https_requests() {
    init_logger();

    // Start a runtime with an HTTP server node, and a thread simulating an Oak node to respond to
    // HTTP requests.
    let mut http_server_tester = HttpServerTester::new(2525, 1);
    let client_with_valid_tls = create_client(LOCAL_CA);

    // Send an HTTPS request, and check that response has StatusCode::OK
    let resp = send_request(client_with_valid_tls, "https://localhost:2525").await;
    assert!(resp.is_ok());
    assert_eq!(
        resp.unwrap().status(),
        http::status::StatusCode::OK.as_u16()
    );

    // Stop the runtime and the servers
    http_server_tester.cleanup();
}

#[tokio::test]
async fn test_https_server_cannot_serve_http_requests() {
    init_logger();

    // Start a runtime with an HTTP server node. The HTTP server in this case rejects the requests,
    // and would not send anything to the Oak node. Creating a thread to simulate the Oak node will
    // result in the thread being blocked for ever. So, we set up the test without an
    // oak-node-simulator thread.
    let mut http_server_tester = HttpServerTester::new(2526, 0);
    let client_with_valid_tls = create_client(LOCAL_CA);

    // Send an HTTP request, and check that the server responds with an error
    let resp = send_request(client_with_valid_tls, "http://localhost:2526").await;
    assert!(resp.is_err());

    // Stop the runtime and the servers
    http_server_tester.cleanup();
}

#[tokio::test]
async fn test_https_server_does_not_terminate_after_a_bad_request() {
    init_logger();

    // Start a runtime with an HTTP server node, and a thread simulating an Oak node to respond to
    // HTTP requests.
    let mut http_server_tester = HttpServerTester::new(2527, 2);
    let client_with_valid_tls = create_client(LOCAL_CA);
    let client_with_invalid_tls = create_client(GCP_CA);

    // Send a valid request, making sure that the server is started
    let resp = send_request(client_with_valid_tls.clone(), "https://localhost:2527").await;
    assert!(resp.is_ok());

    // Send an HTTPS request with invalid certificate, and check that the server responds with error
    let resp = send_request(client_with_invalid_tls, "https://localhost:2527").await;
    assert!(resp.is_err());

    // Send another valid request, and check that the server is alive and responsive
    // let client_with_valid_tls = create_client(LOCAL_CA);
    let resp = send_request(client_with_valid_tls, "https://localhost:2527").await;
    assert!(resp.is_ok());

    // Stop the runtime and the servers
    http_server_tester.cleanup();
}

fn create_runtime() -> RuntimeProxy {
    let configuration = ApplicationConfiguration {
        wasm_modules: hashmap! {},
        initial_node_configuration: None,
    };
    let signature_table = crate::SignatureTable::default();
    info!("Create runtime for test");

    crate::RuntimeProxy::create_runtime(
        &configuration,
        &crate::SecureServerConfiguration::default(),
        &signature_table,
    )
}

fn create_server_node(port: u32) -> Box<HttpServerNode> {
    let tls_config = crate::tls::TlsConfig::new(
        "../examples/certs/local/local.pem",
        "../examples/certs/local/local.key",
    )
    .expect("Could not create TLS config from local certs.");

    // Create http server node
    Box::new(
        HttpServerNode::new(
            "test-node",
            HttpServerConfiguration {
                address: format!("[::]:{}", port),
            },
            tls_config,
        )
        .expect("Could not create server node"),
    )
}

fn create_communication_channel(runtime: &RuntimeProxy) -> (oak_abi::Handle, oak_abi::Handle) {
    // create channel: one end to server_node::run; the other to the Oak node.
    let (init_sender, init_receiver) = runtime
        .channel_create(&Label::public_untrusted())
        .expect("Could not create channel");

    // At the start the HTTP server pseudo-Node expects to receive an invocation channel, with
    // exactly one handle in it.
    //
    // Create a channel for receiving invocations to pass to the HTTP server pseudo-Node.
    let (invocation_sender, invocation_receiver) = runtime
        .channel_create(&Label::public_untrusted())
        .expect("Could not create channel");
    let invocation_sender = HttpInvocationSender {
        sender: Some(Sender::<HttpInvocation>::new(WriteHandle {
            handle: invocation_sender,
        })),
    };
    let init_sender = Sender::<HttpInvocationSender>::new(WriteHandle {
        handle: init_sender,
    });

    if let Err(error) = init_sender.send(invocation_sender, runtime) {
        panic!("Could not write to the `init_sender` channel: {}", error);
    }
    if let Err(error) = init_sender.close(runtime) {
        panic!("Could not close the `init_sender` channel: {}", error);
    }

    (init_receiver, invocation_receiver)
}

// Simulate an Oak node that responds to the specified number of requests. Since the Oak node blocks
// until a new request is received, we need to know the number of requests that the test sends
// beforehand. Alternatively, the node simulator could listen for incoming requests in an infinite
// loop and have a termination mechanism that could be signalled from outside. However, specifying
// the exact number of expected requests is more appropriate for testing purposes.
fn oak_node_simulator(
    number_of_requests: i32,
    runtime: &RuntimeProxy,
    invocation_receiver: oak_abi::Handle,
) {
    // Get invocation message that contains the response_writer handle.
    let invocation_receiver = Receiver::<HttpInvocation>::new(ReadHandle {
        handle: invocation_receiver,
    });

    for _counter in 0..number_of_requests {
        let invocation = invocation_receiver.receive(runtime).unwrap();
        let resp = HttpResponse {
            body: vec![],
            status: http::status::StatusCode::OK.as_u16() as i32,
            headers: hashmap! {},
        };
        invocation
            .sender
            .expect("Empty sender on invocation.")
            .send(resp, runtime)
            .unwrap();
    }
}

// Build a TLS client, using the given CA store
fn create_client(
    ca_path: &str,
) -> hyper::client::Client<hyper_rustls::HttpsConnector<hyper::client::HttpConnector>> {
    let ca_file =
        fs::File::open(ca_path).unwrap_or_else(|e| panic!("failed to open {}: {}", ca_path, e));
    let mut ca = io::BufReader::new(ca_file);

    // Build an HTTP connector which supports HTTPS too.
    let mut http = hyper::client::HttpConnector::new();
    http.enforce_http(false);
    // Build a TLS client, using the custom CA store for lookups.
    let mut tls = rustls::ClientConfig::new();
    tls.root_store
        .add_pem_file(&mut ca)
        .expect("failed to load custom CA store");
    // Join the above part into an HTTPS connector.
    let https = hyper_rustls::HttpsConnector::from((http, tls));

    hyper::client::Client::builder().build(https)
}

async fn send_request(
    client: hyper::client::Client<hyper_rustls::HttpsConnector<hyper::client::HttpConnector>>,
    uri: &str,
) -> Result<http::response::Response<hyper::Body>, hyper::Error> {
    // Send a request, and wait for the response
    let label = oak_abi::label::Label::public_untrusted();
    let mut label_bytes = vec![];
    if let Err(err) = label.encode(&mut label_bytes) {
        panic!("Failed to encode label: {}", err);
    }

    // The client thread may start sending the requests before the server is up. In this case, the
    // request will be rejected with a "ConnectError". To make the tests are stable, we need to
    // retry sending the requests until the server is up. To distinguish between these cases and
    // actual errors (e.g., errors due to invalid TLS certificates), we need to check the cause of
    // the error.
    loop {
        let request = hyper::Request::builder()
            .method(http::Method::GET)
            .uri(uri)
            .header(oak_abi::OAK_LABEL_HTTP_PROTOBUF_KEY, label_bytes.clone())
            .body(hyper::Body::empty())
            .unwrap();

        match client.request(request).await {
            Ok(reps) => return Ok(reps),
            Err(error) => {
                // We cannot access the cause of the error, so we need to check the string instead.
                let error_str = format!("{:?}", error);
                // If the cause is `ConnectError` (https://github.com/hyperium/hyper/blob/66fc127c8d4f81aed9300c9d0f13246b8206067a/src/client/connect/http.rs#L392)
                // it means that a connection to the server cannot be made. Retry sending the
                // request in this case.
                if error_str.contains("ConnectError") {
                    continue;
                } else {
                    return Err(error);
                }
            }
        }
    }
}
<commit_msg>Use the runtime to start test HTTP sever node (#1494)<commit_after>//
// Copyright 2020 The Project Oak Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

use super::*;
use maplit::hashmap;
use oak_abi::{
    label::Label,
    proto::oak::application::{
        node_configuration::ConfigType, ApplicationConfiguration, HttpServerConfiguration,
        NodeConfiguration,
    },
};
use std::{fs, option::Option, thread::JoinHandle};

static LOCAL_CA: &str = "../examples/certs/local/ca.pem";
static GCP_CA: &str = "../examples/certs/gcp/ca.pem";

struct HttpServerTester {
    runtime: RuntimeProxy,
    oak_node_simulator_thread_handle: Option<JoinHandle<()>>,
}

impl HttpServerTester {
    /// Test setup. Creates an Oak runtime, a test HTTP server node on the given port, and an Oak
    /// node simulator thread.
    fn new(port: u32) -> HttpServerTester {
        let runtime = create_runtime();
        let invocation_receiver = create_server_node(&runtime, port);

        // Simulate an Oak node that responds with 200 (OK) to every request it receives. Instead of
        // using `Runtime::node_create` which would require WebAssembly code, create and start the
        // Oak node directly in a separate thread.
        //
        // TODO(#1186): Use tokio instead of spawning a thread.
        let runtime_proxy = runtime.clone();
        let oak_node_simulator_thread = Some(std::thread::spawn(move || {
            oak_node_simulator(&runtime_proxy, invocation_receiver);
        }));

        HttpServerTester {
            runtime,
            oak_node_simulator_thread_handle: oak_node_simulator_thread,
        }
    }

    fn cleanup(&mut self) {
        // stop the runtime and any servers it is running
        self.runtime.runtime.stop();

        if let Some(handle) = self.oak_node_simulator_thread_handle.take() {
            let _ = handle.join();
        };
    }
}

fn init_logger() {
    // Ignore the result. We don't want to panic if the logger cannot be initialized, or is being
    // initialized more than once. Also, if the logger is not initialized, we cannot log an
    // error!
    let _res = env_logger::builder().is_test(true).try_init();
}

#[tokio::test]
async fn test_https_server_can_serve_https_requests() {
    init_logger();

    // Start a runtime with an HTTP server node, and a thread simulating an Oak node to respond to
    // HTTP requests.
    let mut http_server_tester = HttpServerTester::new(2525);
    let client_with_valid_tls = create_client(LOCAL_CA);

    // Send an HTTPS request, and check that response has StatusCode::OK
    let resp = send_request(client_with_valid_tls, "https://localhost:2525").await;
    assert!(resp.is_ok());
    assert_eq!(
        resp.unwrap().status(),
        http::status::StatusCode::OK.as_u16()
    );

    // Stop the runtime and the servers
    http_server_tester.cleanup();
}

#[tokio::test]
async fn test_https_server_cannot_serve_http_requests() {
    init_logger();

    // Start a runtime with an HTTP server node. The HTTP server in this case rejects the requests,
    // and would not send anything to the Oak node. Creating a thread to simulate the Oak node will
    // result in the thread being blocked for ever. So, we set up the test without an
    // oak-node-simulator thread.
    let mut http_server_tester = HttpServerTester::new(2526);
    let client_with_valid_tls = create_client(LOCAL_CA);

    // Send an HTTP request, and check that the server responds with an error
    let resp = send_request(client_with_valid_tls, "http://localhost:2526").await;
    assert!(resp.is_err());

    // Stop the runtime and the servers
    http_server_tester.cleanup();
}

#[tokio::test]
async fn test_https_server_does_not_terminate_after_a_bad_request() {
    init_logger();

    // Start a runtime with an HTTP server node, and a thread simulating an Oak node to respond to
    // HTTP requests.
    let mut http_server_tester = HttpServerTester::new(2527);
    let client_with_valid_tls = create_client(LOCAL_CA);
    let client_with_invalid_tls = create_client(GCP_CA);

    // Send a valid request, making sure that the server is started
    let resp = send_request(client_with_valid_tls.clone(), "https://localhost:2527").await;
    assert!(resp.is_ok());

    // Send an HTTPS request with invalid certificate, and check that the server responds with error
    let resp = send_request(client_with_invalid_tls, "https://localhost:2527").await;
    assert!(resp.is_err());

    // Send another valid request, and check that the server is alive and responsive
    // let client_with_valid_tls = create_client(LOCAL_CA);
    let resp = send_request(client_with_valid_tls, "https://localhost:2527").await;
    assert!(resp.is_ok());

    // Stop the runtime and the servers
    http_server_tester.cleanup();
}

fn create_runtime() -> RuntimeProxy {
    let configuration = ApplicationConfiguration {
        wasm_modules: hashmap! {},
        initial_node_configuration: None,
    };
    let tls_config = crate::tls::TlsConfig::new(
        "../examples/certs/local/local.pem",
        "../examples/certs/local/local.key",
    )
    .expect("Could not create TLS config from local certs.");
    let secure_server_config = crate::SecureServerConfiguration {
        grpc_config: None,
        http_config: Some(crate::HttpConfiguration { tls_config }),
    };
    let signature_table = crate::SignatureTable::default();
    info!("Create runtime for test");

    crate::RuntimeProxy::create_runtime(&configuration, &secure_server_config, &signature_table)
}

fn create_server_node(runtime: &RuntimeProxy, port: u32) -> oak_abi::Handle {
    let (init_receiver, invocation_receiver) = create_communication_channel(runtime);
    let server_config = NodeConfiguration {
        name: "test_server".to_string(),
        config_type: Some(ConfigType::HttpServerConfig(HttpServerConfiguration {
            address: format!("[::]:{}", port),
        })),
    };

    runtime
        .node_create(&server_config, &Label::public_untrusted(), init_receiver)
        .expect("Could not create HTTP server node!");

    invocation_receiver
}

fn create_communication_channel(runtime: &RuntimeProxy) -> (oak_abi::Handle, oak_abi::Handle) {
    // create channel: one end to server_node::run; the other to the Oak node.
    let (init_sender, init_receiver) = runtime
        .channel_create(&Label::public_untrusted())
        .expect("Could not create channel");

    // At the start the HTTP server pseudo-Node expects to receive an invocation channel, with
    // exactly one handle in it.
    //
    // Create a channel for receiving invocations to pass to the HTTP server pseudo-Node.
    let (invocation_sender, invocation_receiver) = runtime
        .channel_create(&Label::public_untrusted())
        .expect("Could not create channel");
    let invocation_sender = HttpInvocationSender {
        sender: Some(Sender::<HttpInvocation>::new(WriteHandle {
            handle: invocation_sender,
        })),
    };
    let init_sender = Sender::<HttpInvocationSender>::new(WriteHandle {
        handle: init_sender,
    });

    if let Err(error) = init_sender.send(invocation_sender, runtime) {
        panic!("Could not write to the `init_sender` channel: {}", error);
    }
    if let Err(error) = init_sender.close(runtime) {
        panic!("Could not close the `init_sender` channel: {}", error);
    }

    (init_receiver, invocation_receiver)
}

// Simulate an Oak node that responds to incoming requests.
fn oak_node_simulator(runtime: &RuntimeProxy, invocation_receiver: oak_abi::Handle) {
    // Get invocation message that contains the response_writer handle.
    let invocation_receiver = Receiver::<HttpInvocation>::new(ReadHandle {
        handle: invocation_receiver,
    });

    while let Ok(invocation) = invocation_receiver.receive(runtime) {
        let resp = HttpResponse {
            body: vec![],
            status: http::status::StatusCode::OK.as_u16() as i32,
            headers: hashmap! {},
        };
        invocation
            .sender
            .expect("Empty sender on invocation.")
            .send(resp, runtime)
            .unwrap();
    }
}

// Build a TLS client, using the given CA store
fn create_client(
    ca_path: &str,
) -> hyper::client::Client<hyper_rustls::HttpsConnector<hyper::client::HttpConnector>> {
    let ca_file =
        fs::File::open(ca_path).unwrap_or_else(|e| panic!("failed to open {}: {}", ca_path, e));
    let mut ca = io::BufReader::new(ca_file);

    // Build an HTTP connector which supports HTTPS too.
    let mut http = hyper::client::HttpConnector::new();
    http.enforce_http(false);
    // Build a TLS client, using the custom CA store for lookups.
    let mut tls = rustls::ClientConfig::new();
    tls.root_store
        .add_pem_file(&mut ca)
        .expect("failed to load custom CA store");
    // Join the above part into an HTTPS connector.
    let https = hyper_rustls::HttpsConnector::from((http, tls));

    hyper::client::Client::builder().build(https)
}

async fn send_request(
    client: hyper::client::Client<hyper_rustls::HttpsConnector<hyper::client::HttpConnector>>,
    uri: &str,
) -> Result<http::response::Response<hyper::Body>, hyper::Error> {
    // Send a request, and wait for the response
    let label = oak_abi::label::Label::public_untrusted();
    let mut label_bytes = vec![];
    if let Err(err) = label.encode(&mut label_bytes) {
        panic!("Failed to encode label: {}", err);
    }

    // The client thread may start sending the requests before the server is up. In this case, the
    // request will be rejected with a "ConnectError". To make the tests are stable, we need to
    // retry sending the requests until the server is up. To distinguish between these cases and
    // actual errors (e.g., errors due to invalid TLS certificates), we need to check the cause of
    // the error.
    loop {
        let request = hyper::Request::builder()
            .method(http::Method::GET)
            .uri(uri)
            .header(oak_abi::OAK_LABEL_HTTP_PROTOBUF_KEY, label_bytes.clone())
            .body(hyper::Body::empty())
            .unwrap();

        match client.request(request).await {
            Ok(reps) => return Ok(reps),
            Err(error) => {
                // We cannot access the cause of the error, so we need to check the string instead.
                let error_str = format!("{:?}", error);
                // If the cause is `ConnectError` (https://github.com/hyperium/hyper/blob/66fc127c8d4f81aed9300c9d0f13246b8206067a/src/client/connect/http.rs#L392)
                // it means that a connection to the server cannot be made. Retry sending the
                // request in this case.
                if error_str.contains("ConnectError") {
                    continue;
                } else {
                    return Err(error);
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>//! Errors that can be sent from the homeserver.

use std::fmt::{self, Display, Formatter};

use ruma_api::{error::ResponseDeserializationError, EndpointError};
use ruma_identifiers::RoomVersionId;
use serde::{Deserialize, Serialize};
use serde_json::{from_slice as from_json_slice, to_vec as to_json_vec};
use strum::{AsRefStr, Display};

/// An enum for the error kind. Items may contain additional information.
#[derive(Debug, Clone, Serialize, Deserialize, AsRefStr, Display)]
#[serde(tag = "errcode")]
#[cfg_attr(test, derive(PartialEq))]
pub enum ErrorKind {
    /// M_FORBIDDEN
    #[serde(rename = "M_FORBIDDEN")]
    #[strum(to_string = "M_FORBIDDEN")]
    Forbidden,

    /// M_UNKNOWN_TOKEN
    #[serde(rename = "M_UNKNOWN_TOKEN")]
    #[strum(to_string = "M_UNKNOWN_TOKEN")]
    UnknownToken {
        /// If this is `true`, the client can acquire a new access token by specifying the device ID
        /// it is already using to the login API. For more information, see [the spec].
        ///
        /// [the spec]: https://matrix.org/docs/spec/client_server/r0.6.1#soft-logout
        #[serde(default, skip_serializing_if = "ruma_serde::is_default")]
        soft_logout: bool,
    },

    /// M_MISSING_TOKEN
    #[serde(rename = "M_MISSING_TOKEN")]
    #[strum(to_string = "M_MISSING_TOKEN")]
    MissingToken,

    /// M_BAD_JSON
    #[serde(rename = "M_BAD_JSON")]
    #[strum(to_string = "M_BAD_JSON")]
    BadJson,

    /// M_NOT_JSON
    #[serde(rename = "M_NOT_JSON")]
    #[strum(to_string = "M_NOT_JSON")]
    NotJson,

    /// M_NOT_FOUND
    #[serde(rename = "M_NOT_FOUND")]
    #[strum(to_string = "M_NOT_FOUND")]
    NotFound,

    /// M_LIMIT_EXCEEDED
    #[serde(rename = "M_LIMIT_EXCEEDED")]
    #[strum(to_string = "M_LIMIT_EXCEEDED")]
    LimitExceeded,

    /// M_UNKNOWN
    #[serde(rename = "M_UNKNOWN")]
    #[strum(to_string = "M_UNKNOWN")]
    Unknown,

    /// M_UNRECOGNIZED
    #[serde(rename = "M_UNRECOGNIZED")]
    #[strum(to_string = "M_UNRECOGNIZED")]
    Unrecognized,

    /// M_UNAUTHORIZED
    #[serde(rename = "M_UNAUTHORIZED")]
    #[strum(to_string = "M_UNAUTHORIZED")]
    Unauthorized,

    /// M_USER_DEACTIVATED
    #[serde(rename = "M_USER_DEACTIVATED")]
    #[strum(to_string = "M_USER_DEACTIVATED")]
    UserDeactivated,

    /// M_USER_IN_USE
    #[serde(rename = "M_USER_IN_USE")]
    #[strum(to_string = "M_USER_IN_USE")]
    UserInUse,

    /// M_INVALID_USERNAME
    #[serde(rename = "M_INVALID_USERNAME")]
    #[strum(to_string = "M_INVALID_USERNAME")]
    InvalidUsername,

    /// M_ROOM_IN_USE
    #[serde(rename = "M_ROOM_IN_USE")]
    #[strum(to_string = "M_ROOM_IN_USE")]
    RoomInUse,

    /// M_INVALID_ROOM_STATE
    #[serde(rename = "M_INVALID_ROOM_STATE")]
    #[strum(to_string = "M_INVALID_ROOM_STATE")]
    InvalidRoomState,

    /// M_THREEPID_IN_USE
    #[serde(rename = "M_THREEPID_IN_USE")]
    #[strum(to_string = "M_THREEPID_IN_USE")]
    ThreepidInUse,

    /// M_THREEPID_NOT_FOUND
    #[serde(rename = "M_THREEPID_NOT_FOUND")]
    #[strum(to_string = "M_THREEPID_NOT_FOUND")]
    ThreepidNotFound,

    /// M_THREEPID_AUTH_FAILED
    #[serde(rename = "M_THREEPID_AUTH_FAILED")]
    #[strum(to_string = "M_THREEPID_AUTH_FAILED")]
    ThreepidAuthFailed,

    /// M_THREEPID_DENIED
    #[serde(rename = "M_THREEPID_DENIED")]
    #[strum(to_string = "M_THREEPID_DENIED")]
    ThreepidDenied,

    /// M_SERVER_NOT_TRUSTED
    #[serde(rename = "M_SERVER_NOT_TRUSTED")]
    #[strum(to_string = "M_SERVER_NOT_TRUSTED")]
    ServerNotTrusted,

    /// M_UNSUPPORTED_ROOM_VERSION
    #[serde(rename = "M_UNSUPPORTED_ROOM_VERSION")]
    #[strum(to_string = "M_UNSUPPORTED_ROOM_VERSION")]
    UnsupportedRoomVersion,

    /// M_INCOMPATIBLE_ROOM_VERSION
    #[serde(rename = "M_INCOMPATIBLE_ROOM_VERSION")]
    #[strum(to_string = "M_INCOMPATIBLE_ROOM_VERSION")]
    IncompatibleRoomVersion {
        /// The room's version.
        room_version: RoomVersionId,
    },

    /// M_BAD_STATE
    #[serde(rename = "M_BAD_STATE")]
    #[strum(to_string = "M_BAD_STATE")]
    BadState,

    /// M_GUEST_ACCESS_FORBIDDEN
    #[serde(rename = "M_GUEST_ACCESS_FORBIDDEN")]
    #[strum(to_string = "M_GUEST_ACCESS_FORBIDDEN")]
    GuestAccessForbidden,

    /// M_CAPTCHA_NEEDED
    #[serde(rename = "M_CAPTCHA_NEEDED")]
    #[strum(to_string = "M_CAPTCHA_NEEDED")]
    CaptchaNeeded,

    /// M_CAPTCHA_INVALID
    #[serde(rename = "M_CAPTCHA_INVALID")]
    #[strum(to_string = "M_CAPTCHA_INVALID")]
    CaptchaInvalid,

    /// M_MISSING_PARAM
    #[serde(rename = "M_MISSING_PARAM")]
    #[strum(to_string = "M_MISSING_PARAM")]
    MissingParam,

    /// M_INVALID_PARAM
    #[serde(rename = "M_INVALID_PARAM")]
    #[strum(to_string = "M_INVALID_PARAM")]
    InvalidParam,

    /// M_TOO_LARGE
    #[serde(rename = "M_TOO_LARGE")]
    #[strum(to_string = "M_TOO_LARGE")]
    TooLarge,

    /// M_EXCLUSIVE
    #[serde(rename = "M_EXCLUSIVE")]
    #[strum(to_string = "M_EXCLUSIVE")]
    Exclusive,

    /// M_RESOURCE_LIMIT_EXCEEDED
    #[serde(rename = "M_RESOURCE_LIMIT_EXCEEDED")]
    #[strum(to_string = "M_RESOURCE_LIMIT_EXCEEDED")]
    ResourceLimitExceeded {
        /// A URI giving a contact method for the server administrator.
        admin_contact: String,
    },

    /// M_CANNOT_LEAVE_SERVER_NOTICE_ROOM
    #[serde(rename = "M_CANNOT_LEAVE_SERVER_NOTICE_ROOM")]
    #[strum(to_string = "M_CANNOT_LEAVE_SERVER_NOTICE_ROOM")]
    CannotLeaveServerNoticeRoom,
}

/// A Matrix Error without a status code
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(test, derive(PartialEq))]
pub struct ErrorBody {
    /// A value which can be used to handle an error message
    #[serde(flatten)]
    pub kind: ErrorKind,

    /// A human-readable error message, usually a sentence explaining what went wrong.
    #[serde(rename = "error")]
    pub message: String,
}

/// A Matrix Error
#[derive(Debug, Clone)]
pub struct Error {
    /// A value which can be used to handle an error message
    pub kind: ErrorKind,

    /// A human-readable error message, usually a sentence explaining what went wrong.
    pub message: String,

    /// The http status code
    pub status_code: http::StatusCode,
}

impl EndpointError for Error {
    fn try_from_response(
        response: http::Response<Vec<u8>>,
    ) -> Result<Self, ResponseDeserializationError> {
        match from_json_slice::<ErrorBody>(response.body()) {
            Ok(error_body) => Ok(error_body.into_error(response.status())),
            Err(de_error) => Err(ResponseDeserializationError::new(de_error, response)),
        }
    }
}

impl Display for Error {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "[{} / {}] {}", self.status_code.as_u16(), self.kind, self.message)
    }
}

impl std::error::Error for Error {}

impl From<Error> for ErrorBody {
    fn from(error: Error) -> Self {
        Self { kind: error.kind, message: error.message }
    }
}

impl ErrorBody {
    /// Convert the ErrorBody into an Error by adding the http status code.
    pub fn into_error(self, status_code: http::StatusCode) -> Error {
        Error { kind: self.kind, message: self.message, status_code }
    }
}

impl From<Error> for http::Response<Vec<u8>> {
    fn from(error: Error) -> http::Response<Vec<u8>> {
        http::Response::builder()
            .header(http::header::CONTENT_TYPE, "application/json")
            .status(error.status_code)
            .body(to_json_vec(&ErrorBody::from(error)).unwrap())
            .unwrap()
    }
}
<commit_msg>client-api: Add retry_after_ms field to ErrorKind::LimitExceeded<commit_after>//! Errors that can be sent from the homeserver.

use std::{
    fmt::{self, Display, Formatter},
    time::Duration,
};

use ruma_api::{error::ResponseDeserializationError, EndpointError};
use ruma_identifiers::RoomVersionId;
use serde::{Deserialize, Serialize};
use serde_json::{from_slice as from_json_slice, to_vec as to_json_vec};
use strum::{AsRefStr, Display};

/// An enum for the error kind. Items may contain additional information.
#[derive(Debug, Clone, Serialize, Deserialize, AsRefStr, Display)]
#[serde(tag = "errcode")]
#[cfg_attr(test, derive(PartialEq))]
pub enum ErrorKind {
    /// M_FORBIDDEN
    #[serde(rename = "M_FORBIDDEN")]
    #[strum(to_string = "M_FORBIDDEN")]
    Forbidden,

    /// M_UNKNOWN_TOKEN
    #[serde(rename = "M_UNKNOWN_TOKEN")]
    #[strum(to_string = "M_UNKNOWN_TOKEN")]
    UnknownToken {
        /// If this is `true`, the client can acquire a new access token by specifying the device ID
        /// it is already using to the login API. For more information, see [the spec].
        ///
        /// [the spec]: https://matrix.org/docs/spec/client_server/r0.6.1#soft-logout
        #[serde(default, skip_serializing_if = "ruma_serde::is_default")]
        soft_logout: bool,
    },

    /// M_MISSING_TOKEN
    #[serde(rename = "M_MISSING_TOKEN")]
    #[strum(to_string = "M_MISSING_TOKEN")]
    MissingToken,

    /// M_BAD_JSON
    #[serde(rename = "M_BAD_JSON")]
    #[strum(to_string = "M_BAD_JSON")]
    BadJson,

    /// M_NOT_JSON
    #[serde(rename = "M_NOT_JSON")]
    #[strum(to_string = "M_NOT_JSON")]
    NotJson,

    /// M_NOT_FOUND
    #[serde(rename = "M_NOT_FOUND")]
    #[strum(to_string = "M_NOT_FOUND")]
    NotFound,

    /// M_LIMIT_EXCEEDED
    #[serde(rename = "M_LIMIT_EXCEEDED")]
    #[strum(to_string = "M_LIMIT_EXCEEDED")]
    LimitExceeded {
        /// How long a client should wait in milliseconds before they can try again.
        #[serde(with = "ruma_serde::duration::opt_ms")]
        retry_after_ms: Option<Duration>,
    },

    /// M_UNKNOWN
    #[serde(rename = "M_UNKNOWN")]
    #[strum(to_string = "M_UNKNOWN")]
    Unknown,

    /// M_UNRECOGNIZED
    #[serde(rename = "M_UNRECOGNIZED")]
    #[strum(to_string = "M_UNRECOGNIZED")]
    Unrecognized,

    /// M_UNAUTHORIZED
    #[serde(rename = "M_UNAUTHORIZED")]
    #[strum(to_string = "M_UNAUTHORIZED")]
    Unauthorized,

    /// M_USER_DEACTIVATED
    #[serde(rename = "M_USER_DEACTIVATED")]
    #[strum(to_string = "M_USER_DEACTIVATED")]
    UserDeactivated,

    /// M_USER_IN_USE
    #[serde(rename = "M_USER_IN_USE")]
    #[strum(to_string = "M_USER_IN_USE")]
    UserInUse,

    /// M_INVALID_USERNAME
    #[serde(rename = "M_INVALID_USERNAME")]
    #[strum(to_string = "M_INVALID_USERNAME")]
    InvalidUsername,

    /// M_ROOM_IN_USE
    #[serde(rename = "M_ROOM_IN_USE")]
    #[strum(to_string = "M_ROOM_IN_USE")]
    RoomInUse,

    /// M_INVALID_ROOM_STATE
    #[serde(rename = "M_INVALID_ROOM_STATE")]
    #[strum(to_string = "M_INVALID_ROOM_STATE")]
    InvalidRoomState,

    /// M_THREEPID_IN_USE
    #[serde(rename = "M_THREEPID_IN_USE")]
    #[strum(to_string = "M_THREEPID_IN_USE")]
    ThreepidInUse,

    /// M_THREEPID_NOT_FOUND
    #[serde(rename = "M_THREEPID_NOT_FOUND")]
    #[strum(to_string = "M_THREEPID_NOT_FOUND")]
    ThreepidNotFound,

    /// M_THREEPID_AUTH_FAILED
    #[serde(rename = "M_THREEPID_AUTH_FAILED")]
    #[strum(to_string = "M_THREEPID_AUTH_FAILED")]
    ThreepidAuthFailed,

    /// M_THREEPID_DENIED
    #[serde(rename = "M_THREEPID_DENIED")]
    #[strum(to_string = "M_THREEPID_DENIED")]
    ThreepidDenied,

    /// M_SERVER_NOT_TRUSTED
    #[serde(rename = "M_SERVER_NOT_TRUSTED")]
    #[strum(to_string = "M_SERVER_NOT_TRUSTED")]
    ServerNotTrusted,

    /// M_UNSUPPORTED_ROOM_VERSION
    #[serde(rename = "M_UNSUPPORTED_ROOM_VERSION")]
    #[strum(to_string = "M_UNSUPPORTED_ROOM_VERSION")]
    UnsupportedRoomVersion,

    /// M_INCOMPATIBLE_ROOM_VERSION
    #[serde(rename = "M_INCOMPATIBLE_ROOM_VERSION")]
    #[strum(to_string = "M_INCOMPATIBLE_ROOM_VERSION")]
    IncompatibleRoomVersion {
        /// The room's version.
        room_version: RoomVersionId,
    },

    /// M_BAD_STATE
    #[serde(rename = "M_BAD_STATE")]
    #[strum(to_string = "M_BAD_STATE")]
    BadState,

    /// M_GUEST_ACCESS_FORBIDDEN
    #[serde(rename = "M_GUEST_ACCESS_FORBIDDEN")]
    #[strum(to_string = "M_GUEST_ACCESS_FORBIDDEN")]
    GuestAccessForbidden,

    /// M_CAPTCHA_NEEDED
    #[serde(rename = "M_CAPTCHA_NEEDED")]
    #[strum(to_string = "M_CAPTCHA_NEEDED")]
    CaptchaNeeded,

    /// M_CAPTCHA_INVALID
    #[serde(rename = "M_CAPTCHA_INVALID")]
    #[strum(to_string = "M_CAPTCHA_INVALID")]
    CaptchaInvalid,

    /// M_MISSING_PARAM
    #[serde(rename = "M_MISSING_PARAM")]
    #[strum(to_string = "M_MISSING_PARAM")]
    MissingParam,

    /// M_INVALID_PARAM
    #[serde(rename = "M_INVALID_PARAM")]
    #[strum(to_string = "M_INVALID_PARAM")]
    InvalidParam,

    /// M_TOO_LARGE
    #[serde(rename = "M_TOO_LARGE")]
    #[strum(to_string = "M_TOO_LARGE")]
    TooLarge,

    /// M_EXCLUSIVE
    #[serde(rename = "M_EXCLUSIVE")]
    #[strum(to_string = "M_EXCLUSIVE")]
    Exclusive,

    /// M_RESOURCE_LIMIT_EXCEEDED
    #[serde(rename = "M_RESOURCE_LIMIT_EXCEEDED")]
    #[strum(to_string = "M_RESOURCE_LIMIT_EXCEEDED")]
    ResourceLimitExceeded {
        /// A URI giving a contact method for the server administrator.
        admin_contact: String,
    },

    /// M_CANNOT_LEAVE_SERVER_NOTICE_ROOM
    #[serde(rename = "M_CANNOT_LEAVE_SERVER_NOTICE_ROOM")]
    #[strum(to_string = "M_CANNOT_LEAVE_SERVER_NOTICE_ROOM")]
    CannotLeaveServerNoticeRoom,
}

/// A Matrix Error without a status code
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(test, derive(PartialEq))]
pub struct ErrorBody {
    /// A value which can be used to handle an error message
    #[serde(flatten)]
    pub kind: ErrorKind,

    /// A human-readable error message, usually a sentence explaining what went wrong.
    #[serde(rename = "error")]
    pub message: String,
}

/// A Matrix Error
#[derive(Debug, Clone)]
pub struct Error {
    /// A value which can be used to handle an error message
    pub kind: ErrorKind,

    /// A human-readable error message, usually a sentence explaining what went wrong.
    pub message: String,

    /// The http status code
    pub status_code: http::StatusCode,
}

impl EndpointError for Error {
    fn try_from_response(
        response: http::Response<Vec<u8>>,
    ) -> Result<Self, ResponseDeserializationError> {
        match from_json_slice::<ErrorBody>(response.body()) {
            Ok(error_body) => Ok(error_body.into_error(response.status())),
            Err(de_error) => Err(ResponseDeserializationError::new(de_error, response)),
        }
    }
}

impl Display for Error {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "[{} / {}] {}", self.status_code.as_u16(), self.kind, self.message)
    }
}

impl std::error::Error for Error {}

impl From<Error> for ErrorBody {
    fn from(error: Error) -> Self {
        Self { kind: error.kind, message: error.message }
    }
}

impl ErrorBody {
    /// Convert the ErrorBody into an Error by adding the http status code.
    pub fn into_error(self, status_code: http::StatusCode) -> Error {
        Error { kind: self.kind, message: self.message, status_code }
    }
}

impl From<Error> for http::Response<Vec<u8>> {
    fn from(error: Error) -> http::Response<Vec<u8>> {
        http::Response::builder()
            .header(http::header::CONTENT_TYPE, "application/json")
            .status(error.status_code)
            .body(to_json_vec(&ErrorBody::from(error)).unwrap())
            .unwrap()
    }
}
<|endoftext|>


<commit_before>extern crate crypto;
extern crate bit_vec;
use std::iter::repeat;
use std::error::Error;
use std::io::prelude::*;
use std::fs::File;
use std::path::Path;

use crypto::digest::Digest;
use crypto::sha1::Sha1;

use bit_vec::BitVec;

const BIT_VEC_SIZE : usize = 5000000;

fn read_file(file_name : &str) -> String {
    let path = Path::new(file_name);
    let display = path.display();

    let mut file = match File::open(&path) {
        Err(why) => panic!("couldn't open {}: {}", display,
            Error::description(&why)),
        Ok(file) => file,
    };

    // Read the file contents into a string, returns `io::Result<usize>`
    let mut s = String::new();
    match file.read_to_string(&mut s) {
        Err(why) => panic!("couldn't read {}: {}", display,
            Error::description(&why)),
        Ok(_) => s,
    }
}

fn bloom_lines<D : Digest>(words : &String, digest : &mut D, bit_vec : &mut BitVec) {
	let word_lines = words.lines();
	for word in word_lines {
		let hashed_word = digest_string(word, digest);
		bloom_hash(&hashed_word, bit_vec);
	}
}

fn digest_string<D : Digest>(input : &str, digest : &mut D) -> Vec<u8> {
	digest.input_str(input);
	let output_bytes = digest.output_bytes();
	let mut buf: Vec<u8> = repeat(0).take(output_bytes).collect();
	digest.result(&mut buf);
	digest.reset();
	buf
}

fn bloom_hash(hash : &[u8], bit_vec : &mut BitVec) {
	if hash.len() < 4 {
		panic!("Need at least 4 bytes to bloom");
	}
	// Cut the hash into 4 chunks, then use them to index into the bit vec to bloom
	let chunk_size = hash.len() / 4;
	let mut hash_iter = hash.iter();

	for _ in 0..3 {
		let mut bit_vec_index : usize = 0;
		for i in 0..chunk_size {
			bit_vec_index += ((*hash_iter.next().unwrap()) as usize) << (8 * i);
		}
		bit_vec_index = bit_vec_index % BIT_VEC_SIZE;
		bit_vec.set(bit_vec_index, true);
	}
}

fn check_hash(hash : &[u8], bit_vec : &BitVec) -> bool {
	if hash.len() < 4 {
		panic!("Need at least 4 bytes to bloom");
	}

	// Cut the hash into 4 chunks, then use them to index into the bit vec to bloom
	let chunk_size = hash.len() / 4;
	let mut hash_iter = hash.iter();

	let mut word_seen = true;

	for _ in 0..3 {
		let mut bit_vec_index : usize = 0;
		for i in 0..chunk_size {
			bit_vec_index += ((*hash_iter.next().unwrap()) as usize) << (8 * i);
		}
		bit_vec_index = bit_vec_index % BIT_VEC_SIZE;
		if bit_vec[bit_vec_index] == false {
			word_seen = false;
		}
	}

	word_seen
}

fn check_spelling<D : Digest>(word : &String, digest : &mut D, bit_vec : &BitVec) -> bool {
	let hashed_word = digest_string(word, digest);
	check_hash(&hashed_word, &bit_vec)
}

fn main() {
	let mut sha1_digest = Sha1::new();
	let mut bit_vec = BitVec::from_elem(BIT_VEC_SIZE, false);

	let words = read_file("wordlist.txt");
	bloom_lines(&words, &mut sha1_digest, &mut bit_vec);

	println!("{} is word?: {}", "dog", check_spelling(&"dog".to_owned(), &mut sha1_digest, &bit_vec));
	println!("{} is word?: {}", "dogs", check_spelling(&"dogs".to_owned(), &mut sha1_digest, &bit_vec));
	println!("{} is word?: {}", "dogz", check_spelling(&"dogz".to_owned(), &mut sha1_digest, &bit_vec));
	println!("{} is word?: {}", "zzzz", check_spelling(&"zzzz".to_owned(), &mut sha1_digest, &bit_vec));
}
<commit_msg>Kata05: remove redundant variable from rust case<commit_after>extern crate crypto;
extern crate bit_vec;
use std::iter::repeat;
use std::error::Error;
use std::io::prelude::*;
use std::fs::File;
use std::path::Path;

use crypto::digest::Digest;
use crypto::sha1::Sha1;

use bit_vec::BitVec;

const BIT_VEC_SIZE : usize = 5000000;

fn read_file(file_name : &str) -> String {
    let path = Path::new(file_name);
    let display = path.display();

    let mut file = match File::open(&path) {
        Err(why) => panic!("couldn't open {}: {}", display,
            Error::description(&why)),
        Ok(file) => file,
    };

    // Read the file contents into a string, returns `io::Result<usize>`
    let mut s = String::new();
    match file.read_to_string(&mut s) {
        Err(why) => panic!("couldn't read {}: {}", display,
            Error::description(&why)),
        Ok(_) => s,
    }
}

fn bloom_lines<D : Digest>(words : &String, digest : &mut D, bit_vec : &mut BitVec) {
	let word_lines = words.lines();
	for word in word_lines {
		let hashed_word = digest_string(word, digest);
		bloom_hash(&hashed_word, bit_vec);
	}
}

fn digest_string<D : Digest>(input : &str, digest : &mut D) -> Vec<u8> {
	digest.input_str(input);
	let output_bytes = digest.output_bytes();
	let mut buf: Vec<u8> = repeat(0).take(output_bytes).collect();
	digest.result(&mut buf);
	digest.reset();
	buf
}

fn bloom_hash(hash : &[u8], bit_vec : &mut BitVec) {
	if hash.len() < 4 {
		panic!("Need at least 4 bytes to bloom");
	}
	// Cut the hash into 4 chunks, then use them to index into the bit vec to bloom
	let chunk_size = hash.len() / 4;
	let mut hash_iter = hash.iter();

	for _ in 0..3 {
		let mut bit_vec_index : usize = 0;
		for i in 0..chunk_size {
			bit_vec_index += ((*hash_iter.next().unwrap()) as usize) << (8 * i);
		}
		bit_vec_index = bit_vec_index % BIT_VEC_SIZE;
		bit_vec.set(bit_vec_index, true);
	}
}

fn check_hash(hash : &[u8], bit_vec : &BitVec) -> bool {
	if hash.len() < 4 {
		panic!("Need at least 4 bytes to bloom");
	}

	// Cut the hash into 4 chunks, then use them to index into the bit vec to bloom
	let chunk_size = hash.len() / 4;
	let mut hash_iter = hash.iter();

	for _ in 0..3 {
		let mut bit_vec_index : usize = 0;
		for i in 0..chunk_size {
			bit_vec_index += ((*hash_iter.next().unwrap()) as usize) << (8 * i);
		}
		bit_vec_index = bit_vec_index % BIT_VEC_SIZE;
		if bit_vec[bit_vec_index] == false {
			return false
		}
	}

	true
}

fn check_spelling<D : Digest>(word : &String, digest : &mut D, bit_vec : &BitVec) -> bool {
	let hashed_word = digest_string(word, digest);
	check_hash(&hashed_word, &bit_vec)
}

fn main() {
	let mut sha1_digest = Sha1::new();
	let mut bit_vec = BitVec::from_elem(BIT_VEC_SIZE, false);

	let words = read_file("wordlist.txt");
	bloom_lines(&words, &mut sha1_digest, &mut bit_vec);

	println!("{} is word?: {}", "dog", check_spelling(&"dog".to_owned(), &mut sha1_digest, &bit_vec));
	println!("{} is word?: {}", "dogs", check_spelling(&"dogs".to_owned(), &mut sha1_digest, &bit_vec));
	println!("{} is word?: {}", "dogz", check_spelling(&"dogz".to_owned(), &mut sha1_digest, &bit_vec));
	println!("{} is word?: {}", "zzzz", check_spelling(&"zzzz".to_owned(), &mut sha1_digest, &bit_vec));
}
<|endoftext|>


<commit_before>/// Problem 26
/// A unit fraction contains 1 in the numerator. The decimal representation of
/// the unit fractions with denominators 2 to 10 are given:
///
/// 		1/2	= 	0.5
/// 		1/3	= 	0.(3)
/// 		1/4	= 	0.25
/// 		1/5	= 	0.2
/// 		1/6	= 	0.1(6)
/// 		1/7	= 	0.(142857)
/// 		1/8	= 	0.125
/// 		1/9	= 	0.(1)
/// 		1/10	= 	0.1
/// Where 0.1(6) means 0.166666..., and has a 1-digit recurring cycle. It can
/// be seen that 1/7 has a 6-digit recurring cycle.
///
/// Find the value of d < 1000 for which 1/d contains the longest recurring
/// cycle in its decimal fraction part.
fn main() {
	let mut longest = 1;
	for d in 2u16..1000u16 {
		let mut top: u16 = 10;
		let mut cycle: Vec<u16> = Vec::new();
		let bot: u16 = d;
		// let mut div = 0;
		let mut rem = 1;
		while rem > 0 {
			// div = top/bot;
			rem = top%bot;
			match cycle.iter().position(|&x| x == top) {
				Some(_) => break,
				None => cycle.push(top)
			};
			top = rem*10;
		}
		if cycle.len() > longest {
			longest = cycle.len();
			println!("1/{} cycle length = {}", d, cycle.len());
		}
	}
	println!("Answer: {}", longest);
}
<commit_msg>Changes tabs to spaces.<commit_after>/// Problem 26
/// A unit fraction contains 1 in the numerator. The decimal representation of
/// the unit fractions with denominators 2 to 10 are given:
///
///         1/2 =   0.5
///         1/3 =   0.(3)
///         1/4 =   0.25
///         1/5 =   0.2
///         1/6 =   0.1(6)
///         1/7 =   0.(142857)
///         1/8 =   0.125
///         1/9 =   0.(1)
///         1/10    =   0.1
/// Where 0.1(6) means 0.166666..., and has a 1-digit recurring cycle. It can
/// be seen that 1/7 has a 6-digit recurring cycle.
///
/// Find the value of d < 1000 for which 1/d contains the longest recurring
/// cycle in its decimal fraction part.
fn main() {
    let mut longest = 1;
    for d in 2u16..1000u16 {
        let mut top: u16 = 10;
        let mut cycle: Vec<u16> = Vec::new();
        let bot: u16 = d;
        // let mut div = 0;
        let mut rem = 1;
        while rem > 0 {
            // div = top/bot;
            rem = top%bot;
            match cycle.iter().position(|&x| x == top) {
                Some(_) => break,
                None => cycle.push(top)
            };
            top = rem*10;
        }
        if cycle.len() > longest {
            longest = cycle.len();
            println!("1/{} cycle length = {}", d, cycle.len());
        }
    }
    println!("Answer: {}", longest);
}
<|endoftext|>


<commit_before>use proc_macro2::TokenStream;

use syn::{self, Field};

use super::context::Context;

pub fn transcoder_decorator(ast: &syn::DeriveInput) -> TokenStream {
    let ctx = Context::from_ast(ast);

    let struct_fields = ctx
        .struct_fields
        .as_ref()
        .expect("NifStruct can only be used with structs");

    let decoder = if ctx.decode() {
        gen_decoder(&ctx, &struct_fields, false)
    } else {
        quote! {}
    };

    let encoder = if ctx.encode() {
        gen_encoder(&ctx, &struct_fields, false)
    } else {
        quote! {}
    };

    let gen = quote! {
        #decoder
        #encoder
    };

    gen
}

fn gen_decoder(ctx: &Context, fields: &[&Field], is_tuple: bool) -> TokenStream {
    let struct_type = &ctx.ident_with_lifetime;
    let struct_name = ctx.ident;

    // Make a decoder for each of the fields in the struct.
    let field_defs: Vec<TokenStream> = fields
        .iter()
        .enumerate()
        .map(|(index, field)| {
            let error_message = format!("Could not decode index {} on tuple", index);
            let decoder = quote! {
                match ::rustler::Decoder::decode(terms[#index]) {
                    Err(_) => return Err(::rustler::Error::RaiseTerm(Box::new(#error_message))),
                    Ok(value) => value
                }
            };

            if is_tuple {
                unimplemented!();
            } else {
                let ident = field.ident.as_ref().unwrap();
                quote! { #ident: #decoder }
            }
        })
        .collect();

    let field_num = field_defs.len();

    // The implementation itself
    let gen = quote! {
        impl<'a> ::rustler::Decoder<'a> for #struct_type {
            fn decode(term: ::rustler::Term<'a>) -> Result<Self, ::rustler::Error> {
                let terms = ::rustler::types::tuple::get_tuple(term)?;
                if terms.len() != #field_num {
                    return Err(::rustler::Error::BadArg);
                }
                Ok(
                    #struct_name {
                        #(#field_defs),*
                    }
                )
            }
        }
    };

    gen
}

fn gen_encoder(ctx: &Context, fields: &[&Field], is_tuple: bool) -> TokenStream {
    let struct_type = &ctx.ident_with_lifetime;

    // Make a field encoder expression for each of the items in the struct.
    let field_encoders: Vec<TokenStream> = fields
        .iter()
        .map(|field| {
            let field_source = if is_tuple {
                unimplemented!();
            } else {
                let field_ident = field.ident.as_ref().unwrap();
                quote! { self.#field_ident }
            };
            quote! { #field_source.encode(env) }
        })
        .collect();

    // Build a slice ast from the field_encoders
    let field_list_ast = quote! {
        [#(#field_encoders),*]
    };

    // The implementation itself
    let gen = quote! {
        impl<'b> ::rustler::Encoder for #struct_type {
            fn encode<'a>(&self, env: ::rustler::Env<'a>) -> ::rustler::Term<'a> {
                let arr = #field_list_ast;
                ::rustler::types::tuple::make_tuple(env, &arr)
            }
        }
    };

    gen
}
<commit_msg>codegen: Fix error message for NifTuple<commit_after>use proc_macro2::TokenStream;

use syn::{self, Field};

use super::context::Context;

pub fn transcoder_decorator(ast: &syn::DeriveInput) -> TokenStream {
    let ctx = Context::from_ast(ast);

    let struct_fields = ctx
        .struct_fields
        .as_ref()
        .expect("NifTuple can only be used with structs");

    let decoder = if ctx.decode() {
        gen_decoder(&ctx, &struct_fields, false)
    } else {
        quote! {}
    };

    let encoder = if ctx.encode() {
        gen_encoder(&ctx, &struct_fields, false)
    } else {
        quote! {}
    };

    let gen = quote! {
        #decoder
        #encoder
    };

    gen
}

fn gen_decoder(ctx: &Context, fields: &[&Field], is_tuple: bool) -> TokenStream {
    let struct_type = &ctx.ident_with_lifetime;
    let struct_name = ctx.ident;

    // Make a decoder for each of the fields in the struct.
    let field_defs: Vec<TokenStream> = fields
        .iter()
        .enumerate()
        .map(|(index, field)| {
            let error_message = format!("Could not decode index {} on tuple", index);
            let decoder = quote! {
                match ::rustler::Decoder::decode(terms[#index]) {
                    Err(_) => return Err(::rustler::Error::RaiseTerm(Box::new(#error_message))),
                    Ok(value) => value
                }
            };

            if is_tuple {
                unimplemented!();
            } else {
                let ident = field.ident.as_ref().unwrap();
                quote! { #ident: #decoder }
            }
        })
        .collect();

    let field_num = field_defs.len();

    // The implementation itself
    let gen = quote! {
        impl<'a> ::rustler::Decoder<'a> for #struct_type {
            fn decode(term: ::rustler::Term<'a>) -> Result<Self, ::rustler::Error> {
                let terms = ::rustler::types::tuple::get_tuple(term)?;
                if terms.len() != #field_num {
                    return Err(::rustler::Error::BadArg);
                }
                Ok(
                    #struct_name {
                        #(#field_defs),*
                    }
                )
            }
        }
    };

    gen
}

fn gen_encoder(ctx: &Context, fields: &[&Field], is_tuple: bool) -> TokenStream {
    let struct_type = &ctx.ident_with_lifetime;

    // Make a field encoder expression for each of the items in the struct.
    let field_encoders: Vec<TokenStream> = fields
        .iter()
        .map(|field| {
            let field_source = if is_tuple {
                unimplemented!();
            } else {
                let field_ident = field.ident.as_ref().unwrap();
                quote! { self.#field_ident }
            };
            quote! { #field_source.encode(env) }
        })
        .collect();

    // Build a slice ast from the field_encoders
    let field_list_ast = quote! {
        [#(#field_encoders),*]
    };

    // The implementation itself
    let gen = quote! {
        impl<'b> ::rustler::Encoder for #struct_type {
            fn encode<'a>(&self, env: ::rustler::Env<'a>) -> ::rustler::Term<'a> {
                let arr = #field_list_ast;
                ::rustler::types::tuple::make_tuple(env, &arr)
            }
        }
    };

    gen
}
<|endoftext|>


<commit_before>///! Handle `cargo add` arguments
use semver;
use std::error::Error;
use std::path::Path;
use cargo_edit::Dependency;
use fetch::{get_crate_name_from_github, get_crate_name_from_gitlab, get_crate_name_from_path,
            get_latest_version};

macro_rules! toml_table {
    ($($key:expr => $value:expr),+) => {
        {
            let mut dep = BTreeMap::new();
            $(dep.insert(String::from($key), $value);)+
            toml::Value::Table(dep)
        }
    }
}

#[derive(Debug, RustcDecodable)]
/// Docopts input args.
pub struct Args {
    /// Crate name (usage 1)
    pub arg_crate: String,
    /// Crate names (usage 2)
    pub arg_crates: Vec<String>,
    /// dev-dependency
    pub flag_dev: bool,
    /// build-dependency
    pub flag_build: bool,
    /// Version
    pub flag_vers: Option<String>,
    /// Git repo Path
    pub flag_git: Option<String>,
    /// Crate directory path
    pub flag_path: Option<String>,
    /// Optional dependency
    pub flag_optional: bool,
    /// `Cargo.toml` path
    pub flag_manifest_path: Option<String>,
    /// `--version`
    pub flag_version: bool,
}

impl Args {
    /// Get depenency section
    pub fn get_section(&self) -> &'static str {
        if self.flag_dev {
            "dev-dependencies"
        } else if self.flag_build {
            "build-dependencies"
        } else {
            "dependencies"
        }
    }

    /// Build dependencies from arguments
    pub fn parse_dependencies(&self) -> Result<Vec<Dependency>, Box<Error>> {
        if !self.arg_crates.is_empty() {
            let mut result = Vec::<Dependency>::new();
            for arg_crate in &self.arg_crates {
                let le_crate = if crate_name_has_version(&arg_crate) {
                                   try!(parse_crate_name_with_version(arg_crate))
                               } else {
                                   let v = try!(get_latest_version(&self.arg_crate));
                                   Dependency::new(arg_crate).set_version(&v)
                               }
                               .set_optional(self.flag_optional);

                result.push(le_crate);
            }
            return Ok(result);
        }

        if crate_name_has_version(&self.arg_crate) {
            return Ok(vec![try!(parse_crate_name_with_version(&self.arg_crate))
                               .set_optional(self.flag_optional)]);
        }

        let dependency = if !crate_name_is_url_or_path(&self.arg_crate) {
                             let dependency = Dependency::new(&self.arg_crate);

                             if let Some(ref version) = self.flag_vers {
                                 try!(semver::VersionReq::parse(&version));
                                 dependency.set_version(version)
                             } else if let Some(ref repo) = self.flag_git {
                                 dependency.set_git(repo)
                             } else if let Some(ref path) = self.flag_path {
                                 dependency.set_path(path)
                             } else {
                                 let v = try!(get_latest_version(&self.arg_crate));
                                 dependency.set_version(&v)
                             }
                         } else {
                             try!(parse_crate_name_from_uri(&self.arg_crate))
                         }
                         .set_optional(self.flag_optional);

        Ok(vec![dependency])
    }
}

impl Default for Args {
    fn default() -> Args {
        Args {
            arg_crate: "demo".to_owned(),
            arg_crates: vec![],
            flag_dev: false,
            flag_build: false,
            flag_vers: None,
            flag_git: None,
            flag_path: None,
            flag_optional: false,
            flag_manifest_path: None,
            flag_version: false,
        }
    }
}

fn crate_name_has_version(name: &str) -> bool {
    name.contains('@')
}

fn crate_name_is_url_or_path(name: &str) -> bool {
    crate_name_is_github_url(name) || crate_name_is_gitlab_url(name) || crate_name_is_path(name)
}

fn crate_name_is_github_url(name: &str) -> bool {
    name.contains("https://github.com")
}

fn crate_name_is_gitlab_url(name: &str) -> bool {
    name.contains("https://gitlab.com")
}

fn crate_name_is_path(name: &str) -> bool {
    // FIXME: how else can we check if the name is a path?
    name.contains('.') || name.contains('/') || name.contains('\\')
}

fn parse_crate_name_with_version(name: &str) -> Result<Dependency, Box<Error>> {
    assert!(crate_name_has_version(&name));

    let xs: Vec<&str> = name.splitn(2, '@').collect();
    let (name, version) = (xs[0], xs[1]);
    try!(semver::VersionReq::parse(&version));

    Ok(Dependency::new(name).set_version(version))
}

fn parse_crate_name_from_uri(name: &str) -> Result<Dependency, Box<Error>> {
    if crate_name_is_github_url(name) {
        if let Ok(ref crate_name) = get_crate_name_from_github(name) {
            return Ok(Dependency::new(crate_name).set_git(name));
        }
    } else if crate_name_is_gitlab_url(name) {
        if let Ok(ref crate_name) = get_crate_name_from_gitlab(name) {
            return Ok(Dependency::new(crate_name).set_git(name));
        }
    } else if crate_name_is_path(name) {
        if let Ok(ref crate_name) = get_crate_name_from_path(&name) {
            return Ok(Dependency::new(crate_name).set_path(name));
        }
    }

    Err(From::from(format!("Unable to obtain crate informations from `{}`.\n", name)))
}

#[cfg(test)]
mod tests {
    use std::env;
    use cargo_edit::Dependency;
    use super::*;

    #[test]
    fn test_dependency_parsing() {
        let args = Args {
            arg_crate: "demo".to_owned(),
            flag_vers: Some("0.4.2".to_owned()),
            ..Args::default()
        };

        assert_eq!(args.parse_dependencies().unwrap(),
                   vec![Dependency::new("demo").set_version("0.4.2")]);
    }

    #[test]
    fn test_repo_as_arg_parsing() {
        // Skip remote tests if no network available
        if env::var("NO_REMOTE_CARGO_TEST").is_err() {
            let github_url = "https://github.com/killercup/cargo-edit/";
            let args_github = Args { arg_crate: github_url.to_owned(), ..Args::default() };
            assert_eq!(args_github.parse_dependencies().unwrap(),
                       vec![Dependency::new("cargo-edit").set_git(github_url)]);

            let gitlab_url = "https://gitlab.com/Polly-lang/Polly.git";
            let args_gitlab = Args { arg_crate: gitlab_url.to_owned(), ..Args::default() };
            assert_eq!(args_gitlab.parse_dependencies().unwrap(),
                       vec![Dependency::new("polly").set_git(gitlab_url)]);
        }
    }

    #[test]
    fn test_path_as_arg_parsing() {
        let self_path = ".";
        let args_path = Args { arg_crate: self_path.to_owned(), ..Args::default() };
        assert_eq!(args_path.parse_dependencies().unwrap(),
                   vec![Dependency::new("cargo-edit").set_path(self_path)]);
    }

}
<commit_msg>fix warning<commit_after>///! Handle `cargo add` arguments
use semver;
use std::error::Error;
use cargo_edit::Dependency;
use fetch::{get_crate_name_from_github, get_crate_name_from_gitlab, get_crate_name_from_path,
            get_latest_version};

macro_rules! toml_table {
    ($($key:expr => $value:expr),+) => {
        {
            let mut dep = BTreeMap::new();
            $(dep.insert(String::from($key), $value);)+
            toml::Value::Table(dep)
        }
    }
}

#[derive(Debug, RustcDecodable)]
/// Docopts input args.
pub struct Args {
    /// Crate name (usage 1)
    pub arg_crate: String,
    /// Crate names (usage 2)
    pub arg_crates: Vec<String>,
    /// dev-dependency
    pub flag_dev: bool,
    /// build-dependency
    pub flag_build: bool,
    /// Version
    pub flag_vers: Option<String>,
    /// Git repo Path
    pub flag_git: Option<String>,
    /// Crate directory path
    pub flag_path: Option<String>,
    /// Optional dependency
    pub flag_optional: bool,
    /// `Cargo.toml` path
    pub flag_manifest_path: Option<String>,
    /// `--version`
    pub flag_version: bool,
}

impl Args {
    /// Get depenency section
    pub fn get_section(&self) -> &'static str {
        if self.flag_dev {
            "dev-dependencies"
        } else if self.flag_build {
            "build-dependencies"
        } else {
            "dependencies"
        }
    }

    /// Build dependencies from arguments
    pub fn parse_dependencies(&self) -> Result<Vec<Dependency>, Box<Error>> {
        if !self.arg_crates.is_empty() {
            let mut result = Vec::<Dependency>::new();
            for arg_crate in &self.arg_crates {
                let le_crate = if crate_name_has_version(&arg_crate) {
                                   try!(parse_crate_name_with_version(arg_crate))
                               } else {
                                   let v = try!(get_latest_version(&self.arg_crate));
                                   Dependency::new(arg_crate).set_version(&v)
                               }
                               .set_optional(self.flag_optional);

                result.push(le_crate);
            }
            return Ok(result);
        }

        if crate_name_has_version(&self.arg_crate) {
            return Ok(vec![try!(parse_crate_name_with_version(&self.arg_crate))
                               .set_optional(self.flag_optional)]);
        }

        let dependency = if !crate_name_is_url_or_path(&self.arg_crate) {
                             let dependency = Dependency::new(&self.arg_crate);

                             if let Some(ref version) = self.flag_vers {
                                 try!(semver::VersionReq::parse(&version));
                                 dependency.set_version(version)
                             } else if let Some(ref repo) = self.flag_git {
                                 dependency.set_git(repo)
                             } else if let Some(ref path) = self.flag_path {
                                 dependency.set_path(path)
                             } else {
                                 let v = try!(get_latest_version(&self.arg_crate));
                                 dependency.set_version(&v)
                             }
                         } else {
                             try!(parse_crate_name_from_uri(&self.arg_crate))
                         }
                         .set_optional(self.flag_optional);

        Ok(vec![dependency])
    }
}

impl Default for Args {
    fn default() -> Args {
        Args {
            arg_crate: "demo".to_owned(),
            arg_crates: vec![],
            flag_dev: false,
            flag_build: false,
            flag_vers: None,
            flag_git: None,
            flag_path: None,
            flag_optional: false,
            flag_manifest_path: None,
            flag_version: false,
        }
    }
}

fn crate_name_has_version(name: &str) -> bool {
    name.contains('@')
}

fn crate_name_is_url_or_path(name: &str) -> bool {
    crate_name_is_github_url(name) || crate_name_is_gitlab_url(name) || crate_name_is_path(name)
}

fn crate_name_is_github_url(name: &str) -> bool {
    name.contains("https://github.com")
}

fn crate_name_is_gitlab_url(name: &str) -> bool {
    name.contains("https://gitlab.com")
}

fn crate_name_is_path(name: &str) -> bool {
    // FIXME: how else can we check if the name is a path?
    name.contains('.') || name.contains('/') || name.contains('\\')
}

fn parse_crate_name_with_version(name: &str) -> Result<Dependency, Box<Error>> {
    assert!(crate_name_has_version(&name));

    let xs: Vec<&str> = name.splitn(2, '@').collect();
    let (name, version) = (xs[0], xs[1]);
    try!(semver::VersionReq::parse(&version));

    Ok(Dependency::new(name).set_version(version))
}

fn parse_crate_name_from_uri(name: &str) -> Result<Dependency, Box<Error>> {
    if crate_name_is_github_url(name) {
        if let Ok(ref crate_name) = get_crate_name_from_github(name) {
            return Ok(Dependency::new(crate_name).set_git(name));
        }
    } else if crate_name_is_gitlab_url(name) {
        if let Ok(ref crate_name) = get_crate_name_from_gitlab(name) {
            return Ok(Dependency::new(crate_name).set_git(name));
        }
    } else if crate_name_is_path(name) {
        if let Ok(ref crate_name) = get_crate_name_from_path(&name) {
            return Ok(Dependency::new(crate_name).set_path(name));
        }
    }

    Err(From::from(format!("Unable to obtain crate informations from `{}`.\n", name)))
}

#[cfg(test)]
mod tests {
    use std::env;
    use cargo_edit::Dependency;
    use super::*;

    #[test]
    fn test_dependency_parsing() {
        let args = Args {
            arg_crate: "demo".to_owned(),
            flag_vers: Some("0.4.2".to_owned()),
            ..Args::default()
        };

        assert_eq!(args.parse_dependencies().unwrap(),
                   vec![Dependency::new("demo").set_version("0.4.2")]);
    }

    #[test]
    fn test_repo_as_arg_parsing() {
        // Skip remote tests if no network available
        if env::var("NO_REMOTE_CARGO_TEST").is_err() {
            let github_url = "https://github.com/killercup/cargo-edit/";
            let args_github = Args { arg_crate: github_url.to_owned(), ..Args::default() };
            assert_eq!(args_github.parse_dependencies().unwrap(),
                       vec![Dependency::new("cargo-edit").set_git(github_url)]);

            let gitlab_url = "https://gitlab.com/Polly-lang/Polly.git";
            let args_gitlab = Args { arg_crate: gitlab_url.to_owned(), ..Args::default() };
            assert_eq!(args_gitlab.parse_dependencies().unwrap(),
                       vec![Dependency::new("polly").set_git(gitlab_url)]);
        }
    }

    #[test]
    fn test_path_as_arg_parsing() {
        let self_path = ".";
        let args_path = Args { arg_crate: self_path.to_owned(), ..Args::default() };
        assert_eq!(args_path.parse_dependencies().unwrap(),
                   vec![Dependency::new("cargo-edit").set_path(self_path)]);
    }

}
<|endoftext|>