<commit_before>extern crate neat;
extern crate rand;
extern crate graph_neighbor_matching;
extern crate graph_io_gml;
extern crate closed01;
extern crate petgraph;
extern crate cppn;
extern crate asexp;
#[macro_use]
extern crate log;

mod common;
mod config;

use neat::population::{Population, Unrated, Runner};
use neat::genomes::acyclic_network::{Genome, GlobalCache, GlobalInnovationCache, Mater,
                                     ElementStrategy};
use neat::fitness::Fitness;
use graph_neighbor_matching::graph::{GraphBuilder, OwnedGraph};
use rand::Rng;
use std::marker::PhantomData;
use common::{load_graph, Neuron, convert_neuron_from_str, GraphSimilarity, NodeCount};
use cppn::cppn::{Cppn, CppnNode};
use cppn::bipolar::BipolarActivationFunction;
use cppn::substrate::Substrate;
use cppn::position::Position2d;
use neat::weight::{Weight, WeightRange};

type Node = CppnNode<BipolarActivationFunction>;

/// Distribute n points equally within the interval [left, right]

struct DistributeIntervalIter {
    n: usize,
    i: usize,
    left: f64,
    right: f64,
}

impl DistributeIntervalIter {
    fn new(n: usize, left: f64, right: f64) -> Self {
        assert!(left <= right);
        DistributeIntervalIter {
            n: n,
            i: 0,
            left: left,
            right: right,
        }
    }
}

impl Iterator for DistributeIntervalIter {
    type Item = f64;

    fn next(&mut self) -> Option<Self::Item> {
        if self.i >= self.n {
            return None;
        }

        debug_assert!(self.n > 0);

        let width = self.right - self.left;
        let step = width / self.n as f64;
        let start = self.left + (step / 2.0);

        let new = start + (self.i as f64) * step;
        self.i += 1;

        return Some(new);
    }
}

#[test]
fn test_distribute_interval() {
    let mut iter = DistributeIntervalIter::new(0, -1.0, 1.0);
    assert_eq!(None, iter.next());

    let mut iter = DistributeIntervalIter::new(1, -1.0, 1.0);
    assert_eq!(Some(0.0), iter.next());
    assert_eq!(None, iter.next());

    let mut iter = DistributeIntervalIter::new(3, -1.0, 1.0);
    assert_eq!(-66, (iter.next().unwrap() * 100.0) as usize);
    assert_eq!(0, (iter.next().unwrap() * 100.0) as usize);
    assert_eq!(66, (iter.next().unwrap() * 100.0) as usize);
    assert_eq!(None, iter.next());

    let mut iter = DistributeIntervalIter::new(4, -1.0, 1.0);
    assert_eq!(-75, (iter.next().unwrap() * 100.0) as usize);
    assert_eq!(-25, (iter.next().unwrap() * 100.0) as usize);
    assert_eq!(25, (iter.next().unwrap() * 100.0) as usize);
    assert_eq!(75, (iter.next().unwrap() * 100.0) as usize);
    assert_eq!(None, iter.next());

    let mut iter = DistributeIntervalIter::new(5, -1.0, 1.0);
    assert_eq!(-80, (iter.next().unwrap() * 100.0) as usize);
    assert_eq!(-40, (iter.next().unwrap() * 100.0) as usize);
    assert_eq!(0, (iter.next().unwrap() * 100.0) as usize);
    assert_eq!(40, (iter.next().unwrap() * 100.0) as usize);
    assert_eq!(80, (iter.next().unwrap() * 100.0) as usize);
    assert_eq!(None, iter.next());
}

fn genome_to_graph(genome: &Genome<Node>, node_count: &NodeCount) -> OwnedGraph<Neuron> {
    let mut substrate = Substrate::new();

    let mut y_iter = DistributeIntervalIter::new(3, -1.0, 1.0); // 3 layers (Input, Hidden, Output)

    // Inputs
    {
        let y = y_iter.next().unwrap();
        for x in DistributeIntervalIter::new(node_count.inputs, -1.0, 1.0) {
            substrate.add_node(Position2d::new(x, y), Neuron::Input);
        }
    }

    // Hidden
    {
        let y = y_iter.next().unwrap();
        for x in DistributeIntervalIter::new(node_count.hidden, -1.0, 1.0) {
            substrate.add_node(Position2d::new(x, y), Neuron::Hidden);
        }
    }

    // Outputs
    {
        let y = y_iter.next().unwrap();
        for x in DistributeIntervalIter::new(node_count.outputs, -1.0, 1.0) {
            substrate.add_node(Position2d::new(x, y), Neuron::Output);
        }
    }

    let mut cppn = Cppn::new(genome.network());

    // now develop the cppn. the result is a graph
    let mut builder = GraphBuilder::new();
    for (i, node) in substrate.nodes().iter().enumerate() {
        let _ = builder.add_node(i, node.node_type.clone());
    }
    for link in substrate.iter_links(&mut cppn, None) {
        if link.weight >= 0.0 && link.weight <= 1.0 {
            builder.add_edge(link.source_idx,
                             link.target_idx,
                             closed01::Closed01::new(link.weight as f32));
        }
    }
    return builder.graph();
}

#[derive(Debug)]
struct FitnessEvaluator {
    sim: GraphSimilarity,
    node_count: NodeCount,
}

impl FitnessEvaluator {
    // A larger fitness means "better"
    fn fitness(&self, genome: &Genome<Node>) -> f32 {
        self.sim.fitness(genome_to_graph(genome, &self.node_count))
    }
}

struct ES;

impl ElementStrategy<Node> for ES {
    fn link_weight_range(&self) -> WeightRange {
        WeightRange::bipolar(1.0)
    }

    fn full_link_weight(&self) -> Weight {
        WeightRange::bipolar(1.0).high()
    }

    fn random_node_type<R: Rng>(&self, rng: &mut R) -> Node {
        let af = &[BipolarActivationFunction::Identity,
                   BipolarActivationFunction::Linear,
                   BipolarActivationFunction::Gaussian,
                   BipolarActivationFunction::Sigmoid,
                   BipolarActivationFunction::Sine];

        CppnNode::Hidden(*rng.choose(af).unwrap())
    }
}

fn main() {
    let mut rng = rand::thread_rng();

    let cfg = config::Configuration::from_file();

    println!("{:?}", cfg);

    let target_graph = load_graph(&cfg.target_graph_file(), convert_neuron_from_str);
    let node_count = NodeCount::from_graph(&target_graph);

    let fitness_evaluator = FitnessEvaluator {
        sim: GraphSimilarity {
            target_graph: target_graph,
            edge_score: cfg.edge_score(),
            iters: cfg.neighbormatching_iters(),
            eps: cfg.neighbormatching_eps(),
        },
        node_count: node_count,
    };

    let mut cache = GlobalInnovationCache::new();

    // start with minimal random topology.

    let template_genome = {
        let mut genome = Genome::new();

        // 4 inputs (x1,y1,x2,y2)
        for _ in 0..4 {
            genome.add_node(cache.create_node_innovation(), CppnNode::Input);
        }

        // 1 output (y)
        genome.add_node(cache.create_node_innovation(), CppnNode::Output);

        // 1 bias node
        genome.add_node(cache.create_node_innovation(), CppnNode::Bias);

        genome
    };

    let mut initial_pop = Population::<_, Unrated>::new();

    for _ in 0..cfg.population_size() {
        initial_pop.add_genome(Box::new(template_genome.clone()));
    }
    assert!(initial_pop.len() == cfg.population_size());

    let mut mater = Mater {
        p_crossover: cfg.p_crossover(),
        p_crossover_detail: cfg.probabilistic_crossover(),
        p_mutate_element: cfg.p_mutate_element(),
        weight_perturbance: cfg.weight_perturbance(),
        mutate_weights: cfg.mutate_weights(),
        global_cache: &mut cache,
        element_strategy: &ES,
        _n: PhantomData,
    };

    let mut runner = Runner {
        pop_size: cfg.population_size(),
        elite_percentage: cfg.elite_percentage(),
        selection_percentage: cfg.selection_percentage(),
        compatibility_threshold: cfg.compatibility_threshold(),
        compatibility: &cfg.genome_compatibility(),
        mate: &mut mater,
        fitness: &|genome| Fitness::new(fitness_evaluator.fitness(genome) as f64),
        _marker: PhantomData,
    };

    let max_iters = cfg.stop_after_iters();
    let good_fitness = cfg.stop_if_fitness_better_than();
    let (iter, new_pop) = runner.run(initial_pop,
                                     &|iter, pop| {
                                         iter >= max_iters ||
                                         pop.best_individual().unwrap().fitness().get() >
                                         good_fitness
                                     },
                                     &mut rng);

    println!("iter: {}", iter);
    println!("{:#?}", new_pop.best_individual());
}
<commit_msg>Refactor<commit_after>extern crate neat;
extern crate rand;
extern crate graph_neighbor_matching;
extern crate graph_io_gml;
extern crate closed01;
extern crate petgraph;
extern crate cppn;
extern crate asexp;
#[macro_use]
extern crate log;

mod common;
mod config;

use neat::population::{Population, Unrated, Runner};
use neat::genomes::acyclic_network::{Genome, GlobalCache, GlobalInnovationCache, Mater,
                                     ElementStrategy};
use neat::fitness::Fitness;
use graph_neighbor_matching::graph::{GraphBuilder, OwnedGraph};
use rand::Rng;
use std::marker::PhantomData;
use common::{load_graph, Neuron, convert_neuron_from_str, GraphSimilarity, NodeCount};
use cppn::cppn::{Cppn, CppnNode};
use cppn::bipolar::BipolarActivationFunction;
use cppn::substrate::Substrate;
use cppn::position::Position2d;
use neat::weight::{Weight, WeightRange};

type Node = CppnNode<BipolarActivationFunction>;

/// Distribute n points equally within the interval [left, right]

struct DistributeIntervalIter {
    n: usize,
    i: usize,
    left: f64,
    right: f64,
}

impl DistributeIntervalIter {
    fn new(n: usize, left: f64, right: f64) -> Self {
        assert!(left <= right);
        DistributeIntervalIter {
            n: n,
            i: 0,
            left: left,
            right: right,
        }
    }
}

impl Iterator for DistributeIntervalIter {
    type Item = f64;

    fn next(&mut self) -> Option<Self::Item> {
        if self.i >= self.n {
            return None;
        }

        debug_assert!(self.n > 0);

        let width = self.right - self.left;
        let step = width / self.n as f64;
        let start = self.left + (step / 2.0);

        let new = start + (self.i as f64) * step;
        self.i += 1;

        return Some(new);
    }
}

#[test]
fn test_distribute_interval() {
    let mut iter = DistributeIntervalIter::new(0, -1.0, 1.0);
    assert_eq!(None, iter.next());

    let mut iter = DistributeIntervalIter::new(1, -1.0, 1.0);
    assert_eq!(Some(0.0), iter.next());
    assert_eq!(None, iter.next());

    let mut iter = DistributeIntervalIter::new(3, -1.0, 1.0);
    assert_eq!(-66, (iter.next().unwrap() * 100.0) as usize);
    assert_eq!(0, (iter.next().unwrap() * 100.0) as usize);
    assert_eq!(66, (iter.next().unwrap() * 100.0) as usize);
    assert_eq!(None, iter.next());

    let mut iter = DistributeIntervalIter::new(4, -1.0, 1.0);
    assert_eq!(-75, (iter.next().unwrap() * 100.0) as usize);
    assert_eq!(-25, (iter.next().unwrap() * 100.0) as usize);
    assert_eq!(25, (iter.next().unwrap() * 100.0) as usize);
    assert_eq!(75, (iter.next().unwrap() * 100.0) as usize);
    assert_eq!(None, iter.next());

    let mut iter = DistributeIntervalIter::new(5, -1.0, 1.0);
    assert_eq!(-80, (iter.next().unwrap() * 100.0) as usize);
    assert_eq!(-40, (iter.next().unwrap() * 100.0) as usize);
    assert_eq!(0, (iter.next().unwrap() * 100.0) as usize);
    assert_eq!(40, (iter.next().unwrap() * 100.0) as usize);
    assert_eq!(80, (iter.next().unwrap() * 100.0) as usize);
    assert_eq!(None, iter.next());
}

fn generate_substrate(node_count: &NodeCount) -> Substrate<Position2d, Neuron> {
    let mut substrate = Substrate::new();

    let mut y_iter = DistributeIntervalIter::new(3, -1.0, 1.0); // 3 layers (Input, Hidden, Output)

    // Inputs
    {
        let y = y_iter.next().unwrap();
        for x in DistributeIntervalIter::new(node_count.inputs, -1.0, 1.0) {
            substrate.add_node(Position2d::new(x, y), Neuron::Input);
        }
    }

    // Hidden
    {
        let y = y_iter.next().unwrap();
        for x in DistributeIntervalIter::new(node_count.hidden, -1.0, 1.0) {
            substrate.add_node(Position2d::new(x, y), Neuron::Hidden);
        }
    }

    // Outputs
    {
        let y = y_iter.next().unwrap();
        for x in DistributeIntervalIter::new(node_count.outputs, -1.0, 1.0) {
            substrate.add_node(Position2d::new(x, y), Neuron::Output);
        }
    }

    return substrate;
}

fn genome_to_graph(genome: &Genome<Node>, node_count: &NodeCount) -> OwnedGraph<Neuron> {
    let substrate = generate_substrate(node_count);
    let mut cppn = Cppn::new(genome.network());

    // now develop the cppn. the result is a graph
    let mut builder = GraphBuilder::new();
    for (i, node) in substrate.nodes().iter().enumerate() {
        let _ = builder.add_node(i, node.node_type.clone());
    }
    for link in substrate.iter_links(&mut cppn, None) {
        if link.weight >= 0.0 && link.weight <= 1.0 {
            builder.add_edge(link.source_idx,
                             link.target_idx,
                             closed01::Closed01::new(link.weight as f32));
        }
    }
    return builder.graph();
}

#[derive(Debug)]
struct FitnessEvaluator {
    sim: GraphSimilarity,
    node_count: NodeCount,
}

impl FitnessEvaluator {
    // A larger fitness means "better"
    fn fitness(&self, genome: &Genome<Node>) -> f32 {
        self.sim.fitness(genome_to_graph(genome, &self.node_count))
    }
}

struct ES;

impl ElementStrategy<Node> for ES {
    fn link_weight_range(&self) -> WeightRange {
        WeightRange::bipolar(1.0)
    }

    fn full_link_weight(&self) -> Weight {
        WeightRange::bipolar(1.0).high()
    }

    fn random_node_type<R: Rng>(&self, rng: &mut R) -> Node {
        let af = &[BipolarActivationFunction::Identity,
                   BipolarActivationFunction::Linear,
                   BipolarActivationFunction::Gaussian,
                   BipolarActivationFunction::Sigmoid,
                   BipolarActivationFunction::Sine];

        CppnNode::Hidden(*rng.choose(af).unwrap())
    }
}

fn main() {
    let mut rng = rand::thread_rng();

    let cfg = config::Configuration::from_file();

    println!("{:?}", cfg);

    let target_graph = load_graph(&cfg.target_graph_file(), convert_neuron_from_str);
    let node_count = NodeCount::from_graph(&target_graph);

    let fitness_evaluator = FitnessEvaluator {
        sim: GraphSimilarity {
            target_graph: target_graph,
            edge_score: cfg.edge_score(),
            iters: cfg.neighbormatching_iters(),
            eps: cfg.neighbormatching_eps(),
        },
        node_count: node_count,
    };

    let mut cache = GlobalInnovationCache::new();

    // start with minimal random topology.

    let template_genome = {
        let mut genome = Genome::new();

        // 4 inputs (x1,y1,x2,y2)
        for _ in 0..4 {
            genome.add_node(cache.create_node_innovation(), CppnNode::Input);
        }

        // 1 output (y)
        genome.add_node(cache.create_node_innovation(), CppnNode::Output);

        // 1 bias node
        genome.add_node(cache.create_node_innovation(), CppnNode::Bias);

        genome
    };

    let mut initial_pop = Population::<_, Unrated>::new();

    for _ in 0..cfg.population_size() {
        initial_pop.add_genome(Box::new(template_genome.clone()));
    }
    assert!(initial_pop.len() == cfg.population_size());

    let mut mater = Mater {
        p_crossover: cfg.p_crossover(),
        p_crossover_detail: cfg.probabilistic_crossover(),
        p_mutate_element: cfg.p_mutate_element(),
        weight_perturbance: cfg.weight_perturbance(),
        mutate_weights: cfg.mutate_weights(),
        global_cache: &mut cache,
        element_strategy: &ES,
        _n: PhantomData,
    };

    let mut runner = Runner {
        pop_size: cfg.population_size(),
        elite_percentage: cfg.elite_percentage(),
        selection_percentage: cfg.selection_percentage(),
        compatibility_threshold: cfg.compatibility_threshold(),
        compatibility: &cfg.genome_compatibility(),
        mate: &mut mater,
        fitness: &|genome| Fitness::new(fitness_evaluator.fitness(genome) as f64),
        _marker: PhantomData,
    };

    let max_iters = cfg.stop_after_iters();
    let good_fitness = cfg.stop_if_fitness_better_than();
    let (iter, new_pop) = runner.run(initial_pop,
                                     &|iter, pop| {
                                         iter >= max_iters ||
                                         pop.best_individual().unwrap().fitness().get() >
                                         good_fitness
                                     },
                                     &mut rng);

    println!("iter: {}", iter);
    println!("{:#?}", new_pop.best_individual());
}
<|endoftext|>


<commit_before>extern crate odbc_sys;
extern crate odbc_safe;

use odbc_safe::*;

#[test]
fn allocate_environment() {
    Environment::new().unwrap();
}

#[test]
fn allocate_connection() {
    let env = Environment::new().unwrap();
    let env: Environment<Odbc3> = env.declare_version().unwrap();
    DataSource::with_parent(&env).unwrap();
}

#[test]
#[should_panic]
fn wrong_datasource() {
    let env = Environment::new().unwrap();
    let env: Environment<Odbc3> = env.declare_version().unwrap();
    let dbc = DataSource::with_parent(&env).unwrap();
    dbc.connect("DoesntExist", "", "").unwrap();
}

#[test]
fn diagnostics() {

    let expected = if cfg!(target_os = "windows") {
        "[Microsoft][ODBC Driver Manager] Data source name not found and no default driver \
         specified"
    } else {
        "[unixODBC][Driver Manager]Data source name not found, and no default driver specified"
    };

    use std::str;

    let env = Environment::new().unwrap();
    let env: Environment<Odbc3> = env.declare_version().unwrap();

    let dbc = DataSource::with_parent(&env).unwrap();
    let dbc = dbc.connect("DoesntExist", "", "");
    if let Error(d) = dbc {
        let mut message = [0; 512];
        match d.diagnostics(1, &mut message) {
            ReturnOption::Success(rec) => {
                let message = str::from_utf8(&mut message[..(rec.text_length as usize)]).unwrap();
                assert_eq!(expected, message);
            }
            _ => panic!("Error retriving diagnostics"),
        }
    }
}

#[cfg_attr(not(feature = "travis"), ignore)]
#[test]
fn connect_to_postgres() {
    let env = Environment::new().unwrap();
    let env: Environment<Odbc3> = env.declare_version().unwrap();
    let dbc = DataSource::with_parent(&env).unwrap();
    let dbc = dbc.connect("PostgreSQL", "postgres", "");
    match dbc {
        Success(c) => assert_no_diagnostic(&c.disconnect()),
        Info(c) => assert_no_diagnostic(&c),
        Error(c) => assert_no_diagnostic(&c),
    };
}

#[cfg_attr(not(feature = "travis"), ignore)]
#[test]
fn query_result() {
    let env = Environment::new().unwrap();
    let env: Environment<Odbc3> = env.declare_version().unwrap();
    let dbc = DataSource::with_parent(&env).unwrap();
    let dbc = dbc.connect("PostgreSQL", "postgres", "").unwrap();
    {
        let stmt = Statement::with_parent(&dbc).unwrap();
        let stmt = match stmt.exec_direct("SELECT title FROM Movies WHERE year=1968;") {
            ReturnOption::Success(s) | ReturnOption::Info(s) => {
                assert_no_diagnostic(&s);
                s
            }
            ReturnOption::NoData(_) => panic!("No Data"),
            ReturnOption::Error(s) => panic!("{}", get_last_error(&s)),
        };
        assert_eq!(1, stmt.num_result_cols().unwrap());
        let mut stmt = match stmt.fetch() {
            ReturnOption::Success(s) => s,
            ReturnOption::Info(s) => s,
            ReturnOption::Error(s) => panic!("Error during fetching row: {}", get_last_error(&s)),
            ReturnOption::NoData(_) => panic!("Empty result set returned from SELECT"),
        };
        let mut buffer = [0u8; 256];
        if let ReturnOption::Success(Indicator::Length(i)) =
            stmt.get_data(1, &mut buffer as &mut [u8])
        {
            assert_eq!("2001: A Space Odyssey".as_bytes(), &buffer[..(i as usize)]);
        } else {
            panic!("No field found!");
        }
    }
    dbc.disconnect().unwrap();
}

#[cfg_attr(not(feature = "travis"), ignore)]
#[test]
fn auto_disconnect() {
    let env = Environment::new().unwrap();
    let env: Environment<Odbc3> = env.declare_version().unwrap();
    let dbc = DataSource::with_parent(&env).unwrap();
    let dbc = dbc.connect("PostgreSQL", "postgres", "").unwrap();
    // No panic on Drop, because of automatic disconnect
}

/// Checks for a diagnstic record. Should one be present this function panics printing the contents
/// of said record.
fn assert_no_diagnostic(diag: &Diagnostics) {
    use std::str;
    let mut buffer = [0; 512];
    match diag.diagnostics(1, &mut buffer) {
        ReturnOption::Success(dr) | ReturnOption::Info(dr) => panic!(
            "{}",
            str::from_utf8(&buffer[0..(dr.text_length as usize)]).unwrap()
        ),
        ReturnOption::Error(()) => panic!("Error during fetching diagnostic record"),
        ReturnOption::NoData(()) => (),
    }
}

fn get_last_error(diag: &Diagnostics) -> String {
    use std::str;
    let mut buffer = [0; 512];
    match diag.diagnostics(1, &mut buffer) {
        ReturnOption::Success(dr) | ReturnOption::Info(dr) => str::from_utf8(
            &buffer[0..(dr.text_length as usize)],
        ).unwrap()
            .to_owned(),
        ReturnOption::Error(()) => panic!("Error during fetching diagnostic record"),
        ReturnOption::NoData(()) => panic!("No diagnostic available"),
    }
}
<commit_msg>remove unused variable<commit_after>extern crate odbc_sys;
extern crate odbc_safe;

use odbc_safe::*;

#[test]
fn allocate_environment() {
    Environment::new().unwrap();
}

#[test]
fn allocate_connection() {
    let env = Environment::new().unwrap();
    let env: Environment<Odbc3> = env.declare_version().unwrap();
    DataSource::with_parent(&env).unwrap();
}

#[test]
#[should_panic]
fn wrong_datasource() {
    let env = Environment::new().unwrap();
    let env: Environment<Odbc3> = env.declare_version().unwrap();
    let dbc = DataSource::with_parent(&env).unwrap();
    dbc.connect("DoesntExist", "", "").unwrap();
}

#[test]
fn diagnostics() {

    let expected = if cfg!(target_os = "windows") {
        "[Microsoft][ODBC Driver Manager] Data source name not found and no default driver \
         specified"
    } else {
        "[unixODBC][Driver Manager]Data source name not found, and no default driver specified"
    };

    use std::str;

    let env = Environment::new().unwrap();
    let env: Environment<Odbc3> = env.declare_version().unwrap();

    let dbc = DataSource::with_parent(&env).unwrap();
    let dbc = dbc.connect("DoesntExist", "", "");
    if let Error(d) = dbc {
        let mut message = [0; 512];
        match d.diagnostics(1, &mut message) {
            ReturnOption::Success(rec) => {
                let message = str::from_utf8(&mut message[..(rec.text_length as usize)]).unwrap();
                assert_eq!(expected, message);
            }
            _ => panic!("Error retriving diagnostics"),
        }
    }
}

#[cfg_attr(not(feature = "travis"), ignore)]
#[test]
fn connect_to_postgres() {
    let env = Environment::new().unwrap();
    let env: Environment<Odbc3> = env.declare_version().unwrap();
    let dbc = DataSource::with_parent(&env).unwrap();
    let dbc = dbc.connect("PostgreSQL", "postgres", "");
    match dbc {
        Success(c) => assert_no_diagnostic(&c.disconnect()),
        Info(c) => assert_no_diagnostic(&c),
        Error(c) => assert_no_diagnostic(&c),
    };
}

#[cfg_attr(not(feature = "travis"), ignore)]
#[test]
fn query_result() {
    let env = Environment::new().unwrap();
    let env: Environment<Odbc3> = env.declare_version().unwrap();
    let dbc = DataSource::with_parent(&env).unwrap();
    let dbc = dbc.connect("PostgreSQL", "postgres", "").unwrap();
    {
        let stmt = Statement::with_parent(&dbc).unwrap();
        let stmt = match stmt.exec_direct("SELECT title FROM Movies WHERE year=1968;") {
            ReturnOption::Success(s) | ReturnOption::Info(s) => {
                assert_no_diagnostic(&s);
                s
            }
            ReturnOption::NoData(_) => panic!("No Data"),
            ReturnOption::Error(s) => panic!("{}", get_last_error(&s)),
        };
        assert_eq!(1, stmt.num_result_cols().unwrap());
        let mut stmt = match stmt.fetch() {
            ReturnOption::Success(s) => s,
            ReturnOption::Info(s) => s,
            ReturnOption::Error(s) => panic!("Error during fetching row: {}", get_last_error(&s)),
            ReturnOption::NoData(_) => panic!("Empty result set returned from SELECT"),
        };
        let mut buffer = [0u8; 256];
        if let ReturnOption::Success(Indicator::Length(i)) =
            stmt.get_data(1, &mut buffer as &mut [u8])
        {
            assert_eq!("2001: A Space Odyssey".as_bytes(), &buffer[..(i as usize)]);
        } else {
            panic!("No field found!");
        }
    }
    dbc.disconnect().unwrap();
}

#[cfg_attr(not(feature = "travis"), ignore)]
#[test]
fn auto_disconnect() {
    let env = Environment::new().unwrap();
    let env: Environment<Odbc3> = env.declare_version().unwrap();
    let dbc = DataSource::with_parent(&env).unwrap();
    dbc.connect("PostgreSQL", "postgres", "").unwrap();
    // No panic on Drop, because of automatic disconnect
}

/// Checks for a diagnstic record. Should one be present this function panics printing the contents
/// of said record.
fn assert_no_diagnostic(diag: &Diagnostics) {
    use std::str;
    let mut buffer = [0; 512];
    match diag.diagnostics(1, &mut buffer) {
        ReturnOption::Success(dr) | ReturnOption::Info(dr) => panic!(
            "{}",
            str::from_utf8(&buffer[0..(dr.text_length as usize)]).unwrap()
        ),
        ReturnOption::Error(()) => panic!("Error during fetching diagnostic record"),
        ReturnOption::NoData(()) => (),
    }
}

fn get_last_error(diag: &Diagnostics) -> String {
    use std::str;
    let mut buffer = [0; 512];
    match diag.diagnostics(1, &mut buffer) {
        ReturnOption::Success(dr) | ReturnOption::Info(dr) => str::from_utf8(
            &buffer[0..(dr.text_length as usize)],
        ).unwrap()
            .to_owned(),
        ReturnOption::Error(()) => panic!("Error during fetching diagnostic record"),
        ReturnOption::NoData(()) => panic!("No diagnostic available"),
    }
}
<|endoftext|>


<commit_before>#[macro_use(owned_tree)]
extern crate entmut;

use ::entmut::Nav;
use ::entmut::owned::Tree;

// This will define macros for generalized tests of Nav and Editor impls.
// #[cfg(test)]
// mod template;

#[test]
#[allow(unused_variables)]
fn view_instantiation() {
    let t = owned_tree!["a"];
    let v = t.view();
}

#[test]
fn view_preserves_leaf_topology() {
    let t = owned_tree!["a"];
    let v = t.view();
    assert![v.at_leaf()];
    assert![v.at_root()];
    assert_eq![0, v.child_count()];
}

#[test]
fn view_preserves_leaf_data() {
    let t = owned_tree!["a"];
    let v = t.view();
    assert_eq!["a", *v];
}

#[test]
fn view_seek_root_sibling_fails() {
    let t = owned_tree!["a"];
    let mut v = t.view();
    assert![v.seek_sibling(0)];
    assert![! v.seek_sibling(-1)];
    assert![! v.seek_sibling(1)];
}
<commit_msg>Additional Nav tests for seeking siblings of root and counting children.<commit_after>#[macro_use(owned_tree)]
extern crate entmut;

use ::entmut::Nav;
use ::entmut::owned::Tree;

// This will define macros for generalized tests of Nav and Editor impls.
// #[cfg(test)]
// mod template;

#[test]
#[allow(unused_variables)]
fn view_instantiation() {
    let t = owned_tree!["a"];
    let v = t.view();
}

#[test]
fn view_preserves_leaf_topology() {
    let t = owned_tree!["a"];
    let v = t.view();
    assert![v.at_leaf()];
    assert![v.at_root()];
    assert_eq![0, v.child_count()];
}

#[test]
fn view_preserves_leaf_data() {
    let t = owned_tree!["a"];
    let v = t.view();
    assert_eq!["a", *v];
}

#[test]
fn view_seek_root_sibling_noop_succeeds() {
    let t = owned_tree!["a"];
    let mut v = t.view();
    assert![v.seek_sibling(0)];
}

#[test]
fn view_seek_root_sibling_fails() {
    let t = owned_tree!["a"];
    let mut v = t.view();
    assert![! v.seek_sibling(-1)];
    assert![! v.seek_sibling(1)];
}

#[test]
fn view_counts_children_correctly() {
    let t = owned_tree!["a", ["b", ["e"], ["f"]], ["c"], ["d"]];
    let mut v = t.view();
    assert_eq![3, v.child_count()];
    assert![v.seek_child(0)];
    assert_eq![2, v.child_count()];
    assert![v.seek_sibling(1)];
    assert_eq![0, v.child_count()];
}
<|endoftext|>


<commit_before>#![allow(dead_code)]
#[macro_use]
extern crate derive_more;

#[derive(Mul)]
struct MyInt(i32);

#[derive(Mul)]
struct MyInts(i32, i32);

#[derive(Mul)]
struct Point1D {
    x: i32,
}

#[derive(Mul)]
struct Point2D {
    x: i32,
    y: i32,
}
<commit_msg>Tests: Ignore a warning<commit_after>#![allow(dead_code, non_camel_case_types)]
#![allow(dead_code)]
#[macro_use]
extern crate derive_more;

#[derive(Mul)]
struct MyInt(i32);

#[derive(Mul)]
struct MyInts(i32, i32);

#[derive(Mul)]
struct Point1D {
    x: i32,
}

#[derive(Mul)]
struct Point2D {
    x: i32,
    y: i32,
}
<|endoftext|>


<commit_before>//
// base64.rs - base64 implementation
//
// The Base64 Alphabet
//
//  Value Encoding  Value Encoding  Value Encoding  Value Encoding
//   0 A            17 R            34 i            51 z
//   1 B            18 S            35 j            52 0
//   2 C            19 T            36 k            53 1
//   3 D            20 U            37 l            54 2
//   4 E            21 V            38 m            55 3
//   5 F            22 W            39 n            56 4
//   6 G            23 X            40 o            57 5
//   7 H            24 Y            41 p            58 6
//   8 I            25 Z            42 q            59 7
//   9 J            26 a            43 r            60 8
//  10 K            27 b            44 s            61 9
//  11 L            28 c            45 t            62 +
//  12 M            29 d            46 u            63 /
//  13 N            30 e            47 v
//  14 O            31 f            48 w         (pad) =
//  15 P            32 g            49 x
//  16 Q            33 h            50 y
//

use std;

import std::map;

export base64, mk_base64;

iface base64 {
    fn encode(src: [u8]) -> [u8];
    fn decode(src: [u8]) -> [u8];
    fn urlsafe_encode(src: [u8]) -> [u8];
    fn urlsafe_decode(src: [u8]) -> [u8];
}

fn mk_base64() -> base64 {
    type _base64 = {padd: u8, mutable table: [u8]};
    impl of base64 for _base64 {
        fn encode(src: [u8]) -> [u8] {
            let srclen = vec::len(src);
            let targ = if srclen % 3u == 0u {
                vec::init_elt_mut((srclen / 3u) * 4u, 0u8)
            } else {
                vec::init_elt_mut((srclen / 3u + 1u) * 4u, 0u8)
            };
            let input = vec::init_elt_mut(3u, 0u8);
            let output = vec::init_elt_mut(4u, 0u8);
            let curr = 0u, src_curr = 0u;
            let table = self.table;

            while srclen > 2u {
                input[0] = src[src_curr];
                input[1] = src[src_curr + 1u];
                input[2] = src[src_curr + 2u];
                srclen -= 3u; src_curr += 3u;

                output[0] = input[0] >> 2u8;
                output[1] = ((input[0] &  3u8) << 4u8) | (input[1] >> 4u8);
                output[2] = ((input[1] & 15u8) << 2u8) | (input[2] >> 6u8);
                output[3] = input[2] & 63u8;

                targ[curr] = table[output[0]]; curr += 1u;
                targ[curr] = table[output[1]]; curr += 1u;
                targ[curr] = table[output[2]]; curr += 1u;
                targ[curr] = table[output[3]]; curr += 1u;
            }

            if srclen != 0u {
                input[0] = 0u8; input[1] = 0u8; input[2] = 0u8;

                alt srclen {
                  1u { input[0] = src[src_curr]; }
                  2u { input[0] = src[src_curr];
                       input[1] = src[src_curr + 1u]; }
                  _  { }
                }

                output[0] = input[0] >> 2u8;
                output[1] = ((input[0] &  3u8) << 4u8) | (input[1] >> 4u8);
                output[2] = ((input[1] & 15u8) << 2u8) | (input[2] >> 6u8);

                targ[curr] = table[output[0]]; curr += 1u;
                targ[curr] = table[output[1]]; curr += 1u;
                targ[curr] = if srclen == 1u {
                    self.padd
                } else {
                    table[output[2]]
                };
                curr += 1u; targ[curr] = self.padd;
            }

            vec::from_mut(targ)
        }
        fn decode(src: [u8]) -> [u8] {
            let srclen = vec::len(src);

            if srclen % 4u != 0u { fail "malformed base64 string"; }
            if srclen == 0u { ret []; }

            let input  = vec::init_elt_mut(4u, 0u8);
            let output = vec::init_elt_mut(4u, 0u8);
            let targ = if src[srclen - 2u] == self.padd {
                vec::init_elt_mut(srclen / 4u * 3u - 2u, 0u8)
            } else if src[srclen - 1u] == self.padd {
                vec::init_elt_mut(srclen / 4u * 3u - 1u, 0u8)
            } else {
                vec::init_elt_mut(srclen / 4u * 3u, 0u8)
            };
            let curr = 0u, src_curr = 0u;

            while srclen > 4u {
                input[0] = src[src_curr];
                input[1] = src[src_curr + 1u];
                input[2] = src[src_curr + 2u];
                input[3] = src[src_curr + 3u];
                srclen -= 4u; src_curr += 4u;

                output[0] = b64idx(input[0]);
                output[1] = b64idx(input[1]);
                output[2] = b64idx(input[2]);
                output[3] = b64idx(input[3]);

                targ[curr] = (output[0] << 2u8) | (output[1] >> 4u8);
                curr += 1u;

                targ[curr] =
                    ((output[1] & 15u8) << 4u8) | (output[2] >> 2u8);
                curr += 1u;

                targ[curr] = ((output[2] &  3u8) << 6u8) | output[3];
                curr += 1u;
            }

            if srclen == 4u {
                input[0] = src[src_curr];
                input[1] = src[src_curr + 1u];
                input[2] = src[src_curr + 2u];
                input[3] = src[src_curr + 3u];

                output[0] = b64idx(input[0]);
                output[1] = b64idx(input[1]);

                targ[curr] = (output[0] << 2u8) | (output[1] >> 4u8);
                curr += 1u;

                if input[2] == self.padd { ret vec::from_mut(targ); }

                output[2] = b64idx(input[2]);

                targ[curr] = ((output[1] & 15u8) << 4u8) | (output[2] >> 2u8);
                curr += 1u;

                if input[3] == self.padd { ret vec::from_mut(targ); }

                output[3] = b64idx(input[3]);

                targ[curr] = ((output[2] & 3u8) << 6u8) | output[3];
            }

            vec::from_mut(targ)
        }
        fn urlsafe_encode(src: [u8]) -> [u8] {
            let tmp = self.table;
            self.table = vec::map(tmp) { |i|
                if i == 43u8 { 45u8 }
                else if i == 47u8 { 95u8 }
                else { i }
            };
            let res = self.encode(src);
            self.table = tmp;
            res
        }
        fn urlsafe_decode(src: [u8]) -> [u8] {
            let tmp = self.table;
            self.table = vec::map(tmp) { |i|
                if i == 43u8 { 45u8 }
                else if i == 47u8 { 95u8 }
                else { i }
            };
            let res = self.decode(src);
            self.table = tmp;
            res
        }
    }

    let table = vec::init_elt_mut(64u, 0u8), i = 0u8;
    u8::range(65u8, 91u8)  { |j| table[i] = j; i += 1u8; }
    u8::range(97u8, 123u8) { |j| table[i] = j; i += 1u8; }
    u8::range(48u8, 58u8)  { |j| table[i] = j; i += 1u8; }
    table[i] = 43u8; i += 1u8;
    table[i] = 47u8; i += 1u8;

    {padd: 61u8, mutable table: vec::from_mut(table)} as base64
}

inline fn b64idx(x: u8) -> u8 {
    if 65u8 <= x && x <= 90u8 { x - 65u8 }
    else if 97u8 <= x && x <= 122u8 { x - 97u8 + 26u8 }
    else if 48u8 <= x && x <= 58u8  { x - 48u8 + 52u8 }
    else if x == 43u8 { 62u8 }
    else if x == 47u8 { 63u8 }
    else { fail "malformed base64 string"; }
}

#[cfg(test)]
mod tests {
    import core::str::{from_bytes, bytes};
    enum mode {
        t_decode,
        t_encode,
        t_urlsafe_encode,
        t_urlsafe_decode
    }
    fn setup(t: mode) -> map::hashmap<str, str> {
        let m = map::new_str_hash::<str>();
        m.insert("", "");
        alt t {
          t_decode | t_urlsafe_decode {
            m.insert("cGxlYXN1cmUu", "pleasure.");
            m.insert("bGVhc3VyZS4=",  "leasure.");
            m.insert("ZWFzdXJlLg==",   "easure.");
            m.insert("YXN1cmUu",        "asure.");
            m.insert("c3VyZS4=",         "sure.");
          }
          t_encode | t_urlsafe_encode {
            m.insert("pleasure.", "cGxlYXN1cmUu");
            m.insert("leasure.",  "bGVhc3VyZS4=");
            m.insert("easure.",   "ZWFzdXJlLg==");
            m.insert("asure.",        "YXN1cmUu");
            m.insert("sure.",         "c3VyZS4=");
          }
        }
        m
    }
    fn do_test(t: mode) {
        let b64 = mk_base64();
        let m = setup(t);
        m.keys { |k|
            let expected = m.get(k);
            let actual = alt t {
              t_decode { from_bytes(b64.decode(bytes(k))) }
              t_encode { from_bytes(b64.encode(bytes(k))) }
              t_urlsafe_decode { from_bytes(b64.urlsafe_decode(bytes(k))) }
              t_urlsafe_encode { from_bytes(b64.urlsafe_encode(bytes(k))) }
            };
            #debug("expected: %s", expected);
            #debug("actual:   %s", actual);
            assert expected == actual;
        }
    }
    #[test]
    fn decode() { do_test(t_decode); }
    #[test]
    fn encode() { do_test(t_encode); }
    #[test]
    fn urlsafe_decode() { do_test(t_urlsafe_decode); }
    #[test]
    fn urlsafe_encode() { do_test(t_urlsafe_encode); }
}
<commit_msg>changes<commit_after>//
// base64.rs - base64 implementation
//
// The Base64 Alphabet
//
//  Value Encoding  Value Encoding  Value Encoding  Value Encoding
//   0 A            17 R            34 i            51 z
//   1 B            18 S            35 j            52 0
//   2 C            19 T            36 k            53 1
//   3 D            20 U            37 l            54 2
//   4 E            21 V            38 m            55 3
//   5 F            22 W            39 n            56 4
//   6 G            23 X            40 o            57 5
//   7 H            24 Y            41 p            58 6
//   8 I            25 Z            42 q            59 7
//   9 J            26 a            43 r            60 8
//  10 K            27 b            44 s            61 9
//  11 L            28 c            45 t            62 +
//  12 M            29 d            46 u            63 /
//  13 N            30 e            47 v
//  14 O            31 f            48 w         (pad) =
//  15 P            32 g            49 x
//  16 Q            33 h            50 y
//

use std;

import std::map;

export base64, mk_base64;

iface base64 {
    fn encode(src: [u8]) -> [u8];
    fn decode(src: [u8]) -> [u8];
    fn urlsafe_encode(src: [u8]) -> [u8];
    fn urlsafe_decode(src: [u8]) -> [u8];
}

fn mk_base64() -> base64 {
    type _base64 = {padd: u8, table: [mutable u8]};
    impl of base64 for _base64 {
        fn encode(src: [u8]) -> [u8] {
            let srclen = vec::len(src);
            let targ = if srclen % 3u == 0u {
                vec::init_elt_mut((srclen / 3u) * 4u, 0u8)
            } else {
                vec::init_elt_mut((srclen / 3u + 1u) * 4u, 0u8)
            };
            let input = vec::init_elt_mut(3u, 0u8);
            let output = vec::init_elt_mut(4u, 0u8);
            let curr = 0u, src_curr = 0u;
            let table = self.table;

            while srclen > 2u {
                input[0] = src[src_curr];
                input[1] = src[src_curr + 1u];
                input[2] = src[src_curr + 2u];
                srclen -= 3u; src_curr += 3u;

                output[0] = input[0] >> 2u8;
                output[1] = ((input[0] &  3u8) << 4u8) | (input[1] >> 4u8);
                output[2] = ((input[1] & 15u8) << 2u8) | (input[2] >> 6u8);
                output[3] = input[2] & 63u8;

                targ[curr] = table[output[0]]; curr += 1u;
                targ[curr] = table[output[1]]; curr += 1u;
                targ[curr] = table[output[2]]; curr += 1u;
                targ[curr] = table[output[3]]; curr += 1u;
            }

            if srclen != 0u {
                input[0] = 0u8; input[1] = 0u8; input[2] = 0u8;

                alt srclen {
                  1u { input[0] = src[src_curr]; }
                  2u { input[0] = src[src_curr];
                       input[1] = src[src_curr + 1u]; }
                  _  { }
                }

                output[0] = input[0] >> 2u8;
                output[1] = ((input[0] &  3u8) << 4u8) | (input[1] >> 4u8);
                output[2] = ((input[1] & 15u8) << 2u8) | (input[2] >> 6u8);

                targ[curr] = table[output[0]]; curr += 1u;
                targ[curr] = table[output[1]]; curr += 1u;
                targ[curr] = if srclen == 1u {
                    self.padd
                } else {
                    table[output[2]]
                };
                curr += 1u; targ[curr] = self.padd;
            }

            vec::from_mut(targ)
        }
        fn decode(src: [u8]) -> [u8] {
            let srclen = vec::len(src);

            if srclen % 4u != 0u { fail "malformed base64 string"; }
            if srclen == 0u { ret []; }

            let input  = vec::init_elt_mut(4u, 0u8);
            let output = vec::init_elt_mut(4u, 0u8);
            let targ = if src[srclen - 2u] == self.padd {
                vec::init_elt_mut(srclen / 4u * 3u - 2u, 0u8)
            } else if src[srclen - 1u] == self.padd {
                vec::init_elt_mut(srclen / 4u * 3u - 1u, 0u8)
            } else {
                vec::init_elt_mut(srclen / 4u * 3u, 0u8)
            };
            let curr = 0u, src_curr = 0u;

            while srclen > 4u {
                input[0] = src[src_curr];
                input[1] = src[src_curr + 1u];
                input[2] = src[src_curr + 2u];
                input[3] = src[src_curr + 3u];
                srclen -= 4u; src_curr += 4u;

                output[0] = b64idx(input[0], self.table[62], self.table[63]);
                output[1] = b64idx(input[1], self.table[62], self.table[63]);
                output[2] = b64idx(input[2], self.table[62], self.table[63]);
                output[3] = b64idx(input[3], self.table[62], self.table[63]);

                targ[curr] = (output[0] << 2u8) | (output[1] >> 4u8);
                curr += 1u;

                targ[curr] =
                    ((output[1] & 15u8) << 4u8) | (output[2] >> 2u8);
                curr += 1u;

                targ[curr] = ((output[2] &  3u8) << 6u8) | output[3];
                curr += 1u;
            }

            if srclen == 4u {
                input[0] = src[src_curr];
                input[1] = src[src_curr + 1u];
                input[2] = src[src_curr + 2u];
                input[3] = src[src_curr + 3u];

                output[0] = b64idx(input[0], self.table[62], self.table[63]);
                output[1] = b64idx(input[1], self.table[62], self.table[63]);

                targ[curr] = (output[0] << 2u8) | (output[1] >> 4u8);
                curr += 1u;

                if input[2] == self.padd { ret vec::from_mut(targ); }

                output[2] = b64idx(input[2], self.table[62], self.table[63]);

                targ[curr] = ((output[1] & 15u8) << 4u8) | (output[2] >> 2u8);
                curr += 1u;

                if input[3] == self.padd { ret vec::from_mut(targ); }

                output[3] = b64idx(input[3], self.table[62], self.table[63]);

                targ[curr] = ((output[2] & 3u8) << 6u8) | output[3];
            }

            vec::from_mut(targ)
        }
        fn urlsafe_encode(src: [u8]) -> [u8] {
            self.table[62] = 45u8;
            self.table[63] = 95u8;
            let res = self.encode(src);
            self.table[62] = 43u8;
            self.table[63] = 47u8;
            res
        }
        fn urlsafe_decode(src: [u8]) -> [u8] {
            self.table[62] = 45u8;
            self.table[63] = 95u8;
            let res = self.decode(src);
            self.table[62] = 43u8;
            self.table[63] = 47u8;
            res
        }
    }

    let table = vec::init_elt_mut(64u, 0u8), i = 0u8;
    u8::range(65u8, 91u8)  { |j| table[i] = j; i += 1u8; }
    u8::range(97u8, 123u8) { |j| table[i] = j; i += 1u8; }
    u8::range(48u8, 58u8)  { |j| table[i] = j; i += 1u8; }
    table[i] = 43u8; i += 1u8;
    table[i] = 47u8; i += 1u8;

    {padd: 61u8, table: table} as base64
}

inline fn b64idx(x: u8, y: u8, z: u8) -> u8 {
    if 65u8 <= x && x <= 90u8 { x - 65u8 }
    else if 97u8 <= x && x <= 122u8 { x - 97u8 + 26u8 }
    else if 48u8 <= x && x <= 58u8  { x - 48u8 + 52u8 }
    else if x == y { 62u8 }
    else if x == z { 63u8 }
    else { fail "malformed base64 string"; }
}

#[cfg(test)]
mod tests {
    import core::str::{from_bytes, bytes};
    enum mode {
        t_decode,
        t_encode,
        t_urlsafe_encode,
        t_urlsafe_decode
    }
    fn setup(t: mode) -> map::hashmap<str, str> {
        let m = map::new_str_hash::<str>();
        m.insert("", "");
        alt t {
          t_decode | t_urlsafe_decode {
            m.insert("cGxlYXN1cmUu", "pleasure.");
            m.insert("bGVhc3VyZS4=",  "leasure.");
            m.insert("ZWFzdXJlLg==",   "easure.");
            m.insert("YXN1cmUu",        "asure.");
            m.insert("c3VyZS4=",         "sure.");
          }
          t_encode | t_urlsafe_encode {
            m.insert("pleasure.", "cGxlYXN1cmUu");
            m.insert("leasure.",  "bGVhc3VyZS4=");
            m.insert("easure.",   "ZWFzdXJlLg==");
            m.insert("asure.",        "YXN1cmUu");
            m.insert("sure.",         "c3VyZS4=");
          }
        }
        m
    }
    fn do_test(t: mode) {
        let b64 = mk_base64();
        let m = setup(t);
        m.keys { |k|
            let expected = m.get(k);
            let actual = alt t {
              t_decode { from_bytes(b64.decode(bytes(k))) }
              t_encode { from_bytes(b64.encode(bytes(k))) }
              t_urlsafe_decode { from_bytes(b64.urlsafe_decode(bytes(k))) }
              t_urlsafe_encode { from_bytes(b64.urlsafe_encode(bytes(k))) }
            };
            #debug("expected: %s", expected);
            #debug("actual:   %s", actual);
            assert expected == actual;
        }
    }
    #[test]
    fn decode() { do_test(t_decode); }
    #[test]
    fn encode() { do_test(t_encode); }
    #[test]
    fn urlsafe_decode() { do_test(t_urlsafe_decode); }
    #[test]
    fn urlsafe_encode() { do_test(t_urlsafe_encode); }
}
<|endoftext|>


<commit_before>///! fff-lang
///!
///! semantic/package, a compilation unit

use codemap::SourceMap;
use codemap::SymbolCollection;
use message::MessageCollection;
use syntax;

use super::Module;
use super::FromSession;
use super::SharedDefScope;
use super::ISemanticAnalyze;

#[cfg_attr(test, derive(Eq, PartialEq, Debug))]
pub struct Package {
    pub main_module: Module,
    pub global_scope: SharedDefScope,
}
impl Package {

    /// semantic module driver
    ///
    /// source, messages, symbols routine, sources is not mutable because logically it is
    pub fn new(tree: syntax::SyntaxTree, sources: &SourceMap, symbols: &mut SymbolCollection, _messages: &mut MessageCollection) -> Package {
        let mut tree = tree; // do not mut in parameter because I want to leave this driver beautiful

        // Phase 1: direct map, scope management, dependent tree
        let main_source = sources.index(0);
        let global_sess = FromSession::new(SharedDefScope::new(""), main_source.as_ref(), symbols);
        let mut main_module = Module::from_syntax(tree.modules[0].move_out(), global_sess.clone_scope());
        main_module.buildup_imports(&tree.import_maps, &mut tree.modules, sources, symbols);

        // Phase 2: collect type declares, not definitions

        Package{ global_scope: global_sess.into_scope(), main_module }
    }
}

#[cfg(test)] #[test]
fn package_buildup_import_map() {
    use std::rc::Rc;
    use codemap::SourceCode;
    use codemap::Span;
    use super::*;

    let sources = make_sources![
        Rc::new(SourceCode::pretend_with_file_name(0, vec!["main.ff"], "import a; import b;")),
        Rc::new(SourceCode::pretend_with_file_name(1, vec!["a", "module.ff"], "import c;")),
        Rc::new(SourceCode::pretend_with_file_name(2, vec!["b.ff"], "")),
        Rc::new(SourceCode::pretend_with_file_name(3, vec!["a", "c", "module.ff"], "import d;")),
        Rc::new(SourceCode::pretend_with_file_name(4, vec!["a", "c", "d.ff"], "")),
    ];
    let mut symbols = make_symbols!["a", "b", "c", "d"];
    let mut messages = make_messages![];

    let package = Package::new(syntax::SyntaxTree::new_modules(vec![
        syntax::Module::new(sources.index(0), vec![
            syntax::Item::Import(syntax::ImportStatement::new_default(make_span!(0, 1, 1), syntax::SimpleName::new(make_id!(1), make_span!(0, 2, 2)))),
            syntax::Item::Import(syntax::ImportStatement::new_default(make_span!(0, 3, 3), syntax::SimpleName::new(make_id!(2), make_span!(0, 4, 4)))),
        ]),
        syntax::Module::new(sources.index(1), vec![
            syntax::Item::Import(syntax::ImportStatement::new_default(make_span!(1, 1, 1), syntax::SimpleName::new(make_id!(3), make_span!(1, 2, 2)))),
        ]),
        syntax::Module::new(sources.index(2), vec![]),
        syntax::Module::new(sources.index(3), vec![
            syntax::Item::Import(syntax::ImportStatement::new_default(make_span!(3, 1, 1), syntax::SimpleName::new(make_id!(4), make_span!(3, 2, 2)))),
        ]),
        syntax::Module::new(sources.index(4), vec![]),
    ], vec![
        syntax::ImportMap::new(0, make_id!(1), 1),
        syntax::ImportMap::new(0, make_id!(2), 2),
        syntax::ImportMap::new(1, make_id!(3), 3),
        syntax::ImportMap::new(3, make_id!(4), 4),
    ]), &sources, &mut symbols, &mut messages);

    let expect = Module{
        module_id: 0,
        this_scope: SharedDefScope::new(""),
        items: vec![
            Item::Import(ImportStatement{
                name: SimpleName{
                    value: make_id!(1),
                    parent_scope: SharedDefScope::new(""),
                },
                alias: None,
                parent_scope: SharedDefScope::new(""),
                module: Some(Module{

                    module_id: 1,
                    this_scope: SharedDefScope::new("").sub("a"),
                    items: vec![
                        Item::Import(ImportStatement{
                            name: SimpleName{
                                value: make_id!(3),
                                parent_scope: SharedDefScope::new("").sub("a"),
                            },
                            alias: None,
                            parent_scope: SharedDefScope::new("").sub("a"),
                            module: Some(Module{
                                module_id: 3,
                                this_scope: SharedDefScope::new("").sub("a").sub("c"),
                                items: vec![
                                    Item::Import(ImportStatement{
                                        name: SimpleName{
                                            value: make_id!(4),
                                            parent_scope: SharedDefScope::new("").sub("a").sub("c"),
                                        },
                                        parent_scope: SharedDefScope::new("").sub("a").sub("c"),
                                        alias: None,
                                        module: Some(Module{
                                            module_id: 4,
                                            this_scope: SharedDefScope::new("").sub("a").sub("c").sub("d"),
                                            items: vec![],
                                        }),
                                    }),
                                ],
                            }),
                        }),
                    ],
                }),
            }),
            Item::Import(ImportStatement{
                name: SimpleName{
                    value: make_id!(2),
                    parent_scope: SharedDefScope::new(""),
                },
                alias: None,
                parent_scope: SharedDefScope::new(""),
                module: Some(Module{
                    module_id: 2,
                    this_scope: SharedDefScope::new("").sub("b"),
                    items: vec![],
                }),
            }),
        ],
    };

    if package.main_module != expect {
        let symbols = make_symbols!["a", "b", "c", "d"];
        // assert_eq!(package.main_module, expect);
        let formatter = Formatter::new(None, Some(&symbols));
        panic!("assertion failed, left: `\n{}`, right: `\n{}`", package.main_module.format(formatter.clone()), expect.format(formatter));
    }
}

// TODO: remove ISemanticAnalyze::format default implementation and check synatx integration tests' missing nodes
// TODO: Check scope management in more precisely
// consider use unique ids to replace unaccessible names (contains scope segment with span)
<commit_msg>[semantic] fix comments<commit_after>///! fff-lang
///!
///! semantic/package, a compilation unit

use codemap::SourceMap;
use codemap::SymbolCollection;
use message::MessageCollection;
use syntax;

use super::Module;
use super::FromSession;
use super::SharedDefScope;
use super::ISemanticAnalyze;

#[cfg_attr(test, derive(Eq, PartialEq, Debug))]
pub struct Package {
    pub main_module: Module,
    pub global_scope: SharedDefScope,
}
impl Package {

    /// semantic module driver
    ///
    /// source, messages, symbols routine, sources is not mutable because logically it is
    pub fn new(tree: syntax::SyntaxTree, sources: &SourceMap, symbols: &mut SymbolCollection, _messages: &mut MessageCollection) -> Package {
        let mut tree = tree; // do not mut in parameter because I want to leave this driver beautiful

        // Phase 1: direct map, scope management, dependent tree
        let main_source = sources.index(0);
        let global_sess = FromSession::new(SharedDefScope::new(""), main_source.as_ref(), symbols);
        let mut main_module = Module::from_syntax(tree.modules[0].move_out(), global_sess.clone_scope());
        main_module.buildup_imports(&tree.import_maps, &mut tree.modules, sources, symbols);

        // Phase 2: collect type declares, not definitions

        Package{ global_scope: global_sess.into_scope(), main_module }
    }
}

#[cfg(test)] #[test]
fn package_buildup_import_map() {
    use std::rc::Rc;
    use codemap::SourceCode;
    use codemap::Span;
    use super::*;

    let sources = make_sources![
        Rc::new(SourceCode::pretend_with_file_name(0, vec!["main.ff"], "import a; import b;")),
        Rc::new(SourceCode::pretend_with_file_name(1, vec!["a", "module.ff"], "import c;")),
        Rc::new(SourceCode::pretend_with_file_name(2, vec!["b.ff"], "")),
        Rc::new(SourceCode::pretend_with_file_name(3, vec!["a", "c", "module.ff"], "import d;")),
        Rc::new(SourceCode::pretend_with_file_name(4, vec!["a", "c", "d.ff"], "")),
    ];
    let mut symbols = make_symbols!["a", "b", "c", "d"];
    let mut messages = make_messages![];

    let package = Package::new(syntax::SyntaxTree::new_modules(vec![
        syntax::Module::new(sources.index(0), vec![
            syntax::Item::Import(syntax::ImportStatement::new_default(make_span!(0, 1, 1), syntax::SimpleName::new(make_id!(1), make_span!(0, 2, 2)))),
            syntax::Item::Import(syntax::ImportStatement::new_default(make_span!(0, 3, 3), syntax::SimpleName::new(make_id!(2), make_span!(0, 4, 4)))),
        ]),
        syntax::Module::new(sources.index(1), vec![
            syntax::Item::Import(syntax::ImportStatement::new_default(make_span!(1, 1, 1), syntax::SimpleName::new(make_id!(3), make_span!(1, 2, 2)))),
        ]),
        syntax::Module::new(sources.index(2), vec![]),
        syntax::Module::new(sources.index(3), vec![
            syntax::Item::Import(syntax::ImportStatement::new_default(make_span!(3, 1, 1), syntax::SimpleName::new(make_id!(4), make_span!(3, 2, 2)))),
        ]),
        syntax::Module::new(sources.index(4), vec![]),
    ], vec![
        syntax::ImportMap::new(0, make_id!(1), 1),
        syntax::ImportMap::new(0, make_id!(2), 2),
        syntax::ImportMap::new(1, make_id!(3), 3),
        syntax::ImportMap::new(3, make_id!(4), 4),
    ]), &sources, &mut symbols, &mut messages);

    let expect = Module{
        module_id: 0,
        this_scope: SharedDefScope::new(""),
        items: vec![
            Item::Import(ImportStatement{
                name: SimpleName{
                    value: make_id!(1),
                    parent_scope: SharedDefScope::new(""),
                },
                alias: None,
                parent_scope: SharedDefScope::new(""),
                module: Some(Module{

                    module_id: 1,
                    this_scope: SharedDefScope::new("").sub("a"),
                    items: vec![
                        Item::Import(ImportStatement{
                            name: SimpleName{
                                value: make_id!(3),
                                parent_scope: SharedDefScope::new("").sub("a"),
                            },
                            alias: None,
                            parent_scope: SharedDefScope::new("").sub("a"),
                            module: Some(Module{
                                module_id: 3,
                                this_scope: SharedDefScope::new("").sub("a").sub("c"),
                                items: vec![
                                    Item::Import(ImportStatement{
                                        name: SimpleName{
                                            value: make_id!(4),
                                            parent_scope: SharedDefScope::new("").sub("a").sub("c"),
                                        },
                                        parent_scope: SharedDefScope::new("").sub("a").sub("c"),
                                        alias: None,
                                        module: Some(Module{
                                            module_id: 4,
                                            this_scope: SharedDefScope::new("").sub("a").sub("c").sub("d"),
                                            items: vec![],
                                        }),
                                    }),
                                ],
                            }),
                        }),
                    ],
                }),
            }),
            Item::Import(ImportStatement{
                name: SimpleName{
                    value: make_id!(2),
                    parent_scope: SharedDefScope::new(""),
                },
                alias: None,
                parent_scope: SharedDefScope::new(""),
                module: Some(Module{
                    module_id: 2,
                    this_scope: SharedDefScope::new("").sub("b"),
                    items: vec![],
                }),
            }),
        ],
    };

    if package.main_module != expect {
        let symbols = make_symbols!["a", "b", "c", "d"];
        // assert_eq!(package.main_module, expect);
        let formatter = Formatter::new(None, Some(&symbols));
        panic!("assertion failed, left: `\n{}`, right: `\n{}`", package.main_module.format(formatter.clone()), expect.format(formatter));
    }
}

// CONSIDER: use unique ids to replace unaccessible names (contains scope segment with span)
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.
use std::time::{Duration, SystemTime, UNIX_EPOCH};

use log::error;

pub struct Response {
    boot_time: SystemTime,
    name: String,
    description: String,
    version: Version,
}

impl super::Response for Response {

    const RDF_NAME: Option<&'static str> = Some("StartupInfo");

    type Proto = rrg_proto::StartupInfo;

    fn into_proto(self) -> rrg_proto::StartupInfo {
        let boot_time_micros = match rrg_proto::micros(self.boot_time) {
            Ok(boot_time_micros) => boot_time_micros,
            Err(error) => {
                error!("failed to convert boot time: {}", error);
                0
            }
        };

        rrg_proto::StartupInfo {
            client_info: Some(rrg_proto::ClientInformation {
                client_name: Some(self.name),
                client_version: Some(self.version.as_numeric()),
                client_description: Some(self.description),
                ..Default::default()
            }),
            boot_time: Some(boot_time_micros),
        }
    }
}

pub fn handle(_: ()) -> Result<Response, super::Error> {
    Ok(Response {
        boot_time: boot_time()?,
        name: String::from(env!("CARGO_PKG_NAME")),
        description: String::from(env!("CARGO_PKG_DESCRIPTION")),
        version: Version::from_crate(),
    })
}

fn boot_time() -> Result<SystemTime, sys_info::Error> {
    let timeval = sys_info::boottime()?;

    let secs = timeval.tv_sec as u64;
    let micros = timeval.tv_usec as u64;

    Ok(UNIX_EPOCH + Duration::from_secs(secs) + Duration::from_micros(micros))
}

pub struct Version {
    pub major: u8,
    pub minor: u8,
    pub patch: u8,
    pub revision: u8,
}

impl Version {

    fn from_crate() -> Version {
        Version {
            major: env!("CARGO_PKG_VERSION_MAJOR").parse().unwrap_or(0),
            minor: env!("CARGO_PKG_VERSION_MINOR").parse().unwrap_or(0),
            patch: env!("CARGO_PKG_VERSION_PATCH").parse().unwrap_or(0),
            revision: env!("CARGO_PKG_VERSION_PRE").parse().unwrap_or(0),
        }
    }

    fn as_numeric(&self) -> u32 {
        let mut result = 0;
        result = 10 * result + self.major as u32;
        result = 10 * result + self.minor as u32;
        result = 10 * result + self.patch as u32;
        result = 10 * result + self.revision as u32;
        result
    }
}
<commit_msg>Write doc comments for the startup action.<commit_after>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

//! A handler and associated types for the startup action.
//!
//! The startup action collects basic information about the system (e.g. its
//! boot time) and metadata about the agent (e.g. it's name and version). It is
//! special in a sense that generally it should be not invoked by flows, but be
//! called explicitly during agent startup.

use std::time::{Duration, SystemTime, UNIX_EPOCH};

use log::error;

/// A response type for the startup action.
pub struct Response {
    /// Time of last system boot.
    boot_time: SystemTime,
    /// Name of the GRR agent.
    name: String,
    /// Description of the GRR agent.
    description: String,
    /// Version of the GRR agent.
    version: Version,
}

impl super::Response for Response {

    const RDF_NAME: Option<&'static str> = Some("StartupInfo");

    type Proto = rrg_proto::StartupInfo;

    fn into_proto(self) -> rrg_proto::StartupInfo {
        let boot_time_micros = match rrg_proto::micros(self.boot_time) {
            Ok(boot_time_micros) => boot_time_micros,
            Err(error) => {
                error!("failed to convert boot time: {}", error);
                0
            }
        };

        rrg_proto::StartupInfo {
            client_info: Some(rrg_proto::ClientInformation {
                client_name: Some(self.name),
                client_version: Some(self.version.as_numeric()),
                client_description: Some(self.description),
                ..Default::default()
            }),
            boot_time: Some(boot_time_micros),
        }
    }
}

/// Handles requests for the startup action.
pub fn handle(_: ()) -> Result<Response, super::Error> {
    Ok(Response {
        boot_time: boot_time()?,
        name: String::from(env!("CARGO_PKG_NAME")),
        description: String::from(env!("CARGO_PKG_DESCRIPTION")),
        version: Version::from_crate(),
    })
}

/// Returns information about the system boot time.
fn boot_time() -> Result<SystemTime, sys_info::Error> {
    let timeval = sys_info::boottime()?;

    let secs = timeval.tv_sec as u64;
    let micros = timeval.tv_usec as u64;

    Ok(UNIX_EPOCH + Duration::from_secs(secs) + Duration::from_micros(micros))
}

/// A type for representing version metadata.
struct Version {
    pub major: u8,
    pub minor: u8,
    pub patch: u8,
    pub revision: u8,
}

impl Version {

    /// Constructs version metadata from Crate information.
    ///
    /// This function assumes that are relevant crate information is correctly
    /// specified in the `Cargo.toml` file.
    fn from_crate() -> Version {
        Version {
            major: env!("CARGO_PKG_VERSION_MAJOR").parse().unwrap_or(0),
            minor: env!("CARGO_PKG_VERSION_MINOR").parse().unwrap_or(0),
            patch: env!("CARGO_PKG_VERSION_PATCH").parse().unwrap_or(0),
            revision: env!("CARGO_PKG_VERSION_PRE").parse().unwrap_or(0),
        }
    }

    /// Returns a numeric representation of version metadata.
    ///
    /// This function assumes that all version components are smaller than 10.
    /// In other cases, the output is undefined (but the function call itself
    /// does not panic).
    ///
    /// # Examples
    ///
    /// ```
    /// use rrg::action::startup::Version;
    ///
    /// let version = Version {
    ///     major: 1,
    ///     minor: 2,
    ///     patch: 3,
    ///     revision: 4,
    /// };
    ///
    /// assert_eq!(version.as_numeric(), 1234)
    /// ```
    fn as_numeric(&self) -> u32 {
        let mut result = 0;
        result = 10 * result + self.major as u32;
        result = 10 * result + self.minor as u32;
        result = 10 * result + self.patch as u32;
        result = 10 * result + self.revision as u32;
        result
    }
}
<|endoftext|>


<commit_before>use std::borrow::Cow;

fn expected_close_char_if_opens_nickname(c: char, prev: char) -> Option<char> {
    let close = match c {
        '(' => Some(')'),
        '[' => Some(']'),
        '<' => Some('>'),
        '“' => Some('”'),
        '〝' => Some('〞'),
        '‹' => Some('›'),
        _ => None
    };

    if !close.is_none() {
        // Treat, e.g., opening parens as the start of a nickname
        // regardless of where it occurs
        return close;
    }

    if prev.is_whitespace() {
        // Treat, e.g., quote character as the start of a nickname
        // only if it occurs after whitespace; otherwise, it
        // might be in-name puntuation
        match c {
            '\'' => Some('\''),
            '"' => Some('"'),
            '‘' => Some('’'),
            _ => None
        }
    } else {
        None
    }
}

pub fn second_char_index(s: &str) -> Option<usize> {
    let mut iter = s.char_indices();

    let first = iter.next();
    if first.is_none() { return None; }

    let second = iter.next();
    if second.is_none() { return None; }

    Some(second.unwrap().0)
}

// Optimized for the case where there is no nickname, and secondarily for the
// case where there is only one. Two or more probably means bad input.
pub fn strip_nickname(input: &str) -> Cow<str> {
    let mut nick_start_ix = 0; // This counts as not-found; we won't classify the whole string as a nickname
    let mut expected_close_char = '\0';
    let mut prev_char = '\0';

    for (i,c) in input.char_indices() {
        if nick_start_ix == 0 {
            let close = expected_close_char_if_opens_nickname(c, prev_char);
            if !close.is_none() {
                nick_start_ix = i;
                expected_close_char = close.unwrap();
            }
        } else if c == expected_close_char {
            match second_char_index(&input[i..]) {
                Some(j) => {
                    return Cow::Owned(input[0..nick_start_ix].to_string() + " " + &strip_nickname(&input[i+j..]));
                }
                None => {
                    return Cow::Borrowed(&input[0..nick_start_ix]);
                }
            }
        }

        prev_char = c;
    }

    if nick_start_ix > 0 {
        if expected_close_char == ')' {
            // When there's an opening parens, but no closing parens, strip the
            // rest of the string
            return Cow::Borrowed(&input[0..nick_start_ix]);
        } else { match second_char_index(&input[nick_start_ix..]) {
            // Otherwise, even if there's an unmatched opening quote, don't
            // modify the string; assume an unmatched opening quote was just
            // in-name punctuation
            //
            // However, in that case, we need to check the remainder of the
            // string for actual nicknames, whose opening character we might
            // have missed while looking for the first closing character
            Some(i) => {
                return Cow::Owned(input[0..nick_start_ix+i].to_string() + " " + &strip_nickname(&input[nick_start_ix+i..]));
            }
            None => {
                return Cow::Borrowed(input);
            }
        } }
    }

    Cow::Borrowed(input)
}
<commit_msg>More consistent ambiguous/unambigious nickname indicator handling<commit_after>use std::borrow::Cow;

// Returns tuple (close_char, must_precede_whitespace)
fn expected_close_char_if_opens_nickname(c: char, follows_whitespace: bool) -> Option<(char, bool)> {
    let close = match c {
        '(' => Some((')', false)),
        '[' => Some((']', false)),
        '<' => Some(('>', false)),
        '“' => Some(('”', false)),
        '〝' => Some(('〞', false)),
        '‹' => Some(('›', false)),
        _ => None
    };

    if !close.is_none() {
        // Treat, e.g., opening parens as the start of a nickname
        // regardless of where it occurs
        return close;
    }

    if follows_whitespace {
        // Treat, e.g., quote character as the start of a nickname
        // only if it occurs after whitespace; otherwise, it
        // might be in-name puntuation
        match c {
            '\'' => Some(('\'', true)),
            '"' => Some(('"', true)),
            '‘' => Some(('’', true)),
            _ => None
        }
    } else {
        None
    }
}

pub fn second_char_index(s: &str) -> Option<usize> {
    let mut iter = s.char_indices();

    let first = iter.next();
    if first.is_none() { return None; }

    let second = iter.next();
    if second.is_none() { return None; }

    Some(second.unwrap().0)
}

// Optimized for the case where there is no nickname, and secondarily for the
// case where there is only one. Two or more probably means bad input.
pub fn strip_nickname(input: &str) -> Cow<str> {
    let mut nick_start_ix = 0; // This counts as not-found; we won't classify the whole string as a nickname
    let mut expected_close_char = '\0';
    let mut must_precede_whitespace = false;
    let mut prev_char = '\0';

    for (i,c) in input.char_indices() {
        if nick_start_ix == 0 {
            let close = expected_close_char_if_opens_nickname(c, prev_char.is_whitespace());
            if !close.is_none() {
                nick_start_ix = i;
                expected_close_char = close.unwrap().0;
                must_precede_whitespace = close.unwrap().1
            }
        } else if c == expected_close_char {
            match second_char_index(&input[i..]) {
                Some(j) => {
                    if input[i+j..].chars().nth(0).unwrap().is_whitespace() || !must_precede_whitespace {
                        return Cow::Owned(input[0..nick_start_ix].to_string() + " " + &strip_nickname(&input[i+j..]));
                    }
                    else {
                        return Cow::Owned(input[0..i].to_string() + &strip_nickname(&input[i..]));
                    }
                }
                None => {
                    return Cow::Borrowed(&input[0..nick_start_ix]);
                }
            }
        }

        prev_char = c;
    }

    if nick_start_ix > 0 {
        if !must_precede_whitespace {
            // When there's, e.g., an opening parens, but no closing parens, strip the
            // rest of the string
            return Cow::Borrowed(&input[0..nick_start_ix]);
        } else { match second_char_index(&input[nick_start_ix..]) {
            // Otherwise, even if there's an unmatched opening quote, don't
            // modify the string; assume an unmatched opening quote was just
            // in-name punctuation
            //
            // However, in that case, we need to check the remainder of the
            // string for actual nicknames, whose opening character we might
            // have missed while looking for the first closing character
            Some(i) => {
                return Cow::Owned(input[0..nick_start_ix+i].to_string() + " " + &strip_nickname(&input[nick_start_ix+i..]));
            }
            None => {
                return Cow::Borrowed(input);
            }
        } }
    }

    Cow::Borrowed(input)
}
<|endoftext|>


<commit_before>use rustc_serialize::json;
use std::fs::File;
use std::path::PathBuf;
use std::sync::mpsc::Sender;

use datatype::{AccessToken, Config, Event, Error, Url, UpdateRequestId,
               UpdateReport, UpdateReportWithVin, Package,
               UpdateResultCode, UpdateState, PendingUpdateRequest};

use http_client::{Auth, HttpClient, HttpRequest, HttpResponse};

fn vehicle_updates_endpoint(config: &Config, path: &str) -> Url {
    config.ota.server.join(& if path.is_empty() {
        format!("/api/v1/vehicle_updates/{}", config.auth.vin)
    } else {
        format!("/api/v1/vehicle_updates/{}/{}", config.auth.vin, path)
    }).unwrap()
}

pub fn download_package_update(config: &Config,
                               client: &mut HttpClient,
                               token:  &AccessToken,
                               id:     &UpdateRequestId) -> Result<PathBuf, Error> {

    let req = HttpRequest::get(
        vehicle_updates_endpoint(config, &format!("{}/download", id)),
        Some(Auth::Token(token)),
    );

    let mut path = PathBuf::new();
    path.push(&config.ota.packages_dir);
    path.push(id);
    path.set_extension(config.ota.package_manager.extension());

    let mut file = try!(File::create(path.as_path()));

    try!(client.send_request_to(&req, &mut file));

    Ok(path)

}

pub fn send_install_report(config: &Config,
                           client: &mut HttpClient,
                           token:  &AccessToken,
                           report: &UpdateReport) -> Result<(), Error> {

    let report_with_vin = UpdateReportWithVin::new(&config.auth.vin, &report);
    let json            = try!(json::encode(&report_with_vin));

    let req = HttpRequest::post(
        vehicle_updates_endpoint(config, &format!("{}", report.update_id)),
        Some(Auth::Token(token)),
        Some(json)
    );

    let _: HttpResponse = try!(client.send_request(&req));

    Ok(())

}

pub fn get_package_updates(config: &Config,
                           client: &mut HttpClient,
                           token:  &AccessToken) -> Result<Vec<PendingUpdateRequest>, Error> {

    let req = HttpRequest::get(
        vehicle_updates_endpoint(&config, ""),
        Some(Auth::Token(token)),
    );

    let resp = try!(client.send_request(&req));
    let body = try!(String::from_utf8(resp.body));

    Ok(try!(json::decode::<Vec<PendingUpdateRequest>>(&body)))
}

// XXX: Remove in favour of update_installed_packages()?
pub fn update_packages(config: &Config,
                       client: &mut HttpClient,
                       token:  &AccessToken,
                       pkgs:   &Vec<Package>) -> Result<(), Error> {

    info!("update_packages, pkgs: {:?}", pkgs);

    let json = try!(json::encode(&pkgs));

    debug!("update_packages, json: {}", json);

    let req = HttpRequest::put(
        vehicle_updates_endpoint(config, "installed"),
        Some(Auth::Token(token)),
        Some(json),
    );

    let _: HttpResponse = try!(client.send_request(&req));

    Ok(())
}

pub fn update_installed_packages(config: &Config,
                                 client: &mut HttpClient,
                                 token:  &AccessToken) -> Result<(), Error> {

    let pkgs = try!(config.ota.package_manager.installed_packages());
    update_packages(config, client, token, &pkgs)

}

pub fn install_package_update(config:      &Config,
                              http_client: &mut HttpClient,
                              token:       &AccessToken,
                              id:          &UpdateRequestId,
                              tx:          &Sender<Event>) -> Result<UpdateReport, Error> {

    match download_package_update(config, http_client, token, id) {

        Ok(path) => {
            info!("Downloaded at {:?}. Installing...", path);
            try!(tx.send(Event::UpdateStateChanged(id.clone(), UpdateState::Installing)));

            let p = try!(path.to_str()
                         .ok_or(Error::ParseError(format!("Path is not valid UTF-8: {:?}", path))));

            match config.ota.package_manager.install_package(p) {

                Ok((code, output)) => {
                    try!(tx.send(Event::UpdateStateChanged(id.clone(), UpdateState::Installed)));
                    try!(update_installed_packages(config, http_client, token));
                    Ok(UpdateReport::new(id.clone(), code, output))
                }

                Err((code, output)) => {
                    try!(tx.send(Event::UpdateErrored(id.clone(), format!("{:?}: {:?}", code, output))));
                    Ok(UpdateReport::new(id.clone(), code, output))
                }

            }

        }

        Err(err) => {
            try!(tx.send(Event::UpdateErrored(id.clone(), format!("{:?}", err))));
            Ok(UpdateReport::new(id.clone(),
                              UpdateResultCode::GENERAL_ERROR,
                              format!("Download failed: {:?}", err)))
        }
    }

}

#[cfg(test)]
mod tests {

    use std::fmt::Debug;
    use std::sync::mpsc::{channel, Receiver};
    use rustc_serialize::json;

    use super::*;
    use datatype::{AccessToken, Config, Event, OtaConfig, Package,
                   UpdateResultCode, UpdateState, PendingUpdateRequest};
    use http_client::TestHttpClient;
    use package_manager::PackageManager;

    fn test_token() -> AccessToken {
        AccessToken {
            access_token: "token".to_string(),
            token_type: "bar".to_string(),
            expires_in: 20,
            scope: vec![]
        }
    }

    fn test_package() -> Package {
        Package {
            name: "hey".to_string(),
            version: "1.2.3".to_string()
        }
    }

    #[test]
    fn test_update_packages_sends_authentication() {
        assert_eq!(update_packages(&Config::default(),
                                 &mut TestHttpClient::from(vec![""]),
                                 &test_token(),
                                 &vec![test_package()])
                   .unwrap(), ())
    }

    #[test]
    fn test_get_package_updates() {
        let pending_update = PendingUpdateRequest {
            requestId: "someid".to_string(),
            installPos: 0,
            packageId: Package {
                name: "fake-pkg".to_string(),
                version: "0.1.1".to_string()
            },
            createdAt: "2010-01-01".to_string()
        };

        let json_response = format!("[{}]",json::encode(&pending_update).unwrap());

        let updates: Vec<PendingUpdateRequest> = get_package_updates(&Config::default(),
                                       &mut TestHttpClient::from(vec![json_response.as_str()]),
                                       &test_token()).unwrap();

        let update_ids: Vec<String> = updates.iter().map(|p| p.requestId.clone()).collect();

        assert_eq!(update_ids, vec!["someid".to_string()])
    }

    #[test]
    #[ignore] // TODO: docker daemon requires user namespaces for this to work
    fn bad_packages_dir_download_package_update() {
        let mut config = Config::default();
        config.ota = OtaConfig { packages_dir: "/".to_string(), .. config.ota };

        assert_eq!(format!("{}", download_package_update(&config,
                                                         &mut TestHttpClient::from(vec![""]),
                                                         &test_token(),
                                                         &"0".to_string())
                           .unwrap_err()),
                   "IO error: Permission denied (os error 13)")
    }

    #[test]
    fn bad_client_download_package_update() {
        assert_eq!(format!("{}",
                           download_package_update(&Config::default(),
                                                   &mut TestHttpClient::new(),
                                                   &test_token(),
                                                   &"0".to_string())
                           .unwrap_err()),
                   "Http client error: GET http://127.0.0.1:8080/api/v1/vehicle_updates/V1234567890123456/0/download")
    }

    fn assert_receiver_eq<X: PartialEq + Debug>(rx: Receiver<X>, xs: &[X]) {

        let mut xs = xs.iter();

        while let Ok(x) = rx.try_recv() {
            if let Some(y) = xs.next() {
                assert_eq!(x, *y)
            } else {
                panic!("assert_receiver_eq: never nexted `{:?}`", x)
            }
        }

        if let Some(x) = xs.next() {
            panic!("assert_receiver_eq: never received `{:?}`", x)
        }

    }

    #[test]
    fn test_install_package_update_0() {

        let (tx, rx) = channel();

        assert_eq!(install_package_update(
            &Config::default(),
            &mut TestHttpClient::new(),
            &AccessToken::default(),
            &"0".to_string(),
            &tx).unwrap().operation_results.pop().unwrap().result_code,
                   UpdateResultCode::GENERAL_ERROR);

        assert_receiver_eq(rx, &[
            Event::UpdateErrored("0".to_string(), String::from(
                "ClientError(\"GET http://127.0.0.1:8080/api/v1/vehicle_updates/V1234567890123456/0/download\")"))])

    }

    #[test]
    fn test_install_package_update_1() {

        let mut config = Config::default();

        config.ota.packages_dir    = "/tmp/".to_string();
        config.ota.package_manager = PackageManager::File {
            filename: "test_install_package_update_1".to_string(),
            succeeds: false };

        let (tx, rx) = channel();

        assert_eq!(install_package_update(
            &config,
            &mut TestHttpClient::from(vec![""]),
            &AccessToken::default(),
            &"0".to_string(),
            &tx).unwrap().operation_results.pop().unwrap().result_code,
                   UpdateResultCode::INSTALL_FAILED);

        assert_receiver_eq(rx, &[
            Event::UpdateStateChanged("0".to_string(), UpdateState::Installing),
            // XXX: Not very helpful message?
            Event::UpdateErrored("0".to_string(), "INSTALL_FAILED: \"failed\"".to_string())])
    }

    #[test]
    fn test_install_package_update_2() {

        let mut config = Config::default();

        config.ota.packages_dir    = "/tmp/".to_string();
        config.ota.package_manager = PackageManager::File {
            filename: "test_install_package_update_2".to_string(),
            succeeds: true };

        let (tx, rx) = channel();

        assert_eq!(install_package_update(
            &config,
            &mut TestHttpClient::from(vec!["", ""]),
            &AccessToken::default(),
            &"0".to_string(),
            &tx).unwrap().operation_results.pop().unwrap().result_code,
                   UpdateResultCode::OK);

        assert_receiver_eq(rx, &[
            Event::UpdateStateChanged("0".to_string(), UpdateState::Installing),
            Event::UpdateStateChanged("0".to_string(), UpdateState::Installed)])

    }
}
<commit_msg>Fix endpoint reference for building on Yocto 1.7.0<commit_after>use rustc_serialize::json;
use std::fs::File;
use std::path::PathBuf;
use std::sync::mpsc::Sender;

use datatype::{AccessToken, Config, Event, Error, Url, UpdateRequestId,
               UpdateReport, UpdateReportWithVin, Package,
               UpdateResultCode, UpdateState, PendingUpdateRequest};

use http_client::{Auth, HttpClient, HttpRequest, HttpResponse};

fn vehicle_updates_endpoint(config: &Config, path: &str) -> Url {
    let endpoint = if path.is_empty() {
        format!("/api/v1/vehicle_updates/{}", config.auth.vin)
    } else {
        format!("/api/v1/vehicle_updates/{}/{}", config.auth.vin, path)
    };
    config.ota.server.join(&endpoint).unwrap()
}

pub fn download_package_update(config: &Config,
                               client: &mut HttpClient,
                               token:  &AccessToken,
                               id:     &UpdateRequestId) -> Result<PathBuf, Error> {

    let req = HttpRequest::get(
        vehicle_updates_endpoint(config, &format!("{}/download", id)),
        Some(Auth::Token(token)),
    );

    let mut path = PathBuf::new();
    path.push(&config.ota.packages_dir);
    path.push(id);
    path.set_extension(config.ota.package_manager.extension());

    let mut file = try!(File::create(path.as_path()));

    try!(client.send_request_to(&req, &mut file));

    Ok(path)

}

pub fn send_install_report(config: &Config,
                           client: &mut HttpClient,
                           token:  &AccessToken,
                           report: &UpdateReport) -> Result<(), Error> {

    let report_with_vin = UpdateReportWithVin::new(&config.auth.vin, &report);
    let json            = try!(json::encode(&report_with_vin));

    let req = HttpRequest::post(
        vehicle_updates_endpoint(config, &format!("{}", report.update_id)),
        Some(Auth::Token(token)),
        Some(json)
    );

    let _: HttpResponse = try!(client.send_request(&req));

    Ok(())

}

pub fn get_package_updates(config: &Config,
                           client: &mut HttpClient,
                           token:  &AccessToken) -> Result<Vec<PendingUpdateRequest>, Error> {

    let req = HttpRequest::get(
        vehicle_updates_endpoint(&config, ""),
        Some(Auth::Token(token)),
    );

    let resp = try!(client.send_request(&req));
    let body = try!(String::from_utf8(resp.body));

    Ok(try!(json::decode::<Vec<PendingUpdateRequest>>(&body)))
}

// XXX: Remove in favour of update_installed_packages()?
pub fn update_packages(config: &Config,
                       client: &mut HttpClient,
                       token:  &AccessToken,
                       pkgs:   &Vec<Package>) -> Result<(), Error> {

    info!("update_packages, pkgs: {:?}", pkgs);

    let json = try!(json::encode(&pkgs));

    debug!("update_packages, json: {}", json);

    let req = HttpRequest::put(
        vehicle_updates_endpoint(config, "installed"),
        Some(Auth::Token(token)),
        Some(json),
    );

    let _: HttpResponse = try!(client.send_request(&req));

    Ok(())
}

pub fn update_installed_packages(config: &Config,
                                 client: &mut HttpClient,
                                 token:  &AccessToken) -> Result<(), Error> {

    let pkgs = try!(config.ota.package_manager.installed_packages());
    update_packages(config, client, token, &pkgs)

}

pub fn install_package_update(config:      &Config,
                              http_client: &mut HttpClient,
                              token:       &AccessToken,
                              id:          &UpdateRequestId,
                              tx:          &Sender<Event>) -> Result<UpdateReport, Error> {

    match download_package_update(config, http_client, token, id) {

        Ok(path) => {
            info!("Downloaded at {:?}. Installing...", path);
            try!(tx.send(Event::UpdateStateChanged(id.clone(), UpdateState::Installing)));

            let p = try!(path.to_str()
                         .ok_or(Error::ParseError(format!("Path is not valid UTF-8: {:?}", path))));

            match config.ota.package_manager.install_package(p) {

                Ok((code, output)) => {
                    try!(tx.send(Event::UpdateStateChanged(id.clone(), UpdateState::Installed)));
                    try!(update_installed_packages(config, http_client, token));
                    Ok(UpdateReport::new(id.clone(), code, output))
                }

                Err((code, output)) => {
                    try!(tx.send(Event::UpdateErrored(id.clone(), format!("{:?}: {:?}", code, output))));
                    Ok(UpdateReport::new(id.clone(), code, output))
                }

            }

        }

        Err(err) => {
            try!(tx.send(Event::UpdateErrored(id.clone(), format!("{:?}", err))));
            Ok(UpdateReport::new(id.clone(),
                              UpdateResultCode::GENERAL_ERROR,
                              format!("Download failed: {:?}", err)))
        }
    }

}

#[cfg(test)]
mod tests {

    use std::fmt::Debug;
    use std::sync::mpsc::{channel, Receiver};
    use rustc_serialize::json;

    use super::*;
    use datatype::{AccessToken, Config, Event, OtaConfig, Package,
                   UpdateResultCode, UpdateState, PendingUpdateRequest};
    use http_client::TestHttpClient;
    use package_manager::PackageManager;

    fn test_token() -> AccessToken {
        AccessToken {
            access_token: "token".to_string(),
            token_type: "bar".to_string(),
            expires_in: 20,
            scope: vec![]
        }
    }

    fn test_package() -> Package {
        Package {
            name: "hey".to_string(),
            version: "1.2.3".to_string()
        }
    }

    #[test]
    fn test_update_packages_sends_authentication() {
        assert_eq!(update_packages(&Config::default(),
                                 &mut TestHttpClient::from(vec![""]),
                                 &test_token(),
                                 &vec![test_package()])
                   .unwrap(), ())
    }

    #[test]
    fn test_get_package_updates() {
        let pending_update = PendingUpdateRequest {
            requestId: "someid".to_string(),
            installPos: 0,
            packageId: Package {
                name: "fake-pkg".to_string(),
                version: "0.1.1".to_string()
            },
            createdAt: "2010-01-01".to_string()
        };

        let json_response = format!("[{}]",json::encode(&pending_update).unwrap());

        let updates: Vec<PendingUpdateRequest> = get_package_updates(&Config::default(),
                                       &mut TestHttpClient::from(vec![json_response.as_str()]),
                                       &test_token()).unwrap();

        let update_ids: Vec<String> = updates.iter().map(|p| p.requestId.clone()).collect();

        assert_eq!(update_ids, vec!["someid".to_string()])
    }

    #[test]
    #[ignore] // TODO: docker daemon requires user namespaces for this to work
    fn bad_packages_dir_download_package_update() {
        let mut config = Config::default();
        config.ota = OtaConfig { packages_dir: "/".to_string(), .. config.ota };

        assert_eq!(format!("{}", download_package_update(&config,
                                                         &mut TestHttpClient::from(vec![""]),
                                                         &test_token(),
                                                         &"0".to_string())
                           .unwrap_err()),
                   "IO error: Permission denied (os error 13)")
    }

    #[test]
    fn bad_client_download_package_update() {
        assert_eq!(format!("{}",
                           download_package_update(&Config::default(),
                                                   &mut TestHttpClient::new(),
                                                   &test_token(),
                                                   &"0".to_string())
                           .unwrap_err()),
                   "Http client error: GET http://127.0.0.1:8080/api/v1/vehicle_updates/V1234567890123456/0/download")
    }

    fn assert_receiver_eq<X: PartialEq + Debug>(rx: Receiver<X>, xs: &[X]) {

        let mut xs = xs.iter();

        while let Ok(x) = rx.try_recv() {
            if let Some(y) = xs.next() {
                assert_eq!(x, *y)
            } else {
                panic!("assert_receiver_eq: never nexted `{:?}`", x)
            }
        }

        if let Some(x) = xs.next() {
            panic!("assert_receiver_eq: never received `{:?}`", x)
        }

    }

    #[test]
    fn test_install_package_update_0() {

        let (tx, rx) = channel();

        assert_eq!(install_package_update(
            &Config::default(),
            &mut TestHttpClient::new(),
            &AccessToken::default(),
            &"0".to_string(),
            &tx).unwrap().operation_results.pop().unwrap().result_code,
                   UpdateResultCode::GENERAL_ERROR);

        assert_receiver_eq(rx, &[
            Event::UpdateErrored("0".to_string(), String::from(
                "ClientError(\"GET http://127.0.0.1:8080/api/v1/vehicle_updates/V1234567890123456/0/download\")"))])

    }

    #[test]
    fn test_install_package_update_1() {

        let mut config = Config::default();

        config.ota.packages_dir    = "/tmp/".to_string();
        config.ota.package_manager = PackageManager::File {
            filename: "test_install_package_update_1".to_string(),
            succeeds: false };

        let (tx, rx) = channel();

        assert_eq!(install_package_update(
            &config,
            &mut TestHttpClient::from(vec![""]),
            &AccessToken::default(),
            &"0".to_string(),
            &tx).unwrap().operation_results.pop().unwrap().result_code,
                   UpdateResultCode::INSTALL_FAILED);

        assert_receiver_eq(rx, &[
            Event::UpdateStateChanged("0".to_string(), UpdateState::Installing),
            // XXX: Not very helpful message?
            Event::UpdateErrored("0".to_string(), "INSTALL_FAILED: \"failed\"".to_string())])
    }

    #[test]
    fn test_install_package_update_2() {

        let mut config = Config::default();

        config.ota.packages_dir    = "/tmp/".to_string();
        config.ota.package_manager = PackageManager::File {
            filename: "test_install_package_update_2".to_string(),
            succeeds: true };

        let (tx, rx) = channel();

        assert_eq!(install_package_update(
            &config,
            &mut TestHttpClient::from(vec!["", ""]),
            &AccessToken::default(),
            &"0".to_string(),
            &tx).unwrap().operation_results.pop().unwrap().result_code,
                   UpdateResultCode::OK);

        assert_receiver_eq(rx, &[
            Event::UpdateStateChanged("0".to_string(), UpdateState::Installing),
            Event::UpdateStateChanged("0".to_string(), UpdateState::Installed)])

    }
}
<|endoftext|>