<commit_before>// Copyright (c) 2019, The rav1e contributors. All rights reserved
//
// This source code is subject to the terms of the BSD 2 Clause License and
// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
// was not distributed with this source code in the LICENSE file, you can
// obtain it at www.aomedia.org/license/software. If the Alliance for Open
// Media Patent License 1.0 was not distributed with this source code in the
// PATENTS file, you can obtain it at www.aomedia.org/license/patent.

use std::sync::Arc;

use libfuzzer_sys::arbitrary::{Arbitrary, Error, Unstructured};

use crate::prelude::*;

// Adding new fuzz targets
//
// 1. Add a function to this file which looks like this:
//
//    pub fn fuzz_something(data: Data) {
//      // Invoke everything you need.
//      //
//      // Your function may accept a value of any type that implements
//      // Arbitrary [1]. This is how fuzzer affects the execution—by
//      // feeding in different bytes, which result in different
//      // arbitrary values being generated.
//      // [1]: https://docs.rs/arbitrary/0.3.3/arbitrary/trait.Arbitrary.html
//      //
//      // Derive Debug for the structures you create with arbitrary data.
//    }
//
// 2. cargo fuzz add something
// 3. Copy the contents of any other .rs file from fuzz/fuzz_targets/ into the
//    newly created fuzz/fuzz_targets/something.rs and change the function
//    being called to fuzz_something.
//
// Now you can fuzz the new target with cargo fuzz.

#[derive(Debug)]
pub struct ArbitraryConfig {
  config: Config,
}

#[inline]
fn arbitrary_rational(u: &mut Unstructured<'_>) -> Result<Rational, Error> {
  Ok(Rational::new(Arbitrary::arbitrary(u)?, Arbitrary::arbitrary(u)?))
}

impl Arbitrary for ArbitraryConfig {
  fn arbitrary(u: &mut Unstructured<'_>) -> Result<Self, Error> {
    let mut enc = EncoderConfig::with_speed_preset(Arbitrary::arbitrary(u)?);
    enc.width = Arbitrary::arbitrary(u)?;
    enc.height = Arbitrary::arbitrary(u)?;
    enc.bit_depth = u.int_in_range(0..=16)?;
    enc.still_picture = Arbitrary::arbitrary(u)?;
    enc.time_base = arbitrary_rational(u)?;
    enc.min_key_frame_interval = Arbitrary::arbitrary(u)?;
    enc.max_key_frame_interval = Arbitrary::arbitrary(u)?;
    enc.reservoir_frame_delay = Arbitrary::arbitrary(u)?;
    enc.low_latency = Arbitrary::arbitrary(u)?;
    enc.quantizer = Arbitrary::arbitrary(u)?;
    enc.min_quantizer = Arbitrary::arbitrary(u)?;
    enc.bitrate = Arbitrary::arbitrary(u)?;
    enc.tile_cols = Arbitrary::arbitrary(u)?;
    enc.tile_rows = Arbitrary::arbitrary(u)?;
    enc.tiles = Arbitrary::arbitrary(u)?;
    enc.rdo_lookahead_frames = Arbitrary::arbitrary(u)?;
    let config = Config::new().with_encoder_config(enc).with_threads(1);
    Ok(Self { config })
  }
}

pub fn fuzz_construct_context(arbitrary: ArbitraryConfig) {
  let _: Result<Context<u16>, _> = arbitrary.config.new_context();
}

fn encode_frames(
  ctx: &mut Context<u8>, mut frames: impl Iterator<Item = Frame<u8>>,
) -> Result<(), EncoderStatus> {
  loop {
    let rv = ctx.receive_packet();
    debug!("ctx.receive_packet() = {:#?}", rv);

    match rv {
      Ok(_packet) => {}
      Err(EncoderStatus::Encoded) => {}
      Err(EncoderStatus::LimitReached) => {
        break;
      }
      Err(EncoderStatus::NeedMoreData) => {
        ctx.send_frame(frames.next().map(Arc::new))?;
      }
      Err(EncoderStatus::EnoughData) => {
        unreachable!();
      }
      Err(EncoderStatus::NotReady) => {
        unreachable!();
      }
      Err(EncoderStatus::Failure) => {
        return Err(EncoderStatus::Failure);
      }
    }
  }

  Ok(())
}

#[derive(Debug)]
pub struct ArbitraryEncoder {
  config: Config,
  frame_count: u8,
  pixels: Box<[u8]>,
}

impl Arbitrary for ArbitraryEncoder {
  fn arbitrary(u: &mut Unstructured<'_>) -> Result<Self, Error> {
    let mut enc = EncoderConfig::with_speed_preset(u.int_in_range(0..=10)?);
    enc.width = u.int_in_range(1..=256)?;
    enc.height = u.int_in_range(1..=256)?;
    enc.still_picture = Arbitrary::arbitrary(u)?;
    enc.time_base = arbitrary_rational(u)?;
    enc.min_key_frame_interval = u.int_in_range(0..=3)?;
    enc.max_key_frame_interval = u.int_in_range(1..=4)?;
    enc.low_latency = Arbitrary::arbitrary(u)?;
    enc.quantizer = Arbitrary::arbitrary(u)?;
    enc.min_quantizer = Arbitrary::arbitrary(u)?;
    enc.bitrate = Arbitrary::arbitrary(u)?;
    enc.tile_cols = u.int_in_range(0..=2)?;
    enc.tile_rows = u.int_in_range(0..=2)?;
    enc.tiles = u.int_in_range(0..=16)?;
    enc.rdo_lookahead_frames = Arbitrary::arbitrary(u)?;

    enc.chroma_sampling = *u.choose(&[
      ChromaSampling::Cs420,
      ChromaSampling::Cs422,
      ChromaSampling::Cs444,
      ChromaSampling::Cs400,
    ])?;
    enc.chroma_sample_position = *u.choose(&[
      ChromaSamplePosition::Unknown,
      ChromaSamplePosition::Vertical,
      ChromaSamplePosition::Colocated,
    ])?;
    enc.pixel_range = *u.choose(&[PixelRange::Limited, PixelRange::Full])?;
    enc.error_resilient = Arbitrary::arbitrary(u)?;
    enc.reservoir_frame_delay = Arbitrary::arbitrary(u)?;

    let frame_count =
      if enc.still_picture { 1 } else { u.int_in_range(1..=3)? };
    if u.is_empty() {
      return Err(Error::NotEnoughData);
    }
    let pixels = u.get_bytes(u.len())?.to_vec().into_boxed_slice();
    let config = Config::new().with_encoder_config(enc).with_threads(1);
    Ok(Self { config, frame_count, pixels })
  }
}

pub fn fuzz_encode(arbitrary: ArbitraryEncoder) {
  let res = arbitrary.config.new_context();
  if res.is_err() {
    return;
  }
  let mut context: Context<u8> = res.unwrap();

  let mut pixels = arbitrary.pixels.iter().cycle();
  let mut frame = context.new_frame();
  let frames = (0..arbitrary.frame_count).map(|_| {
    for plane in &mut frame.planes {
      let stride = plane.cfg.stride;
      for row in plane.data_origin_mut().chunks_mut(stride) {
        for pixel in row {
          *pixel = *pixels.next().unwrap();
        }
      }
    }

    frame.clone()
  });

  let _ = encode_frames(&mut context, frames);
}

#[derive(Debug)]
pub struct DecodeTestParameters {
  w: usize,
  h: usize,
  speed: usize,
  q: usize,
  limit: usize,
  bit_depth: usize,
  chroma_sampling: ChromaSampling,
  min_keyint: u64,
  max_keyint: u64,
  switch_frame_interval: u64,
  low_latency: bool,
  error_resilient: bool,
  bitrate: i32,
  tile_cols_log2: usize,
  tile_rows_log2: usize,
  still_picture: bool,
}

impl Arbitrary for DecodeTestParameters {
  fn arbitrary(u: &mut Unstructured<'_>) -> Result<Self, Error> {
    let mut p = Self {
      w: u.int_in_range(16..=16 + 255)?,
      h: u.int_in_range(16..=16 + 255)?,
      speed: u.int_in_range(0..=10)?,
      q: u8::arbitrary(u)?.into(),
      limit: u.int_in_range(1..=3)?,
      bit_depth: 8,
      chroma_sampling: *u.choose(&[
        ChromaSampling::Cs420,
        ChromaSampling::Cs422,
        ChromaSampling::Cs444,
        ChromaSampling::Cs400,
      ])?,
      min_keyint: u.int_in_range(0..=3)?,
      max_keyint: u.int_in_range(1..=4)?,
      switch_frame_interval: u.int_in_range(0..=3)?,
      low_latency: bool::arbitrary(u)?,
      error_resilient: bool::arbitrary(u)?,
      bitrate: u16::arbitrary(u)?.into(),
      tile_cols_log2: u.int_in_range(0..=2)?,
      tile_rows_log2: u.int_in_range(0..=2)?,
      still_picture: bool::arbitrary(u)?,
    };
    if !p.low_latency {
      p.switch_frame_interval = 0;
    }
    if p.still_picture {
      p.limit = 1
    }
    Ok(p)
  }
}

#[cfg(feature = "decode_test_dav1d")]
pub fn fuzz_encode_decode(p: DecodeTestParameters) {
  use crate::test_encode_decode::*;

  let mut dec = get_decoder::<u8>("dav1d", p.w, p.h);
  dec.encode_decode(
    p.w,
    p.h,
    p.speed,
    p.q,
    p.limit,
    p.bit_depth,
    p.chroma_sampling,
    p.min_keyint,
    p.max_keyint,
    p.switch_frame_interval,
    p.low_latency,
    p.error_resilient,
    p.bitrate,
    p.tile_cols_log2,
    p.tile_rows_log2,
    p.still_picture,
  );
}
<commit_msg>fuzz: Explicit constants for fields of EncoderConfig<commit_after>// Copyright (c) 2019, The rav1e contributors. All rights reserved
//
// This source code is subject to the terms of the BSD 2 Clause License and
// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
// was not distributed with this source code in the LICENSE file, you can
// obtain it at www.aomedia.org/license/software. If the Alliance for Open
// Media Patent License 1.0 was not distributed with this source code in the
// PATENTS file, you can obtain it at www.aomedia.org/license/patent.

use std::sync::Arc;

use libfuzzer_sys::arbitrary::{Arbitrary, Error, Unstructured};

use crate::prelude::*;

// Adding new fuzz targets
//
// 1. Add a function to this file which looks like this:
//
//    pub fn fuzz_something(data: Data) {
//      // Invoke everything you need.
//      //
//      // Your function may accept a value of any type that implements
//      // Arbitrary [1]. This is how fuzzer affects the execution—by
//      // feeding in different bytes, which result in different
//      // arbitrary values being generated.
//      // [1]: https://docs.rs/arbitrary/0.3.3/arbitrary/trait.Arbitrary.html
//      //
//      // Derive Debug for the structures you create with arbitrary data.
//    }
//
// 2. cargo fuzz add something
// 3. Copy the contents of any other .rs file from fuzz/fuzz_targets/ into the
//    newly created fuzz/fuzz_targets/something.rs and change the function
//    being called to fuzz_something.
//
// Now you can fuzz the new target with cargo fuzz.

#[derive(Debug)]
pub struct ArbitraryConfig {
  config: Config,
}

#[inline]
fn arbitrary_rational(u: &mut Unstructured<'_>) -> Result<Rational, Error> {
  Ok(Rational::new(Arbitrary::arbitrary(u)?, Arbitrary::arbitrary(u)?))
}

impl Arbitrary for ArbitraryConfig {
  fn arbitrary(u: &mut Unstructured<'_>) -> Result<Self, Error> {
    let mut enc = EncoderConfig::with_speed_preset(Arbitrary::arbitrary(u)?);
    enc.width = Arbitrary::arbitrary(u)?;
    enc.height = Arbitrary::arbitrary(u)?;
    enc.bit_depth = u.int_in_range(0..=16)?;
    enc.still_picture = Arbitrary::arbitrary(u)?;
    enc.time_base = arbitrary_rational(u)?;
    enc.min_key_frame_interval = Arbitrary::arbitrary(u)?;
    enc.max_key_frame_interval = Arbitrary::arbitrary(u)?;
    enc.reservoir_frame_delay = Arbitrary::arbitrary(u)?;
    enc.low_latency = Arbitrary::arbitrary(u)?;
    enc.quantizer = Arbitrary::arbitrary(u)?;
    enc.min_quantizer = Arbitrary::arbitrary(u)?;
    enc.bitrate = Arbitrary::arbitrary(u)?;
    enc.tile_cols = Arbitrary::arbitrary(u)?;
    enc.tile_rows = Arbitrary::arbitrary(u)?;
    enc.tiles = Arbitrary::arbitrary(u)?;
    enc.rdo_lookahead_frames = Arbitrary::arbitrary(u)?;
    let config = Config::new().with_encoder_config(enc).with_threads(1);
    Ok(Self { config })
  }
}

pub fn fuzz_construct_context(arbitrary: ArbitraryConfig) {
  let _: Result<Context<u16>, _> = arbitrary.config.new_context();
}

fn encode_frames(
  ctx: &mut Context<u8>, mut frames: impl Iterator<Item = Frame<u8>>,
) -> Result<(), EncoderStatus> {
  loop {
    let rv = ctx.receive_packet();
    debug!("ctx.receive_packet() = {:#?}", rv);

    match rv {
      Ok(_packet) => {}
      Err(EncoderStatus::Encoded) => {}
      Err(EncoderStatus::LimitReached) => {
        break;
      }
      Err(EncoderStatus::NeedMoreData) => {
        ctx.send_frame(frames.next().map(Arc::new))?;
      }
      Err(EncoderStatus::EnoughData) => {
        unreachable!();
      }
      Err(EncoderStatus::NotReady) => {
        unreachable!();
      }
      Err(EncoderStatus::Failure) => {
        return Err(EncoderStatus::Failure);
      }
    }
  }

  Ok(())
}

#[derive(Debug)]
pub struct ArbitraryEncoder {
  config: Config,
  frame_count: u8,
  pixels: Box<[u8]>,
}

impl Arbitrary for ArbitraryEncoder {
  fn arbitrary(u: &mut Unstructured<'_>) -> Result<Self, Error> {
    let enc = EncoderConfig {
      speed_settings: SpeedSettings::from_preset(u.int_in_range(0..=10)?),
      width: u.int_in_range(1..=256)?,
      height: u.int_in_range(1..=256)?,
      still_picture: Arbitrary::arbitrary(u)?,
      time_base: arbitrary_rational(u)?,
      min_key_frame_interval: u.int_in_range(0..=3)?,
      max_key_frame_interval: u.int_in_range(1..=4)?,
      low_latency: Arbitrary::arbitrary(u)?,
      quantizer: Arbitrary::arbitrary(u)?,
      min_quantizer: Arbitrary::arbitrary(u)?,
      bitrate: Arbitrary::arbitrary(u)?,
      tile_cols: u.int_in_range(0..=2)?,
      tile_rows: u.int_in_range(0..=2)?,
      tiles: u.int_in_range(0..=16)?,
      rdo_lookahead_frames: Arbitrary::arbitrary(u)?,

      chroma_sampling: *u.choose(&[
        ChromaSampling::Cs420,
        ChromaSampling::Cs422,
        ChromaSampling::Cs444,
        ChromaSampling::Cs400,
      ])?,
      chroma_sample_position: *u.choose(&[
        ChromaSamplePosition::Unknown,
        ChromaSamplePosition::Vertical,
        ChromaSamplePosition::Colocated,
      ])?,
      pixel_range: *u.choose(&[PixelRange::Limited, PixelRange::Full])?,
      error_resilient: Arbitrary::arbitrary(u)?,
      reservoir_frame_delay: Arbitrary::arbitrary(u)?,

      sample_aspect_ratio: Rational { num: 1, den: 1 },
      bit_depth: 8,
      color_description: None,
      mastering_display: None,
      content_light: None,
      enable_timing_info: false,
      switch_frame_interval: 0,
      tune: Tune::default(),
    };

    let frame_count =
      if enc.still_picture { 1 } else { u.int_in_range(1..=3)? };
    if u.is_empty() {
      return Err(Error::NotEnoughData);
    }
    let pixels = u.get_bytes(u.len())?.to_vec().into_boxed_slice();
    let config = Config::new().with_encoder_config(enc).with_threads(1);
    Ok(Self { config, frame_count, pixels })
  }
}

pub fn fuzz_encode(arbitrary: ArbitraryEncoder) {
  let res = arbitrary.config.new_context();
  if res.is_err() {
    return;
  }
  let mut context: Context<u8> = res.unwrap();

  let mut pixels = arbitrary.pixels.iter().cycle();
  let mut frame = context.new_frame();
  let frames = (0..arbitrary.frame_count).map(|_| {
    for plane in &mut frame.planes {
      let stride = plane.cfg.stride;
      for row in plane.data_origin_mut().chunks_mut(stride) {
        for pixel in row {
          *pixel = *pixels.next().unwrap();
        }
      }
    }

    frame.clone()
  });

  let _ = encode_frames(&mut context, frames);
}

#[derive(Debug)]
pub struct DecodeTestParameters {
  w: usize,
  h: usize,
  speed: usize,
  q: usize,
  limit: usize,
  bit_depth: usize,
  chroma_sampling: ChromaSampling,
  min_keyint: u64,
  max_keyint: u64,
  switch_frame_interval: u64,
  low_latency: bool,
  error_resilient: bool,
  bitrate: i32,
  tile_cols_log2: usize,
  tile_rows_log2: usize,
  still_picture: bool,
}

impl Arbitrary for DecodeTestParameters {
  fn arbitrary(u: &mut Unstructured<'_>) -> Result<Self, Error> {
    let mut p = Self {
      w: u.int_in_range(16..=16 + 255)?,
      h: u.int_in_range(16..=16 + 255)?,
      speed: u.int_in_range(0..=10)?,
      q: u8::arbitrary(u)?.into(),
      limit: u.int_in_range(1..=3)?,
      bit_depth: 8,
      chroma_sampling: *u.choose(&[
        ChromaSampling::Cs420,
        ChromaSampling::Cs422,
        ChromaSampling::Cs444,
        ChromaSampling::Cs400,
      ])?,
      min_keyint: u.int_in_range(0..=3)?,
      max_keyint: u.int_in_range(1..=4)?,
      switch_frame_interval: u.int_in_range(0..=3)?,
      low_latency: bool::arbitrary(u)?,
      error_resilient: bool::arbitrary(u)?,
      bitrate: u16::arbitrary(u)?.into(),
      tile_cols_log2: u.int_in_range(0..=2)?,
      tile_rows_log2: u.int_in_range(0..=2)?,
      still_picture: bool::arbitrary(u)?,
    };
    if !p.low_latency {
      p.switch_frame_interval = 0;
    }
    if p.still_picture {
      p.limit = 1
    }
    Ok(p)
  }
}

#[cfg(feature = "decode_test_dav1d")]
pub fn fuzz_encode_decode(p: DecodeTestParameters) {
  use crate::test_encode_decode::*;

  let mut dec = get_decoder::<u8>("dav1d", p.w, p.h);
  dec.encode_decode(
    p.w,
    p.h,
    p.speed,
    p.q,
    p.limit,
    p.bit_depth,
    p.chroma_sampling,
    p.min_keyint,
    p.max_keyint,
    p.switch_frame_interval,
    p.low_latency,
    p.error_resilient,
    p.bitrate,
    p.tile_cols_log2,
    p.tile_rows_log2,
    p.still_picture,
  );
}
<|endoftext|>


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

extern crate bincode;
extern crate rand;
extern crate rusqlite;
extern crate "rustc-serialize" as rustc_serialize;
extern crate time;

use std::net::{IpAddr, SocketAddr, UdpSocket};

use self::rand::Rng;
use rusqlite::SqliteConnection;

use parse_packets::*;

// struct used by update announce to make passing data easy (vs. 4 more parameters)
struct ID {
    info_hash:  [u8; 20],
    ip:         u32,
    port:       u16,
    peer_id:    [u8; 20],
    remaining:  i64,
}

// Generate a UUID to make the client happy
fn gen_uuid() -> i64 {
    let mut rng = rand::thread_rng();
    let mut uuid = time::precise_time_ns();
    uuid <<= 32;
    uuid as i64 | rng.gen::<u32>() as i64
}

// On announce, update the client's remaining and last_active info
// Get the Seeders and Leechers for the provided info_hash
fn update_announce(conn: &SqliteConnection, id: &ID, data: &ClientAnnounce) -> (Vec<(i32,i32)>,i32, i32) {

    // Update the user info
    conn.execute(
        "INSERT OR REPLACE INTO torrent (info_hash, ip, port, peer_id, remaining, last_active)
        VALUES (?, ?, ?, ?, ?, strftime('%s', 'now'))",
        &[&id.info_hash.as_slice(), &(id.ip as i32), &(id.port as i32),
          &id.peer_id.as_slice(), &id.remaining]
    ).unwrap();

    // Info Hash swarm IP and ports
    // i32 due to current rusqlite type handling
    let mut swarm: Vec<(i32, i32)> = Vec::new();

    // Get Seeders
    let mut stmt = conn.prepare(
        "SELECT ip,port,COUNT(*)
         FROM torrent
         WHERE info_hash = ? AND remaining = 0
         GROUP BY ip,port"
    ).unwrap();

    // Each row produces a count, update it as we continue along
    let mut seeders: i32 = 0;
    for row in stmt.query(&[&data.info_hash.as_slice()]).unwrap().map(|row| row.unwrap()) {
        let i: i32 = row.get(0);
        let p: i32 = row.get(1);
        swarm.push((i,p));
        let c: i32 = row.get(2);
        if c > seeders {
            seeders = c;
        }
    }

    // Get Leechers
    let mut stmt = conn.prepare(
        "SELECT ip,port,COUNT(*)
         FROM torrent
         WHERE info_hash = ? AND remaining > 0
         GROUP BY ip,port"
    ).unwrap();

    // Each row produces a count, update it as we continue along
    let mut leechers: i32 = 0;
    for row in stmt.query(&[&data.info_hash.as_slice()]).unwrap().map(|row| row.unwrap()) {
        let i: i32 = row.get(0);
        let p: i32 = row.get(1);
        swarm.push((i,p));
        let c: i32 = row.get(2);
        if c > leechers {
            leechers = c;
        }
    }

    // Return the swarm, seeders, and leechers for packeting
    (swarm, seeders, leechers)
}

pub fn handle_response(tsock: UdpSocket, src: &SocketAddr, packet: Vec<u8>, conn: &SqliteConnection) {
    // Split the packet into header and body parts
    let mut packet_header = packet;
    let packet_body = packet_header.split_off(16);

    // parse the header to act on it
    let header = parse_header(&packet_header);

    match header.action {
        0 => {
            if header.connection_id == 0x41727101980 {
                // Cool Story, we got a new connection.
                // We need to generate an unique id for this client.
                // 32bits of the current time in nanoseconds combined with 32bits of
                // random numbers
                let uuid = gen_uuid();

                // Now they're in the db, let's say hi
                let encoded = encode_connect_response(uuid, header.transaction_id);
                tsock.send_to(&encoded, src).unwrap();
            } else {
                ()
            }
        },
        1 => {
            // Decode the announce info
            let decoded = decode_client_announce(&packet_body);

            // handle an IP of 0
            let mut ip = decoded.ip;
            if ip == 0 {
                ip = match src.ip() {
                    IpAddr::V4(x) => {
                        bincode::decode(&x.octets()).unwrap()
                    },
                    _ => panic!("This is possible?")
                };
            }

            // Package up the announce info for DB consumption
            let id = ID {
                info_hash: decoded.info_hash,
                ip: ip,
                port: decoded.port,
                peer_id: decoded.peer_id,
                remaining: decoded.remaining,
            };

            // Get the swarm, seeder, and leecher info
            let (swarm, seeders, leechers) = update_announce(conn, &id, &decoded);

            // Send it back to the client
            let serv_announce = encode_server_announce(
                header.transaction_id, swarm, decoded.num_want, leechers, seeders
            );
            tsock.send_to(&serv_announce, src).unwrap();
        },
        _ => {
            let err_packet = encode_error(header.transaction_id, "Unsupported Action");
            tsock.send_to(&err_packet, src).unwrap();
        },
    }
}
<commit_msg>Remove pointless `else` block<commit_after>// Copyright 2015 Justin Noah, All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

extern crate bincode;
extern crate rand;
extern crate rusqlite;
extern crate "rustc-serialize" as rustc_serialize;
extern crate time;

use std::net::{IpAddr, SocketAddr, UdpSocket};

use self::rand::Rng;
use rusqlite::SqliteConnection;

use parse_packets::*;

// struct used by update announce to make passing data easy (vs. 4 more parameters)
struct ID {
    info_hash:  [u8; 20],
    ip:         u32,
    port:       u16,
    peer_id:    [u8; 20],
    remaining:  i64,
}

// Generate a UUID to make the client happy
fn gen_uuid() -> i64 {
    let mut rng = rand::thread_rng();
    let mut uuid = time::precise_time_ns();
    uuid <<= 32;
    uuid as i64 | rng.gen::<u32>() as i64
}

// On announce, update the client's remaining and last_active info
// Get the Seeders and Leechers for the provided info_hash
fn update_announce(conn: &SqliteConnection, id: &ID, data: &ClientAnnounce) -> (Vec<(i32,i32)>,i32, i32) {

    // Update the user info
    conn.execute(
        "INSERT OR REPLACE INTO torrent (info_hash, ip, port, peer_id, remaining, last_active)
        VALUES (?, ?, ?, ?, ?, strftime('%s', 'now'))",
        &[&id.info_hash.as_slice(), &(id.ip as i32), &(id.port as i32),
          &id.peer_id.as_slice(), &id.remaining]
    ).unwrap();

    // Info Hash swarm IP and ports
    // i32 due to current rusqlite type handling
    let mut swarm: Vec<(i32, i32)> = Vec::new();

    // Get Seeders
    let mut stmt = conn.prepare(
        "SELECT ip,port,COUNT(*)
         FROM torrent
         WHERE info_hash = ? AND remaining = 0
         GROUP BY ip,port"
    ).unwrap();

    // Each row produces a count, update it as we continue along
    let mut seeders: i32 = 0;
    for row in stmt.query(&[&data.info_hash.as_slice()]).unwrap().map(|row| row.unwrap()) {
        let i: i32 = row.get(0);
        let p: i32 = row.get(1);
        swarm.push((i,p));
        let c: i32 = row.get(2);
        if c > seeders {
            seeders = c;
        }
    }

    // Get Leechers
    let mut stmt = conn.prepare(
        "SELECT ip,port,COUNT(*)
         FROM torrent
         WHERE info_hash = ? AND remaining > 0
         GROUP BY ip,port"
    ).unwrap();

    // Each row produces a count, update it as we continue along
    let mut leechers: i32 = 0;
    for row in stmt.query(&[&data.info_hash.as_slice()]).unwrap().map(|row| row.unwrap()) {
        let i: i32 = row.get(0);
        let p: i32 = row.get(1);
        swarm.push((i,p));
        let c: i32 = row.get(2);
        if c > leechers {
            leechers = c;
        }
    }

    // Return the swarm, seeders, and leechers for packeting
    (swarm, seeders, leechers)
}

pub fn handle_response(tsock: UdpSocket, src: &SocketAddr, packet: Vec<u8>, conn: &SqliteConnection) {
    // Split the packet into header and body parts
    let mut packet_header = packet;
    let packet_body = packet_header.split_off(16);

    // parse the header to act on it
    let header = parse_header(&packet_header);

    match header.action {
        0 => {
            if header.connection_id == 0x41727101980 {
                // Cool Story, we got a new connection.
                // We need to generate an unique id for this client.
                // 32bits of the current time in nanoseconds combined with 32bits of
                // random numbers
                let uuid = gen_uuid();

                // Now they're in the db, let's say hi
                let encoded = encode_connect_response(uuid, header.transaction_id);
                tsock.send_to(&encoded, src).unwrap();
            }
        },
        1 => {
            // Decode the announce info
            let decoded = decode_client_announce(&packet_body);

            // handle an IP of 0
            let mut ip = decoded.ip;
            if ip == 0 {
                ip = match src.ip() {
                    IpAddr::V4(x) => {
                        bincode::decode(&x.octets()).unwrap()
                    },
                    _ => panic!("This is possible?")
                };
            }

            // Package up the announce info for DB consumption
            let id = ID {
                info_hash: decoded.info_hash,
                ip: ip,
                port: decoded.port,
                peer_id: decoded.peer_id,
                remaining: decoded.remaining,
            };

            // Get the swarm, seeder, and leecher info
            let (swarm, seeders, leechers) = update_announce(conn, &id, &decoded);

            // Send it back to the client
            let serv_announce = encode_server_announce(
                header.transaction_id, swarm, decoded.num_want, leechers, seeders
            );
            tsock.send_to(&serv_announce, src).unwrap();
        },
        _ => {
            let err_packet = encode_error(header.transaction_id, "Unsupported Action");
            tsock.send_to(&err_packet, src).unwrap();
        },
    }
}
<|endoftext|>


<commit_before>//! History API

use std::collections::VecDeque;
use std::fs::File;
use std::path::Path;

use super::Result;
use config::{Config, HistoryDuplicates};

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Direction {
    Forward,
    Reverse,
}

pub struct History {
    entries: VecDeque<String>,
    max_len: usize,
    ignore_space: bool,
    ignore_dups: bool,
}

impl History {
    pub fn new(config: Config) -> History {
        History {
            entries: VecDeque::new(),
            max_len: config.max_history_size(),
            ignore_space: config.history_duplicates() == HistoryDuplicates::IgnoreConsecutive,
            ignore_dups: config.history_ignore_space(),
        }
    }

    /// Return the history entry at position `index`, starting from 0.
    pub fn get(&self, index: usize) -> Option<&String> {
        self.entries.get(index)
    }

    /// Add a new entry in the history.
    pub fn add(&mut self, line: &str) -> bool {
        if self.max_len == 0 {
            return false;
        }
        if line.is_empty() ||
           (self.ignore_space && line.chars().next().map_or(true, |c| c.is_whitespace())) {
            return false;
        }
        if self.ignore_dups {
            if let Some(s) = self.entries.back() {
                if s == line {
                    return false;
                }
            }
        }
        if self.entries.len() == self.max_len {
            self.entries.pop_front();
        }
        self.entries.push_back(String::from(line));
        true
    }

    /// Returns the number of entries in the history.
    pub fn len(&self) -> usize {
        self.entries.len()
    }
    /// Returns true if the history has no entry.
    pub fn is_empty(&self) -> bool {
        self.entries.is_empty()
    }

    /// Set the maximum length for the history. This function can be called even
    /// if there is already some history, the function will make sure to retain
    /// just the latest `len` elements if the new history length value is smaller
    /// than the amount of items already inside the history.
    pub fn set_max_len(&mut self, len: usize) {
        self.max_len = len;
        if len == 0 {
            self.entries.clear();
            return;
        }
        loop {
            if self.entries.len() <= len {
                break;
            }
            self.entries.pop_front();
        }
    }

    /// Save the history in the specified file.
    /// TODO append_history http://cnswww.cns.cwru.edu/php/chet/readline/history.html#IDX30
    /// TODO history_truncate_file http://cnswww.cns.cwru.edu/php/chet/readline/history.html#IDX31
    pub fn save<P: AsRef<Path> + ?Sized>(&self, path: &P) -> Result<()> {
        use std::io::{BufWriter, Write};

        if self.is_empty() {
            return Ok(());
        }
        let file = try!(File::create(path));
        let mut wtr = BufWriter::new(file);
        for entry in &self.entries {
            try!(wtr.write_all(&entry.as_bytes()));
            try!(wtr.write_all(b"\n"));
        }
        Ok(())
    }

    /// Load the history from the specified file.
    pub fn load<P: AsRef<Path> + ?Sized>(&mut self, path: &P) -> Result<()> {
        use std::io::{BufRead, BufReader};

        let file = try!(File::open(&path));
        let rdr = BufReader::new(file);
        for line in rdr.lines() {
            self.add(try!(line).as_ref()); // TODO truncate to MAX_LINE
        }
        Ok(())
    }

    /// Clear history
    pub fn clear(&mut self) {
        self.entries.clear()
    }

    /// Search history (start position inclusive [0, len-1]).
    /// Return the absolute index of the nearest history entry that matches `term`.
    /// Return None if no entry contains `term` between [start, len -1] for forward search
    /// or between [0, start] for reverse search.
    pub fn search(&self, term: &str, start: usize, dir: Direction) -> Option<usize> {
        if term.is_empty() || start >= self.len() {
            return None;
        }
        match dir {
            Direction::Reverse => {
                let index = self.entries
                    .iter()
                    .rev()
                    .skip(self.entries.len() - 1 - start)
                    .position(|entry| entry.contains(term));
                index.and_then(|index| Some(start - index))
            }
            Direction::Forward => {
                let index = self.entries.iter().skip(start).position(|entry| entry.contains(term));
                index.and_then(|index| Some(index + start))
            }
        }
    }
}

#[cfg(test)]
mod tests {
    extern crate tempdir;
    use std::path::Path;
    use config::Config;
    use super::{Direction, History};

    fn init() -> History {
        let mut history = History::new(Config::default());
        assert!(history.add("line1"));
        assert!(history.add("line2"));
        assert!(history.add("line3"));
        history
    }

    #[test]
    fn new() {
        let config = Config::default();
        let history = History::new(config);
        assert_eq!(config.max_history_size(), history.max_len);
        assert_eq!(0, history.entries.len());
    }

    #[test]
    fn add() {
        let config = Config::builder()
            .history_ignore_space(true)
            .build();
        let mut history = History::new(config);
        assert!(history.add("line1"));
        assert!(history.add("line2"));
        assert!(!history.add("line2"));
        assert!(!history.add(""));
        assert!(!history.add(" line3"));
    }

    #[test]
    fn set_max_len() {
        let mut history = init();
        history.set_max_len(1);
        assert_eq!(1, history.entries.len());
        assert_eq!(Some(&"line3".to_string()), history.entries.back());
    }

    #[test]
    fn save() {
        let mut history = init();
        let td = tempdir::TempDir::new_in(&Path::new("."), "histo").unwrap();
        let history_path = td.path().join(".history");

        history.save(&history_path).unwrap();
        history.load(&history_path).unwrap();
        td.close().unwrap();
    }

    #[test]
    fn search() {
        let history = init();
        assert_eq!(None, history.search("", 0, Direction::Forward));
        assert_eq!(None, history.search("none", 0, Direction::Forward));
        assert_eq!(None, history.search("line", 3, Direction::Forward));

        assert_eq!(Some(0), history.search("line", 0, Direction::Forward));
        assert_eq!(Some(1), history.search("line", 1, Direction::Forward));
        assert_eq!(Some(2), history.search("line3", 1, Direction::Forward));
    }

    #[test]
    fn reverse_search() {
        let history = init();
        assert_eq!(None, history.search("", 2, Direction::Reverse));
        assert_eq!(None, history.search("none", 2, Direction::Reverse));
        assert_eq!(None, history.search("line", 3, Direction::Reverse));

        assert_eq!(Some(2), history.search("line", 2, Direction::Reverse));
        assert_eq!(Some(1), history.search("line", 1, Direction::Reverse));
        assert_eq!(Some(0), history.search("line1", 1, Direction::Reverse));
    }
}
<commit_msg>Fix #80<commit_after>//! History API

use std::collections::VecDeque;
use std::fs::File;
use std::path::Path;

use super::Result;
use config::{Config, HistoryDuplicates};

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Direction {
    Forward,
    Reverse,
}

pub struct History {
    entries: VecDeque<String>,
    max_len: usize,
    ignore_space: bool,
    ignore_dups: bool,
}

impl History {
    pub fn new(config: Config) -> History {
        History {
            entries: VecDeque::new(),
            max_len: config.max_history_size(),
            ignore_space: config.history_duplicates() == HistoryDuplicates::IgnoreConsecutive,
            ignore_dups: config.history_ignore_space(),
        }
    }

    /// Return the history entry at position `index`, starting from 0.
    pub fn get(&self, index: usize) -> Option<&String> {
        self.entries.get(index)
    }

    /// Add a new entry in the history.
    pub fn add(&mut self, line: &str) -> bool {
        if self.max_len == 0 {
            return false;
        }
        if line.is_empty() ||
           (self.ignore_space && line.chars().next().map_or(true, |c| c.is_whitespace())) {
            return false;
        }
        if self.ignore_dups {
            if let Some(s) = self.entries.back() {
                if s == line {
                    return false;
                }
            }
        }
        if self.entries.len() == self.max_len {
            self.entries.pop_front();
        }
        self.entries.push_back(String::from(line));
        true
    }

    /// Returns the number of entries in the history.
    pub fn len(&self) -> usize {
        self.entries.len()
    }
    /// Returns true if the history has no entry.
    pub fn is_empty(&self) -> bool {
        self.entries.is_empty()
    }

    /// Set the maximum length for the history. This function can be called even
    /// if there is already some history, the function will make sure to retain
    /// just the latest `len` elements if the new history length value is smaller
    /// than the amount of items already inside the history.
    pub fn set_max_len(&mut self, len: usize) {
        self.max_len = len;
        if len == 0 {
            self.entries.clear();
            return;
        }
        loop {
            if self.entries.len() <= len {
                break;
            }
            self.entries.pop_front();
        }
    }

    /// Save the history in the specified file.
    /// TODO append_history http://cnswww.cns.cwru.edu/php/chet/readline/history.html#IDX30
    /// TODO history_truncate_file http://cnswww.cns.cwru.edu/php/chet/readline/history.html#IDX31
    pub fn save<P: AsRef<Path> + ?Sized>(&self, path: &P) -> Result<()> {
        use std::io::{BufWriter, Write};

        if self.is_empty() {
            return Ok(());
        }
        let file = try!(File::create(path));
        let mut wtr = BufWriter::new(file);
        for entry in &self.entries {
            try!(wtr.write_all(&entry.as_bytes()));
            try!(wtr.write_all(b"\n"));
        }
        Ok(())
    }

    /// Load the history from the specified file.
    ///
    /// # Failure
    /// Will return `Err` if path does not already exist.
    pub fn load<P: AsRef<Path> + ?Sized>(&mut self, path: &P) -> Result<()> {
        use std::io::{BufRead, BufReader};

        let file = try!(File::open(&path));
        let rdr = BufReader::new(file);
        for line in rdr.lines() {
            self.add(try!(line).as_ref()); // TODO truncate to MAX_LINE
        }
        Ok(())
    }

    /// Clear history
    pub fn clear(&mut self) {
        self.entries.clear()
    }

    /// Search history (start position inclusive [0, len-1]).
    /// Return the absolute index of the nearest history entry that matches `term`.
    /// Return None if no entry contains `term` between [start, len -1] for forward search
    /// or between [0, start] for reverse search.
    pub fn search(&self, term: &str, start: usize, dir: Direction) -> Option<usize> {
        if term.is_empty() || start >= self.len() {
            return None;
        }
        match dir {
            Direction::Reverse => {
                let index = self.entries
                    .iter()
                    .rev()
                    .skip(self.entries.len() - 1 - start)
                    .position(|entry| entry.contains(term));
                index.and_then(|index| Some(start - index))
            }
            Direction::Forward => {
                let index = self.entries.iter().skip(start).position(|entry| entry.contains(term));
                index.and_then(|index| Some(index + start))
            }
        }
    }
}

#[cfg(test)]
mod tests {
    extern crate tempdir;
    use std::path::Path;
    use config::Config;
    use super::{Direction, History};

    fn init() -> History {
        let mut history = History::new(Config::default());
        assert!(history.add("line1"));
        assert!(history.add("line2"));
        assert!(history.add("line3"));
        history
    }

    #[test]
    fn new() {
        let config = Config::default();
        let history = History::new(config);
        assert_eq!(config.max_history_size(), history.max_len);
        assert_eq!(0, history.entries.len());
    }

    #[test]
    fn add() {
        let config = Config::builder()
            .history_ignore_space(true)
            .build();
        let mut history = History::new(config);
        assert!(history.add("line1"));
        assert!(history.add("line2"));
        assert!(!history.add("line2"));
        assert!(!history.add(""));
        assert!(!history.add(" line3"));
    }

    #[test]
    fn set_max_len() {
        let mut history = init();
        history.set_max_len(1);
        assert_eq!(1, history.entries.len());
        assert_eq!(Some(&"line3".to_string()), history.entries.back());
    }

    #[test]
    fn save() {
        let mut history = init();
        let td = tempdir::TempDir::new_in(&Path::new("."), "histo").unwrap();
        let history_path = td.path().join(".history");

        history.save(&history_path).unwrap();
        history.load(&history_path).unwrap();
        td.close().unwrap();
    }

    #[test]
    fn search() {
        let history = init();
        assert_eq!(None, history.search("", 0, Direction::Forward));
        assert_eq!(None, history.search("none", 0, Direction::Forward));
        assert_eq!(None, history.search("line", 3, Direction::Forward));

        assert_eq!(Some(0), history.search("line", 0, Direction::Forward));
        assert_eq!(Some(1), history.search("line", 1, Direction::Forward));
        assert_eq!(Some(2), history.search("line3", 1, Direction::Forward));
    }

    #[test]
    fn reverse_search() {
        let history = init();
        assert_eq!(None, history.search("", 2, Direction::Reverse));
        assert_eq!(None, history.search("none", 2, Direction::Reverse));
        assert_eq!(None, history.search("line", 3, Direction::Reverse));

        assert_eq!(Some(2), history.search("line", 2, Direction::Reverse));
        assert_eq!(Some(1), history.search("line", 1, Direction::Reverse));
        assert_eq!(Some(0), history.search("line1", 1, Direction::Reverse));
    }
}
<|endoftext|>


<commit_before>extern crate camera_controllers;
extern crate gfx;
extern crate piston_window;
extern crate terra;
extern crate vecmath;
extern crate cgmath;

use piston_window::*;
use camera_controllers::{FirstPersonSettings, FirstPerson, CameraPerspective,
                         model_view_projection};
use vecmath::traits::Sqrt;

use terra::{MaterialSet, DemSource, TerrainFileParams};

fn main() {
    let mut window: PistonWindow = WindowSettings::new("terra preview", [1920 / 2, 1080 / 2])
        .exit_on_esc(true)
        .opengl(OpenGL::V3_3)
        .samples(1)
        .build()
        .unwrap();
    window.set_capture_cursor(true);

    let _materials = MaterialSet::load(&mut window.factory, &mut window.encoder).unwrap();
    window.encoder.flush(&mut window.device);

    let mut terrain = TerrainFileParams {
        latitude: 44,
        longitude: -74,
        source: DemSource::Usgs30m,
    }.build_quadtree(
        window.factory.clone(),
        &window.output_color,
        &window.output_stencil,
    )
        .unwrap();

    let get_projection = |w: &PistonWindow| {
        let draw_size = w.window.draw_size();
        CameraPerspective {
            fov: 90.0,
            near_clip: 0.5,
            far_clip: 100000.0,
            aspect_ratio: (draw_size.width as f32) / (draw_size.height as f32),
        }.projection()
    };

    let mut projection = get_projection(&window);
    let mut first_person = FirstPerson::new([0.0, 10.0, 0.0], FirstPersonSettings::keyboard_wasd());
    first_person.settings.speed_vertical = 500.0;
    first_person.settings.speed_horizontal = 200.0;

    while let Some(e) = window.next() {
        first_person.event(&e);

        if let Some(_) = e.resize_args() {
            projection = get_projection(&window);
        }

        window.draw_3d(&e, |window| {
            let args = e.render_args().unwrap();

            window.encoder.clear(
                &window.output_color,
                [0.3, 0.3, 0.3, 1.0],
            );
            window.encoder.clear_depth(&window.output_stencil, 1.0);

            let center_distance = (first_person.position[0] * first_person.position[0] +
                                       first_person.position[2] * first_person.position[2])
                .sqrt();

            if center_distance > 3000.0 {
                first_person.position[0] /= center_distance / 3000.0;
                first_person.position[2] /= center_distance / 3000.0;
            }

            let camera = first_person.camera(args.ext_dt);
            // if let Some(h) = terrain.get_approximate_height(
            //     [camera.position[0], camera.position[2]],
            // )
            // {
            //     camera.position[1] += h + 2.0;
            // }
            terrain.update(
                model_view_projection(vecmath::mat4_id(), camera.orthogonal(), projection),
                cgmath::Point3::new(camera.position[0], camera.position[1], camera.position[2]),
                &mut window.encoder,
            );
            terrain.render(&mut window.encoder);
        });
    }
}
<commit_msg>Add a detached camera mode to preview<commit_after>extern crate camera_controllers;
extern crate gfx;
extern crate piston_window;
extern crate terra;
extern crate vecmath;
extern crate cgmath;

use piston_window::*;
use camera_controllers::{FirstPersonSettings, FirstPerson, CameraPerspective,
                         model_view_projection};
use vecmath::traits::Sqrt;

use terra::{MaterialSet, DemSource, TerrainFileParams};

fn main() {
    let mut window: PistonWindow = WindowSettings::new("terra preview", [1920 / 2, 1080 / 2])
        .exit_on_esc(true)
        .opengl(OpenGL::V3_3)
        .samples(1)
        .build()
        .unwrap();
    window.set_capture_cursor(true);

    let _materials = MaterialSet::load(&mut window.factory, &mut window.encoder).unwrap();
    window.encoder.flush(&mut window.device);

    let mut terrain = TerrainFileParams {
        latitude: 44,
        longitude: -74,
        source: DemSource::Usgs30m,
    }.build_quadtree(
        window.factory.clone(),
        &window.output_color,
        &window.output_stencil,
    )
        .unwrap();

    let get_projection = |w: &PistonWindow| {
        let draw_size = w.window.draw_size();
        CameraPerspective {
            fov: 90.0,
            near_clip: 0.5,
            far_clip: 100000.0,
            aspect_ratio: (draw_size.width as f32) / (draw_size.height as f32),
        }.projection()
    };

    let mut projection = get_projection(&window);
    let mut first_person = FirstPerson::new([0.0, 30.0, 0.0], FirstPersonSettings::keyboard_wasd());
    first_person.settings.speed_vertical = 500.0;
    first_person.settings.speed_horizontal = 200.0;

    let mut detached_camera = false;
    let mut camera_position = cgmath::Point3::new(0.0, 0.0, 0.0);

    while let Some(e) = window.next() {
        first_person.event(&e);

        if let Some(_) = e.resize_args() {
            projection = get_projection(&window);
        }
        if let Some(Button::Keyboard(key)) = e.press_args() {
            if key == Key::Tab {
                detached_camera = !detached_camera;
            }
        }

        window.draw_3d(&e, |window| {
            let args = e.render_args().unwrap();

            window.encoder.clear(
                &window.output_color,
                [0.3, 0.3, 0.3, 1.0],
            );
            window.encoder.clear_depth(&window.output_stencil, 1.0);

            if !detached_camera {
                let center_distance = (first_person.position[0] * first_person.position[0] +
                                           first_person.position[2] * first_person.position[2])
                    .sqrt();

                if center_distance > 3000.0 {
                    first_person.position[0] /= center_distance / 3000.0;
                    first_person.position[2] /= center_distance / 3000.0;
                }
            }

            let camera = first_person.camera(args.ext_dt);
            if !detached_camera {
                camera_position =
                    cgmath::Point3::new(camera.position[0], camera.position[1], camera.position[2]);
            }
            // if let Some(h) = terrain.get_approximate_height(
            //     [camera.position[0], camera.position[2]],
            // )
            // {
            //     camera.position[1] += h + 2.0;
            // }
            terrain.update(
                model_view_projection(vecmath::mat4_id(), camera.orthogonal(), projection),
                camera_position,
                &mut window.encoder,
            );
            terrain.render(&mut window.encoder);
        });
    }
}
<|endoftext|>


<commit_before>mod utils;

use clap::{App, Arg, ArgGroup, ErrorKind};

static CONFLICT_ERR: &str = "error: The argument '--flag' cannot be used with '-F'

USAGE:
    clap-test <positional> <positional2> --flag --long-option-2 <option2>

For more information try --help";

static CONFLICT_ERR_REV: &str = "error: The argument '-F' cannot be used with '--flag'

USAGE:
    clap-test <positional> <positional2> -F --long-option-2 <option2>

For more information try --help";

#[test]
fn flag_conflict() {
    let result = App::new("flag_conflict")
        .arg(Arg::from("-f, --flag 'some flag'").conflicts_with("other"))
        .arg(Arg::from("-o, --other 'some flag'"))
        .try_get_matches_from(vec!["myprog", "-f", "-o"]);
    assert!(result.is_err());
    let err = result.err().unwrap();
    assert_eq!(err.kind, ErrorKind::ArgumentConflict);
}

#[test]
fn flag_conflict_2() {
    let result = App::new("flag_conflict")
        .arg(Arg::from("-f, --flag 'some flag'").conflicts_with("other"))
        .arg(Arg::from("-o, --other 'some flag'"))
        .try_get_matches_from(vec!["myprog", "-o", "-f"]);
    assert!(result.is_err());
    let err = result.err().unwrap();
    assert_eq!(err.kind, ErrorKind::ArgumentConflict);
}

#[test]
fn flag_conflict_with_all() {
    let result = App::new("flag_conflict")
        .arg(Arg::from("-f, --flag 'some flag'").conflicts_with_all(&["other"]))
        .arg(Arg::from("-o, --other 'some flag'"))
        .try_get_matches_from(vec!["myprog", "-o", "-f"]);
    assert!(result.is_err());
    let err = result.err().unwrap();
    assert_eq!(err.kind, ErrorKind::ArgumentConflict);
}

#[test]
fn flag_conflict_with_everything() {
    let result = App::new("flag_conflict")
        .arg(Arg::from("-f, --flag 'some flag'").exclusive(true))
        .arg(Arg::from("-o, --other 'some flag'"))
        .try_get_matches_from(vec!["myprog", "-o", "-f"]);
    assert!(result.is_err());
    let err = result.err().unwrap();
    assert_eq!(err.kind, ErrorKind::ArgumentConflict);
}

#[test]
fn group_conflict() {
    let result = App::new("group_conflict")
        .arg(Arg::from("-f, --flag 'some flag'").conflicts_with("gr"))
        .group(ArgGroup::new("gr").required(true).arg("some").arg("other"))
        .arg(Arg::from("--some 'some arg'"))
        .arg(Arg::from("--other 'other arg'"))
        .try_get_matches_from(vec!["myprog", "--other", "-f"]);
    assert!(result.is_err());
    let err = result.err().unwrap();
    assert_eq!(err.kind, ErrorKind::ArgumentConflict);
}

#[test]
fn group_conflict_2() {
    let result = App::new("group_conflict")
        .arg(Arg::from("-f, --flag 'some flag'").conflicts_with("gr"))
        .group(ArgGroup::new("gr").required(true).arg("some").arg("other"))
        .arg(Arg::from("--some 'some arg'"))
        .arg(Arg::from("--other 'other arg'"))
        .try_get_matches_from(vec!["myprog", "-f", "--some"]);
    assert!(result.is_err());
    let err = result.err().unwrap();
    assert_eq!(err.kind, ErrorKind::ArgumentConflict);
}

#[test]
fn conflict_output() {
    assert!(utils::compare_output(
        utils::complex_app(),
        "clap-test val1 --flag --long-option-2 val2 -F",
        CONFLICT_ERR,
        true,
    ));
}

#[test]
fn conflict_output_rev() {
    assert!(utils::compare_output(
        utils::complex_app(),
        "clap-test val1 -F --long-option-2 val2 --flag",
        CONFLICT_ERR_REV,
        true,
    ));
}

#[test]
fn conflict_with_unused_default_value() {
    let result = App::new("conflict")
        .arg(Arg::from("-o, --opt=[opt] 'some opt'").default_value("default"))
        .arg(Arg::from("-f, --flag 'some flag'").conflicts_with("opt"))
        .try_get_matches_from(vec!["myprog", "-f"]);
    assert!(result.is_ok());
    let m = result.unwrap();
    assert_eq!(m.value_of("opt"), Some("default"));
    assert!(m.is_present("flag"));
}

#[test]
fn two_conflicting_arguments() {
    let a = App::new("two_conflicting_arguments")
        .arg(
            Arg::new("develop")
                .long("develop")
                .conflicts_with("production"),
        )
        .arg(
            Arg::new("production")
                .long("production")
                .conflicts_with("develop"),
        )
        .try_get_matches_from(vec!["", "--develop", "--production"]);

    assert!(a.is_err());
    let a = a.unwrap_err();
    assert_eq!(
        a.cause,
        "The argument \'--develop\' cannot be used with \'--production\'"
    );
}

#[test]
fn three_conflicting_arguments() {
    let a = App::new("two_conflicting_arguments")
        .arg(
            Arg::new("one")
                .long("one")
                .conflicts_with_all(&["two", "three"]),
        )
        .arg(
            Arg::new("two")
                .long("two")
                .conflicts_with_all(&["one", "three"]),
        )
        .arg(
            Arg::new("three")
                .long("three")
                .conflicts_with_all(&["one", "two"]),
        )
        .try_get_matches_from(vec!["", "--one", "--two", "--three"]);

    assert!(a.is_err());
    let a = a.unwrap_err();
    assert_eq!(
        a.cause,
        "The argument \'--one\' cannot be used with \'--two\'"
    );
}

#[cfg(debug_assertions)]
#[test]
#[should_panic = "Argument 'config' cannot conflict with itself"]
fn self_conflicting_arg() {
    let _ = App::new("prog")
        .arg(Arg::new("config").long("config").conflicts_with("config"))
        .try_get_matches_from(vec!["", "--config"]);
}

#[cfg(debug_assertions)]
#[test]
#[should_panic = "Argument or group 'extra' specified in 'conflicts_with*' for 'config' does not exist"]
fn conflicts_with_invalid_arg() {
    let _ = App::new("prog")
        .arg(Arg::new("config").long("config").conflicts_with("extra"))
        .try_get_matches_from(vec!["", "--config"]);
}

#[test]
fn conflicts_with_default() {
    let result = App::new("conflict")
        .arg(
            Arg::from("-o, --opt=[opt] 'some opt'")
                .default_value("default")
                .conflicts_with("flag"),
        )
        .arg(Arg::from("-f, --flag 'some flag'").conflicts_with("opt"))
        .try_get_matches_from(vec!["myprog", "-f"]);

    assert!(result.is_ok(), "{:?}", result.unwrap());
    let m = result.unwrap();

    assert_eq!(m.value_of("opt"), Some("default"));
    assert!(m.is_present("flag"));
}
<commit_msg>Add new tests for usage including required args<commit_after>mod utils;

use clap::{App, Arg, ArgGroup, ErrorKind};

static CONFLICT_ERR: &str = "error: The argument '--flag' cannot be used with '-F'

USAGE:
    clap-test <positional> <positional2> --flag --long-option-2 <option2>

For more information try --help";

static CONFLICT_ERR_REV: &str = "error: The argument '-F' cannot be used with '--flag'

USAGE:
    clap-test <positional> <positional2> -F --long-option-2 <option2>

For more information try --help";

#[test]
fn flag_conflict() {
    let result = App::new("flag_conflict")
        .arg(Arg::from("-f, --flag 'some flag'").conflicts_with("other"))
        .arg(Arg::from("-o, --other 'some flag'"))
        .try_get_matches_from(vec!["myprog", "-f", "-o"]);
    assert!(result.is_err());
    let err = result.err().unwrap();
    assert_eq!(err.kind, ErrorKind::ArgumentConflict);
}

#[test]
fn flag_conflict_2() {
    let result = App::new("flag_conflict")
        .arg(Arg::from("-f, --flag 'some flag'").conflicts_with("other"))
        .arg(Arg::from("-o, --other 'some flag'"))
        .try_get_matches_from(vec!["myprog", "-o", "-f"]);
    assert!(result.is_err());
    let err = result.err().unwrap();
    assert_eq!(err.kind, ErrorKind::ArgumentConflict);
}

#[test]
fn flag_conflict_with_all() {
    let result = App::new("flag_conflict")
        .arg(Arg::from("-f, --flag 'some flag'").conflicts_with_all(&["other"]))
        .arg(Arg::from("-o, --other 'some flag'"))
        .try_get_matches_from(vec!["myprog", "-o", "-f"]);
    assert!(result.is_err());
    let err = result.err().unwrap();
    assert_eq!(err.kind, ErrorKind::ArgumentConflict);
}

#[test]
fn flag_conflict_with_everything() {
    let result = App::new("flag_conflict")
        .arg(Arg::from("-f, --flag 'some flag'").exclusive(true))
        .arg(Arg::from("-o, --other 'some flag'"))
        .try_get_matches_from(vec!["myprog", "-o", "-f"]);
    assert!(result.is_err());
    let err = result.err().unwrap();
    assert_eq!(err.kind, ErrorKind::ArgumentConflict);
}

#[test]
fn group_conflict() {
    let result = App::new("group_conflict")
        .arg(Arg::from("-f, --flag 'some flag'").conflicts_with("gr"))
        .group(ArgGroup::new("gr").required(true).arg("some").arg("other"))
        .arg(Arg::from("--some 'some arg'"))
        .arg(Arg::from("--other 'other arg'"))
        .try_get_matches_from(vec!["myprog", "--other", "-f"]);
    assert!(result.is_err());
    let err = result.err().unwrap();
    assert_eq!(err.kind, ErrorKind::ArgumentConflict);
}

#[test]
fn group_conflict_2() {
    let result = App::new("group_conflict")
        .arg(Arg::from("-f, --flag 'some flag'").conflicts_with("gr"))
        .group(ArgGroup::new("gr").required(true).arg("some").arg("other"))
        .arg(Arg::from("--some 'some arg'"))
        .arg(Arg::from("--other 'other arg'"))
        .try_get_matches_from(vec!["myprog", "-f", "--some"]);
    assert!(result.is_err());
    let err = result.err().unwrap();
    assert_eq!(err.kind, ErrorKind::ArgumentConflict);
}

#[test]
fn conflict_output() {
    assert!(utils::compare_output(
        utils::complex_app(),
        "clap-test val1 fa --flag --long-option-2 val2 -F",
        CONFLICT_ERR,
        true,
    ));
}

#[test]
fn conflict_output_rev() {
    assert!(utils::compare_output(
        utils::complex_app(),
        "clap-test val1 fa -F --long-option-2 val2 --flag",
        CONFLICT_ERR_REV,
        true,
    ));
}

#[test]
fn conflict_output_with_required() {
    utils::compare_output(
        utils::complex_app(),
        "clap-test val1 --flag --long-option-2 val2 -F",
        CONFLICT_ERR,
        true,
    );
}

#[test]
fn conflict_output_rev_with_required() {
    utils::compare_output(
        utils::complex_app(),
        "clap-test val1 -F --long-option-2 val2 --flag",
        CONFLICT_ERR_REV,
        true,
    );
}

#[test]
fn conflict_with_unused_default_value() {
    let result = App::new("conflict")
        .arg(Arg::from("-o, --opt=[opt] 'some opt'").default_value("default"))
        .arg(Arg::from("-f, --flag 'some flag'").conflicts_with("opt"))
        .try_get_matches_from(vec!["myprog", "-f"]);
    assert!(result.is_ok());
    let m = result.unwrap();
    assert_eq!(m.value_of("opt"), Some("default"));
    assert!(m.is_present("flag"));
}

#[test]
fn two_conflicting_arguments() {
    let a = App::new("two_conflicting_arguments")
        .arg(
            Arg::new("develop")
                .long("develop")
                .conflicts_with("production"),
        )
        .arg(
            Arg::new("production")
                .long("production")
                .conflicts_with("develop"),
        )
        .try_get_matches_from(vec!["", "--develop", "--production"]);

    assert!(a.is_err());
    let a = a.unwrap_err();
    assert_eq!(
        a.cause,
        "The argument \'--develop\' cannot be used with \'--production\'"
    );
}

#[test]
fn three_conflicting_arguments() {
    let a = App::new("two_conflicting_arguments")
        .arg(
            Arg::new("one")
                .long("one")
                .conflicts_with_all(&["two", "three"]),
        )
        .arg(
            Arg::new("two")
                .long("two")
                .conflicts_with_all(&["one", "three"]),
        )
        .arg(
            Arg::new("three")
                .long("three")
                .conflicts_with_all(&["one", "two"]),
        )
        .try_get_matches_from(vec!["", "--one", "--two", "--three"]);

    assert!(a.is_err());
    let a = a.unwrap_err();
    assert_eq!(
        a.cause,
        "The argument \'--one\' cannot be used with \'--two\'"
    );
}

#[cfg(debug_assertions)]
#[test]
#[should_panic = "Argument 'config' cannot conflict with itself"]
fn self_conflicting_arg() {
    let _ = App::new("prog")
        .arg(Arg::new("config").long("config").conflicts_with("config"))
        .try_get_matches_from(vec!["", "--config"]);
}

#[cfg(debug_assertions)]
#[test]
#[should_panic = "Argument or group 'extra' specified in 'conflicts_with*' for 'config' does not exist"]
fn conflicts_with_invalid_arg() {
    let _ = App::new("prog")
        .arg(Arg::new("config").long("config").conflicts_with("extra"))
        .try_get_matches_from(vec!["", "--config"]);
}

#[test]
fn conflicts_with_default() {
    let result = App::new("conflict")
        .arg(
            Arg::from("-o, --opt=[opt] 'some opt'")
                .default_value("default")
                .conflicts_with("flag"),
        )
        .arg(Arg::from("-f, --flag 'some flag'").conflicts_with("opt"))
        .try_get_matches_from(vec!["myprog", "-f"]);

    assert!(result.is_ok(), "{:?}", result.unwrap());
    let m = result.unwrap();

    assert_eq!(m.value_of("opt"), Some("default"));
    assert!(m.is_present("flag"));
}
<|endoftext|>


<commit_before>extern crate test;
use context::Context;
use get;
use std::default::Default;
use types::Type;
use types::kind::*;
use function::{Function, flags};
use label::Label;
use test::Bencher;
macro_rules! test_compile(
    ($ty:ty, $test_name:ident, $kind:expr) => (
        #[test]
        fn $test_name() {
            let default_value:$ty = Default::default();
            let mut ctx = Context::new();
            jit_func!(ctx, func, fn gen_value() -> $ty {
                let ref val = func.insn_of(&default_value);
                assert!(val.get_type().get_kind() == $kind);
                func.insn_return(val);
            }, |func| {
                assert_eq!(func(()), default_value);
            });
        }
    );
);
#[bench]
fn bench_raw_pi(b: &mut Bencher) {
    fn raw_pi() -> f64 {
        let mut pi = 3.0f64;
        let mut n = 2.0f64;
        let four = 4.0f64;
        while n < 100.0 {
            pi += four / (n * (n + 1.0) * (n + 2.0)) - four / ((n + 2.0) * (n + 3.0) * (n + 4.0));
            n += four;
        }
        pi
    }
    b.iter(|| raw_pi());
}
#[bench]
fn bench_pi(b: &mut Bencher) {
    let mut ctx = Context::new();
    jit_func!(ctx, func, fn pi() -> f64 {
        let f64_size = func.insn_of(&8u);
        let four = func.insn_of(&4.0f64);
        let three = func.insn_of(&3.0f64);
        let two = func.insn_of(&2.0f64);
        let one = func.insn_of(&1.0f64);
        let pi = func.insn_alloca(&f64_size);
        func.insn_store_relative(&pi, 0, &three);
        let n = func.insn_alloca(&f64_size);
        func.insn_store(&n, &two);
        let limit = func.insn_of(&100.0f64);
        func.insn_while(|| func.insn_lt(&func.insn_load(&n), &limit), || {
            let ln = func.insn_load(&n);
            let n_two = ln + two;
            let first_part = four / (ln * (ln + one) * n_two);
            let second_part = four / (n_two * (ln + three) * (ln + four));
            let new_pi = first_part - second_part;
            func.insn_store_relative(&pi, 0, &(func.insn_load_relative(&pi, 0, get::<f64>()) + new_pi));
            func.insn_store(&n, &(ln + four));
        });
        func.insn_return(&func.insn_load_relative(&pi, 0, get::<f64>()));
    }, |pi| {
        b.iter(|| pi(()));
    });
}
#[bench]
fn bench_raw_gcd(b: &mut Bencher) {
    fn gcd(x: uint, y: uint) -> uint {
        if x == y {
            x
        } else if x < y {
            gcd(x, y - x)
        } else {
            gcd(x - y, y)
        }
    }
    b.iter(|| gcd(70, 81));
}

#[bench]
fn bench_gcd(b: &mut Bencher) {
    let mut ctx = Context::new();
    jit_func!(ctx, func, fn gcd(x: uint, y:uint) -> uint {
        func.insn_if(&func.insn_eq(x, y), || func.insn_return(x));
        func.insn_if(&func.insn_lt(x, y), || {
            let mut args = [x, &(*y - *x)];
            let v = func.insn_call(Some("gcd"), func, None, args.as_mut_slice(), flags::JIT_CALL_NO_THROW);
            func.insn_return(&v);
        });
        let mut args = [&(*x - *y), y];
        let temp4 = func.insn_call(Some("gcd"), func, None, args.as_mut_slice(), flags::JIT_CALL_NO_THROW);
        func.insn_return(&temp4);
    }, |gcd| {
        b.iter(|| gcd((70, 81)));
    });
}
#[test]
fn test_sqrt() {
    let mut ctx = Context::new();
    assert_eq!(ctx.functions().count(), 0);
    jit_func!(ctx, func, fn sqrt(num: uint) -> uint {
        let sqrt = func.insn_sqrt(num);
        let sqrt_arg_ui = func.insn_convert(&sqrt, get::<uint>(), false);
        func.insn_return(&sqrt_arg_ui);
    }, |sqrt| {
        assert_eq!(sqrt(64), 8);
        assert_eq!(sqrt(16), 4);
        assert_eq!(sqrt(9), 3);
        assert_eq!(sqrt(4), 2);
        assert_eq!(sqrt(1), 1);
    });
    assert_eq!(ctx.functions().count(), 1);
}

#[test]
fn test_overflow() {
    let mut ctx = Context::new();
    jit_func!(ctx, func, fn add_500(num: uint) -> uint {
        let ret = func.insn_sub_ovf(num, &func.insn_of(&500u));
        func.insn_return(&ret);
    }, |add_500| {
        assert_eq!(add_500(4), 0)
    });
}
#[test]
fn test_struct() {
    let pos_t = jit_struct!{
        x: f64,
        y: f64
    };
    for (i, field) in pos_t.fields().enumerate() {
        assert_eq!(field.get_type(), get::<f64>());
        assert_eq!(field.get_name().unwrap()[], match i {
            0 => "x",
            1 => "y",
            _ => unimplemented!()
        })
    }
}
struct PanicDrop {
    val: i32
}
impl Drop for PanicDrop {
    fn drop(&mut self) {
        panic!("Dropped {}", self.val)
    }
}
#[test]
#[should_fail]
fn test_tags() {
    let pos_t = jit_struct!{
        x: f64,
        y: f64
    };
    let kind = pos_t.get_kind();
    let pos_t = Type::create_tagged(pos_t, kind, box PanicDrop{val: 323});
    assert_eq!(pos_t.get_tagged_data::<PanicDrop>().map(|v| v.val), Some(323));
}

test_compile!((), test_compile_void, Void);
test_compile!(f64, test_compile_f64, Float64);
test_compile!(f32, test_compile_f32, Float32);
test_compile!(int, test_compile_int, NInt);
test_compile!(uint, test_compile_uint, NUInt);
test_compile!(i32, test_compile_i32, Int);
test_compile!(u32, test_compile_u32, UInt);
test_compile!(i16, test_compile_i16, Short);
test_compile!(u16, test_compile_u16, UShort);
test_compile!(i8, test_compile_i8, SByte);
test_compile!(u8, test_compile_u8, UByte);<commit_msg>Remove bad test<commit_after>extern crate test;
use context::Context;
use get;
use std::default::Default;
use types::Type;
use types::kind::*;
use function::{Function, flags};
use label::Label;
use test::Bencher;
macro_rules! test_compile(
    ($ty:ty, $test_name:ident, $kind:expr) => (
        #[test]
        fn $test_name() {
            let default_value:$ty = Default::default();
            let mut ctx = Context::new();
            jit_func!(ctx, func, fn gen_value() -> $ty {
                let ref val = func.insn_of(&default_value);
                assert!(val.get_type().get_kind() == $kind);
                func.insn_return(val);
            }, |func| {
                assert_eq!(func(()), default_value);
            });
        }
    );
);
#[bench]
fn bench_raw_pi(b: &mut Bencher) {
    fn raw_pi() -> f64 {
        let mut pi = 3.0f64;
        let mut n = 2.0f64;
        let four = 4.0f64;
        while n < 100.0 {
            pi += four / (n * (n + 1.0) * (n + 2.0)) - four / ((n + 2.0) * (n + 3.0) * (n + 4.0));
            n += four;
        }
        pi
    }
    b.iter(|| raw_pi());
}
#[bench]
fn bench_pi(b: &mut Bencher) {
    let mut ctx = Context::new();
    jit_func!(ctx, func, fn pi() -> f64 {
        let f64_size = func.insn_of(&8u);
        let four = func.insn_of(&4.0f64);
        let three = func.insn_of(&3.0f64);
        let two = func.insn_of(&2.0f64);
        let one = func.insn_of(&1.0f64);
        let pi = func.insn_alloca(&f64_size);
        func.insn_store_relative(&pi, 0, &three);
        let n = func.insn_alloca(&f64_size);
        func.insn_store(&n, &two);
        let limit = func.insn_of(&100.0f64);
        func.insn_while(|| func.insn_lt(&func.insn_load(&n), &limit), || {
            let ln = func.insn_load(&n);
            let n_two = ln + two;
            let first_part = four / (ln * (ln + one) * n_two);
            let second_part = four / (n_two * (ln + three) * (ln + four));
            let new_pi = first_part - second_part;
            func.insn_store_relative(&pi, 0, &(func.insn_load_relative(&pi, 0, get::<f64>()) + new_pi));
            func.insn_store(&n, &(ln + four));
        });
        func.insn_return(&func.insn_load_relative(&pi, 0, get::<f64>()));
    }, |pi| {
        b.iter(|| pi(()));
    });
}
#[bench]
fn bench_raw_gcd(b: &mut Bencher) {
    fn gcd(x: uint, y: uint) -> uint {
        if x == y {
            x
        } else if x < y {
            gcd(x, y - x)
        } else {
            gcd(x - y, y)
        }
    }
    b.iter(|| gcd(70, 81));
}

#[bench]
fn bench_gcd(b: &mut Bencher) {
    let mut ctx = Context::new();
    jit_func!(ctx, func, fn gcd(x: uint, y:uint) -> uint {
        func.insn_if(&func.insn_eq(x, y), || func.insn_return(x));
        func.insn_if(&func.insn_lt(x, y), || {
            let mut args = [x, &(*y - *x)];
            let v = func.insn_call(Some("gcd"), func, None, args.as_mut_slice(), flags::JIT_CALL_NO_THROW);
            func.insn_return(&v);
        });
        let mut args = [&(*x - *y), y];
        let temp4 = func.insn_call(Some("gcd"), func, None, args.as_mut_slice(), flags::JIT_CALL_NO_THROW);
        func.insn_return(&temp4);
    }, |gcd| {
        b.iter(|| gcd((70, 81)));
    });
}
#[test]
fn test_sqrt() {
    let mut ctx = Context::new();
    assert_eq!(ctx.functions().count(), 0);
    jit_func!(ctx, func, fn sqrt(num: uint) -> uint {
        let sqrt = func.insn_sqrt(num);
        let sqrt_arg_ui = func.insn_convert(&sqrt, get::<uint>(), false);
        func.insn_return(&sqrt_arg_ui);
    }, |sqrt| {
        assert_eq!(sqrt(64), 8);
        assert_eq!(sqrt(16), 4);
        assert_eq!(sqrt(9), 3);
        assert_eq!(sqrt(4), 2);
        assert_eq!(sqrt(1), 1);
    });
    assert_eq!(ctx.functions().count(), 1);
}

#[test]
fn test_struct() {
    let pos_t = jit_struct!{
        x: f64,
        y: f64
    };
    for (i, field) in pos_t.fields().enumerate() {
        assert_eq!(field.get_type(), get::<f64>());
        assert_eq!(field.get_name().unwrap()[], match i {
            0 => "x",
            1 => "y",
            _ => unimplemented!()
        })
    }
}
struct PanicDrop {
    val: i32
}
impl Drop for PanicDrop {
    fn drop(&mut self) {
        panic!("Dropped {}", self.val)
    }
}
#[test]
#[should_fail]
fn test_tags() {
    let pos_t = jit_struct!{
        x: f64,
        y: f64
    };
    let kind = pos_t.get_kind();
    let pos_t = Type::create_tagged(pos_t, kind, box PanicDrop{val: 323});
    assert_eq!(pos_t.get_tagged_data::<PanicDrop>().map(|v| v.val), Some(323));
}

test_compile!((), test_compile_void, Void);
test_compile!(f64, test_compile_f64, Float64);
test_compile!(f32, test_compile_f32, Float32);
test_compile!(int, test_compile_int, NInt);
test_compile!(uint, test_compile_uint, NUInt);
test_compile!(i32, test_compile_i32, Int);
test_compile!(u32, test_compile_u32, UInt);
test_compile!(i16, test_compile_i16, Short);
test_compile!(u16, test_compile_u16, UShort);
test_compile!(i8, test_compile_i8, SByte);
test_compile!(u8, test_compile_u8, UByte);<|endoftext|>


<commit_before>use ngrams::ngrams;
use classifier::Classifier;
use model::Model;

//model

#[test]
fn test_serialization_and_deserialization() {
    let model = Model::build_from_text("Testing text for serialization");
    let serialized = model.serialize();
    let deserialized = Model::deserialize(serialized);
    assert_eq!(model.ngram_ranks, deserialized.ngram_ranks);
}

// classifier

#[test]
fn test_classification() {
    let en_training_text = "Estimates of the number of languages in the world vary between 5,000 and 7,000. However, any precise estimate depends on a partly arbitrary distinction between languages and dialects. Natural languages are spoken or signed, but any language can be encoded into secondary media using auditory, visual, or tactile stimuli – for example, in graphic writing, braille, or whistling. This is because human language is modality-independent. Depending on philosophical perspectives regarding the definition of language and meaning, when used as a general concept, 'language' may refer to the cognitive ability to learn and use systems of complex communication, or to describe the set of rules that makes up these systems, or the set of utterances that can be produced from those rules. All languages rely on the process of semiosis to relate signs to particular meanings. Oral and sign languages contain a phonological system that governs how symbols are used to form sequences known as words or morphemes, and a syntactic system that governs how words and morphemes are combined to form phrases and utterances.";
    let ru_training_text = "Фрида Кало родилась 6 июля 1907 года в Койоакане, пригороде Мехико (позднее она поменяла год рождения на 1910 — год Мексиканской революции). Её отцом был фотограф Гильермо Кало, немец еврейского происхождения. Мать Фриды, Матильда Кальдерон, была мексиканкой с индейскими корнями. Фрида Кало была третьим ребёнком в семье. В 6 лет она перенесла полиомиелит, после болезни на всю жизнь осталась хромота, а её правая нога стала тоньше левой (что Кало всю жизнь скрывала под длинными юбками). Столь ранний опыт борьбы за право полноценной жизни закалил характер Фриды. Фрида занималась боксом и другими видами спорта. В 15 лет она поступила в «Препараторию» (Национальную подготовительную школу), одну из лучших школ Мексики, с целью изучать медицину. Из 2000 учащихся в этой школе было всего 35 девушек. Фрида сразу же заработала авторитет, создав с восемью другими учащимися закрытую группу «Качучас». Её поведение часто называли эпатажным. В Препаратории произошла её первая встреча с будущим мужем, известным мексиканским художником Диего Риверой, с 1921 по 1923 работавшим в Подготовительной школе над росписью «Созидание». В возрасте восемнадцати лет 17 сентября 1925 года Фрида попала в тяжёлую аварию. Автобус, на котором она ехала, столкнулся с трамваем. Фрида получила серьёзные травмы: тройной перелом позвоночника (в поясничной области), перелом ключицы, сломанные рёбра, тройной перелом таза, одиннадцать переломов костей правой ноги, раздробленную и вывихнутую правую стопу, вывихнутое плечо. Кроме того, её живот и матка были проколоты металлическим перилом, что серьёзно повредило её репродуктивную функцию. Она год была прикована к кровати, а проблемы со здоровьем остались на всю жизнь. Впоследствии Фриде пришлось перенести несколько десятков операций, месяцами не выходя из больниц. Она, несмотря на горячее желание, так и не смогла стать матерью. Именно после трагедии она впервые попросила у отца кисти и краски. Для Фриды сделали специальный подрамник, позволявший писать лёжа. Под балдахином кровати прикрепили большое зеркало, чтобы она могла видеть себя. Первой картиной был автопортрет, что навсегда определило основное направление творчества: «Я пишу себя, потому что много времени провожу в одиночестве и потому что являюсь той темой, которую знаю лучше всего». В 1928 году вступила в Мексиканскую коммунистическую партию. В 1929 году Фрида Кало стала женой Диего Риверы. Ему было 43 года, ей — 22. Сближало двух художников не только искусство, но и общие политические убеждения — коммунистические. Их бурная совместная жизнь стала легендой. Спустя много лет Фрида говорила: «В моей жизни было две аварии: одна — когда автобус врезался в трамвай, другая — это Диего». В 1930-х годах Фрида какое-то время жила в США, где работал муж. Это вынужденное долгое пребывание за границей, в развитой индустриальной стране, заставило её острее чувствовать национальные различия. С тех пор Фрида с особенной любовью относилась к народной мексиканской культуре, коллекционировала старинные произведения прикладного искусства, даже в повседневной жизни носила национальные костюмы. Поездка в Париж в 1939, где Фрида стала сенсацией тематической выставки мексиканского искусства (одна из её картин была даже приобретена Лувром), ещё сильнее развила патриотическое чувство. В 1937 году в доме Диего и Фриды ненадолго нашёл убежище советский революционный деятель Лев Троцкий; у них с Фридой завязался роман. Считается, что уехать от них его вынудило слишком явное увлечение темпераментной мексиканкой. В 1940-е годы картины Фриды появляются на нескольких заметных выставках. В то же время обостряются её проблемы со здоровьем. Лекарства и наркотики, призванные уменьшить физические страдания, меняют её душевное состояние, что ярко отражается в Дневнике, ставшем культовым среди её поклонников. В 1953 году состоялась её первая персональная выставка на родине. К тому времени Фрида уже не могла встать с постели, и на открытие выставки её принесли на больничной койке.. Вскоре из-за начавшейся гангрены ей ампутировали правую ногу ниже колена. Фрида Кало умерла 13 июля 1954 года от воспаления лёгких. Незадолго до смерти она оставила в своём дневнике последнюю запись: «Надеюсь, что уход будет удачным, и я больше не вернусь». Некоторые друзья Фриды Кало предполагали, она умерла от передозировки, и её смерть могла быть неслучайной. Тем не менее, доказательств этой версии не существует, вскрытие тела не проводилось. Прощание с Фридой Кало проходило во Дворце изящных искусств. На церемонии помимо Диего Риверы присутствовал президент Мексики Ласаро Карденас и многие деятели искусств. С 1955 года «Голубой дом» Фриды Кало стал музеем её памяти.";

    let mut classifier = Classifier::new();
    classifier.train(en_training_text, "en");
    classifier.train(ru_training_text, "ru");

    assert_eq!(
        classifier.classify("This is a sample of text in English language."),
        "en"
    );
    assert_eq!(
        classifier.classify("А это кажется пример текста на русском языке."),
        "ru"
    );
}

// ngrams

#[test]
fn unigrams() {
    let text = "Estimates";
    let unigrams: Vec<_> = ngrams(text, 1).collect();
    assert_eq!(unigrams, ["E", "s", "t", "i", "m", "a", "t", "e", "s"]);
}

#[test]
fn bigrams() {
    let text = "Estimates";
    let bigrams: Vec<_> = ngrams(text, 2).collect();
    assert_eq!(bigrams, ["Es", "st", "ti", "im", "ma", "at", "te", "es"]);
}

#[test]
fn trigrams() {
    let text = "Estimates";
    let trigrams: Vec<_> = ngrams(text, 3).collect();
    assert_eq!(trigrams, ["Est", "sti", "tim", "ima", "mat", "ate", "tes"]);
}

#[test]
fn longer_than_string_ngrams() {
    let text = "String";
    let sevengrams: Vec<_> = ngrams(text, 7).collect();
    let empty_vector: Vec<String> = Vec::new();
    assert_eq!(sevengrams, empty_vector);
}
<commit_msg>Rename ngram tests<commit_after>use ngrams::ngrams;
use classifier::Classifier;
use model::Model;

//model

#[test]
fn test_serialization_and_deserialization() {
    let model = Model::build_from_text("Testing text for serialization");
    let serialized = model.serialize();
    let deserialized = Model::deserialize(serialized);
    assert_eq!(model.ngram_ranks, deserialized.ngram_ranks);
}

// classifier

#[test]
fn test_classification() {
    let en_training_text = "Estimates of the number of languages in the world vary between 5,000 and 7,000. However, any precise estimate depends on a partly arbitrary distinction between languages and dialects. Natural languages are spoken or signed, but any language can be encoded into secondary media using auditory, visual, or tactile stimuli – for example, in graphic writing, braille, or whistling. This is because human language is modality-independent. Depending on philosophical perspectives regarding the definition of language and meaning, when used as a general concept, 'language' may refer to the cognitive ability to learn and use systems of complex communication, or to describe the set of rules that makes up these systems, or the set of utterances that can be produced from those rules. All languages rely on the process of semiosis to relate signs to particular meanings. Oral and sign languages contain a phonological system that governs how symbols are used to form sequences known as words or morphemes, and a syntactic system that governs how words and morphemes are combined to form phrases and utterances.";
    let ru_training_text = "Фрида Кало родилась 6 июля 1907 года в Койоакане, пригороде Мехико (позднее она поменяла год рождения на 1910 — год Мексиканской революции). Её отцом был фотограф Гильермо Кало, немец еврейского происхождения. Мать Фриды, Матильда Кальдерон, была мексиканкой с индейскими корнями. Фрида Кало была третьим ребёнком в семье. В 6 лет она перенесла полиомиелит, после болезни на всю жизнь осталась хромота, а её правая нога стала тоньше левой (что Кало всю жизнь скрывала под длинными юбками). Столь ранний опыт борьбы за право полноценной жизни закалил характер Фриды. Фрида занималась боксом и другими видами спорта. В 15 лет она поступила в «Препараторию» (Национальную подготовительную школу), одну из лучших школ Мексики, с целью изучать медицину. Из 2000 учащихся в этой школе было всего 35 девушек. Фрида сразу же заработала авторитет, создав с восемью другими учащимися закрытую группу «Качучас». Её поведение часто называли эпатажным. В Препаратории произошла её первая встреча с будущим мужем, известным мексиканским художником Диего Риверой, с 1921 по 1923 работавшим в Подготовительной школе над росписью «Созидание». В возрасте восемнадцати лет 17 сентября 1925 года Фрида попала в тяжёлую аварию. Автобус, на котором она ехала, столкнулся с трамваем. Фрида получила серьёзные травмы: тройной перелом позвоночника (в поясничной области), перелом ключицы, сломанные рёбра, тройной перелом таза, одиннадцать переломов костей правой ноги, раздробленную и вывихнутую правую стопу, вывихнутое плечо. Кроме того, её живот и матка были проколоты металлическим перилом, что серьёзно повредило её репродуктивную функцию. Она год была прикована к кровати, а проблемы со здоровьем остались на всю жизнь. Впоследствии Фриде пришлось перенести несколько десятков операций, месяцами не выходя из больниц. Она, несмотря на горячее желание, так и не смогла стать матерью. Именно после трагедии она впервые попросила у отца кисти и краски. Для Фриды сделали специальный подрамник, позволявший писать лёжа. Под балдахином кровати прикрепили большое зеркало, чтобы она могла видеть себя. Первой картиной был автопортрет, что навсегда определило основное направление творчества: «Я пишу себя, потому что много времени провожу в одиночестве и потому что являюсь той темой, которую знаю лучше всего». В 1928 году вступила в Мексиканскую коммунистическую партию. В 1929 году Фрида Кало стала женой Диего Риверы. Ему было 43 года, ей — 22. Сближало двух художников не только искусство, но и общие политические убеждения — коммунистические. Их бурная совместная жизнь стала легендой. Спустя много лет Фрида говорила: «В моей жизни было две аварии: одна — когда автобус врезался в трамвай, другая — это Диего». В 1930-х годах Фрида какое-то время жила в США, где работал муж. Это вынужденное долгое пребывание за границей, в развитой индустриальной стране, заставило её острее чувствовать национальные различия. С тех пор Фрида с особенной любовью относилась к народной мексиканской культуре, коллекционировала старинные произведения прикладного искусства, даже в повседневной жизни носила национальные костюмы. Поездка в Париж в 1939, где Фрида стала сенсацией тематической выставки мексиканского искусства (одна из её картин была даже приобретена Лувром), ещё сильнее развила патриотическое чувство. В 1937 году в доме Диего и Фриды ненадолго нашёл убежище советский революционный деятель Лев Троцкий; у них с Фридой завязался роман. Считается, что уехать от них его вынудило слишком явное увлечение темпераментной мексиканкой. В 1940-е годы картины Фриды появляются на нескольких заметных выставках. В то же время обостряются её проблемы со здоровьем. Лекарства и наркотики, призванные уменьшить физические страдания, меняют её душевное состояние, что ярко отражается в Дневнике, ставшем культовым среди её поклонников. В 1953 году состоялась её первая персональная выставка на родине. К тому времени Фрида уже не могла встать с постели, и на открытие выставки её принесли на больничной койке.. Вскоре из-за начавшейся гангрены ей ампутировали правую ногу ниже колена. Фрида Кало умерла 13 июля 1954 года от воспаления лёгких. Незадолго до смерти она оставила в своём дневнике последнюю запись: «Надеюсь, что уход будет удачным, и я больше не вернусь». Некоторые друзья Фриды Кало предполагали, она умерла от передозировки, и её смерть могла быть неслучайной. Тем не менее, доказательств этой версии не существует, вскрытие тела не проводилось. Прощание с Фридой Кало проходило во Дворце изящных искусств. На церемонии помимо Диего Риверы присутствовал президент Мексики Ласаро Карденас и многие деятели искусств. С 1955 года «Голубой дом» Фриды Кало стал музеем её памяти.";

    let mut classifier = Classifier::new();
    classifier.train(en_training_text, "en");
    classifier.train(ru_training_text, "ru");

    assert_eq!(
        classifier.classify("This is a sample of text in English language."),
        "en"
    );
    assert_eq!(
        classifier.classify("А это кажется пример текста на русском языке."),
        "ru"
    );
}

// ngrams

#[test]
fn test_unigrams() {
    let text = "Estimates";
    let unigrams: Vec<_> = ngrams(text, 1).collect();
    assert_eq!(unigrams, ["E", "s", "t", "i", "m", "a", "t", "e", "s"]);
}

#[test]
fn test_bigrams() {
    let text = "Estimates";
    let bigrams: Vec<_> = ngrams(text, 2).collect();
    assert_eq!(bigrams, ["Es", "st", "ti", "im", "ma", "at", "te", "es"]);
}

#[test]
fn test_trigrams() {
    let text = "Estimates";
    let trigrams: Vec<_> = ngrams(text, 3).collect();
    assert_eq!(trigrams, ["Est", "sti", "tim", "ima", "mat", "ate", "tes"]);
}

#[test]
fn test_longer_than_string_ngrams() {
    let text = "String";
    let sevengrams: Vec<_> = ngrams(text, 7).collect();
    let empty_vector: Vec<String> = Vec::new();
    assert_eq!(sevengrams, empty_vector);
}
<|endoftext|>


<commit_before>/* Cymbalum, Molecular Simulation in Rust - Copyright (C) 2015 Guillaume Fraux
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/
 */

/// Macro for testing approximated equality of floats.
macro_rules! assert_approx_eq {
    ($left: expr, $right: expr, $tol: expr) => (
        {
            match (&($left), &($right), ($tol)) {
                (left_val , right_val, tol_val) => {
                    let delta: f64 = (*left_val - *right_val) as f64;
                    let delta = delta.abs();
                    if !(delta < tol_val) {
                        panic!(
                            "assertion failed: `(left ≈ right)` \
                             (left: `{:?}`, right: `{:?}`) \
                             with ∆={:1.1e} (allowed ∆={:e})
                             "
                        , *left_val , *right_val, delta, tol_val)
                    }
                }
            }
        }
    )
}

#[cfg(test)]
mod tests {
    //use std::num::Float;

    #[test]
    fn approx_eq() {
        assert_approx_eq!(1.0, 1.0, 1e-90);
        assert_approx_eq!(1.1, 1.1000003, 1e-3);
    }

    #[test]
    #[should_panic]
    fn not_approx_eq() {
        assert_approx_eq!(1.1, 1.1000003, 1e-8);
    }

    #[test]
    fn all_float_types() {
        assert_approx_eq!(1.0f32, 1.0f32, 1e-90);
        assert_approx_eq!(1.0f64, 1.0f64, 1e-90);
    }
}
<commit_msg>Typo in error message for assert_appro_eq!<commit_after>/* Cymbalum, Molecular Simulation in Rust - Copyright (C) 2015 Guillaume Fraux
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/
 */

/// Macro for testing approximated equality of floats.
macro_rules! assert_approx_eq {
    ($left: expr, $right: expr, $tol: expr) => (
        {
            match (&($left), &($right), ($tol)) {
                (left_val , right_val, tol_val) => {
                    let delta: f64 = (*left_val - *right_val) as f64;
                    let delta = delta.abs();
                    if !(delta < tol_val) {
                        panic!(
                            "assertion failed: `(left ≈ right)` \
                             (left: `{:?}`, right: `{:?}`) \
                             with ∆={:1.1e} (allowed ∆={:e})\
                             "
                        , *left_val , *right_val, delta, tol_val)
                    }
                }
            }
        }
    )
}

#[cfg(test)]
mod tests {
    //use std::num::Float;

    #[test]
    fn approx_eq() {
        assert_approx_eq!(1.0, 1.0, 1e-90);
        assert_approx_eq!(1.1, 1.1000003, 1e-3);
    }

    #[test]
    #[should_panic]
    fn not_approx_eq() {
        assert_approx_eq!(1.1, 1.1000003, 1e-8);
    }

    #[test]
    fn all_float_types() {
        assert_approx_eq!(1.0f32, 1.0f32, 1e-90);
        assert_approx_eq!(1.0f64, 1.0f64, 1e-90);
    }
}
<|endoftext|>