<commit_before>use proc_macro2::{Ident, Span, TokenStream};
use quote::quote;

use super::{Metadata, Request, RequestField, RequestFieldKind};

impl Request {
    pub fn expand_incoming(
        &self,
        metadata: &Metadata,
        error_ty: &TokenStream,
        ruma_api: &TokenStream,
    ) -> TokenStream {
        let http = quote! { #ruma_api::exports::http };
        let percent_encoding = quote! { #ruma_api::exports::percent_encoding };
        let ruma_serde = quote! { #ruma_api::exports::ruma_serde };
        let serde_json = quote! { #ruma_api::exports::serde_json };

        let method = &metadata.method;

        let incoming_request_type =
            if self.contains_lifetimes() { quote!(IncomingRequest) } else { quote!(Request) };

        let (parse_request_path, path_vars) = if self.has_path_fields() {
            let path_string = metadata.path.value();

            assert!(path_string.starts_with('/'), "path needs to start with '/'");
            assert!(
                path_string.chars().filter(|c| *c == ':').count() == self.path_field_count(),
                "number of declared path parameters needs to match amount of placeholders in path"
            );

            let path_var_decls = path_string[1..]
                .split('/')
                .enumerate()
                .filter(|(_, seg)| seg.starts_with(':'))
                .map(|(i, seg)| {
                    let path_var = Ident::new(&seg[1..], Span::call_site());
                    quote! {
                        let #path_var = {
                            let segment = path_segments[#i].as_bytes();
                            let decoded =
                                #percent_encoding::percent_decode(segment).decode_utf8()?;

                            ::std::convert::TryFrom::try_from(&*decoded)?
                        };
                    }
                });

            let parse_request_path = quote! {
                let path_segments: ::std::vec::Vec<&::std::primitive::str> =
                    request.uri().path()[1..].split('/').collect();

                #(#path_var_decls)*
            };

            let path_vars = path_string[1..]
                .split('/')
                .filter(|seg| seg.starts_with(':'))
                .map(|seg| Ident::new(&seg[1..], Span::call_site()));

            (parse_request_path, quote! { #(#path_vars,)* })
        } else {
            (TokenStream::new(), TokenStream::new())
        };

        let (parse_query, query_vars) = if let Some(field) = self.query_map_field() {
            let field_name = field.ident.as_ref().expect("expected field to have an identifier");
            let parse = quote! {
                let #field_name = #ruma_serde::urlencoded::from_str(
                    &request.uri().query().unwrap_or(""),
                )?;
            };

            (parse, quote! { #field_name, })
        } else if self.has_query_fields() {
            let (decls, names) = self.vars(RequestFieldKind::Query, quote!(request_query));

            let parse = quote! {
                let request_query: <RequestQuery as #ruma_serde::Outgoing>::Incoming =
                    #ruma_serde::urlencoded::from_str(
                        &request.uri().query().unwrap_or("")
                    )?;

                #decls
            };

            (parse, names)
        } else {
            (TokenStream::new(), TokenStream::new())
        };

        let (parse_headers, header_vars) = if self.has_header_fields() {
            let (decls, names): (TokenStream, Vec<_>) = self
                .header_fields()
                .map(|request_field| {
                    let (field, header_name) = match request_field {
                        RequestField::Header(field, header_name) => (field, header_name),
                        _ => panic!("expected request field to be header variant"),
                    };

                    let field_name = &field.ident;
                    let header_name_string = header_name.to_string();

                    let (some_case, none_case) = match &field.ty {
                        syn::Type::Path(syn::TypePath {
                            path: syn::Path { segments, .. }, ..
                        }) if segments.last().unwrap().ident == "Option" => {
                            (quote! { Some(str_value.to_owned()) }, quote! { None })
                        }
                        _ => (
                            quote! { str_value.to_owned() },
                            quote! {
                                return Err(
                                    #ruma_api::error::HeaderDeserializationError::MissingHeader(
                                        #header_name_string.into()
                                    ).into(),
                                )
                            },
                        ),
                    };

                    let decl = quote! {
                        let #field_name = match headers.get(#http::header::#header_name) {
                            Some(header_value) => {
                                let str_value = header_value.to_str()?;
                                #some_case
                            }
                            None => #none_case,
                        };
                    };

                    (decl, field_name)
                })
                .unzip();

            let parse = quote! {
                let headers = request.headers();

                #decls
            };

            (parse, quote! { #(#names,)* })
        } else {
            (TokenStream::new(), TokenStream::new())
        };

        let extract_body = if self.has_body_fields() || self.newtype_body_field().is_some() {
            let body_lifetimes = if self.has_body_lifetimes() {
                // duplicate the anonymous lifetime as many times as needed
                let lifetimes = std::iter::repeat(quote! { '_ }).take(self.lifetimes.body.len());
                quote! { < #( #lifetimes, )* >}
            } else {
                TokenStream::new()
            };

            quote! {
                let request_body: <
                    RequestBody #body_lifetimes
                    as #ruma_serde::Outgoing
                >::Incoming = {
                    let body = ::std::convert::AsRef::<[::std::primitive::u8]>::as_ref(
                        request.body(),
                    );

                    #serde_json::from_slice(match body {
                        // If the request body is completely empty, pretend it is an empty JSON
                        // object instead. This allows requests with only optional body parameters
                        // to be deserialized in that case.
                        [] => b"{}",
                        b => b,
                    })?
                };
            }
        } else {
            TokenStream::new()
        };

        let (parse_body, body_vars) = if let Some(field) = self.newtype_body_field() {
            let field_name = field.ident.as_ref().expect("expected field to have an identifier");
            let parse = quote! {
                let #field_name = request_body.0;
            };

            (parse, quote! { #field_name, })
        } else if let Some(field) = self.newtype_raw_body_field() {
            let field_name = field.ident.as_ref().expect("expected field to have an identifier");
            let parse = quote! {
                let #field_name =
                    ::std::convert::AsRef::<[u8]>::as_ref(request.body()).to_vec();
            };

            (parse, quote! { #field_name, })
        } else {
            self.vars(RequestFieldKind::Body, quote!(request_body))
        };

        let non_auth_impls = metadata.authentication.iter().map(|auth| {
            if auth.value == "None" {
                let attrs = &auth.attrs;
                quote! {
                    #( #attrs )*
                    #[automatically_derived]
                    #[cfg(feature = "server")]
                    impl #ruma_api::IncomingNonAuthRequest for #incoming_request_type {}
                }
            } else {
                TokenStream::new()
            }
        });

        quote! {
            #[automatically_derived]
            #[cfg(feature = "server")]
            impl #ruma_api::IncomingRequest for #incoming_request_type {
                type EndpointError = #error_ty;
                type OutgoingResponse = Response;

                const METADATA: #ruma_api::Metadata = self::METADATA;

                fn try_from_http_request<T: ::std::convert::AsRef<[::std::primitive::u8]>>(
                    request: #http::Request<T>
                ) -> ::std::result::Result<Self, #ruma_api::error::FromHttpRequestError> {
                    if request.method() != #http::Method::#method {
                        return Err(#ruma_api::error::FromHttpRequestError::MethodMismatch {
                            expected: #http::Method::#method,
                            received: request.method().clone(),
                        });
                    }

                    #parse_request_path
                    #parse_query
                    #parse_headers

                    #extract_body
                    #parse_body

                    ::std::result::Result::Ok(Self {
                        #path_vars
                        #query_vars
                        #header_vars
                        #body_vars
                    })
                }
            }

            #(#non_auth_impls)*
        }
    }

    fn vars(
        &self,
        request_field_kind: RequestFieldKind,
        src: TokenStream,
    ) -> (TokenStream, TokenStream) {
        self.fields
            .iter()
            .filter_map(|f| f.field_of_kind(request_field_kind))
            .map(|field| {
                let field_name =
                    field.ident.as_ref().expect("expected field to have an identifier");
                let cfg_attrs =
                    field.attrs.iter().filter(|a| a.path.is_ident("cfg")).collect::<Vec<_>>();

                let decl = quote! {
                    #( #cfg_attrs )*
                    let #field_name = #src.#field_name;
                };

                (decl, quote! { #field_name, })
            })
            .unzip()
    }
}
<commit_msg>api-macros: Fix tiny formatting inconsistency<commit_after>use proc_macro2::{Ident, Span, TokenStream};
use quote::quote;

use super::{Metadata, Request, RequestField, RequestFieldKind};

impl Request {
    pub fn expand_incoming(
        &self,
        metadata: &Metadata,
        error_ty: &TokenStream,
        ruma_api: &TokenStream,
    ) -> TokenStream {
        let http = quote! { #ruma_api::exports::http };
        let percent_encoding = quote! { #ruma_api::exports::percent_encoding };
        let ruma_serde = quote! { #ruma_api::exports::ruma_serde };
        let serde_json = quote! { #ruma_api::exports::serde_json };

        let method = &metadata.method;

        let incoming_request_type =
            if self.contains_lifetimes() { quote!(IncomingRequest) } else { quote!(Request) };

        let (parse_request_path, path_vars) = if self.has_path_fields() {
            let path_string = metadata.path.value();

            assert!(path_string.starts_with('/'), "path needs to start with '/'");
            assert!(
                path_string.chars().filter(|c| *c == ':').count() == self.path_field_count(),
                "number of declared path parameters needs to match amount of placeholders in path"
            );

            let path_var_decls = path_string[1..]
                .split('/')
                .enumerate()
                .filter(|(_, seg)| seg.starts_with(':'))
                .map(|(i, seg)| {
                    let path_var = Ident::new(&seg[1..], Span::call_site());
                    quote! {
                        let #path_var = {
                            let segment = path_segments[#i].as_bytes();
                            let decoded =
                                #percent_encoding::percent_decode(segment).decode_utf8()?;

                            ::std::convert::TryFrom::try_from(&*decoded)?
                        };
                    }
                });

            let parse_request_path = quote! {
                let path_segments: ::std::vec::Vec<&::std::primitive::str> =
                    request.uri().path()[1..].split('/').collect();

                #(#path_var_decls)*
            };

            let path_vars = path_string[1..]
                .split('/')
                .filter(|seg| seg.starts_with(':'))
                .map(|seg| Ident::new(&seg[1..], Span::call_site()));

            (parse_request_path, quote! { #(#path_vars,)* })
        } else {
            (TokenStream::new(), TokenStream::new())
        };

        let (parse_query, query_vars) = if let Some(field) = self.query_map_field() {
            let field_name = field.ident.as_ref().expect("expected field to have an identifier");
            let parse = quote! {
                let #field_name = #ruma_serde::urlencoded::from_str(
                    &request.uri().query().unwrap_or(""),
                )?;
            };

            (parse, quote! { #field_name, })
        } else if self.has_query_fields() {
            let (decls, names) = self.vars(RequestFieldKind::Query, quote!(request_query));

            let parse = quote! {
                let request_query: <RequestQuery as #ruma_serde::Outgoing>::Incoming =
                    #ruma_serde::urlencoded::from_str(
                        &request.uri().query().unwrap_or("")
                    )?;

                #decls
            };

            (parse, names)
        } else {
            (TokenStream::new(), TokenStream::new())
        };

        let (parse_headers, header_vars) = if self.has_header_fields() {
            let (decls, names): (TokenStream, Vec<_>) = self
                .header_fields()
                .map(|request_field| {
                    let (field, header_name) = match request_field {
                        RequestField::Header(field, header_name) => (field, header_name),
                        _ => panic!("expected request field to be header variant"),
                    };

                    let field_name = &field.ident;
                    let header_name_string = header_name.to_string();

                    let (some_case, none_case) = match &field.ty {
                        syn::Type::Path(syn::TypePath {
                            path: syn::Path { segments, .. }, ..
                        }) if segments.last().unwrap().ident == "Option" => {
                            (quote! { Some(str_value.to_owned()) }, quote! { None })
                        }
                        _ => (
                            quote! { str_value.to_owned() },
                            quote! {
                                return Err(
                                    #ruma_api::error::HeaderDeserializationError::MissingHeader(
                                        #header_name_string.into()
                                    ).into(),
                                )
                            },
                        ),
                    };

                    let decl = quote! {
                        let #field_name = match headers.get(#http::header::#header_name) {
                            Some(header_value) => {
                                let str_value = header_value.to_str()?;
                                #some_case
                            }
                            None => #none_case,
                        };
                    };

                    (decl, field_name)
                })
                .unzip();

            let parse = quote! {
                let headers = request.headers();

                #decls
            };

            (parse, quote! { #(#names,)* })
        } else {
            (TokenStream::new(), TokenStream::new())
        };

        let extract_body = if self.has_body_fields() || self.newtype_body_field().is_some() {
            let body_lifetimes = if self.has_body_lifetimes() {
                // duplicate the anonymous lifetime as many times as needed
                let lifetimes = std::iter::repeat(quote! { '_ }).take(self.lifetimes.body.len());
                quote! { < #( #lifetimes, )* > }
            } else {
                TokenStream::new()
            };

            quote! {
                let request_body: <
                    RequestBody #body_lifetimes
                    as #ruma_serde::Outgoing
                >::Incoming = {
                    let body = ::std::convert::AsRef::<[::std::primitive::u8]>::as_ref(
                        request.body(),
                    );

                    #serde_json::from_slice(match body {
                        // If the request body is completely empty, pretend it is an empty JSON
                        // object instead. This allows requests with only optional body parameters
                        // to be deserialized in that case.
                        [] => b"{}",
                        b => b,
                    })?
                };
            }
        } else {
            TokenStream::new()
        };

        let (parse_body, body_vars) = if let Some(field) = self.newtype_body_field() {
            let field_name = field.ident.as_ref().expect("expected field to have an identifier");
            let parse = quote! {
                let #field_name = request_body.0;
            };

            (parse, quote! { #field_name, })
        } else if let Some(field) = self.newtype_raw_body_field() {
            let field_name = field.ident.as_ref().expect("expected field to have an identifier");
            let parse = quote! {
                let #field_name =
                    ::std::convert::AsRef::<[u8]>::as_ref(request.body()).to_vec();
            };

            (parse, quote! { #field_name, })
        } else {
            self.vars(RequestFieldKind::Body, quote!(request_body))
        };

        let non_auth_impls = metadata.authentication.iter().map(|auth| {
            if auth.value == "None" {
                let attrs = &auth.attrs;
                quote! {
                    #( #attrs )*
                    #[automatically_derived]
                    #[cfg(feature = "server")]
                    impl #ruma_api::IncomingNonAuthRequest for #incoming_request_type {}
                }
            } else {
                TokenStream::new()
            }
        });

        quote! {
            #[automatically_derived]
            #[cfg(feature = "server")]
            impl #ruma_api::IncomingRequest for #incoming_request_type {
                type EndpointError = #error_ty;
                type OutgoingResponse = Response;

                const METADATA: #ruma_api::Metadata = self::METADATA;

                fn try_from_http_request<T: ::std::convert::AsRef<[::std::primitive::u8]>>(
                    request: #http::Request<T>
                ) -> ::std::result::Result<Self, #ruma_api::error::FromHttpRequestError> {
                    if request.method() != #http::Method::#method {
                        return Err(#ruma_api::error::FromHttpRequestError::MethodMismatch {
                            expected: #http::Method::#method,
                            received: request.method().clone(),
                        });
                    }

                    #parse_request_path
                    #parse_query
                    #parse_headers

                    #extract_body
                    #parse_body

                    ::std::result::Result::Ok(Self {
                        #path_vars
                        #query_vars
                        #header_vars
                        #body_vars
                    })
                }
            }

            #(#non_auth_impls)*
        }
    }

    fn vars(
        &self,
        request_field_kind: RequestFieldKind,
        src: TokenStream,
    ) -> (TokenStream, TokenStream) {
        self.fields
            .iter()
            .filter_map(|f| f.field_of_kind(request_field_kind))
            .map(|field| {
                let field_name =
                    field.ident.as_ref().expect("expected field to have an identifier");
                let cfg_attrs =
                    field.attrs.iter().filter(|a| a.path.is_ident("cfg")).collect::<Vec<_>>();

                let decl = quote! {
                    #( #cfg_attrs )*
                    let #field_name = #src.#field_name;
                };

                (decl, quote! { #field_name, })
            })
            .unzip()
    }
}
<|endoftext|>


<commit_before>extern crate mime_guess;

use std::convert::TryInto;
use std::path::{Path, PathBuf};

use task_maker_format::ioi;

use turingarena::award::*;
use turingarena::content::*;
use turingarena::evaluation::record::*;
use turingarena::feedback::{table::*, *};
use turingarena::problem::material::*;
use turingarena::rusage::{MemoryUsage, TimeUsage};
use turingarena::submission::form::*;

fn subtasks_of(task: &ioi::Task) -> Vec<&ioi::SubtaskInfo> {
    let mut subtasks: Vec<_> = task.subtasks.values().collect();
    subtasks.sort_by(|a, b| a.id.cmp(&b.id));
    subtasks
}

fn testcases_of(subtask: &ioi::SubtaskInfo) -> Vec<&ioi::TestcaseInfo> {
    let mut testcases: Vec<_> = subtask.testcases.values().collect();
    testcases.sort_by(|a, b| a.id.cmp(&b.id));
    testcases
}

fn submission_form() -> Form {
    Form {
        fields: vec![Field {
            id: FieldId("solution".into()),
            title: vec![TextVariant {
                attributes: vec![],
                value: "Solution".into(),
            }],
            types: vec![FileType {
                id: FileTypeId("cpp".into()),
                title: vec![TextVariant {
                    attributes: vec![],
                    value: "C++".into(),
                }],
                extensions: vec![
                    FileTypeExtension(".cpp".into()),
                    FileTypeExtension(".cc".into()),
                ],
                primary_extension: FileTypeExtension(".cpp".into()),
            }],
        }],
    }
}

fn award_of(subtask: &ioi::SubtaskInfo) -> Award {
    Award {
        name: AwardName(format!("subtask.{}", subtask.id)),
        title: vec![
            TextVariant {
                attributes: vec![],
                value: format!("Subtask {}", subtask.id),
            },
            TextVariant {
                attributes: vec![VariantAttribute {
                    key: "style".to_owned(),
                    value: "short".to_owned(),
                }],
                value: format!("ST {}", subtask.id),
            },
        ],
        content: if subtask.max_score > 0.0 {
            AwardContent::Score(ScoreAwardContent {
                range: ScoreRange {
                    // TODO: determine actual precision (may depend on the task)
                    precision: 0,
                    max: Score(subtask.max_score),
                    // TODO: determine whether partial scores are allowed (may depend on the task)
                    allow_partial: true,
                },
            })
        } else {
            AwardContent::Badge(BadgeAwardContent)
        },
    }
}

fn cols() -> Vec<Col> {
    vec![
        Col {
            title: vec![TextVariant {
                attributes: vec![],
                value: format!("Case"),
            }],
            content: ColContent::RowNumber(RowNumberColContent {}),
        },
        Col {
            title: vec![TextVariant {
                attributes: vec![],
                value: format!("Score"),
            }],
            content: ColContent::Score(ScoreColContent {
                range: ScoreRange {
                    // TODO: determine actual precision
                    precision: 2,
                    max: Score(1.),
                    // TODO: determine if partial scores are actually allowed
                    allow_partial: true,
                },
            }),
        },
        Col {
            title: vec![TextVariant {
                attributes: vec![],
                value: format!("Time usage"),
            }],
            content: ColContent::TimeUsage(TimeUsageColContent),
        },
        Col {
            title: vec![TextVariant {
                attributes: vec![],
                value: format!("Memory usage"),
            }],
            content: ColContent::MemoryUsage(MemoryUsageColContent),
        },
        Col {
            title: vec![TextVariant {
                attributes: vec![],
                value: format!("Message"),
            }],
            content: ColContent::Message(MessageColContent),
        },
    ]
}

fn caption() -> Text {
    vec![TextVariant {
        attributes: vec![],
        value: format!("Test case results"),
    }]
}

fn row_group_of(task: &ioi::Task, subtask: &ioi::SubtaskInfo) -> RowGroup {
    RowGroup {
        title: vec![TextVariant {
            attributes: vec![],
            value: format!("Subtask {}", subtask.id),
        }],
        rows: testcases_of(subtask)
            .into_iter()
            .map(|testcase| row_of(task, subtask, testcase))
            .collect(),
    }
}

fn row_of(task: &ioi::Task, subtask: &ioi::SubtaskInfo, testcase: &ioi::TestcaseInfo) -> Row {
    Row {
        content: RowContent::Data,
        cells: vec![
            Cell {
                content: CellContent::RowNumber(RowNumberCellContent {
                    number: testcase.id.try_into().expect("Testcase ID too large"),
                }),
            },
            Cell {
                content: CellContent::Score(ScoreCellContent {
                    range: ScoreRange {
                        precision: 2,
                        max: Score(1.),
                        allow_partial: true,
                    },
                    key: Key(format!("testcase.{}.score", testcase.id)),
                }),
            },
            Cell {
                content: CellContent::TimeUsage(TimeUsageCellContent {
                    max_relevant: TimeUsage(task.time_limit.unwrap_or(10.0)),
                    primary_watermark: task.time_limit.map(|l| TimeUsage(l)),
                    key: Key(format!("testcase.{}.time_usage", testcase.id)),
                    valence_key: Some(Key(format!("testcase.{}.time_usage_valence", testcase.id))),
                }),
            },
            Cell {
                content: CellContent::MemoryUsage(MemoryUsageCellContent {
                    max_relevant: MemoryUsage(
                        (task.memory_limit.unwrap_or(1024) * 1024 * 1024 * 2) as i32,
                    ),
                    primary_watermark: task
                        .memory_limit
                        .map(|l| MemoryUsage((l * 1024 * 1024) as i32)),
                    key: Key(format!("testcase.{}.memory_usage", testcase.id)),
                    valence_key: Some(Key(format!(
                        "testcase.{}.memory_usage_valence",
                        testcase.id
                    ))),
                }),
            },
            Cell {
                content: CellContent::Message(MessageCellContent {
                    key: Key(format!("testcase.{}.message", testcase.id)),
                    valence_key: Some(Key(format!("testcase.{}.valence", testcase.id))),
                }),
            },
        ],
    }
}

fn files_in_dir(dir_path: &std::path::PathBuf) -> impl Iterator<Item = std::path::PathBuf> {
    std::fs::read_dir(dir_path)
        .expect("unable to read_dir")
        .map(|entry| entry.expect("unable to read_dir").path())
}

fn attachment_at_path(file_path: std::path::PathBuf) -> Attachment {
    Attachment {
        title: vec![TextVariant {
            attributes: vec![],
            value: file_path
                .file_name()
                .unwrap()
                .to_string_lossy()
                .into_owned(),
        }],
        file: vec![FileVariant {
            attributes: vec![],
            name: Some(FileName(
                file_path
                    .file_name()
                    .unwrap()
                    .to_string_lossy()
                    .into_owned(),
            )),
            r#type: mime_guess::from_path(&file_path)
                .first_raw()
                .map(|t| MediaType(t.to_owned())),
            content: FileContent(std::fs::read(&file_path.to_string_lossy().as_ref()).unwrap()),
        }],
    }
}

/// Mapping (extension, MIME type)
const STATEMENT_FORMATS: [(&'static str, &'static str); 3] = [
    ("pdf", "application/pdf"),
    ("html", "text/html"),
    ("md", "application/markdown"),
];

/// Find the statements directory, as in the italy_yaml task format
/// Searches the paths $task_dir/statement and $task_dir/testo
fn statements_dir(task_dir: &Path) -> Option<PathBuf> {
    for dir in vec!["statement", "testo"] {
        let dir = task_dir.join(dir);
        if dir.exists() && dir.is_dir() {
            return Some(dir);
        }
    }
    None
}

/// Tries to match the filename, returning the mimetype of the
/// matched item, if any
fn match_statement(path: &Path) -> Option<(String, FileName, MediaType)> {
    let ext = path.extension().unwrap().to_str().unwrap();
    let filename = path.file_name().unwrap().to_str().unwrap();
    let language = path.file_stem().unwrap().to_str().unwrap();
    for &(extension, mime_type) in &STATEMENT_FORMATS {
        if ext == extension {
            return Some((
                language.to_owned(),
                FileName(filename.to_owned()),
                MediaType(mime_type.to_owned()),
            ));
        }
    }
    None
}

/// find all the statements in the directory
fn statements_of(task_dir: &Path) -> Vec<FileVariant> {
    let mut result = Vec::new();
    let dir = statements_dir(task_dir);
    if let Some(dir) = dir {
        for file in dir.read_dir().unwrap() {
            let file = file.unwrap().path();
            if let Some((language, filename, mime_type)) = match_statement(&file) {
                result.push(FileVariant {
                    attributes: vec![VariantAttribute {
                        key: "language_name".to_owned(),
                        value: language,
                    }],
                    name: Some(filename),
                    r#type: Some(mime_type),
                    content: FileContent(
                        std::fs::read(file).expect("Unable to read statement file"),
                    ),
                });
            }
        }
    }
    result
}

pub fn gen_material(task: &ioi::Task) -> Material {
    Material {
        title: vec![
            TextVariant {
                attributes: vec![],
                value: task.title.clone().into(),
            },
            TextVariant {
                attributes: vec![VariantAttribute {
                    key: "style".to_owned(),
                    value: "short".to_owned(),
                }],
                value: task.name.clone().into(),
            },
        ],
        statement: statements_of(&task.path),
        attachments: files_in_dir(&task.path.join("att"))
            .map(attachment_at_path)
            .collect(),
        submission_form: submission_form(),
        awards: { subtasks_of(task).into_iter().map(award_of).collect() },
        feedback: vec![Section::Table(TableSection {
            caption: caption(),
            cols: cols(),
            row_groups: subtasks_of(task)
                .into_iter()
                .map(|subtask| row_group_of(task, subtask))
                .collect(),
        })],
    }
}
<commit_msg>task-maker: move score column last<commit_after>extern crate mime_guess;

use std::convert::TryInto;
use std::path::{Path, PathBuf};

use task_maker_format::ioi;

use turingarena::award::*;
use turingarena::content::*;
use turingarena::evaluation::record::*;
use turingarena::feedback::{table::*, *};
use turingarena::problem::material::*;
use turingarena::rusage::{MemoryUsage, TimeUsage};
use turingarena::submission::form::*;

fn subtasks_of(task: &ioi::Task) -> Vec<&ioi::SubtaskInfo> {
    let mut subtasks: Vec<_> = task.subtasks.values().collect();
    subtasks.sort_by(|a, b| a.id.cmp(&b.id));
    subtasks
}

fn testcases_of(subtask: &ioi::SubtaskInfo) -> Vec<&ioi::TestcaseInfo> {
    let mut testcases: Vec<_> = subtask.testcases.values().collect();
    testcases.sort_by(|a, b| a.id.cmp(&b.id));
    testcases
}

fn submission_form() -> Form {
    Form {
        fields: vec![Field {
            id: FieldId("solution".into()),
            title: vec![TextVariant {
                attributes: vec![],
                value: "Solution".into(),
            }],
            types: vec![FileType {
                id: FileTypeId("cpp".into()),
                title: vec![TextVariant {
                    attributes: vec![],
                    value: "C++".into(),
                }],
                extensions: vec![
                    FileTypeExtension(".cpp".into()),
                    FileTypeExtension(".cc".into()),
                ],
                primary_extension: FileTypeExtension(".cpp".into()),
            }],
        }],
    }
}

fn award_of(subtask: &ioi::SubtaskInfo) -> Award {
    Award {
        name: AwardName(format!("subtask.{}", subtask.id)),
        title: vec![
            TextVariant {
                attributes: vec![],
                value: format!("Subtask {}", subtask.id),
            },
            TextVariant {
                attributes: vec![VariantAttribute {
                    key: "style".to_owned(),
                    value: "short".to_owned(),
                }],
                value: format!("ST {}", subtask.id),
            },
        ],
        content: if subtask.max_score > 0.0 {
            AwardContent::Score(ScoreAwardContent {
                range: ScoreRange {
                    // TODO: determine actual precision (may depend on the task)
                    precision: 0,
                    max: Score(subtask.max_score),
                    // TODO: determine whether partial scores are allowed (may depend on the task)
                    allow_partial: true,
                },
            })
        } else {
            AwardContent::Badge(BadgeAwardContent)
        },
    }
}

fn cols() -> Vec<Col> {
    vec![
        Col {
            title: vec![TextVariant {
                attributes: vec![],
                value: format!("Case"),
            }],
            content: ColContent::RowNumber(RowNumberColContent {}),
        },
        Col {
            title: vec![TextVariant {
                attributes: vec![],
                value: format!("Time usage"),
            }],
            content: ColContent::TimeUsage(TimeUsageColContent),
        },
        Col {
            title: vec![TextVariant {
                attributes: vec![],
                value: format!("Memory usage"),
            }],
            content: ColContent::MemoryUsage(MemoryUsageColContent),
        },
        Col {
            title: vec![TextVariant {
                attributes: vec![],
                value: format!("Message"),
            }],
            content: ColContent::Message(MessageColContent),
        },
        Col {
            title: vec![TextVariant {
                attributes: vec![],
                value: format!("Score"),
            }],
            content: ColContent::Score(ScoreColContent {
                range: ScoreRange {
                    // TODO: determine actual precision
                    precision: 2,
                    max: Score(1.),
                    // TODO: determine if partial scores are actually allowed
                    allow_partial: true,
                },
            }),
        },
    ]
}

fn caption() -> Text {
    vec![TextVariant {
        attributes: vec![],
        value: format!("Test case results"),
    }]
}

fn row_group_of(task: &ioi::Task, subtask: &ioi::SubtaskInfo) -> RowGroup {
    RowGroup {
        title: vec![TextVariant {
            attributes: vec![],
            value: format!("Subtask {}", subtask.id),
        }],
        rows: testcases_of(subtask)
            .into_iter()
            .map(|testcase| row_of(task, subtask, testcase))
            .collect(),
    }
}

fn row_of(task: &ioi::Task, subtask: &ioi::SubtaskInfo, testcase: &ioi::TestcaseInfo) -> Row {
    Row {
        content: RowContent::Data,
        cells: vec![
            Cell {
                content: CellContent::RowNumber(RowNumberCellContent {
                    number: testcase.id.try_into().expect("Testcase ID too large"),
                }),
            },
            Cell {
                content: CellContent::TimeUsage(TimeUsageCellContent {
                    max_relevant: TimeUsage(task.time_limit.unwrap_or(10.0)),
                    primary_watermark: task.time_limit.map(|l| TimeUsage(l)),
                    key: Key(format!("testcase.{}.time_usage", testcase.id)),
                    valence_key: Some(Key(format!("testcase.{}.time_usage_valence", testcase.id))),
                }),
            },
            Cell {
                content: CellContent::MemoryUsage(MemoryUsageCellContent {
                    max_relevant: MemoryUsage(
                        (task.memory_limit.unwrap_or(1024) * 1024 * 1024 * 2) as i32,
                    ),
                    primary_watermark: task
                        .memory_limit
                        .map(|l| MemoryUsage((l * 1024 * 1024) as i32)),
                    key: Key(format!("testcase.{}.memory_usage", testcase.id)),
                    valence_key: Some(Key(format!(
                        "testcase.{}.memory_usage_valence",
                        testcase.id
                    ))),
                }),
            },
            Cell {
                content: CellContent::Message(MessageCellContent {
                    key: Key(format!("testcase.{}.message", testcase.id)),
                    valence_key: Some(Key(format!("testcase.{}.valence", testcase.id))),
                }),
            },
            Cell {
                content: CellContent::Score(ScoreCellContent {
                    range: ScoreRange {
                        precision: 2,
                        max: Score(1.),
                        allow_partial: true,
                    },
                    key: Key(format!("testcase.{}.score", testcase.id)),
                }),
            },
        ],
    }
}

fn files_in_dir(dir_path: &std::path::PathBuf) -> impl Iterator<Item = std::path::PathBuf> {
    std::fs::read_dir(dir_path)
        .expect("unable to read_dir")
        .map(|entry| entry.expect("unable to read_dir").path())
}

fn attachment_at_path(file_path: std::path::PathBuf) -> Attachment {
    Attachment {
        title: vec![TextVariant {
            attributes: vec![],
            value: file_path
                .file_name()
                .unwrap()
                .to_string_lossy()
                .into_owned(),
        }],
        file: vec![FileVariant {
            attributes: vec![],
            name: Some(FileName(
                file_path
                    .file_name()
                    .unwrap()
                    .to_string_lossy()
                    .into_owned(),
            )),
            r#type: mime_guess::from_path(&file_path)
                .first_raw()
                .map(|t| MediaType(t.to_owned())),
            content: FileContent(std::fs::read(&file_path.to_string_lossy().as_ref()).unwrap()),
        }],
    }
}

/// Mapping (extension, MIME type)
const STATEMENT_FORMATS: [(&'static str, &'static str); 3] = [
    ("pdf", "application/pdf"),
    ("html", "text/html"),
    ("md", "application/markdown"),
];

/// Find the statements directory, as in the italy_yaml task format
/// Searches the paths $task_dir/statement and $task_dir/testo
fn statements_dir(task_dir: &Path) -> Option<PathBuf> {
    for dir in vec!["statement", "testo"] {
        let dir = task_dir.join(dir);
        if dir.exists() && dir.is_dir() {
            return Some(dir);
        }
    }
    None
}

/// Tries to match the filename, returning the mimetype of the
/// matched item, if any
fn match_statement(path: &Path) -> Option<(String, FileName, MediaType)> {
    let ext = path.extension().unwrap().to_str().unwrap();
    let filename = path.file_name().unwrap().to_str().unwrap();
    let language = path.file_stem().unwrap().to_str().unwrap();
    for &(extension, mime_type) in &STATEMENT_FORMATS {
        if ext == extension {
            return Some((
                language.to_owned(),
                FileName(filename.to_owned()),
                MediaType(mime_type.to_owned()),
            ));
        }
    }
    None
}

/// find all the statements in the directory
fn statements_of(task_dir: &Path) -> Vec<FileVariant> {
    let mut result = Vec::new();
    let dir = statements_dir(task_dir);
    if let Some(dir) = dir {
        for file in dir.read_dir().unwrap() {
            let file = file.unwrap().path();
            if let Some((language, filename, mime_type)) = match_statement(&file) {
                result.push(FileVariant {
                    attributes: vec![VariantAttribute {
                        key: "language_name".to_owned(),
                        value: language,
                    }],
                    name: Some(filename),
                    r#type: Some(mime_type),
                    content: FileContent(
                        std::fs::read(file).expect("Unable to read statement file"),
                    ),
                });
            }
        }
    }
    result
}

pub fn gen_material(task: &ioi::Task) -> Material {
    Material {
        title: vec![
            TextVariant {
                attributes: vec![],
                value: task.title.clone().into(),
            },
            TextVariant {
                attributes: vec![VariantAttribute {
                    key: "style".to_owned(),
                    value: "short".to_owned(),
                }],
                value: task.name.clone().into(),
            },
        ],
        statement: statements_of(&task.path),
        attachments: files_in_dir(&task.path.join("att"))
            .map(attachment_at_path)
            .collect(),
        submission_form: submission_form(),
        awards: { subtasks_of(task).into_iter().map(award_of).collect() },
        feedback: vec![Section::Table(TableSection {
            caption: caption(),
            cols: cols(),
            row_groups: subtasks_of(task)
                .into_iter()
                .map(|subtask| row_group_of(task, subtask))
                .collect(),
        })],
    }
}
<|endoftext|>


<commit_before>// use std::io::prelude::*;
use std::net::TcpStream;
use std::ffi::CString;
use std::thread;
use std::str;

extern crate mbedtls;

use mbedtls::mbed;
use mbedtls::mbed::ssl::error::SSLError;

const TO_WRITE : &'static [u8] = b"GET / HTTP/1.1\r\n\r\n";

fn main() {
    let mut stream = TcpStream::connect("216.58.210.78:443").unwrap();

    let mut entropy = mbedtls::mbed::entropy::EntropyContext::new();
    let mut entropy_func = |d : &mut[u8] | entropy.entropy_func(d);

    let mut ctr_drbg = mbed::ctr_drbg::CtrDrbgContext::new();
    ctr_drbg.seed(&mut entropy_func, None).unwrap();

    let mut random_func = |f:  &mut[u8] | ctr_drbg.random(f);

    let mut ssl_config = mbed::ssl::SSLConfig::new();
    let mut ssl_context = mbed::ssl::SSLContext::new();

    ssl_config.set_rng(&mut random_func);

    ssl_config.set_defaults(
        mbed::ssl::EndpointType::Client,
        mbed::ssl::TransportType::Stream,
        mbed::ssl::SSLPreset::Default,
    ).unwrap();

    ssl_config.set_authmode(mbed::ssl::AuthMode::VerifyNone);

    ssl_context.setup(&ssl_config).unwrap();

    ssl_context.set_hostname(&CString::new("mbed TLS Server 1").unwrap()).unwrap();

    ssl_context.set_bio_async(&mut stream);

    attempt_io(|| ssl_context.handshake());

    let size_written = attempt_io(|| ssl_context.write(TO_WRITE));
    assert!(size_written == TO_WRITE.len());

    let mut buffer = [0; 4096];
    let size_read = attempt_io(|| ssl_context.read(&mut buffer));

    println!(
        "Read: {} bytes: {}",
        size_read, str::from_utf8(&buffer[..size_read]).unwrap()
    );

    attempt_io(|| ssl_context.close_notify());

    // let _ = stream.write("GET / HTTP/1.1\r\n\r\n".as_bytes());
    // let _ = stream.read(&mut [0; 128]);
}

fn attempt_io<I, F: FnMut() -> Result<I, SSLError>>(mut f: F) -> I {
    loop {
        match f() {
            Ok(i) => return i,
            Err(SSLError::WantRead) | Err(SSLError::WantWrite) => {
                thread::sleep_ms(100);
                continue
            },
            Err(e) => panic!("Got error: {}", e),
        }
    }
}
<commit_msg>Shutdown stream nicely<commit_after>// use std::io::prelude::*;
use std::net::{Shutdown, TcpStream};
use std::ffi::CString;
use std::thread;
use std::str;

extern crate mbedtls;

use mbedtls::mbed;
use mbedtls::mbed::ssl::error::SSLError;

const TO_WRITE : &'static [u8] = b"GET / HTTP/1.1\r\n\r\n";

fn main() {
    let mut stream = TcpStream::connect("216.58.210.78:443").unwrap();

    {
        let mut entropy = mbedtls::mbed::entropy::EntropyContext::new();
        let mut entropy_func = |d : &mut[u8] | entropy.entropy_func(d);

        let mut ctr_drbg = mbed::ctr_drbg::CtrDrbgContext::new();
        ctr_drbg.seed(&mut entropy_func, None).unwrap();

        let mut random_func = |f:  &mut[u8] | ctr_drbg.random(f);

        let mut ssl_config = mbed::ssl::SSLConfig::new();
        let mut ssl_context = mbed::ssl::SSLContext::new();

        ssl_config.set_rng(&mut random_func);

        ssl_config.set_defaults(
            mbed::ssl::EndpointType::Client,
            mbed::ssl::TransportType::Stream,
            mbed::ssl::SSLPreset::Default,
        ).unwrap();

        ssl_config.set_authmode(mbed::ssl::AuthMode::VerifyNone);

        ssl_context.setup(&ssl_config).unwrap();

        ssl_context.set_hostname(&CString::new("mbed TLS Server 1").unwrap()).unwrap();

        ssl_context.set_bio_async(&mut stream);

        attempt_io(|| ssl_context.handshake());

        let size_written = attempt_io(|| ssl_context.write(TO_WRITE));
        assert!(size_written == TO_WRITE.len());

        let mut buffer = [0; 4096];
        let size_read = attempt_io(|| ssl_context.read(&mut buffer));

        println!(
            "Read: {} bytes: {}",
            size_read, str::from_utf8(&buffer[..size_read]).unwrap()
        );

        attempt_io(|| ssl_context.close_notify());
    }

    stream.shutdown(Shutdown::Both).unwrap();
}

fn attempt_io<I, F: FnMut() -> Result<I, SSLError>>(mut f: F) -> I {
    loop {
        match f() {
            Ok(i) => return i,
            Err(SSLError::WantRead) | Err(SSLError::WantWrite) => {
                thread::sleep_ms(100);
                continue
            },
            Err(e) => panic!("Got error: {}", e),
        }
    }
}
<|endoftext|>


<commit_before>extern crate kinder;

use kinder::lift::{Foldable, Monoid, SemiGroup};

fn sum_foldable<B : Monoid<A=B>, T: Foldable<A=B>>(xs: &T) -> B
{
    xs.foldr(B::id(), |x, y| x.add(y))
}

fn main() {
    let ints: Vec<i32> = vec!(1,2,3);
    let floats = vec!(1.0, 2.0, 3.0);
    let strings = vec!(String::from("Hello"), String::from(", "), String::from("World!"));

    println!("{}", sum_foldable(&ints)); //should print 6
    println!("{}", sum_foldable(&floats)); //should print 6.0
    println!("{}", sum_foldable(&strings)); //should print Hello, World!
}
<commit_msg>forgot to remove semigroup import<commit_after>extern crate kinder;

use kinder::lift::{Foldable, Monoid};

fn sum_foldable<B : Monoid<A=B>, T: Foldable<A=B>>(xs: &T) -> B
{
    xs.foldr(B::id(), |x, y| x.add(y))
}

fn main() {
    let ints: Vec<i32> = vec!(1,2,3);
    let floats = vec!(1.0, 2.0, 3.0);
    let strings = vec!(String::from("Hello"), String::from(", "), String::from("World!"));

    println!("{}", sum_foldable(&ints)); //should print 6
    println!("{}", sum_foldable(&floats)); //should print 6.0
    println!("{}", sum_foldable(&strings)); //should print Hello, World!
}
<|endoftext|>


<commit_before>//! Set up resource content for game.

use glium;
use calx_color::color::*;
use calx_resource::ResourceStore;
use world::BrushBuilder;
use world::terrain::Id;
use display::Backend;

pub fn init_brushes(display: &glium::Display, backend: &mut Backend) {
    BrushBuilder::new()
        .file("content/assets/floors.png")
        ////
        .tile(0, 0)
        .brush("blank_floor")
        ////
        .color(DARKGREEN)
        .tile(32, 0)
        .brush("grass")
        ////
        .color(DARKGREEN)
        .tile(64, 0)
        .brush("grass2")
        ////
        .color(SLATEGRAY)
        .tile(32, 0)
        .brush("ground")
        ////
        .color(ROYALBLUE)
        .tile(96, 0)
        .brush("water")
        ////
        .file("content/assets/portals.png")
        ////
        .color(LIGHTCYAN)
        .tile(0, 0)
        .frame()
        .tile(32, 0)
        .frame()
        .tile(64, 0)
        .frame()
        .tile(96, 0)
        .frame()
        .tile(128, 0)
        .frame()
        .tile(160, 0)
        .frame()
        .tile(192, 0)
        .frame()
        .tile(224, 0)
        .frame()
        .tile(256, 0)
        .frame()
        .tile(288, 0)
        .frame()
        .tile(320, 0)
        .frame()
        .tile(352, 0)
        .frame()
        .tile(384, 0)
        .brush("gate")
        ////
        .file("content/assets/props.png")
        ////
        .color(RED)
        .splat(0, 0, 32, 32)
        .brush("cursor")
        .color(RED)
        .splat(32, 0, 32, 32)
        .brush("cursor_top")
        .color(ORANGE)
        .splat(0, 0, 32, 32)
        .brush("portal")
        ////
        .color(SADDLEBROWN)
        .tile(160, 64)
        .color(GREEN)
        .tile(192, 64)
        .brush("tree")
        ////
        .file("content/assets/walls.png")
        ////
        .color(LIGHTSLATEGRAY)
        .wall(0, 0, 32, 0)
        .brush("wall")
        ////
        .file("content/assets/blobs.png")
        ////
        .color(DARKGOLDENROD)
        .blob(0, 0, 0, 32, 0, 64)
        .brush("rock")
        .finish(|img| backend.make_texture(&display, img));
}

pub fn init_terrain() {
    use world::terrain::{Form, Kind, Tile};

    // Void, terrain 0 is special.
    Tile::insert_resource(Id::Empty as u8, Tile::new("blank_floor", Kind::Block, Form::Void));
    // "Level exit", a visible portal tile.
    Tile::insert_resource(Id::Gate as u8, Tile::new("gate", Kind::Ground, Form::Gate));
    Tile::insert_resource(Id::Ground as u8, Tile::new("ground", Kind::Ground, Form::Floor));
    Tile::insert_resource(Id::Grass as u8, Tile::new("grass", Kind::Ground, Form::Floor));
    Tile::insert_resource(Id::Water as u8, Tile::new("water", Kind::Water, Form::Floor));
    Tile::insert_resource(Id::Tree as u8, Tile::new("tree", Kind::Block, Form::Prop));
    Tile::insert_resource(Id::Wall as u8, Tile::new("wall", Kind::Block, Form::Wall));
    Tile::insert_resource(Id::Rock as u8, Tile::new("rock", Kind::Block, Form::Blob));
}
<commit_msg>Proper tile-like offsetting for the portal debug brush<commit_after>//! Set up resource content for game.

use glium;
use calx_color::color::*;
use calx_resource::ResourceStore;
use world::BrushBuilder;
use world::terrain::Id;
use display::Backend;

pub fn init_brushes(display: &glium::Display, backend: &mut Backend) {
    BrushBuilder::new()
        .file("content/assets/floors.png")
        ////
        .tile(0, 0)
        .brush("blank_floor")
        ////
        .color(DARKGREEN)
        .tile(32, 0)
        .brush("grass")
        ////
        .color(DARKGREEN)
        .tile(64, 0)
        .brush("grass2")
        ////
        .color(SLATEGRAY)
        .tile(32, 0)
        .brush("ground")
        ////
        .color(ROYALBLUE)
        .tile(96, 0)
        .brush("water")
        ////
        .file("content/assets/portals.png")
        ////
        .color(LIGHTCYAN)
        .tile(0, 0)
        .frame()
        .tile(32, 0)
        .frame()
        .tile(64, 0)
        .frame()
        .tile(96, 0)
        .frame()
        .tile(128, 0)
        .frame()
        .tile(160, 0)
        .frame()
        .tile(192, 0)
        .frame()
        .tile(224, 0)
        .frame()
        .tile(256, 0)
        .frame()
        .tile(288, 0)
        .frame()
        .tile(320, 0)
        .frame()
        .tile(352, 0)
        .frame()
        .tile(384, 0)
        .brush("gate")
        ////
        .file("content/assets/props.png")
        ////
        .color(RED)
        .splat(0, 0, 32, 32)
        .brush("cursor")
        .color(RED)
        .splat(32, 0, 32, 32)
        .brush("cursor_top")
        .color(ORANGE)
        .tile(0, 0)
        .brush("portal") // TODO: This thing is a temporary display helper for mapedit, maybe remove when can?
        ////
        .color(SADDLEBROWN)
        .tile(160, 64)
        .color(GREEN)
        .tile(192, 64)
        .brush("tree")
        ////
        .file("content/assets/walls.png")
        ////
        .color(LIGHTSLATEGRAY)
        .wall(0, 0, 32, 0)
        .brush("wall")
        ////
        .file("content/assets/blobs.png")
        ////
        .color(DARKGOLDENROD)
        .blob(0, 0, 0, 32, 0, 64)
        .brush("rock")
        .finish(|img| backend.make_texture(&display, img));
}

pub fn init_terrain() {
    use world::terrain::{Form, Kind, Tile};

    // Void, terrain 0 is special.
    Tile::insert_resource(Id::Empty as u8, Tile::new("blank_floor", Kind::Block, Form::Void));
    // "Level exit", a visible portal tile.
    Tile::insert_resource(Id::Gate as u8, Tile::new("gate", Kind::Ground, Form::Gate));
    Tile::insert_resource(Id::Ground as u8, Tile::new("ground", Kind::Ground, Form::Floor));
    Tile::insert_resource(Id::Grass as u8, Tile::new("grass", Kind::Ground, Form::Floor));
    Tile::insert_resource(Id::Water as u8, Tile::new("water", Kind::Water, Form::Floor));
    Tile::insert_resource(Id::Tree as u8, Tile::new("tree", Kind::Block, Form::Prop));
    Tile::insert_resource(Id::Wall as u8, Tile::new("wall", Kind::Block, Form::Wall));
    Tile::insert_resource(Id::Rock as u8, Tile::new("rock", Kind::Block, Form::Blob));
}
<|endoftext|>


<commit_before>use std::ffi::{OsString, OsStr};
use std::path::Path;

use ops::{self, ExecEngine, ProcessEngine, Compilation};
use util::{self, CargoResult, CargoTestError, ProcessError};

pub struct TestOptions<'a> {
    pub compile_opts: ops::CompileOptions<'a>,
    pub no_run: bool,
    pub no_fail_fast: bool,
    pub only_doc: bool,
}

pub fn run_tests(manifest_path: &Path,
                 options: &TestOptions,
                 test_args: &[String]) -> CargoResult<Option<CargoTestError>> {
    let compilation = try!(compile_tests(manifest_path, options));

    if options.no_run {
        return Ok(None)
    }
    let mut errors = if options.only_doc {
        Vec::new()
    } else {
        try!(run_unit_tests(options, test_args, &compilation))
    };

    // If we have an error and want to fail fast, return
    if !errors.is_empty() && !options.no_fail_fast {
        return Ok(Some(CargoTestError::new(errors)))
    }

    // If a specific test was requested or we're not running any tests at all,
    // don't run any doc tests.
    if let ops::CompileFilter::Only { .. } = options.compile_opts.filter {
        match errors.len() {
            0 => return Ok(None),
            _ => return Ok(Some(CargoTestError::new(errors)))
        }
    }

    errors.extend(try!(run_doc_tests(options, test_args, &compilation)));
    if errors.is_empty() {
        Ok(None)
    } else {
        Ok(Some(CargoTestError::new(errors)))
    }
}

pub fn run_benches(manifest_path: &Path,
                   options: &TestOptions,
                   args: &[String]) -> CargoResult<Option<CargoTestError>> {
    let mut args = args.to_vec();
    args.push("--bench".to_string());
    let compilation = try!(compile_tests(manifest_path, options));

    if options.no_run {
        return Ok(None)
    }
    let errors = try!(run_unit_tests(options, &args, &compilation));
    match errors.len() {
        0 => Ok(None),
        _ => Ok(Some(CargoTestError::new(errors))),
    }
}

fn compile_tests<'a>(manifest_path: &Path,
                     options: &TestOptions<'a>)
                     -> CargoResult<Compilation<'a>> {
    let mut compilation = try!(ops::compile(manifest_path,
                                            &options.compile_opts));
    compilation.tests.sort_by(|a, b| {
        (a.0.package_id(), &a.1).cmp(&(b.0.package_id(), &b.1))
    });
    Ok(compilation)
}

/// Run the unit and integration tests of a project.
fn run_unit_tests(options: &TestOptions,
                  test_args: &[String],
                  compilation: &Compilation)
                  -> CargoResult<Vec<ProcessError>> {
    let config = options.compile_opts.config;
    let cwd = options.compile_opts.config.cwd();

    let mut errors = Vec::new();

    for &(ref pkg, _, ref exe) in &compilation.tests {
        let to_display = match util::without_prefix(exe, &cwd) {
            Some(path) => path,
            None => &**exe,
        };
        let mut cmd = try!(compilation.target_process(exe, pkg));
        cmd.args(test_args);
        try!(config.shell().concise(|shell| {
            shell.status("Running", to_display.display().to_string())
        }));
        try!(config.shell().verbose(|shell| {
            shell.status("Running", cmd.to_string())
        }));

        if let Err(e) = ExecEngine::exec(&ProcessEngine, cmd) {
            errors.push(e);
            if !options.no_fail_fast {
                break
            }
        }
    }
    Ok(errors)
}

fn run_doc_tests(options: &TestOptions,
                 test_args: &[String],
                 compilation: &Compilation)
                 -> CargoResult<Vec<ProcessError>> {
    let mut errors = Vec::new();
    let config = options.compile_opts.config;

    // We don't build/rust doctests if target != host
    if let Some(target) = options.compile_opts.target {
        if config.rustc_info().host != target {
            return Ok(errors);
        }
    }

    let libs = compilation.to_doc_test.iter().map(|package| {
        (package, package.targets().iter().filter(|t| t.doctested())
                         .map(|t| (t.src_path(), t.name(), t.crate_name())))
    });

    for (package, tests) in libs {
        for (lib, name, crate_name) in tests {
            try!(config.shell().status("Doc-tests", name));
            let mut p = try!(compilation.rustdoc_process(package));
            p.arg("--test").arg(lib)
             .arg("--crate-name").arg(&crate_name);

            for &rust_dep in &[&compilation.deps_output, &compilation.root_output] {
                let mut arg = OsString::from("dependency=");
                arg.push(rust_dep);
                p.arg("-L").arg(arg);
            }
            for native_dep in compilation.native_dirs.values() {
                p.arg("-L").arg(native_dep);
            }

            if test_args.len() > 0 {
                p.arg("--test-args").arg(&test_args.join(" "));
            }

            for cfg in compilation.cfgs.iter() {
                p.arg("--cfg").arg(cfg);
            }

            for (_, libs) in compilation.libraries.iter() {
                for &(ref target, ref lib) in libs.iter() {
                    // Note that we can *only* doctest rlib outputs here.  A
                    // staticlib output cannot be linked by the compiler (it just
                    // doesn't do that). A dylib output, however, can be linked by
                    // the compiler, but will always fail. Currently all dylibs are
                    // built as "static dylibs" where the standard library is
                    // statically linked into the dylib. The doc tests fail,
                    // however, for now as they try to link the standard library
                    // dynamically as well, causing problems. As a result we only
                    // pass `--extern` for rlib deps and skip out on all other
                    // artifacts.
                    if lib.extension() != Some(OsStr::new("rlib")) &&
                       !target.for_host() {
                        continue
                    }
                    let mut arg = OsString::from(target.crate_name());
                    arg.push("=");
                    arg.push(lib);
                    p.arg("--extern").arg(&arg);
                }
            }

            try!(config.shell().verbose(|shell| {
                shell.status("Running", p.to_string())
            }));
            if let Err(e) = ExecEngine::exec(&ProcessEngine, p) {
                errors.push(e);
                if !options.no_fail_fast {
                    return Ok(errors);
                }
            }
        }
    }
    Ok(errors)
}
<commit_msg>Fix `cargo test --doc` not testing examples<commit_after>use std::ffi::{OsString, OsStr};
use std::path::Path;

use ops::{self, ExecEngine, ProcessEngine, Compilation};
use util::{self, CargoResult, CargoTestError, ProcessError};

pub struct TestOptions<'a> {
    pub compile_opts: ops::CompileOptions<'a>,
    pub no_run: bool,
    pub no_fail_fast: bool,
    pub only_doc: bool,
}

pub fn run_tests(manifest_path: &Path,
                 options: &TestOptions,
                 test_args: &[String]) -> CargoResult<Option<CargoTestError>> {
    let compilation = try!(compile_tests(manifest_path, options));

    if options.no_run {
        return Ok(None)
    }
    let mut errors = if options.only_doc {
        try!(run_doc_tests(options, test_args, &compilation))
    } else {
        try!(run_unit_tests(options, test_args, &compilation))
    };

    // If we have an error and want to fail fast, return
    if !errors.is_empty() && !options.no_fail_fast {
        return Ok(Some(CargoTestError::new(errors)))
    }

    // If a specific test was requested or we're not running any tests at all,
    // don't run any doc tests.
    if let ops::CompileFilter::Only { .. } = options.compile_opts.filter {
        match errors.len() {
            0 => return Ok(None),
            _ => return Ok(Some(CargoTestError::new(errors)))
        }
    }

    errors.extend(try!(run_doc_tests(options, test_args, &compilation)));
    if errors.is_empty() {
        Ok(None)
    } else {
        Ok(Some(CargoTestError::new(errors)))
    }
}

pub fn run_benches(manifest_path: &Path,
                   options: &TestOptions,
                   args: &[String]) -> CargoResult<Option<CargoTestError>> {
    let mut args = args.to_vec();
    args.push("--bench".to_string());
    let compilation = try!(compile_tests(manifest_path, options));

    if options.no_run {
        return Ok(None)
    }
    let errors = try!(run_unit_tests(options, &args, &compilation));
    match errors.len() {
        0 => Ok(None),
        _ => Ok(Some(CargoTestError::new(errors))),
    }
}

fn compile_tests<'a>(manifest_path: &Path,
                     options: &TestOptions<'a>)
                     -> CargoResult<Compilation<'a>> {
    let mut compilation = try!(ops::compile(manifest_path,
                                            &options.compile_opts));
    compilation.tests.sort_by(|a, b| {
        (a.0.package_id(), &a.1).cmp(&(b.0.package_id(), &b.1))
    });
    Ok(compilation)
}

/// Run the unit and integration tests of a project.
fn run_unit_tests(options: &TestOptions,
                  test_args: &[String],
                  compilation: &Compilation)
                  -> CargoResult<Vec<ProcessError>> {
    let config = options.compile_opts.config;
    let cwd = options.compile_opts.config.cwd();

    let mut errors = Vec::new();

    for &(ref pkg, _, ref exe) in &compilation.tests {
        let to_display = match util::without_prefix(exe, &cwd) {
            Some(path) => path,
            None => &**exe,
        };
        let mut cmd = try!(compilation.target_process(exe, pkg));
        cmd.args(test_args);
        try!(config.shell().concise(|shell| {
            shell.status("Running", to_display.display().to_string())
        }));
        try!(config.shell().verbose(|shell| {
            shell.status("Running", cmd.to_string())
        }));

        if let Err(e) = ExecEngine::exec(&ProcessEngine, cmd) {
            errors.push(e);
            if !options.no_fail_fast {
                break
            }
        }
    }
    Ok(errors)
}

fn run_doc_tests(options: &TestOptions,
                 test_args: &[String],
                 compilation: &Compilation)
                 -> CargoResult<Vec<ProcessError>> {
    let mut errors = Vec::new();
    let config = options.compile_opts.config;

    // We don't build/rust doctests if target != host
    if let Some(target) = options.compile_opts.target {
        if config.rustc_info().host != target {
            return Ok(errors);
        }
    }

    let libs = compilation.to_doc_test.iter().map(|package| {
        (package, package.targets().iter().filter(|t| t.doctested())
                         .map(|t| (t.src_path(), t.name(), t.crate_name())))
    });

    for (package, tests) in libs {
        for (lib, name, crate_name) in tests {
            try!(config.shell().status("Doc-tests", name));
            let mut p = try!(compilation.rustdoc_process(package));
            p.arg("--test").arg(lib)
             .arg("--crate-name").arg(&crate_name);

            for &rust_dep in &[&compilation.deps_output, &compilation.root_output] {
                let mut arg = OsString::from("dependency=");
                arg.push(rust_dep);
                p.arg("-L").arg(arg);
            }
            for native_dep in compilation.native_dirs.values() {
                p.arg("-L").arg(native_dep);
            }

            if test_args.len() > 0 {
                p.arg("--test-args").arg(&test_args.join(" "));
            }

            for cfg in compilation.cfgs.iter() {
                p.arg("--cfg").arg(cfg);
            }

            for (_, libs) in compilation.libraries.iter() {
                for &(ref target, ref lib) in libs.iter() {
                    // Note that we can *only* doctest rlib outputs here.  A
                    // staticlib output cannot be linked by the compiler (it just
                    // doesn't do that). A dylib output, however, can be linked by
                    // the compiler, but will always fail. Currently all dylibs are
                    // built as "static dylibs" where the standard library is
                    // statically linked into the dylib. The doc tests fail,
                    // however, for now as they try to link the standard library
                    // dynamically as well, causing problems. As a result we only
                    // pass `--extern` for rlib deps and skip out on all other
                    // artifacts.
                    if lib.extension() != Some(OsStr::new("rlib")) &&
                       !target.for_host() {
                        continue
                    }
                    let mut arg = OsString::from(target.crate_name());
                    arg.push("=");
                    arg.push(lib);
                    p.arg("--extern").arg(&arg);
                }
            }

            try!(config.shell().verbose(|shell| {
                shell.status("Running", p.to_string())
            }));
            if let Err(e) = ExecEngine::exec(&ProcessEngine, p) {
                errors.push(e);
                if !options.no_fail_fast {
                    return Ok(errors);
                }
            }
        }
    }
    Ok(errors)
}
<|endoftext|>


<commit_before>// Kevin Cantu
// hash function testing

#[link(name = "bench", author = "kcantu", vers = "0.0")];

use std;
use str2;

fn word_of_god () -> [str]
{
   std::io::println ("Loading the lolcat bible...");
   let path = "../lolcat/LOLCatBible_2012-01-04.xml";
   let bible = std::io::read_whole_file (path);
   let bible_ = str::unsafe_from_bytes (result::get (bible));

   ret str2::words(bible_) +
       vec::map(str2::lines(bible_), {|ln| ln+ln+ln+ln});
}

fn hash_bench <TT> ( label: str, hashfn: fn(&&str)->TT, data: [str] )
{
   let t0 = std::time::precise_time_s();
   let _v = vec::map(data, hashfn);
   let t1 = std::time::precise_time_s();

   std::io::println(label + #fmt("%06.3f sec", t1 - t0));
}

<commit_msg>s/fn()/native fn()/<commit_after>// Kevin Cantu
// hash function testing

#[link(name = "bench", author = "kcantu", vers = "0.0")];

use std;
use str2;

fn word_of_god () -> [str]
{
   std::io::println ("Loading the lolcat bible...");
   let path = "../lolcat/LOLCatBible_2012-01-04.xml";
   let bible = std::io::read_whole_file (path);
   let bible_ = str::unsafe_from_bytes (result::get (bible));

   ret str2::words(bible_) +
       vec::map(str2::lines(bible_), {|ln| ln+ln+ln+ln});
}

fn hash_bench <TT> ( label: str, hashfn: native fn(&&str)->TT, data: [str] )
{
   let t0 = std::time::precise_time_s();
   let _v = vec::map(data, hashfn);
   let t1 = std::time::precise_time_s();

   std::io::println(label + #fmt("%06.3f sec", t1 - t0));
}

<|endoftext|>