<commit_before>use std::{env,
          ffi::OsString,
          fs as stdfs,
          path::{Path,
                 PathBuf}};

use crate::{common::ui::UI,
            hcore::{crypto::CACHE_KEY_PATH_ENV_VAR,
                    env as henv,
                    fs}};

use crate::{config,
            error::{Error,
                    Result},
            BLDR_URL_ENVVAR,
            CTL_SECRET_ENVVAR,
            ORIGIN_ENVVAR};

use habitat_core::AUTH_TOKEN_ENVVAR;
use same_file::is_same_file;

pub const ARTIFACT_PATH_ENVVAR: &str = "ARTIFACT_PATH";
pub const CERT_PATH_ENVVAR: &str = "CERT_PATH";
pub const SSL_CERT_FILE_ENVVAR: &str = "SSL_CERT_FILE";

const STUDIO_CMD: &str = "hab-studio";
const STUDIO_CMD_ENVVAR: &str = "HAB_STUDIO_BINARY";
const STUDIO_PACKAGE_IDENT: &str = "core/hab-studio";

#[derive(Clone, Copy)]
enum Sensitivity {
    PrintValue,
    NoPrintValue,
}

fn set_env_var_from_config(env_var: &str, config_val: Option<String>, sensitive: Sensitivity) {
    if henv::var(env_var).is_err() {
        if let Some(val) = config_val {
            match sensitive {
                Sensitivity::NoPrintValue => {
                    debug!("Setting {}=REDACTED (sensitive) via config file", env_var)
                }
                Sensitivity::PrintValue => debug!("Setting {}={} via config file", env_var, val),
            }
            env::set_var(env_var, val);
        }
    }
}

fn cache_ssl_cert_file(cert_file: &str, cert_cache_dir: &Path) -> Result<()> {
    let cert_path = Path::new(&cert_file);

    let cert_filename = match cert_path.file_name() {
        Some(cert_filename) => cert_filename,
        None => return Err(Error::CacheSslCertError(format!("{:?} is not a file", &cert_file))),
    };
    let cache_file = cert_cache_dir.join(&cert_filename);

    if cache_file.exists() && cert_path.exists() && is_same_file(&cache_file, &cert_path)? {
        return Err(Error::CacheSslCertError("Source and destination certificate are the same \
                                             file"
                                                  .to_string()));
    }

    debug!("Caching SSL_CERT_FILE {:?} => {:?}", cert_file, cache_file);
    stdfs::copy(cert_file, &cache_file)?;

    Ok(())
}

pub fn start(ui: &mut UI, args: &[OsString]) -> Result<()> {
    let config = config::load()?;

    set_env_var_from_config(AUTH_TOKEN_ENVVAR,
                            config.auth_token,
                            Sensitivity::NoPrintValue);
    set_env_var_from_config(BLDR_URL_ENVVAR, config.bldr_url, Sensitivity::PrintValue);
    set_env_var_from_config(CTL_SECRET_ENVVAR,
                            config.ctl_secret,
                            Sensitivity::NoPrintValue);
    set_env_var_from_config(ORIGIN_ENVVAR, config.origin, Sensitivity::PrintValue);

    if henv::var(CACHE_KEY_PATH_ENV_VAR).is_err() {
        let path = fs::cache_key_path(None::<&str>);
        debug!("Setting {}={}", CACHE_KEY_PATH_ENV_VAR, path.display());
        env::set_var(CACHE_KEY_PATH_ENV_VAR, &path);
    };

    let artifact_path = match henv::var(ARTIFACT_PATH_ENVVAR) {
        Ok(p) => PathBuf::from(p),
        Err(_) => {
            let path = fs::cache_artifact_path(None::<&str>);
            debug!("Setting {}={}", ARTIFACT_PATH_ENVVAR, path.display());
            env::set_var(ARTIFACT_PATH_ENVVAR, &path);
            path
        }
    };
    if !artifact_path.is_dir() {
        debug!("Creating artifact_path at: {}", artifact_path.display());
        stdfs::create_dir_all(&artifact_path)?;
    }

    let ssl_path = match henv::var(CERT_PATH_ENVVAR) {
        Ok(p) => PathBuf::from(p),
        Err(_) => {
            let path = fs::cache_ssl_path(None::<&str>);
            debug!("Setting {}={}", CERT_PATH_ENVVAR, path.display());
            env::set_var(CERT_PATH_ENVVAR, &path);
            path
        }
    };
    if !ssl_path.is_dir() {
        debug!("Creating ssl_path at: {}", ssl_path.display());
        stdfs::create_dir_all(&ssl_path)?;
    }

    if let Ok(ssl_cert_file) = env::var(SSL_CERT_FILE_ENVVAR) {
        if let Err(err) = cache_ssl_cert_file(&ssl_cert_file, &ssl_path) {
            warn!("Unable to cache SSL_CERT_FILE: {}", err);
        }
    }

    inner::start(ui, args)
}

#[cfg(target_os = "linux")]
mod inner {
    use crate::{command::studio::docker,
                common::ui::{UIWriter,
                             UI},
                error::{Error,
                        Result},
                exec,
                hcore::{crypto::init,
                        env as henv,
                        fs::{am_i_root,
                             find_command},
                        os::process,
                        package::{PackageIdent,
                                  PackageInstall},
                        users::linux as group},
                VERSION};
    use std::{env,
              ffi::OsString,
              path::PathBuf,
              str::FromStr};

    const SUDO_CMD: &str = "sudo";

    pub fn start(ui: &mut UI, args: &[OsString]) -> Result<()> {
        rerun_with_sudo_if_needed(ui, &args)?;
        if is_docker_studio(&args) {
            docker::start_docker_studio(ui, args)
        } else {
            let command = match henv::var(super::STUDIO_CMD_ENVVAR) {
                Ok(command) => PathBuf::from(command),
                Err(_) => {
                    init();
                    let version: Vec<&str> = VERSION.split('/').collect();
                    let ident = PackageIdent::from_str(&format!("{}/{}",
                                                                super::STUDIO_PACKAGE_IDENT,
                                                                version[0]))?;
                    let command = exec::command_from_min_pkg(ui, super::STUDIO_CMD, &ident)?;
                    // This is a duplicate of the code in `hab pkg exec` and
                    // should be refactored as part of or after:
                    // https://github.com/habitat-sh/habitat/issues/6633
                    // https://github.com/habitat-sh/habitat/issues/6634
                    let pkg_install = PackageInstall::load(&ident, None)?;
                    let cmd_env = pkg_install.environment_for_command()?;
                    for (key, value) in cmd_env.into_iter() {
                        debug!("Setting: {}='{}'", key, value);
                        env::set_var(key, value);
                    }

                    let mut display_args = super::STUDIO_CMD.to_string();
                    for arg in args {
                        display_args.push(' ');
                        display_args.push_str(arg.to_string_lossy().as_ref());
                    }
                    debug!("Running: {}", display_args);

                    command
                }
            };

            if let Some(cmd) = find_command(command.to_string_lossy().as_ref()) {
                process::become_command(cmd, args)?;
                Ok(())
            } else {
                Err(Error::ExecCommandNotFound(command))
            }
        }
    }

    fn is_docker_studio(args: &[OsString]) -> bool {
        if cfg!(not(target_os = "linux")) {
            return false;
        }

        for arg in args.iter() {
            let str_arg = arg.to_string_lossy();
            if str_arg == "-D" {
                return true;
            }
        }

        false
    }

    fn has_docker_group() -> bool {
        let current_user = group::get_current_username().unwrap();
        let docker_members = group::get_members_by_groupname("docker");
        docker_members.map_or(false, |d| d.contains(&current_user))
    }

    fn rerun_with_sudo_if_needed(ui: &mut UI, args: &[OsString]) -> Result<()> {
        // If I have root permissions or if I am executing a docker studio
        // and have the appropriate group - early return, we are done.
        if am_i_root() || (is_docker_studio(args) && has_docker_group()) {
            return Ok(());
        }

        // Otherwise we will try to re-run this program using `sudo`
        match find_command(SUDO_CMD) {
            Some(sudo_prog) => {
                let mut args: Vec<OsString> = vec!["-p".into(),
                                                   "[sudo hab-studio] password for %u: ".into(),
                                                   "-E".into(),];
                args.append(&mut env::args_os().collect());
                process::become_command(sudo_prog, &args)?;
                Ok(())
            }
            None => {
                ui.warn(format!("Could not find the `{}' command, is it in your PATH?",
                                SUDO_CMD))?;
                ui.warn("Running Habitat Studio requires root or administrator privileges. \
                         Please retry this command as a super user or use a privilege-granting \
                         facility such as sudo.")?;
                ui.br()?;
                Err(Error::RootRequired)
            }
        }
    }
}

#[cfg(not(target_os = "linux"))]
mod inner {
    use crate::{command::studio::docker,
                common::ui::UI,
                error::{Error,
                        Result},
                exec,
                hcore::{crypto::init,
                        env as henv,
                        fs::find_command,
                        os::process,
                        package::PackageIdent},
                VERSION};
    use std::{ffi::OsString,
              path::PathBuf,
              str::FromStr};

    pub fn start(_ui: &mut UI, args: &[OsString]) -> Result<()> {
        if is_windows_studio(&args) {
            start_windows_studio(_ui, args)
        } else {
            docker::start_docker_studio(_ui, args)
        }
    }

    pub fn start_windows_studio(ui: &mut UI, args: &[OsString]) -> Result<()> {
        let command = match henv::var(super::STUDIO_CMD_ENVVAR) {
            Ok(command) => PathBuf::from(command),
            Err(_) => {
                init();
                let version: Vec<&str> = VERSION.split('/').collect();
                let ident = PackageIdent::from_str(&format!("{}/{}",
                                                            super::STUDIO_PACKAGE_IDENT,
                                                            version[0]))?;
                exec::command_from_min_pkg(ui, super::STUDIO_CMD, &ident)?
            }
        };

        if let Some(cmd) = find_command(command.to_string_lossy().as_ref()) {
            process::become_command(cmd, args)?;
        } else {
            return Err(Error::ExecCommandNotFound(command));
        }
        Ok(())
    }

    fn is_windows_studio(args: &[OsString]) -> bool {
        if cfg!(not(target_os = "windows")) {
            return false;
        }

        for arg in args.iter() {
            let str_arg = arg.to_string_lossy();
            if str_arg == "-D" {
                return false;
            }
        }

        true
    }
}

#[cfg(test)]
mod tests {
    use super::cache_ssl_cert_file;
    use std::fs::File;
    use tempfile::TempDir;

    #[test]
    fn cache_ssl_cert_file_caches_file() -> std::io::Result<()> {
        let cert_name = "ssl-test-cert.pem";
        let cert_cache_dir = TempDir::new()?.into_path();
        let ssl_cert_dir = TempDir::new()?;
        let ssl_cert_filepath = ssl_cert_dir.path().join(cert_name);
        File::create(&ssl_cert_filepath)?;

        cache_ssl_cert_file(&ssl_cert_filepath.to_str().unwrap(), &cert_cache_dir).unwrap();
        assert!(cert_cache_dir.join(cert_name).exists());

        Ok(())
    }

    #[test]
    fn cache_ssl_cert_file_replaces_already_cached() -> std::io::Result<()> {
        let cert_name = "ssl-test-cert.pem";

        let cert_cache_dir = TempDir::new()?.into_path();
        let cached_cert = cert_cache_dir.join(&cert_name);
        File::create(&cached_cert)?;

        let ssl_cert_dir = TempDir::new()?;
        let ssl_cert_filepath = ssl_cert_dir.path().join(&cert_name);
        std::fs::write(&ssl_cert_filepath, "new cert from environment")?;

        cache_ssl_cert_file(&ssl_cert_filepath.to_str().unwrap(), &cert_cache_dir).unwrap();

        let contents = std::fs::read_to_string(&cached_cert)?;

        assert_eq!(contents, "new cert from environment");

        Ok(())
    }
    #[test]
    fn cache_ssl_cert_file_invalid_file() -> std::io::Result<()> {
        let cert_cache_dir = TempDir::new()?.into_path();

        let non_existant_file_name = "i_shouldnt_exist";
        let non_existant_file = TempDir::new()?.path().join(non_existant_file_name);

        assert!(cache_ssl_cert_file(non_existant_file.to_str().unwrap(), &cert_cache_dir).is_err());

        Ok(())
    }

    #[test]
    fn cache_ssl_cert_file_cert_file_is_dir() -> std::io::Result<()> {
        let cert_cache_dir = TempDir::new()?.into_path();
        let ssl_cert_dir = TempDir::new()?.into_path();

        assert!(cache_ssl_cert_file(ssl_cert_dir.to_str().unwrap(), &cert_cache_dir).is_err());

        Ok(())
    }

    #[test]
    fn cache_ssl_cert_file_cert_file_is_cached_file() -> std::io::Result<()> {
        let cached_cert_dir = TempDir::new()?.into_path();
        let cached_cert = cached_cert_dir.join("ssl-cert-file.pem");
        File::create(&cached_cert)?;

        assert!(cache_ssl_cert_file(cached_cert.to_str().unwrap(), &cached_cert_dir).is_err());

        Ok(())
    }

    #[test]
    fn cache_ssl_cert_file_is_empty_string() -> std::io::Result<()> {
        let cached_cert_dir = TempDir::new()?.into_path();

        assert!(cache_ssl_cert_file("", &cached_cert_dir).is_err());

        Ok(())
    }
}
<commit_msg>do not inject studio environment with ctl_secret from cli.toml<commit_after>use std::{env,
          ffi::OsString,
          fs as stdfs,
          path::{Path,
                 PathBuf}};

use crate::{common::ui::{UIWriter,
                         UI},
            hcore::{crypto::CACHE_KEY_PATH_ENV_VAR,
                    env as henv,
                    fs}};

use crate::{config,
            error::{Error,
                    Result},
            BLDR_URL_ENVVAR,
            ORIGIN_ENVVAR};

use habitat_core::AUTH_TOKEN_ENVVAR;
use same_file::is_same_file;

pub const ARTIFACT_PATH_ENVVAR: &str = "ARTIFACT_PATH";
pub const CERT_PATH_ENVVAR: &str = "CERT_PATH";
pub const SSL_CERT_FILE_ENVVAR: &str = "SSL_CERT_FILE";

const STUDIO_CMD: &str = "hab-studio";
const STUDIO_CMD_ENVVAR: &str = "HAB_STUDIO_BINARY";
const STUDIO_PACKAGE_IDENT: &str = "core/hab-studio";

#[derive(Clone, Copy)]
enum Sensitivity {
    PrintValue,
    NoPrintValue,
}

fn set_env_var_from_config(env_var: &str, config_val: Option<String>, sensitive: Sensitivity) {
    if henv::var(env_var).is_err() {
        if let Some(val) = config_val {
            match sensitive {
                Sensitivity::NoPrintValue => {
                    debug!("Setting {}=REDACTED (sensitive) via config file", env_var)
                }
                Sensitivity::PrintValue => debug!("Setting {}={} via config file", env_var, val),
            }
            env::set_var(env_var, val);
        }
    }
}

fn cache_ssl_cert_file(cert_file: &str, cert_cache_dir: &Path) -> Result<()> {
    let cert_path = Path::new(&cert_file);

    let cert_filename = match cert_path.file_name() {
        Some(cert_filename) => cert_filename,
        None => return Err(Error::CacheSslCertError(format!("{:?} is not a file", &cert_file))),
    };
    let cache_file = cert_cache_dir.join(&cert_filename);

    if cache_file.exists() && cert_path.exists() && is_same_file(&cache_file, &cert_path)? {
        return Err(Error::CacheSslCertError("Source and destination certificate are the same \
                                             file"
                                                  .to_string()));
    }

    debug!("Caching SSL_CERT_FILE {:?} => {:?}", cert_file, cache_file);
    stdfs::copy(cert_file, &cache_file)?;

    Ok(())
}

pub fn start(ui: &mut UI, args: &[OsString]) -> Result<()> {
    let config = config::load()?;

    set_env_var_from_config(AUTH_TOKEN_ENVVAR,
                            config.auth_token,
                            Sensitivity::NoPrintValue);
    set_env_var_from_config(BLDR_URL_ENVVAR, config.bldr_url, Sensitivity::PrintValue);
    set_env_var_from_config(ORIGIN_ENVVAR, config.origin, Sensitivity::PrintValue);

    if config.ctl_secret.is_some() {
        ui.warn("Your Supervisor CtlGateway secret is not being copied to the Studio \
                 environment because the Studio's Supervisor is local. If you wish to contact a \
                 remote Supervisor from the Studio, please set the HAB_CTL_SECRET variable with \
                 your secret.")?;
    }

    if henv::var(CACHE_KEY_PATH_ENV_VAR).is_err() {
        let path = fs::cache_key_path(None::<&str>);
        debug!("Setting {}={}", CACHE_KEY_PATH_ENV_VAR, path.display());
        env::set_var(CACHE_KEY_PATH_ENV_VAR, &path);
    };

    let artifact_path = match henv::var(ARTIFACT_PATH_ENVVAR) {
        Ok(p) => PathBuf::from(p),
        Err(_) => {
            let path = fs::cache_artifact_path(None::<&str>);
            debug!("Setting {}={}", ARTIFACT_PATH_ENVVAR, path.display());
            env::set_var(ARTIFACT_PATH_ENVVAR, &path);
            path
        }
    };
    if !artifact_path.is_dir() {
        debug!("Creating artifact_path at: {}", artifact_path.display());
        stdfs::create_dir_all(&artifact_path)?;
    }

    let ssl_path = match henv::var(CERT_PATH_ENVVAR) {
        Ok(p) => PathBuf::from(p),
        Err(_) => {
            let path = fs::cache_ssl_path(None::<&str>);
            debug!("Setting {}={}", CERT_PATH_ENVVAR, path.display());
            env::set_var(CERT_PATH_ENVVAR, &path);
            path
        }
    };
    if !ssl_path.is_dir() {
        debug!("Creating ssl_path at: {}", ssl_path.display());
        stdfs::create_dir_all(&ssl_path)?;
    }

    if let Ok(ssl_cert_file) = env::var(SSL_CERT_FILE_ENVVAR) {
        if let Err(err) = cache_ssl_cert_file(&ssl_cert_file, &ssl_path) {
            warn!("Unable to cache SSL_CERT_FILE: {}", err);
        }
    }

    inner::start(ui, args)
}

#[cfg(target_os = "linux")]
mod inner {
    use crate::{command::studio::docker,
                common::ui::{UIWriter,
                             UI},
                error::{Error,
                        Result},
                exec,
                hcore::{crypto::init,
                        env as henv,
                        fs::{am_i_root,
                             find_command},
                        os::process,
                        package::{PackageIdent,
                                  PackageInstall},
                        users::linux as group},
                VERSION};
    use std::{env,
              ffi::OsString,
              path::PathBuf,
              str::FromStr};

    const SUDO_CMD: &str = "sudo";

    pub fn start(ui: &mut UI, args: &[OsString]) -> Result<()> {
        rerun_with_sudo_if_needed(ui, &args)?;
        if is_docker_studio(&args) {
            docker::start_docker_studio(ui, args)
        } else {
            let command = match henv::var(super::STUDIO_CMD_ENVVAR) {
                Ok(command) => PathBuf::from(command),
                Err(_) => {
                    init();
                    let version: Vec<&str> = VERSION.split('/').collect();
                    let ident = PackageIdent::from_str(&format!("{}/{}",
                                                                super::STUDIO_PACKAGE_IDENT,
                                                                version[0]))?;
                    let command = exec::command_from_min_pkg(ui, super::STUDIO_CMD, &ident)?;
                    // This is a duplicate of the code in `hab pkg exec` and
                    // should be refactored as part of or after:
                    // https://github.com/habitat-sh/habitat/issues/6633
                    // https://github.com/habitat-sh/habitat/issues/6634
                    let pkg_install = PackageInstall::load(&ident, None)?;
                    let cmd_env = pkg_install.environment_for_command()?;
                    for (key, value) in cmd_env.into_iter() {
                        debug!("Setting: {}='{}'", key, value);
                        env::set_var(key, value);
                    }

                    let mut display_args = super::STUDIO_CMD.to_string();
                    for arg in args {
                        display_args.push(' ');
                        display_args.push_str(arg.to_string_lossy().as_ref());
                    }
                    debug!("Running: {}", display_args);

                    command
                }
            };

            if let Some(cmd) = find_command(command.to_string_lossy().as_ref()) {
                process::become_command(cmd, args)?;
                Ok(())
            } else {
                Err(Error::ExecCommandNotFound(command))
            }
        }
    }

    fn is_docker_studio(args: &[OsString]) -> bool {
        if cfg!(not(target_os = "linux")) {
            return false;
        }

        for arg in args.iter() {
            let str_arg = arg.to_string_lossy();
            if str_arg == "-D" {
                return true;
            }
        }

        false
    }

    fn has_docker_group() -> bool {
        let current_user = group::get_current_username().unwrap();
        let docker_members = group::get_members_by_groupname("docker");
        docker_members.map_or(false, |d| d.contains(&current_user))
    }

    fn rerun_with_sudo_if_needed(ui: &mut UI, args: &[OsString]) -> Result<()> {
        // If I have root permissions or if I am executing a docker studio
        // and have the appropriate group - early return, we are done.
        if am_i_root() || (is_docker_studio(args) && has_docker_group()) {
            return Ok(());
        }

        // Otherwise we will try to re-run this program using `sudo`
        match find_command(SUDO_CMD) {
            Some(sudo_prog) => {
                let mut args: Vec<OsString> = vec!["-p".into(),
                                                   "[sudo hab-studio] password for %u: ".into(),
                                                   "-E".into(),];
                args.append(&mut env::args_os().collect());
                process::become_command(sudo_prog, &args)?;
                Ok(())
            }
            None => {
                ui.warn(format!("Could not find the `{}' command, is it in your PATH?",
                                SUDO_CMD))?;
                ui.warn("Running Habitat Studio requires root or administrator privileges. \
                         Please retry this command as a super user or use a privilege-granting \
                         facility such as sudo.")?;
                ui.br()?;
                Err(Error::RootRequired)
            }
        }
    }
}

#[cfg(not(target_os = "linux"))]
mod inner {
    use crate::{command::studio::docker,
                common::ui::UI,
                error::{Error,
                        Result},
                exec,
                hcore::{crypto::init,
                        env as henv,
                        fs::find_command,
                        os::process,
                        package::PackageIdent},
                VERSION};
    use std::{ffi::OsString,
              path::PathBuf,
              str::FromStr};

    pub fn start(_ui: &mut UI, args: &[OsString]) -> Result<()> {
        if is_windows_studio(&args) {
            start_windows_studio(_ui, args)
        } else {
            docker::start_docker_studio(_ui, args)
        }
    }

    pub fn start_windows_studio(ui: &mut UI, args: &[OsString]) -> Result<()> {
        let command = match henv::var(super::STUDIO_CMD_ENVVAR) {
            Ok(command) => PathBuf::from(command),
            Err(_) => {
                init();
                let version: Vec<&str> = VERSION.split('/').collect();
                let ident = PackageIdent::from_str(&format!("{}/{}",
                                                            super::STUDIO_PACKAGE_IDENT,
                                                            version[0]))?;
                exec::command_from_min_pkg(ui, super::STUDIO_CMD, &ident)?
            }
        };

        if let Some(cmd) = find_command(command.to_string_lossy().as_ref()) {
            process::become_command(cmd, args)?;
        } else {
            return Err(Error::ExecCommandNotFound(command));
        }
        Ok(())
    }

    fn is_windows_studio(args: &[OsString]) -> bool {
        if cfg!(not(target_os = "windows")) {
            return false;
        }

        for arg in args.iter() {
            let str_arg = arg.to_string_lossy();
            if str_arg == "-D" {
                return false;
            }
        }

        true
    }
}

#[cfg(test)]
mod tests {
    use super::cache_ssl_cert_file;
    use std::fs::File;
    use tempfile::TempDir;

    #[test]
    fn cache_ssl_cert_file_caches_file() -> std::io::Result<()> {
        let cert_name = "ssl-test-cert.pem";
        let cert_cache_dir = TempDir::new()?.into_path();
        let ssl_cert_dir = TempDir::new()?;
        let ssl_cert_filepath = ssl_cert_dir.path().join(cert_name);
        File::create(&ssl_cert_filepath)?;

        cache_ssl_cert_file(&ssl_cert_filepath.to_str().unwrap(), &cert_cache_dir).unwrap();
        assert!(cert_cache_dir.join(cert_name).exists());

        Ok(())
    }

    #[test]
    fn cache_ssl_cert_file_replaces_already_cached() -> std::io::Result<()> {
        let cert_name = "ssl-test-cert.pem";

        let cert_cache_dir = TempDir::new()?.into_path();
        let cached_cert = cert_cache_dir.join(&cert_name);
        File::create(&cached_cert)?;

        let ssl_cert_dir = TempDir::new()?;
        let ssl_cert_filepath = ssl_cert_dir.path().join(&cert_name);
        std::fs::write(&ssl_cert_filepath, "new cert from environment")?;

        cache_ssl_cert_file(&ssl_cert_filepath.to_str().unwrap(), &cert_cache_dir).unwrap();

        let contents = std::fs::read_to_string(&cached_cert)?;

        assert_eq!(contents, "new cert from environment");

        Ok(())
    }
    #[test]
    fn cache_ssl_cert_file_invalid_file() -> std::io::Result<()> {
        let cert_cache_dir = TempDir::new()?.into_path();

        let non_existant_file_name = "i_shouldnt_exist";
        let non_existant_file = TempDir::new()?.path().join(non_existant_file_name);

        assert!(cache_ssl_cert_file(non_existant_file.to_str().unwrap(), &cert_cache_dir).is_err());

        Ok(())
    }

    #[test]
    fn cache_ssl_cert_file_cert_file_is_dir() -> std::io::Result<()> {
        let cert_cache_dir = TempDir::new()?.into_path();
        let ssl_cert_dir = TempDir::new()?.into_path();

        assert!(cache_ssl_cert_file(ssl_cert_dir.to_str().unwrap(), &cert_cache_dir).is_err());

        Ok(())
    }

    #[test]
    fn cache_ssl_cert_file_cert_file_is_cached_file() -> std::io::Result<()> {
        let cached_cert_dir = TempDir::new()?.into_path();
        let cached_cert = cached_cert_dir.join("ssl-cert-file.pem");
        File::create(&cached_cert)?;

        assert!(cache_ssl_cert_file(cached_cert.to_str().unwrap(), &cached_cert_dir).is_err());

        Ok(())
    }

    #[test]
    fn cache_ssl_cert_file_is_empty_string() -> std::io::Result<()> {
        let cached_cert_dir = TempDir::new()?.into_path();

        assert!(cache_ssl_cert_file("", &cached_cert_dir).is_err());

        Ok(())
    }
}
<|endoftext|>


<commit_before>static START_ADDR: u16 = 0x200;
static MEM_SIZE: uint = 4096;
pub static DISPLAY_WIDTH: uint = 64;
pub static DISPLAY_HEIGHT: uint = 32;

static fontset: [[u8, .. 5], .. 0x10] = [
    [0xF0, 0x90, 0x90, 0x90, 0xF0], // 0
    [0x20, 0x60, 0x20, 0x20, 0x70], // 1
    [0xF0, 0x10, 0xF0, 0x80, 0xF0], // 2
    [0xF0, 0x10, 0xF0, 0x10, 0xF0], // 3
    [0x90, 0x90, 0xF0, 0x10, 0x10], // 4
    [0xF0, 0x80, 0xF0, 0x10, 0xF0], // 5
    [0xF0, 0x80, 0xF0, 0x90, 0xF0], // 6
    [0xF0, 0x10, 0x20, 0x40, 0x40], // 7
    [0xF0, 0x90, 0xF0, 0x90, 0xF0], // 8
    [0xF0, 0x90, 0xF0, 0x10, 0xF0], // 9
    [0xF0, 0x90, 0xF0, 0x90, 0x90], // A
    [0xE0, 0x90, 0xE0, 0x90, 0xE0], // B
    [0xF0, 0x80, 0x80, 0x80, 0xF0], // C
    [0xE0, 0x90, 0x90, 0x90, 0xE0], // D
    [0xF0, 0x80, 0xF0, 0x80, 0xF0], // E
    [0xF0, 0x80, 0xF0, 0x80, 0x80], // F
];

pub struct Chip8 {
    ram: [u8, .. MEM_SIZE],
    v: [u8, .. 16],
    i: u16,
    delay_timer: u8,
    sound_timer: u8,
    pc: u16,
    sp: u8,
    stack: [u16, .. 16],
    display: [u8, .. DISPLAY_WIDTH * DISPLAY_HEIGHT]
}

impl Chip8 {
    pub fn new() -> Chip8 {
        Chip8 {
            ram: [0u8, .. MEM_SIZE],
            v: [0u8, .. 16],
            i: 0u16,
            delay_timer: 0u8,
            sound_timer: 0u8,
            pc: START_ADDR,
            sp: 0,
            stack: [0u16, .. 16],
            display: [0u8, .. DISPLAY_WIDTH * DISPLAY_HEIGHT]
        }
    }

    pub fn load_rom(&mut self, rom: &[u8]) {
        use std::slice::bytes::copy_memory;
        let len = self.ram.len();
        copy_memory(self.ram.mut_slice(START_ADDR as uint, len), rom);
    }

    pub fn get_display(&self) -> [u8, .. DISPLAY_WIDTH * DISPLAY_HEIGHT] {
        self.display
    }

    pub fn do_cycle(&mut self) {
        let ins = self.get_ins();
        self.pc += 2;

        match ins & 0xF000 {
            0x1000 => self.jump_addr(ins & 0x0FFF),
            0x3000 => self.skip_next_vx_eq(((ins & 0x0F00) >> 8) as uint, (ins & 0x00FF) as u8),
            0x7000 => self.add_vx_byte(((ins & 0x0F00) >> 8) as uint, (ins & 0x00FF) as u8),
            0xA000 => self.set_i(ins & 0x0FFF),
            0xC000 => self.set_vx_rand_and(((ins & 0x0F00) >> 8) as uint, (ins & 0x00FF) as u8),
            0xD000 => self.display_sprite(((ins & 0x0F00) >> 8) as uint, ((ins & 0x00F0) >> 4) as uint, ((ins & 0x000F)) as uint),
            _ => fail!("Unkown instruction: {:x}", ins)
        }
    }

    fn get_ins(&self) -> u16 {
        let b1 = self.ram[self.pc as uint];
        let b2 = self.ram[(self.pc + 1) as uint];
        b1 as u16 << 8 | b2 as u16
    }

    fn set_i(&mut self, to: u16) {
        self.i = to;
    }

    fn set_vx_rand_and(&mut self, x: uint, to: u8) {
        use std::rand::{task_rng, Rng};
        let mut rgen = task_rng();
        self.v[x] = rgen.gen::<u8>() & to;
    }

    fn skip_next_vx_eq(&mut self, x: uint, to: u8) {
        if self.v[x] == to {
            self.pc += 2;
        }
    }

    fn display_sprite(&mut self, vx: uint, vy: uint, n: uint) {
        let offset = self.v[vx] as uint + (self.v[vy] as uint * DISPLAY_WIDTH);
        println!("n={}", n);

        for y in range(0u, n) {
            let b = self.ram[self.i as uint + y];
            for x in range(0u, 8) {
                self.display[offset + (y * DISPLAY_WIDTH) + x] ^= b & (0b10000000 >> x);
            }
        }
    }

    fn add_vx_byte(&mut self, x: uint, byte: u8) {
        self.v[x] = byte;
    }

    fn jump_addr(&mut self, addr: u16) {
        self.pc = addr;
    }
}
<commit_msg>Fix add_vx_byte<commit_after>static START_ADDR: u16 = 0x200;
static MEM_SIZE: uint = 4096;
pub static DISPLAY_WIDTH: uint = 64;
pub static DISPLAY_HEIGHT: uint = 32;

static fontset: [[u8, .. 5], .. 0x10] = [
    [0xF0, 0x90, 0x90, 0x90, 0xF0], // 0
    [0x20, 0x60, 0x20, 0x20, 0x70], // 1
    [0xF0, 0x10, 0xF0, 0x80, 0xF0], // 2
    [0xF0, 0x10, 0xF0, 0x10, 0xF0], // 3
    [0x90, 0x90, 0xF0, 0x10, 0x10], // 4
    [0xF0, 0x80, 0xF0, 0x10, 0xF0], // 5
    [0xF0, 0x80, 0xF0, 0x90, 0xF0], // 6
    [0xF0, 0x10, 0x20, 0x40, 0x40], // 7
    [0xF0, 0x90, 0xF0, 0x90, 0xF0], // 8
    [0xF0, 0x90, 0xF0, 0x10, 0xF0], // 9
    [0xF0, 0x90, 0xF0, 0x90, 0x90], // A
    [0xE0, 0x90, 0xE0, 0x90, 0xE0], // B
    [0xF0, 0x80, 0x80, 0x80, 0xF0], // C
    [0xE0, 0x90, 0x90, 0x90, 0xE0], // D
    [0xF0, 0x80, 0xF0, 0x80, 0xF0], // E
    [0xF0, 0x80, 0xF0, 0x80, 0x80], // F
];

pub struct Chip8 {
    ram: [u8, .. MEM_SIZE],
    v: [u8, .. 16],
    i: u16,
    delay_timer: u8,
    sound_timer: u8,
    pc: u16,
    sp: u8,
    stack: [u16, .. 16],
    display: [u8, .. DISPLAY_WIDTH * DISPLAY_HEIGHT]
}

impl Chip8 {
    pub fn new() -> Chip8 {
        Chip8 {
            ram: [0u8, .. MEM_SIZE],
            v: [0u8, .. 16],
            i: 0u16,
            delay_timer: 0u8,
            sound_timer: 0u8,
            pc: START_ADDR,
            sp: 0,
            stack: [0u16, .. 16],
            display: [0u8, .. DISPLAY_WIDTH * DISPLAY_HEIGHT]
        }
    }

    pub fn load_rom(&mut self, rom: &[u8]) {
        use std::slice::bytes::copy_memory;
        let len = self.ram.len();
        copy_memory(self.ram.mut_slice(START_ADDR as uint, len), rom);
    }

    pub fn get_display(&self) -> [u8, .. DISPLAY_WIDTH * DISPLAY_HEIGHT] {
        self.display
    }

    pub fn do_cycle(&mut self) {
        let ins = self.get_ins();
        self.pc += 2;

        match ins & 0xF000 {
            0x1000 => self.jump_addr(ins & 0x0FFF),
            0x3000 => self.skip_next_vx_eq(((ins & 0x0F00) >> 8) as uint, (ins & 0x00FF) as u8),
            0x7000 => self.add_vx_byte(((ins & 0x0F00) >> 8) as uint, (ins & 0x00FF) as u8),
            0xA000 => self.set_i(ins & 0x0FFF),
            0xC000 => self.set_vx_rand_and(((ins & 0x0F00) >> 8) as uint, (ins & 0x00FF) as u8),
            0xD000 => self.display_sprite(((ins & 0x0F00) >> 8) as uint, ((ins & 0x00F0) >> 4) as uint, ((ins & 0x000F)) as uint),
            _ => fail!("Unkown instruction: {:x}", ins)
        }
    }

    fn get_ins(&self) -> u16 {
        let b1 = self.ram[self.pc as uint];
        let b2 = self.ram[(self.pc + 1) as uint];
        b1 as u16 << 8 | b2 as u16
    }

    fn set_i(&mut self, to: u16) {
        self.i = to;
    }

    fn set_vx_rand_and(&mut self, x: uint, to: u8) {
        use std::rand::{task_rng, Rng};
        let mut rgen = task_rng();
        self.v[x] = rgen.gen::<u8>() & to;
    }

    fn skip_next_vx_eq(&mut self, x: uint, to: u8) {
        if self.v[x] == to {
            self.pc += 2;
        }
    }

    fn display_sprite(&mut self, vx: uint, vy: uint, n: uint) {
        let offset = self.v[vx] as uint + (self.v[vy] as uint * DISPLAY_WIDTH);
        println!("n={}", n);

        for y in range(0u, n) {
            let b = self.ram[self.i as uint + y];
            for x in range(0u, 8) {
                self.display[offset + (y * DISPLAY_WIDTH) + x] ^= b & (0b10000000 >> x);
            }
        }
    }

    fn add_vx_byte(&mut self, x: uint, byte: u8) {
        self.v[x] += byte;
    }

    fn jump_addr(&mut self, addr: u16) {
        self.pc = addr;
    }
}
<|endoftext|>


<commit_before>#[cfg(test)]
use ::{card, deck, hand};

#[test]
fn create_hand() {
    let mut deck = deck::Deck::new();
    let mut cards: Vec<card::Card> = vec![];
    for _i in 0..5 {
        cards.push(deck.draw().unwrap());
    }
    let hand = hand::Hand::new(cards);

    assert_eq!(hand.cards.len(), 5);
}

#[test]
fn has_flush() {
    let a = card::Card::new(card::Rank::Three, card::Suit::Hearts);
    let b = card::Card::new(card::Rank::Six, card::Suit::Hearts);
    let c = card::Card::new(card::Rank::Ten, card::Suit::Hearts);
    let d = card::Card::new(card::Rank::Queen, card::Suit::Hearts);
    let e = card::Card::new(card::Rank::Two, card::Suit::Hearts);
    let cards: Vec<card::Card> = vec![a, b, c, d, e];
    let hand: hand::Hand = hand::Hand::new(cards);

    assert_eq!(hand.has_flush(), true);
}

#[test]
fn no_flush() {
    let a = card::Card::new(card::Rank::Three, card::Suit::Hearts);
    let b = card::Card::new(card::Rank::Six, card::Suit::Spades);
    let c = card::Card::new(card::Rank::Ten, card::Suit::Hearts);
    let d = card::Card::new(card::Rank::Queen, card::Suit::Hearts);
    let e = card::Card::new(card::Rank::Two, card::Suit::Hearts);
    let cards: Vec<card::Card> = vec![a, b, c, d, e];
    let hand: hand::Hand = hand::Hand::new(cards);

    assert_eq!(hand.has_flush(), false);
}

#[test]
fn has_straight() {
    let a = card::Card::new(card::Rank::Three, card::Suit::Hearts);
    let b = card::Card::new(card::Rank::Six, card::Suit::Diamonds);
    let c = card::Card::new(card::Rank::Four, card::Suit::Hearts);
    let d = card::Card::new(card::Rank::Seven, card::Suit::Clubs);
    let e = card::Card::new(card::Rank::Five, card::Suit::Spades);
    let cards: Vec<card::Card> = vec![a, b, c, d, e];
    let hand: hand::Hand = hand::Hand::new(cards);

    assert_eq!(hand.has_straight(), true);
}

#[test]
fn has_ace_low_straight() {
    let a = card::Card::new(card::Rank::Three, card::Suit::Hearts);
    let b = card::Card::new(card::Rank::Two, card::Suit::Diamonds);
    let c = card::Card::new(card::Rank::Four, card::Suit::Hearts);
    let d = card::Card::new(card::Rank::Ace, card::Suit::Clubs);
    let e = card::Card::new(card::Rank::Five, card::Suit::Spades);
    let cards: Vec<card::Card> = vec![a, b, c, d, e];
    let hand: hand::Hand = hand::Hand::new(cards);

    assert_eq!(hand.has_straight(), true);
}

#[test]
fn no_straight() {
    let a = card::Card::new(card::Rank::Three, card::Suit::Hearts);
    let b = card::Card::new(card::Rank::Six, card::Suit::Diamonds);
    let c = card::Card::new(card::Rank::King, card::Suit::Hearts);
    let d = card::Card::new(card::Rank::Seven, card::Suit::Clubs);
    let e = card::Card::new(card::Rank::Five, card::Suit::Spades);
    let cards: Vec<card::Card> = vec![a, b, c, d, e];
    let hand: hand::Hand = hand::Hand::new(cards);

    assert_eq!(hand.has_straight(), false);
}

#[test]
fn has_pair() {
    let a = card::Card::new(card::Rank::Seven, card::Suit::Hearts);
    let b = card::Card::new(card::Rank::Six, card::Suit::Diamonds);
    let c = card::Card::new(card::Rank::King, card::Suit::Hearts);
    let d = card::Card::new(card::Rank::Seven, card::Suit::Clubs);
    let e = card::Card::new(card::Rank::Five, card::Suit::Spades);
    let cards: Vec<card::Card> = vec![a, b, c, d, e];
    let hand: hand::Hand = hand::Hand::new(cards);

    assert_eq!(hand.has_pair(), true);
}

#[test]
fn no_pair() {
    let a = card::Card::new(card::Rank::Three, card::Suit::Hearts);
    let b = card::Card::new(card::Rank::Six, card::Suit::Diamonds);
    let c = card::Card::new(card::Rank::King, card::Suit::Hearts);
    let d = card::Card::new(card::Rank::Seven, card::Suit::Clubs);
    let e = card::Card::new(card::Rank::Five, card::Suit::Spades);
    let cards: Vec<card::Card> = vec![a, b, c, d, e];
    let hand: hand::Hand = hand::Hand::new(cards);

    assert_eq!(hand.has_pair(), false);
}

#[test]
fn high_card_raw_value() {
    assert_eq!(hand::PokerRanking::HighCard as u32, 0);
}

#[test]
fn one_pair_raw_value() {
    assert_eq!(hand::PokerRanking::OnePair as u32, 1);
}

#[test]
fn two_pair_raw_value() {
    assert_eq!(hand::PokerRanking::TwoPair as u32, 2);
}

#[test]
fn trips_raw_value() {
    assert_eq!(hand::PokerRanking::Trips as u32, 3);
}

#[test]
fn straight_raw_value() {
    assert_eq!(hand::PokerRanking::Straight as u32, 4);
}

#[test]
fn flush_raw_value() {
    assert_eq!(hand::PokerRanking::Flush as u32, 5);
}

#[test]
fn full_house_raw_value() {
    assert_eq!(hand::PokerRanking::FullHouse as u32, 6);
}

#[test]
fn quads_raw_value() {
    assert_eq!(hand::PokerRanking::Quads as u32, 7);
}

#[test]
fn straight_flush_raw_value() {
    assert_eq!(hand::PokerRanking::StraightFlush as u32, 8);
}
<commit_msg>Added test to detect pair in set for has_pair()<commit_after>#[cfg(test)]
use ::{card, deck, hand};

#[test]
fn create_hand() {
    let mut deck = deck::Deck::new();
    let mut cards: Vec<card::Card> = vec![];
    for _i in 0..5 {
        cards.push(deck.draw().unwrap());
    }
    let hand = hand::Hand::new(cards);

    assert_eq!(hand.cards.len(), 5);
}

#[test]
fn has_flush() {
    let a = card::Card::new(card::Rank::Three, card::Suit::Hearts);
    let b = card::Card::new(card::Rank::Six, card::Suit::Hearts);
    let c = card::Card::new(card::Rank::Ten, card::Suit::Hearts);
    let d = card::Card::new(card::Rank::Queen, card::Suit::Hearts);
    let e = card::Card::new(card::Rank::Two, card::Suit::Hearts);
    let cards: Vec<card::Card> = vec![a, b, c, d, e];
    let hand: hand::Hand = hand::Hand::new(cards);

    assert_eq!(hand.has_flush(), true);
}

#[test]
fn no_flush() {
    let a = card::Card::new(card::Rank::Three, card::Suit::Hearts);
    let b = card::Card::new(card::Rank::Six, card::Suit::Spades);
    let c = card::Card::new(card::Rank::Ten, card::Suit::Hearts);
    let d = card::Card::new(card::Rank::Queen, card::Suit::Hearts);
    let e = card::Card::new(card::Rank::Two, card::Suit::Hearts);
    let cards: Vec<card::Card> = vec![a, b, c, d, e];
    let hand: hand::Hand = hand::Hand::new(cards);

    assert_eq!(hand.has_flush(), false);
}

#[test]
fn has_straight() {
    let a = card::Card::new(card::Rank::Three, card::Suit::Hearts);
    let b = card::Card::new(card::Rank::Six, card::Suit::Diamonds);
    let c = card::Card::new(card::Rank::Four, card::Suit::Hearts);
    let d = card::Card::new(card::Rank::Seven, card::Suit::Clubs);
    let e = card::Card::new(card::Rank::Five, card::Suit::Spades);
    let cards: Vec<card::Card> = vec![a, b, c, d, e];
    let hand: hand::Hand = hand::Hand::new(cards);

    assert_eq!(hand.has_straight(), true);
}

#[test]
fn has_ace_low_straight() {
    let a = card::Card::new(card::Rank::Three, card::Suit::Hearts);
    let b = card::Card::new(card::Rank::Two, card::Suit::Diamonds);
    let c = card::Card::new(card::Rank::Four, card::Suit::Hearts);
    let d = card::Card::new(card::Rank::Ace, card::Suit::Clubs);
    let e = card::Card::new(card::Rank::Five, card::Suit::Spades);
    let cards: Vec<card::Card> = vec![a, b, c, d, e];
    let hand: hand::Hand = hand::Hand::new(cards);

    assert_eq!(hand.has_straight(), true);
}

#[test]
fn no_straight() {
    let a = card::Card::new(card::Rank::Three, card::Suit::Hearts);
    let b = card::Card::new(card::Rank::Six, card::Suit::Diamonds);
    let c = card::Card::new(card::Rank::King, card::Suit::Hearts);
    let d = card::Card::new(card::Rank::Seven, card::Suit::Clubs);
    let e = card::Card::new(card::Rank::Five, card::Suit::Spades);
    let cards: Vec<card::Card> = vec![a, b, c, d, e];
    let hand: hand::Hand = hand::Hand::new(cards);

    assert_eq!(hand.has_straight(), false);
}

#[test]
fn has_pair() {
    let a = card::Card::new(card::Rank::Seven, card::Suit::Hearts);
    let b = card::Card::new(card::Rank::Six, card::Suit::Diamonds);
    let c = card::Card::new(card::Rank::King, card::Suit::Hearts);
    let d = card::Card::new(card::Rank::Seven, card::Suit::Clubs);
    let e = card::Card::new(card::Rank::Five, card::Suit::Spades);
    let cards: Vec<card::Card> = vec![a, b, c, d, e];
    let hand: hand::Hand = hand::Hand::new(cards);

    assert_eq!(hand.has_pair(), true);
}

#[test]
fn has_pair_in_set() {
    let a = card::Card::new(card::Rank::Seven, card::Suit::Hearts);
    let b = card::Card::new(card::Rank::Six, card::Suit::Diamonds);
    let c = card::Card::new(card::Rank::King, card::Suit::Hearts);
    let d = card::Card::new(card::Rank::Seven, card::Suit::Clubs);
    let e = card::Card::new(card::Rank::Seven, card::Suit::Spades);
    let cards: Vec<card::Card> = vec![a, b, c, d, e];
    let hand: hand::Hand = hand::Hand::new(cards);

    assert_eq!(hand.has_pair(), true);
}

#[test]
fn no_pair() {
    let a = card::Card::new(card::Rank::Three, card::Suit::Hearts);
    let b = card::Card::new(card::Rank::Six, card::Suit::Diamonds);
    let c = card::Card::new(card::Rank::King, card::Suit::Hearts);
    let d = card::Card::new(card::Rank::Seven, card::Suit::Clubs);
    let e = card::Card::new(card::Rank::Five, card::Suit::Spades);
    let cards: Vec<card::Card> = vec![a, b, c, d, e];
    let hand: hand::Hand = hand::Hand::new(cards);

    assert_eq!(hand.has_pair(), false);
}

#[test]
fn high_card_raw_value() {
    assert_eq!(hand::PokerRanking::HighCard as u32, 0);
}

#[test]
fn one_pair_raw_value() {
    assert_eq!(hand::PokerRanking::OnePair as u32, 1);
}

#[test]
fn two_pair_raw_value() {
    assert_eq!(hand::PokerRanking::TwoPair as u32, 2);
}

#[test]
fn trips_raw_value() {
    assert_eq!(hand::PokerRanking::Trips as u32, 3);
}

#[test]
fn straight_raw_value() {
    assert_eq!(hand::PokerRanking::Straight as u32, 4);
}

#[test]
fn flush_raw_value() {
    assert_eq!(hand::PokerRanking::Flush as u32, 5);
}

#[test]
fn full_house_raw_value() {
    assert_eq!(hand::PokerRanking::FullHouse as u32, 6);
}

#[test]
fn quads_raw_value() {
    assert_eq!(hand::PokerRanking::Quads as u32, 7);
}

#[test]
fn straight_flush_raw_value() {
    assert_eq!(hand::PokerRanking::StraightFlush as u32, 8);
}
<|endoftext|>


<commit_before>pub use std::mem;
pub use std::slice;

pub enum IndexDatumType {
    UnsignedByte,
    UnsignedShort
}

pub trait IndexData {
    fn index_datum_type() -> IndexDatumType;
    fn index_bytes(&self) -> &[u8];
    fn index_elements(&self) -> usize;
}

pub trait IndexDatum {
    fn index_datum_type() -> IndexDatumType;
}
<commit_msg>Add `IndexDatum` impls for `u8`/`u16`<commit_after>pub use std::mem;
pub use std::slice;

pub enum IndexDatumType {
    UnsignedByte,
    UnsignedShort
}

pub trait IndexData {
    fn index_datum_type() -> IndexDatumType;
    fn index_bytes(&self) -> &[u8];
    fn index_elements(&self) -> usize;
}

pub trait IndexDatum {
    fn index_datum_type() -> IndexDatumType;
}

impl IndexDatum for u8 {
    fn index_datum_type() -> IndexDatumType { IndexDatumType::UnsignedByte }
}

impl IndexDatum for u16 {
    fn index_datum_type() -> IndexDatumType { IndexDatumType::UnsignedShort }
}
<|endoftext|>


<commit_before>pub struct GPU {
    mode: Mode,
    line: u32,
    cycles: u32,
    vram: VideoMemory
}

/// Video memory and related data/registers
/// The main VRAM (`data`) is used for the following values:
///     8000-87FF	Tile set #1: tiles 0-127
///     8800-8FFF	Tile set #1: tiles 128-255 Tile set #0: tiles -1 to -128
///     9000-97FF	Tile set #0: tiles 0-127
///     9800-9BFF	Tile map #0
///     9C00-9FFF	Tile map #1
///
/// The rest of the memory (`oam`) is used for sprite data and addressed separately
/// from FE00 to FE9F.
pub struct VideoMemory {
    data: [u8; 8192],
    oam: [u8; 160],
}

impl GPU {
    pub fn new() -> GPU {
        GPU {
            mode: Mode::HBlank,
            line: 0,
            cycles: 0,
            vram: VideoMemory {
                data: [0; 8192],
                oam: [0; 160],
            },
        }
    }

    pub fn write_vram(&mut self, addr: usize, value: u8) {
        self.vram.data[addr] = value;
    }

    pub fn read_vram(&self, addr: usize) -> u8 {
        self.vram.data[addr]
    }

    pub fn write_oam(&mut self, addr: usize, value: u8) {
        self.vram.oam[addr] = value;
    }

    pub fn read_oam(&self, addr: usize) -> u8 {
        self.vram.oam[addr]
    }

    /// Emulates the GPU.
    /// This function should be called after an instruction is executed by the CPU,
    /// `delta` is the number of cycles passed from the last instruction.
    pub fn emulate(&mut self, delta: u32) {

        self.cycles += delta;

        match self.mode {
            Mode::OAMRead => {
                if self.cycles >= 80 {
                    self.cycles = 0;
                    self.mode = Mode::VRAMRead;
                }
            }
            Mode::VRAMRead => {
                if self.cycles >= 172 {
                    self.cycles = 0;
                    self.mode = Mode::HBlank;

                    // TODO: scanline is done, write it to framebuffer
                }
            }
            Mode::HBlank => {
                if self.cycles >= 204 {
                    self.cycles = 0;
                    self.line += 1;

                    self.mode = if self.line == 143 {
                        Mode::VBlank
                    } else {
                        Mode::OAMRead
                    };
                }
            }
            Mode::VBlank => {
                if self.cycles >= 456 {
                    self.mode = Mode::HBlank;
                    self.line += 1;

                    if self.line > 153 {
                        self.mode = Mode::OAMRead;
                        self.line = 0;
                    }
                }
            }
        }
    }
}

///  Mode 0 (HBlank): The LCD controller is in the H-Blank period and
///          the CPU can access both the display RAM (8000h-9FFFh)
///          and OAM (FE00h-FE9Fh)
///
///  Mode 1 (VBlank): The LCD controller is in the V-Blank period (or the
///          display is disabled) and the CPU can access both the
///          display RAM (8000h-9FFFh) and OAM (FE00h-FE9Fh)
///
///  Mode 2 (OAMRead): The LCD controller is reading from OAM memory.
///          The CPU <cannot> access OAM memory (FE00h-FE9Fh)
///          during this period.
///
///  Mode 3 (VRAMRead): The LCD controller is reading from both OAM and VRAM,
///          The CPU <cannot> access OAM and VRAM during this period.
///          CGB Mode: Cannot access Palette Data (FF69,FF6B) either.
enum Mode {
    HBlank,
    VBlank,
    OAMRead,
    VRAMRead,
}
<commit_msg>Added data structures and comments for GPU<commit_after>pub struct GPU {
    mode: Mode,
    line: u32,
    cycles: u32,
    vram: VideoMemory
}

/// Video memory and related data/registers
/// The main VRAM (`data`) is used for the following values:
///     8000-87FF	Tile set #1: tiles 0-127
///     8800-8FFF	Tile set #1: tiles 128-255 Tile set #0: tiles -1 to -128
///     9000-97FF	Tile set #0: tiles 0-127
///     9800-9BFF	Tile map #0
///     9C00-9FFF	Tile map #1
///
/// There are 2 tile sets of 256 tiles, but 128 tiles are shared between them, so the
/// total amounts to 384 tiles.
/// The tile maps hold indexes to a corresponding tile in the tilesets.
/// Pixel data is 2 bits and is split between two adjacent bytes, low bit first:
///
///     1 0 0 0 1 1 0 1 -- 0x8000
///     0 1 1 0 1 0 1 1 -- 0x8001
///
///     1 2 2 0 3 1 2 3 -- pixel value (0 to 3)
///
/// The rest of the memory (`oam`) is used for sprite data and addressed separately
/// from FE00 to FE9F.
pub struct VideoMemory {
    data: [u8; 8192],
    oam: [u8; 160],
}

///  Mode 0 (HBlank): The LCD controller is in the H-Blank period and
///          the CPU can access both the display RAM (8000h-9FFFh)
///          and OAM (FE00h-FE9Fh)
///
///  Mode 1 (VBlank): The LCD controller is in the V-Blank period (or the
///          display is disabled) and the CPU can access both the
///          display RAM (8000h-9FFFh) and OAM (FE00h-FE9Fh)
///
///  Mode 2 (OAMRead): The LCD controller is reading from OAM memory.
///          The CPU <cannot> access OAM memory (FE00h-FE9Fh)
///          during this period.
///
///  Mode 3 (VRAMRead): The LCD controller is reading from both OAM and VRAM,
///          The CPU <cannot> access OAM and VRAM during this period.
///          CGB Mode: Cannot access Palette Data (FF69,FF6B) either.
enum Mode {
    HBlank,
    VBlank,
    OAMRead,
    VRAMRead,
}

/// An enum representing the possible color values for a pixel in the original GB.
/// While the GB is said to be monochromatic, it can actually display 4 different shades.
#[derive(Copy, Clone)]
enum GBColor {
    // white, rgb #FFFFFF
    Off = 0,
    // light grey, rgb #C0C0C0
    On33 = 1,
    // dark grey, rgb #606060
    On66 = 2,
    // black, rgb #000000
    On = 3,
}

/// A tile is an 8x8 square of pixels, each one stored in one of the VRAM's tilesets.
struct Tile {
    pixels: [GBColor; 64],
}

impl Tile {
    pub fn new() -> Tile {
        Tile { pixels: [GBColor::Off; 64] }
    }
}

impl GPU {
    pub fn new() -> GPU {
        GPU {
            mode: Mode::HBlank,
            line: 0,
            cycles: 0,
            vram: VideoMemory {
                data: [0; 8192],
                oam: [0; 160],
            },
        }
    }

    pub fn write_vram(&mut self, addr: usize, value: u8) {
        self.vram.data[addr] = value;
    }

    pub fn read_vram(&self, addr: usize) -> u8 {
        self.vram.data[addr]
    }

    pub fn write_oam(&mut self, addr: usize, value: u8) {
        self.vram.oam[addr] = value;
    }

    pub fn read_oam(&self, addr: usize) -> u8 {
        self.vram.oam[addr]
    }

    /// Emulates the GPU.
    /// This function should be called after an instruction is executed by the CPU,
    /// `delta` is the number of cycles passed from the last instruction.
    pub fn emulate(&mut self, delta: u32) {

        self.cycles += delta;

        match self.mode {
            Mode::OAMRead => {
                if self.cycles >= 80 {
                    self.cycles = 0;
                    self.mode = Mode::VRAMRead;
                }
            }
            Mode::VRAMRead => {
                if self.cycles >= 172 {
                    self.cycles = 0;
                    self.mode = Mode::HBlank;

                    // TODO: scanline is done, write it to framebuffer
                }
            }
            Mode::HBlank => {
                if self.cycles >= 204 {
                    self.cycles = 0;
                    self.line += 1;

                    self.mode = if self.line == 143 {
                        Mode::VBlank
                    } else {
                        Mode::OAMRead
                    };
                }
            }
            Mode::VBlank => {
                if self.cycles >= 456 {
                    self.mode = Mode::HBlank;
                    self.line += 1;

                    if self.line > 153 {
                        self.mode = Mode::OAMRead;
                        self.line = 0;
                    }
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>// Copyright (C) 2016 Élisabeth HENRY.
//
// This file is part of Crowbook.
//
// Crowbook is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, either version 2.1 of the License, or
// (at your option) any later version.
//
// Caribon is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received ba copy of the GNU Lesser General Public License
// along with Crowbook.  If not, see <http://www.gnu.org/licenses/>.

//! Provides utility functions for escaping text to HTML or LaTeX

use std::borrow::Cow;

const NB_CHAR:char = ' '; // non breaking space
const NB_CHAR_NARROW:char = '\u{202F}'; // narrow non breaking space
const NB_CHAR_EM:char = '\u{2002}'; // demi em space

/// Escape non breaking spaces for HTML, so they are visible.
#[doc(hidden)]
pub fn escape_nb_spaces<'a, S: Into<Cow<'a, str>>>(input: S) -> Cow<'a, str> {
    let input = input.into();
    if input.contains(|c| match c {
        NB_CHAR | NB_CHAR_NARROW | NB_CHAR_EM => true,
        _ => false
    }) {
        let mut output = String::with_capacity(input.len());
        for c in input.chars() {
            match c {
                NB_CHAR_NARROW
                    | NB_CHAR_EM
                    | NB_CHAR
                    => output.push_str(&format!("{}",
                                                match c {
                                                    NB_CHAR => "#ffff66",
                                                    NB_CHAR_NARROW => "#9999ff",
                                                    NB_CHAR_EM => "#ff9999",
                                                    _ => unreachable!()
                                                },
                                                c)),
                _ => output.push(c),
            }
        }
        Cow::Owned(output)
    } else {
        input.into()
    }
}

/// Escape characters `<`, `>`, and `&`
///
/// # Examples
///
/// ```
/// use crowbook::escape::escape_html;
/// let s = escape_html("<foo> & <bar>");
/// assert_eq!(&s, "<foo> & <bar>");
/// ```
pub fn escape_html<'a, S: Into<Cow<'a, str>>>(input: S) -> Cow<'a, str> {
    let input = input.into();
    let first = input.chars().position(|c| match c {
        '<'| '>'| '&' => true,
        _ => false
    });
    if let Some(first) = first {
        let mut chars = input.chars().collect::<Vec<_>>();
        let mut output = String::with_capacity(chars.len());
        let rest = chars.split_off(first);
        output.push_str(&chars.into_iter().collect::<String>());
        for c in rest {
            match c {
                '<' => output.push_str("<"),
                '>' => output.push_str(">"),
                '&' => output.push_str("&"),
                _ => output.push(c),
            }
        }

        Cow::Owned(output)
    } else {
        input.into()
    }
}

/// Escape characters for LaTeX
///
/// # Examples
///
/// ```
/// use crowbook::escape::escape_tex;
/// let s = escape_tex("command --foo # calls command with option foo");
/// assert_eq!(&s, r"command -{}-foo \# calls command with option foo");
/// ```
pub fn escape_tex<'a, S: Into<Cow<'a, str>>>(input: S) -> Cow<'a, str> {
    let input = input.into();
    if input.contains(|c| match c {
        '&'|'%'|'$'|'#'|'_'|'{'|'}'|'~'|'^'|'\\'|'-' => true,
        _ => false
    }) {
        let mut output = String::with_capacity(input.len());
        let mut chars:Vec<char> = input.chars().collect();
        chars.push(' '); // add a dummy char for call to .windows()
        // for &[c, next] in chars.windows(2) { // still experimental, uncomment when stable
        for win in chars.windows(2) {
            let c = win[0];
            let next = win[1];
            match c {
                '-' => {
                    if next == '-' {
                        output.push_str(r"-{}"); // if next char is also a -, to avoid tex ligatures
                    } else {
                        output.push(c);
                    }
                },
                '&' => output.push_str(r"\&"),
                '%' => output.push_str(r"\%"),
                '$' => output.push_str(r"\$"),
                '#' => output.push_str(r"\#"),
                '_' => output.push_str(r"\_"),
                '{' => output.push_str(r"\{"),
                '}' => output.push_str(r"\}"),
                '~' => output.push_str(r"\textasciitilde{}" ),
                '^' => output.push_str(r"\textasciicircum{}"),
                '\\' => output.push_str(r"\textbackslash{}"),
                _  => output.push(c)
            }
        }
        Cow::Owned(output)
    } else {
        input
    }
}
<commit_msg>Enhance performance for escape_html<commit_after>// Copyright (C) 2016 Élisabeth HENRY.
//
// This file is part of Crowbook.
//
// Crowbook is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, either version 2.1 of the License, or
// (at your option) any later version.
//
// Caribon is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received ba copy of the GNU Lesser General Public License
// along with Crowbook.  If not, see <http://www.gnu.org/licenses/>.

//! Provides utility functions for escaping text to HTML or LaTeX

use std::borrow::Cow;

const NB_CHAR:char = ' '; // non breaking space
const NB_CHAR_NARROW:char = '\u{202F}'; // narrow non breaking space
const NB_CHAR_EM:char = '\u{2002}'; // demi em space

/// Escape non breaking spaces for HTML, so they are visible.
#[doc(hidden)]
pub fn escape_nb_spaces<'a, S: Into<Cow<'a, str>>>(input: S) -> Cow<'a, str> {
    let input = input.into();
    if input.contains(|c| match c {
        NB_CHAR | NB_CHAR_NARROW | NB_CHAR_EM => true,
        _ => false
    }) {
        let mut output = String::with_capacity(input.len());
        for c in input.chars() {
            match c {
                NB_CHAR_NARROW
                    | NB_CHAR_EM
                    | NB_CHAR
                    => output.push_str(&format!("{}",
                                                match c {
                                                    NB_CHAR => "#ffff66",
                                                    NB_CHAR_NARROW => "#9999ff",
                                                    NB_CHAR_EM => "#ff9999",
                                                    _ => unreachable!()
                                                },
                                                c)),
                _ => output.push(c),
            }
        }
        Cow::Owned(output)
    } else {
        input.into()
    }
}

/// Escape characters `<`, `>`, and `&`
///
/// # Examples
///
/// ```
/// use crowbook::escape::escape_html;
/// let s = escape_html("<foo> & <bar>");
/// assert_eq!(&s, "<foo> & <bar>");
/// ```
pub fn escape_html<'a, S: Into<Cow<'a, str>>>(input: S) -> Cow<'a, str> {
    let input = input.into();
    let first = input.chars().position(|c| match c {
        '<'| '>'| '&' => true,
        _ => false
    });
    if let Some(first) = first {
        let mut chars = input.chars().collect::<Vec<_>>();
        let rest = chars.split_off(first);
        let mut output = chars.into_iter().collect::<String>();
        for c in rest {
            match c {
                '<' => output.push_str("<"),
                '>' => output.push_str(">"),
                '&' => output.push_str("&"),
                _ => output.push(c),
            }
        }

        Cow::Owned(output)
    } else {
        input.into()
    }
}

/// Escape characters for LaTeX
///
/// # Examples
///
/// ```
/// use crowbook::escape::escape_tex;
/// let s = escape_tex("command --foo # calls command with option foo");
/// assert_eq!(&s, r"command -{}-foo \# calls command with option foo");
/// ```
pub fn escape_tex<'a, S: Into<Cow<'a, str>>>(input: S) -> Cow<'a, str> {
    let input = input.into();
    if input.contains(|c| match c {
        '&'|'%'|'$'|'#'|'_'|'{'|'}'|'~'|'^'|'\\'|'-' => true,
        _ => false
    }) {
        let mut output = String::with_capacity(input.len());
        let mut chars:Vec<char> = input.chars().collect();
        chars.push(' '); // add a dummy char for call to .windows()
        // for &[c, next] in chars.windows(2) { // still experimental, uncomment when stable
        for win in chars.windows(2) {
            let c = win[0];
            let next = win[1];
            match c {
                '-' => {
                    if next == '-' {
                        output.push_str(r"-{}"); // if next char is also a -, to avoid tex ligatures
                    } else {
                        output.push(c);
                    }
                },
                '&' => output.push_str(r"\&"),
                '%' => output.push_str(r"\%"),
                '$' => output.push_str(r"\$"),
                '#' => output.push_str(r"\#"),
                '_' => output.push_str(r"\_"),
                '{' => output.push_str(r"\{"),
                '}' => output.push_str(r"\}"),
                '~' => output.push_str(r"\textasciitilde{}" ),
                '^' => output.push_str(r"\textasciicircum{}"),
                '\\' => output.push_str(r"\textbackslash{}"),
                _  => output.push(c)
            }
        }
        Cow::Owned(output)
    } else {
        input
    }
}
<|endoftext|>


<commit_before>//! Tests that don't fit into a specific category.

use expect_test::{expect, Expect};

use crate::tests::{check_edit, completion_list_no_kw};

fn check(ra_fixture: &str, expect: Expect) {
    let actual = completion_list_no_kw(ra_fixture);
    expect.assert_eq(&actual)
}

#[test]
fn completes_if_prefix_is_keyword() {
    check_edit(
        "wherewolf",
        r#"
fn main() {
    let wherewolf = 92;
    drop(where$0)
}
"#,
        r#"
fn main() {
    let wherewolf = 92;
    drop(wherewolf)
}
"#,
    )
}

/// Regression test for issue #6091.
#[test]
fn correctly_completes_module_items_prefixed_with_underscore() {
    check_edit(
        "_alpha",
        r#"
fn main() {
    _$0
}
fn _alpha() {}
"#,
        r#"
fn main() {
    _alpha()$0
}
fn _alpha() {}
"#,
    )
}

#[test]
fn completes_prelude() {
    check(
        r#"
//- /main.rs crate:main deps:std
fn foo() { let x: $0 }

//- /std/lib.rs crate:std
pub mod prelude {
    pub mod rust_2018 {
        pub struct Option;
    }
}
"#,
        expect![[r#"
                md std
                st Option
                bt u32
            "#]],
    );
}

#[test]
fn completes_prelude_macros() {
    check(
        r#"
//- /main.rs crate:main deps:std
fn f() {$0}

//- /std/lib.rs crate:std
pub mod prelude {
    pub mod rust_2018 {
        pub use crate::concat;
    }
}

mod macros {
    #[rustc_builtin_macro]
    #[macro_export]
    macro_rules! concat { }
}
"#,
        expect![[r#"
                fn f()        fn()
                ma concat!(…) macro_rules! concat
                md std
                bt u32
            "#]],
    );
}

#[test]
fn completes_std_prelude_if_core_is_defined() {
    check(
        r#"
//- /main.rs crate:main deps:core,std
fn foo() { let x: $0 }

//- /core/lib.rs crate:core
pub mod prelude {
    pub mod rust_2018 {
        pub struct Option;
    }
}

//- /std/lib.rs crate:std deps:core
pub mod prelude {
    pub mod rust_2018 {
        pub struct String;
    }
}
"#,
        expect![[r#"
                md core
                md std
                st String
                bt u32
            "#]],
    );
}

#[test]
fn respects_doc_hidden() {
    check(
        r#"
//- /lib.rs crate:lib deps:std
fn f() {
    format_$0
}

//- /std.rs crate:std
#[doc(hidden)]
#[macro_export]
macro_rules! format_args_nl {
    () => {}
}

pub mod prelude {
    pub mod rust_2018 {}
}
            "#,
        expect![[r#"
                fn f() fn()
                md std
                bt u32
            "#]],
    );
}

#[test]
fn respects_doc_hidden_in_assoc_item_list() {
    check(
        r#"
//- /lib.rs crate:lib deps:std
struct S;
impl S {
    format_$0
}

//- /std.rs crate:std
#[doc(hidden)]
#[macro_export]
macro_rules! format_args_nl {
    () => {}
}

pub mod prelude {
    pub mod rust_2018 {}
}
            "#,
        expect![[r#"
                md std
            "#]],
    );
}

#[test]
fn associated_item_visibility() {
    check(
        r#"
//- /lib.rs crate:lib new_source_root:library
pub struct S;

impl S {
    pub fn public_method() { }
    fn private_method() { }
    pub type PublicType = u32;
    type PrivateType = u32;
    pub const PUBLIC_CONST: u32 = 1;
    const PRIVATE_CONST: u32 = 1;
}

//- /main.rs crate:main deps:lib new_source_root:local
fn foo() { let _ = lib::S::$0 }
"#,
        expect![[r#"
                ct PUBLIC_CONST    pub const PUBLIC_CONST: u32
                fn public_method() fn()
                ta PublicType      pub type PublicType = u32
            "#]],
    );
}

#[test]
fn completes_union_associated_method() {
    check(
        r#"
union U {};
impl U { fn m() { } }

fn foo() { let _ = U::$0 }
"#,
        expect![[r#"
                fn m() fn()
            "#]],
    );
}

#[test]
fn completes_trait_associated_method_1() {
    check(
        r#"
trait Trait { fn m(); }

fn foo() { let _ = Trait::$0 }
"#,
        expect![[r#"
                fn m() (as Trait) fn()
            "#]],
    );
}

#[test]
fn completes_trait_associated_method_2() {
    check(
        r#"
trait Trait { fn m(); }

struct S;
impl Trait for S {}

fn foo() { let _ = S::$0 }
"#,
        expect![[r#"
                fn m() (as Trait) fn()
            "#]],
    );
}

#[test]
fn completes_trait_associated_method_3() {
    check(
        r#"
trait Trait { fn m(); }

struct S;
impl Trait for S {}

fn foo() { let _ = <S as Trait>::$0 }
"#,
        expect![[r#"
                fn m() (as Trait) fn()
            "#]],
    );
}

#[test]
fn completes_ty_param_assoc_ty() {
    check(
        r#"
trait Super {
    type Ty;
    const CONST: u8;
    fn func() {}
    fn method(&self) {}
}

trait Sub: Super {
    type SubTy;
    const C2: ();
    fn subfunc() {}
    fn submethod(&self) {}
}

fn foo<T: Sub>() { T::$0 }
"#,
        expect![[r#"
                ct C2 (as Sub)           const C2: ()
                ct CONST (as Super)      const CONST: u8
                fn func() (as Super)     fn()
                fn subfunc() (as Sub)    fn()
                ta SubTy (as Sub)        type SubTy
                ta Ty (as Super)         type Ty
                me method(…) (as Super)  fn(&self)
                me submethod(…) (as Sub) fn(&self)
            "#]],
    );
}

#[test]
fn completes_self_param_assoc_ty() {
    check(
        r#"
trait Super {
    type Ty;
    const CONST: u8 = 0;
    fn func() {}
    fn method(&self) {}
}

trait Sub: Super {
    type SubTy;
    const C2: () = ();
    fn subfunc() {}
    fn submethod(&self) {}
}

struct Wrap<T>(T);
impl<T> Super for Wrap<T> {}
impl<T> Sub for Wrap<T> {
    fn subfunc() {
        // Should be able to assume `Self: Sub + Super`
        Self::$0
    }
}
"#,
        expect![[r#"
                ct C2 (as Sub)           const C2: ()
                ct CONST (as Super)      const CONST: u8
                fn func() (as Super)     fn()
                fn subfunc() (as Sub)    fn()
                ta SubTy (as Sub)        type SubTy
                ta Ty (as Super)         type Ty
                me method(…) (as Super)  fn(&self)
                me submethod(…) (as Sub) fn(&self)
            "#]],
    );
}

#[test]
fn completes_type_alias() {
    check(
        r#"
struct S;
impl S { fn foo() {} }
type T = S;
impl T { fn bar() {} }

fn main() { T::$0; }
"#,
        expect![[r#"
                fn bar() fn()
                fn foo() fn()
            "#]],
    );
}

#[test]
fn completes_qualified_macros() {
    check(
        r#"
#[macro_export]
macro_rules! foo { () => {} }

fn main() { let _ = crate::$0 }
"#,
        expect![[r#"
                fn main()  fn()
                ma foo!(…) macro_rules! foo
            "#]],
    );
}

#[test]
fn does_not_complete_non_fn_macros() {
    check(
        r#"
mod m {
    #[rustc_builtin_macro]
    pub macro Clone {}
}

fn f() {m::$0}
"#,
        expect![[r#""#]],
    );
    check(
        r#"
mod m {
    #[rustc_builtin_macro]
    pub macro bench {}
}

fn f() {m::$0}
"#,
        expect![[r#""#]],
    );
}

#[test]
fn completes_reexported_items_under_correct_name() {
    check(
        r#"
fn foo() { self::m::$0 }

mod m {
    pub use super::p::wrong_fn as right_fn;
    pub use super::p::WRONG_CONST as RIGHT_CONST;
    pub use super::p::WrongType as RightType;
}
mod p {
    fn wrong_fn() {}
    const WRONG_CONST: u32 = 1;
    struct WrongType {};
}
"#,
        expect![[r#"
                ct RIGHT_CONST
                fn right_fn()  fn()
                st RightType
            "#]],
    );

    check_edit(
        "RightType",
        r#"
fn foo() { self::m::$0 }

mod m {
    pub use super::p::wrong_fn as right_fn;
    pub use super::p::WRONG_CONST as RIGHT_CONST;
    pub use super::p::WrongType as RightType;
}
mod p {
    fn wrong_fn() {}
    const WRONG_CONST: u32 = 1;
    struct WrongType {};
}
"#,
        r#"
fn foo() { self::m::RightType }

mod m {
    pub use super::p::wrong_fn as right_fn;
    pub use super::p::WRONG_CONST as RIGHT_CONST;
    pub use super::p::WrongType as RightType;
}
mod p {
    fn wrong_fn() {}
    const WRONG_CONST: u32 = 1;
    struct WrongType {};
}
"#,
    );
}

#[test]
fn completes_in_simple_macro_call() {
    check(
        r#"
macro_rules! m { ($e:expr) => { $e } }
fn main() { m!(self::f$0); }
fn foo() {}
"#,
        expect![[r#"
                fn foo()  fn()
                fn main() fn()
            "#]],
    );
}

#[test]
fn function_mod_share_name() {
    check(
        r#"
fn foo() { self::m::$0 }

mod m {
    pub mod z {}
    pub fn z() {}
}
"#,
        expect![[r#"
                fn z() fn()
                md z
            "#]],
    );
}

#[test]
fn completes_hashmap_new() {
    check(
        r#"
struct RandomState;
struct HashMap<K, V, S = RandomState> {}

impl<K, V> HashMap<K, V, RandomState> {
    pub fn new() -> HashMap<K, V, RandomState> { }
}
fn foo() {
    HashMap::$0
}
"#,
        expect![[r#"
                fn new() fn() -> HashMap<K, V, RandomState>
            "#]],
    );
}

#[test]
fn completes_variant_through_self() {
    check(
        r#"
enum Foo {
    Bar,
    Baz,
}

impl Foo {
    fn foo(self) {
        Self::$0
    }
}
"#,
        expect![[r#"
                ev Bar    Bar
                ev Baz    Baz
                me foo(…) fn(self)
            "#]],
    );
}

#[test]
fn completes_primitive_assoc_const() {
    cov_mark::check!(completes_primitive_assoc_const);
    check(
        r#"
//- /lib.rs crate:lib deps:core
fn f() {
    u8::$0
}

//- /core.rs crate:core
#[lang = "u8"]
impl u8 {
    pub const MAX: Self = 255;

    pub fn func(self) {}
}
"#,
        expect![[r#"
                ct MAX     pub const MAX: Self
                me func(…) fn(self)
            "#]],
    );
}

#[test]
fn completes_variant_through_alias() {
    cov_mark::check!(completes_variant_through_alias);
    check(
        r#"
enum Foo {
    Bar
}
type Foo2 = Foo;
fn main() {
    Foo2::$0
}
"#,
        expect![[r#"
                ev Bar Bar
            "#]],
    );
}

#[test]
fn respects_doc_hidden2() {
    cov_mark::check!(qualified_path_doc_hidden);
    check(
        r#"
//- /lib.rs crate:lib deps:dep
fn f() {
    dep::$0
}

//- /dep.rs crate:dep
#[doc(hidden)]
#[macro_export]
macro_rules! m {
    () => {}
}

#[doc(hidden)]
pub fn f() {}

#[doc(hidden)]
pub struct S;

#[doc(hidden)]
pub mod m {}
            "#,
        expect![[r#""#]],
    )
}

#[test]
fn type_anchor_empty() {
    check(
        r#"
trait Foo {
    fn foo() -> Self;
}
struct Bar;
impl Foo for Bar {
    fn foo() -> {
        Bar
    }
}
fn bar() -> Bar {
    <_>::$0
}
"#,
        expect![[r#"
                fn foo() (as Foo) fn() -> Self
            "#]],
    )
}
<commit_msg>add test cases to complete fn generated by macro in pub trait<commit_after>//! Tests that don't fit into a specific category.

use expect_test::{expect, Expect};

use crate::{
    tests::{check_edit, completion_list_no_kw, completion_list_with_config, TEST_CONFIG},
    CompletionConfig,
};

fn check(ra_fixture: &str, expect: Expect) {
    let actual = completion_list_no_kw(ra_fixture);
    expect.assert_eq(&actual)
}

fn check_with_config(config: CompletionConfig, ra_fixture: &str, expect: Expect) {
    let actual = completion_list_with_config(config, ra_fixture, true, None);
    expect.assert_eq(&actual)
}

#[test]
fn completes_if_prefix_is_keyword() {
    check_edit(
        "wherewolf",
        r#"
fn main() {
    let wherewolf = 92;
    drop(where$0)
}
"#,
        r#"
fn main() {
    let wherewolf = 92;
    drop(wherewolf)
}
"#,
    )
}

/// Regression test for issue #6091.
#[test]
fn correctly_completes_module_items_prefixed_with_underscore() {
    check_edit(
        "_alpha",
        r#"
fn main() {
    _$0
}
fn _alpha() {}
"#,
        r#"
fn main() {
    _alpha()$0
}
fn _alpha() {}
"#,
    )
}

#[test]
fn completes_prelude() {
    check(
        r#"
//- /main.rs crate:main deps:std
fn foo() { let x: $0 }

//- /std/lib.rs crate:std
pub mod prelude {
    pub mod rust_2018 {
        pub struct Option;
    }
}
"#,
        expect![[r#"
                md std
                st Option
                bt u32
            "#]],
    );
}

#[test]
fn completes_prelude_macros() {
    check(
        r#"
//- /main.rs crate:main deps:std
fn f() {$0}

//- /std/lib.rs crate:std
pub mod prelude {
    pub mod rust_2018 {
        pub use crate::concat;
    }
}

mod macros {
    #[rustc_builtin_macro]
    #[macro_export]
    macro_rules! concat { }
}
"#,
        expect![[r#"
                fn f()        fn()
                ma concat!(…) macro_rules! concat
                md std
                bt u32
            "#]],
    );
}

#[test]
fn completes_std_prelude_if_core_is_defined() {
    check(
        r#"
//- /main.rs crate:main deps:core,std
fn foo() { let x: $0 }

//- /core/lib.rs crate:core
pub mod prelude {
    pub mod rust_2018 {
        pub struct Option;
    }
}

//- /std/lib.rs crate:std deps:core
pub mod prelude {
    pub mod rust_2018 {
        pub struct String;
    }
}
"#,
        expect![[r#"
                md core
                md std
                st String
                bt u32
            "#]],
    );
}

#[test]
fn respects_doc_hidden() {
    check(
        r#"
//- /lib.rs crate:lib deps:std
fn f() {
    format_$0
}

//- /std.rs crate:std
#[doc(hidden)]
#[macro_export]
macro_rules! format_args_nl {
    () => {}
}

pub mod prelude {
    pub mod rust_2018 {}
}
            "#,
        expect![[r#"
                fn f() fn()
                md std
                bt u32
            "#]],
    );
}

#[test]
fn respects_doc_hidden_in_assoc_item_list() {
    check(
        r#"
//- /lib.rs crate:lib deps:std
struct S;
impl S {
    format_$0
}

//- /std.rs crate:std
#[doc(hidden)]
#[macro_export]
macro_rules! format_args_nl {
    () => {}
}

pub mod prelude {
    pub mod rust_2018 {}
}
            "#,
        expect![[r#"
                md std
            "#]],
    );
}

#[test]
fn associated_item_visibility() {
    check(
        r#"
//- /lib.rs crate:lib new_source_root:library
pub struct S;

impl S {
    pub fn public_method() { }
    fn private_method() { }
    pub type PublicType = u32;
    type PrivateType = u32;
    pub const PUBLIC_CONST: u32 = 1;
    const PRIVATE_CONST: u32 = 1;
}

//- /main.rs crate:main deps:lib new_source_root:local
fn foo() { let _ = lib::S::$0 }
"#,
        expect![[r#"
                ct PUBLIC_CONST    pub const PUBLIC_CONST: u32
                fn public_method() fn()
                ta PublicType      pub type PublicType = u32
            "#]],
    );
}

#[test]
fn completes_union_associated_method() {
    check(
        r#"
union U {};
impl U { fn m() { } }

fn foo() { let _ = U::$0 }
"#,
        expect![[r#"
                fn m() fn()
            "#]],
    );
}

#[test]
fn completes_trait_associated_method_1() {
    check(
        r#"
trait Trait { fn m(); }

fn foo() { let _ = Trait::$0 }
"#,
        expect![[r#"
                fn m() (as Trait) fn()
            "#]],
    );
}

#[test]
fn completes_trait_associated_method_2() {
    check(
        r#"
trait Trait { fn m(); }

struct S;
impl Trait for S {}

fn foo() { let _ = S::$0 }
"#,
        expect![[r#"
                fn m() (as Trait) fn()
            "#]],
    );
}

#[test]
fn completes_trait_associated_method_3() {
    check(
        r#"
trait Trait { fn m(); }

struct S;
impl Trait for S {}

fn foo() { let _ = <S as Trait>::$0 }
"#,
        expect![[r#"
                fn m() (as Trait) fn()
            "#]],
    );
}

#[test]
fn completes_ty_param_assoc_ty() {
    check(
        r#"
trait Super {
    type Ty;
    const CONST: u8;
    fn func() {}
    fn method(&self) {}
}

trait Sub: Super {
    type SubTy;
    const C2: ();
    fn subfunc() {}
    fn submethod(&self) {}
}

fn foo<T: Sub>() { T::$0 }
"#,
        expect![[r#"
                ct C2 (as Sub)           const C2: ()
                ct CONST (as Super)      const CONST: u8
                fn func() (as Super)     fn()
                fn subfunc() (as Sub)    fn()
                ta SubTy (as Sub)        type SubTy
                ta Ty (as Super)         type Ty
                me method(…) (as Super)  fn(&self)
                me submethod(…) (as Sub) fn(&self)
            "#]],
    );
}

#[test]
fn completes_self_param_assoc_ty() {
    check(
        r#"
trait Super {
    type Ty;
    const CONST: u8 = 0;
    fn func() {}
    fn method(&self) {}
}

trait Sub: Super {
    type SubTy;
    const C2: () = ();
    fn subfunc() {}
    fn submethod(&self) {}
}

struct Wrap<T>(T);
impl<T> Super for Wrap<T> {}
impl<T> Sub for Wrap<T> {
    fn subfunc() {
        // Should be able to assume `Self: Sub + Super`
        Self::$0
    }
}
"#,
        expect![[r#"
                ct C2 (as Sub)           const C2: ()
                ct CONST (as Super)      const CONST: u8
                fn func() (as Super)     fn()
                fn subfunc() (as Sub)    fn()
                ta SubTy (as Sub)        type SubTy
                ta Ty (as Super)         type Ty
                me method(…) (as Super)  fn(&self)
                me submethod(…) (as Sub) fn(&self)
            "#]],
    );
}

#[test]
fn completes_type_alias() {
    check(
        r#"
struct S;
impl S { fn foo() {} }
type T = S;
impl T { fn bar() {} }

fn main() { T::$0; }
"#,
        expect![[r#"
                fn bar() fn()
                fn foo() fn()
            "#]],
    );
}

#[test]
fn completes_qualified_macros() {
    check(
        r#"
#[macro_export]
macro_rules! foo { () => {} }

fn main() { let _ = crate::$0 }
"#,
        expect![[r#"
                fn main()  fn()
                ma foo!(…) macro_rules! foo
            "#]],
    );
}

#[test]
fn does_not_complete_non_fn_macros() {
    check(
        r#"
mod m {
    #[rustc_builtin_macro]
    pub macro Clone {}
}

fn f() {m::$0}
"#,
        expect![[r#""#]],
    );
    check(
        r#"
mod m {
    #[rustc_builtin_macro]
    pub macro bench {}
}

fn f() {m::$0}
"#,
        expect![[r#""#]],
    );
}

#[test]
fn completes_reexported_items_under_correct_name() {
    check(
        r#"
fn foo() { self::m::$0 }

mod m {
    pub use super::p::wrong_fn as right_fn;
    pub use super::p::WRONG_CONST as RIGHT_CONST;
    pub use super::p::WrongType as RightType;
}
mod p {
    fn wrong_fn() {}
    const WRONG_CONST: u32 = 1;
    struct WrongType {};
}
"#,
        expect![[r#"
                ct RIGHT_CONST
                fn right_fn()  fn()
                st RightType
            "#]],
    );

    check_edit(
        "RightType",
        r#"
fn foo() { self::m::$0 }

mod m {
    pub use super::p::wrong_fn as right_fn;
    pub use super::p::WRONG_CONST as RIGHT_CONST;
    pub use super::p::WrongType as RightType;
}
mod p {
    fn wrong_fn() {}
    const WRONG_CONST: u32 = 1;
    struct WrongType {};
}
"#,
        r#"
fn foo() { self::m::RightType }

mod m {
    pub use super::p::wrong_fn as right_fn;
    pub use super::p::WRONG_CONST as RIGHT_CONST;
    pub use super::p::WrongType as RightType;
}
mod p {
    fn wrong_fn() {}
    const WRONG_CONST: u32 = 1;
    struct WrongType {};
}
"#,
    );
}

#[test]
fn completes_in_simple_macro_call() {
    check(
        r#"
macro_rules! m { ($e:expr) => { $e } }
fn main() { m!(self::f$0); }
fn foo() {}
"#,
        expect![[r#"
                fn foo()  fn()
                fn main() fn()
            "#]],
    );
}

#[test]
fn function_mod_share_name() {
    check(
        r#"
fn foo() { self::m::$0 }

mod m {
    pub mod z {}
    pub fn z() {}
}
"#,
        expect![[r#"
                fn z() fn()
                md z
            "#]],
    );
}

#[test]
fn completes_hashmap_new() {
    check(
        r#"
struct RandomState;
struct HashMap<K, V, S = RandomState> {}

impl<K, V> HashMap<K, V, RandomState> {
    pub fn new() -> HashMap<K, V, RandomState> { }
}
fn foo() {
    HashMap::$0
}
"#,
        expect![[r#"
                fn new() fn() -> HashMap<K, V, RandomState>
            "#]],
    );
}

#[test]
fn completes_variant_through_self() {
    check(
        r#"
enum Foo {
    Bar,
    Baz,
}

impl Foo {
    fn foo(self) {
        Self::$0
    }
}
"#,
        expect![[r#"
                ev Bar    Bar
                ev Baz    Baz
                me foo(…) fn(self)
            "#]],
    );
}

#[test]
fn completes_primitive_assoc_const() {
    cov_mark::check!(completes_primitive_assoc_const);
    check(
        r#"
//- /lib.rs crate:lib deps:core
fn f() {
    u8::$0
}

//- /core.rs crate:core
#[lang = "u8"]
impl u8 {
    pub const MAX: Self = 255;

    pub fn func(self) {}
}
"#,
        expect![[r#"
                ct MAX     pub const MAX: Self
                me func(…) fn(self)
            "#]],
    );
}

#[test]
fn completes_variant_through_alias() {
    cov_mark::check!(completes_variant_through_alias);
    check(
        r#"
enum Foo {
    Bar
}
type Foo2 = Foo;
fn main() {
    Foo2::$0
}
"#,
        expect![[r#"
                ev Bar Bar
            "#]],
    );
}

#[test]
fn respects_doc_hidden2() {
    cov_mark::check!(qualified_path_doc_hidden);
    check(
        r#"
//- /lib.rs crate:lib deps:dep
fn f() {
    dep::$0
}

//- /dep.rs crate:dep
#[doc(hidden)]
#[macro_export]
macro_rules! m {
    () => {}
}

#[doc(hidden)]
pub fn f() {}

#[doc(hidden)]
pub struct S;

#[doc(hidden)]
pub mod m {}
            "#,
        expect![[r#""#]],
    )
}

#[test]
fn type_anchor_empty() {
    check(
        r#"
trait Foo {
    fn foo() -> Self;
}
struct Bar;
impl Foo for Bar {
    fn foo() -> {
        Bar
    }
}
fn bar() -> Bar {
    <_>::$0
}
"#,
        expect![[r#"
                fn foo() (as Foo) fn() -> Self
            "#]],
    )
}

#[test]
fn completes_fn_in_pub_trait_generated_by_macro() {
    let mut config = TEST_CONFIG.clone();
    config.enable_private_editable = false;

    check_with_config(
        config,
        r#"
mod other_mod {
    macro_rules! make_method {
        ($name:ident) => {
            fn $name(&self) {}
        };
    }

    pub trait MyTrait {
        make_method! { by_macro }
        fn not_by_macro(&self) {}
    }

    pub struct Foo {}

    impl MyTrait for Foo {}
}

fn main() {
    use other_mod::{Foo, MyTrait};
    let f = Foo {};
    f.$0
}
"#,
        expect![[r#"
            me by_macro() (as MyTrait) fn(&self)
            me not_by_macro() (as MyTrait) fn(&self)
            sn box                    Box::new(expr)
            sn call                   function(expr)
            sn dbg                    dbg!(expr)
            sn dbgr                   dbg!(&expr)
            sn let                    let
            sn letm                   let mut
            sn match                  match expr {}
            sn ref                    &expr
            sn refm                   &mut expr
        "#]],
    )
}

#[test]
fn completes_fn_in_pub_trait_generated_by_recursive_macro() {
    let mut config = TEST_CONFIG.clone();
    config.enable_private_editable = false;

    check_with_config(
        config,
        r#"
mod other_mod {
    macro_rules! make_method {
        ($name:ident) => {
            fn $name(&self) {}
        };
    }

    macro_rules! make_trait {
        () => {
            pub trait MyTrait {
                make_method! { by_macro }
                fn not_by_macro(&self) {}
            }
        }
    }

    make_trait!();

    pub struct Foo {}

    impl MyTrait for Foo {}
}

fn main() {
    use other_mod::{Foo, MyTrait};
    let f = Foo {};
    f.$0
}
"#,
        expect![[r#"
            me by_macro() (as MyTrait) fn(&self)
            me not_by_macro() (as MyTrait) fn(&self)
            sn box                    Box::new(expr)
            sn call                   function(expr)
            sn dbg                    dbg!(expr)
            sn dbgr                   dbg!(&expr)
            sn let                    let
            sn letm                   let mut
            sn match                  match expr {}
            sn ref                    &expr
            sn refm                   &mut expr
        "#]],
    )
}<|endoftext|>