thinlinelib/
lib.rs

1#![cfg_attr(feature = "clippy", feature(plugin))]
2#![cfg_attr(feature = "clippy", plugin(clippy))]
3
4extern crate clang;
5#[macro_use]
6extern crate failure;
7extern crate glob;
8#[macro_use]
9extern crate lazy_static;
10#[macro_use]
11extern crate log;
12extern crate python_parser;
13extern crate regex;
14extern crate run_script;
15#[macro_use]
16extern crate serde_derive;
17extern crate serde;
18extern crate slog_envlogger;
19extern crate snapshot;
20extern crate walkdir;
21extern crate yaml_rust;
22
23pub mod analysis;
24pub mod config_parser;
25pub mod entity;
26pub mod language_type;
27pub mod synthesis;
28
29use analysis::{Analysis, ProjectFile};
30use config_parser::ProjectParameters;
31use failure::{err_msg, Fallible};
32use language_type::LanguageType;
33use std::path::PathBuf;
34use synthesis::*;
35
36#[derive(Default, Debug)]
37/// Global structure representing the Thinline lib.
38pub struct Thinline<T>
39where
40    T: LanguageType,
41{
42    /// The parsed project parameters.
43    pub project_parameters: ProjectParameters,
44
45    /// The structure holding the analysis_c data.
46    pub analysis: Analysis<T>,
47
48    /// The structure holding the synthesized testdata.
49    pub synthesis: Synthesis,
50}
51
52impl<T> Thinline<T>
53where
54    T: LanguageType,
55{
56    /// Creates an instance of the lib containing Thinlines functionality.
57    pub fn new() -> Self {
58        Self::default()
59    }
60
61    /// Parses configuration from the given config yaml.
62    pub fn parse_project_config<P: Into<PathBuf>>(
63        &mut self,
64        project_dir: P,
65        config_name: &str,
66    ) -> Fallible<()> {
67        let project_config = project_dir.into().join(config_name);
68
69        if !project_config.exists() || !project_config.is_file() {
70            return Err(format_err!(
71                "The given project config file '{}' does not exist or is a directory.",
72                project_config
73                    .to_str()
74                    .ok_or_else(|| err_msg("Unable to stringify project config file."))?
75            ));
76        }
77
78        self.project_parameters = ProjectParameters::parse(
79            project_config
80                .to_str()
81                .ok_or_else(|| err_msg("Unable to stringify project config file."))?,
82        )?;
83
84        debug!("{:#?}", self.project_parameters);
85
86        Ok(())
87    }
88
89    /// Analyzes the project which should be tested.
90    pub fn analyze_project<P: Into<PathBuf>>(&mut self, project_path: P) -> Fallible<()> {
91        let project_path_p = project_path.into();
92
93        if let Some(project_path_s) = project_path_p.to_str() {
94            info!("Starting project analysis at '{}'", project_path_s);
95        }
96
97        self.analysis = Analysis::new();
98
99        if project_path_p.is_dir() {
100            // Project path is a directory, thus it is neccessay to traverse to the project
101            // and collect all the sources.
102            self.analysis
103                .collect_sources(&project_path_p, &self.project_parameters.source_dirs)?;
104        }
105
106        if project_path_p.is_file() {
107            if let Some(ext) = project_path_p.extension() {
108                // Project path is a file and has the right extension.
109                if T::file_types().contains(
110                    &ext.to_str()
111                        .ok_or_else(|| err_msg("Unable to stringify file extension."))?,
112                ) {
113                    // Push it to the project file vectory for analyzing purposes.
114                    self.analysis
115                        .project_files_mut()
116                        .push(ProjectFile::new(&project_path_p));
117                }
118            }
119        }
120
121        self.analysis.extract_entities()?;
122
123        Ok(())
124    }
125}