Permalink
Browse files

[Test] Full prototype of the framework for testing the runtime output…

… of Bonsai programs.
  • Loading branch information...
ptal committed Sep 8, 2017
1 parent 762b21e commit 40183ee5c970420c197aa08b642e9ba5b4985426
@@ -16,11 +16,15 @@
package test;
import bonsai.runtime.core.*;
import bonsai.runtime.choco.*;
import bonsai.runtime.sugarcubes.*;
import inria.meije.rc.sugarcubes.*;
import inria.meije.rc.sugarcubes.implementation.*;
public class SequentialOutput
{
proc test() {
System.out.print("1");
System.out.print("2");
System.out.print("3");
}
}
View
@@ -28,19 +28,25 @@ pub struct ModuleFile
impl ModuleFile
{
pub fn new(config: &Config, file_path: PathBuf, lib: bool) -> Option<Self> {
if let Some(mod_name) = Self::extract_mod_name(file_path.clone()) {
let mod_file = match lib {
false => Self::core_file(config, file_path, mod_name),
true => Self::lib_file(file_path, mod_name),
};
return Some(mod_file);
}
None
}
pub fn extract_mod_name(file_path: PathBuf) -> Option<String> {
if let Some(ext) = file_path.clone().extension() {
if ext == "java" {
let p = file_path.clone();
let bonsai_file = Path::new(p.file_stem().unwrap());
if let Some(bonsai_ext) = bonsai_file.extension() {
if bonsai_ext == "bonsai" {
let mod_name = String::from(bonsai_file.file_stem().unwrap().to_str().unwrap());
let mod_file =
match lib {
false => Self::core_file(config, file_path, mod_name),
true => Self::lib_file(file_path, mod_name),
};
return Some(mod_file);
return Some(mod_name);
}
}
}
View
@@ -31,7 +31,8 @@ pub struct CompileTest<'a>
expect: ExpectedResult,
expected_diagnostics: Vec<CompilerTest>,
obtained_diagnostics: Vec<CompilerTest>,
test_path: PathBuf
test_path: PathBuf,
intermediate_step: bool, // do not print success message because the compilation is just a step of the test.
}
impl<'a> CompileTest<'a>
@@ -40,15 +41,12 @@ impl<'a> CompileTest<'a>
result: Partial<Context>, expect: ExpectedResult,
expected_diagnostics: Vec<CompilerTest>,
obtained_diagnostics: Vec<CompilerTest>,
test_path: PathBuf) -> Self
test_path: PathBuf,
intermediate_step: bool) -> Self
{
CompileTest {
display: display,
result: result,
expect: expect,
expected_diagnostics: expected_diagnostics,
obtained_diagnostics: obtained_diagnostics,
test_path: test_path
display, result, expect, expected_diagnostics,
obtained_diagnostics, test_path, intermediate_step
}
}
@@ -94,7 +92,9 @@ impl<'a> CompileTest<'a>
None
}
else {
self.display.success(file_name);
if !self.intermediate_step {
self.display.success(file_name);
}
self.context_to_option()
}
}
View
@@ -18,7 +18,7 @@ extern crate term;
use libbonsai::ast::*;
use std::path::{PathBuf};
use std::io;
use std::process::{Output};
use term::*;
@@ -41,6 +41,12 @@ impl Display
}
}
fn write_line(&mut self, color: color::Color, header: &str, msg: String) {
self.write_header(color, header);
self.write_msg(&msg);
self.write_msg("\n");
}
pub fn title(&mut self, msg: &str) {
self.write_header(color::CYAN, msg);
self.write_msg("\n\n");
@@ -141,23 +147,17 @@ impl Display
self.write_line(color::YELLOW, " [ warning ] ", msg);
}
pub fn fs_error(&mut self, msg: &str, path: PathBuf, io_err: &io::Error) {
pub fn io_error(&mut self, msg: &str, path: PathBuf, err: String) {
self.system_failure(format!("{}", msg));
self.path(path);
self.error(format!("{}", io_err));
self.error(err);
}
pub fn system_failure(&mut self, msg: String) {
self.num_system_failure += 1;
self.write_line(color::RED, "[ system error ] ", msg);
}
fn write_line(&mut self, color: color::Color, header: &str, msg: String) {
self.write_header(color, header);
self.write_msg(&msg);
self.write_msg("\n");
}
fn write_header(&mut self, color: color::Color, header: &str) {
self.terminal.fg(color).unwrap();
self.write_msg(header);
@@ -167,4 +167,35 @@ impl Display
fn write_msg(&mut self, msg: &str) {
(write!(self.terminal, "{}", msg)).unwrap();
}
fn write_maven_output(&mut self, color: color::Color, header: &str, output: Vec<u8>) {
if output.len() == 0 {
self.write_line(color, header, format!("Maven did not write on this output stream."));
}
else {
self.write_line(color, header, format!("Maven produced the following output:"));
match String::from_utf8(output.clone()) {
Result::Ok(output) => self.write_msg(&output),
Result::Err(_) => self.write_msg(&format!("{:?}", output))
}
}
}
pub fn maven_failure(&mut self, phase: &str, path: PathBuf,
test_name: String, output: Output)
{
self.failure(path, test_name);
self.error(format!("Maven {} should have succeeded but failed.", phase));
self.write_maven_output(color::CYAN, " [ stdout ] ", output.stdout);
self.write_maven_output(color::CYAN, " [ stderr ] ", output.stderr);
}
pub fn execution_failure(&mut self, path: PathBuf, test_name: String,
expected: String, obtained: String)
{
self.failure(path, test_name);
self.error(format!("The output does not match the expected regex."));
self.write_line(color::CYAN, " [ expected ] ", expected);
self.write_line(color::CYAN, " [ obtained ] ", obtained);
}
}
View
@@ -15,6 +15,7 @@
use libbonsai::session::*;
use libbonsai::driver::*;
use libbonsai::context::*;
use libbonsai::driver::module_file::ModuleFile;
use syntex_syntax::codemap::{CodeMap};
use std::rc::Rc;
@@ -81,7 +82,7 @@ impl Engine
}
}
Err(ref io_err) => {
self.display.fs_error("Can't read directory.", directory, io_err);
self.display.io_error("Can't read directory.", directory, format!("{}", io_err));
}
}
}
@@ -101,25 +102,36 @@ impl Engine
.expect("Could not extract `obtained_diagnostics`.").into_inner();
let context = {
let compile_test = CompileTest::new(&mut self.display, context, expect, session.compiler_tests.clone(),
obtained_diagnostics, filepath);
obtained_diagnostics, filepath.clone(), execute);
compile_test.diagnostic()
};
if let Some(context) = context {
if execute {
self.run_file(session, context);
self.run_file(session, context, filepath);
}
}
}
fn run_file(&mut self, mut session: Session, mut context: Context) {
/// Given the analysed module (after front and middle phases), we execute the following phases for each test case:
/// (1) Compile it (back phase)
/// (2) Execute it in a sandbox ("data/test/sandbox")
/// (3) Compare the output result with the expected regex result.
fn run_file(&mut self, mut session: Session, mut context: Context, filepath: PathBuf) {
self.maven.delete_source_files();
for test in session.execution_tests.clone() {
self.maven.delete_source_files();
session.config.configure_execution_test(&test);
let env = run_back(session, context).ensure("[Test] Could not generate the Bonsai code.");
let (s, c) = env.decompose();
session = s;
context = c.unwrap();
// self.maven.delete_source_files();
let mod_name = ModuleFile::extract_mod_name(filepath.clone()).expect("bonsai file name (run_file)");
let compile_result = self.maven.compile_sandbox();
let execute_result = self.maven.execute_sandbox(mod_name);
let execution_test = ExecuteTest::new(&mut self.display, compile_result,
execute_result, test.output_regex, filepath.clone());
execution_test.diagnostic();
self.maven.delete_source_files();
}
}
}
View
@@ -0,0 +1,123 @@
// Copyright 2017 Pierre Talbot (IRCAM)
// 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 libbonsai;
use test::*;
use libbonsai::ast::*;
use std::path::{PathBuf};
use std::process::{Output};
use std::io;
pub struct ExecuteTest<'a>
{
display: &'a mut Display,
compile_result: io::Result<Output>,
execute_result: io::Result<Output>,
expect: Regex,
file_path: PathBuf
}
impl<'a> ExecuteTest<'a>
{
pub fn new(display: &'a mut Display,
compile_result: io::Result<Output>,
execute_result: io::Result<Output>,
expect: Regex,
file_path: PathBuf) -> Self
{
ExecuteTest {
display, compile_result, execute_result, expect, file_path
}
}
pub fn diagnostic(mut self) {
if self.diagnose_compilation() {
self.diagnose_execution();
}
}
fn diagnose_result(&mut self, phase: &str, result: Result<Output, String>) -> Option<Output> {
match result {
Result::Ok(output) => Some(output.clone()),
Result::Err(error) => {
self.display.io_error(&format!("Failure of the {}.", phase),
self.file_path.clone(), error);
None
}
}
}
fn diagnose_maven_result(&mut self, phase: &str, result: Result<Output, String>) -> Option<Vec<u8>> {
let result = self.diagnose_result(phase, result);
if let Some(output) = result {
if output.status.success() {
return Some(output.stdout);
}
else {
let file_name = self.file_name();
self.display.maven_failure(phase, self.file_path.clone(), file_name, output);
}
}
None
}
/// io::Error is not cloneable so we transform it into a String now.
fn clone_result(result: &io::Result<Output>) -> Result<Output, String> {
match result {
&Result::Err(ref err) => Result::Err(format!("{}", err)),
&Result::Ok(ref output) => Result::Ok(output.clone())
}
}
fn diagnose_compilation(&mut self) -> bool {
let compile_result = Self::clone_result(&self.compile_result);
self.diagnose_maven_result("compilation", compile_result).is_some()
}
fn diagnose_execution(&mut self) {
let execute_result = Self::clone_result(&self.execute_result);
let maven_output = self.diagnose_maven_result("execution", execute_result);
if let Some(raw_stdout) = maven_output {
match String::from_utf8(raw_stdout) {
Result::Ok(stdout) => {
self.compare_output(stdout);
}
Result::Err(error) => {
self.display.io_error(
&format!("The output of the bonsai code is not in a valid UTF8 encoding."),
self.file_path.clone(), format!("{}", error));
}
}
}
}
fn compare_output(&mut self, output: String) {
let file_name = self.file_name();
if self.expect.is_match(&output) {
self.display.success(file_name);
}
else {
self.display.execution_failure(
self.file_path.clone(), file_name,
format!("{}", self.expect.as_str()), output);
}
}
fn file_name(&self) -> String {
format!("{}", self.file_path.file_name().unwrap().to_str().unwrap())
}
}
View
@@ -16,6 +16,8 @@
use std::path::{PathBuf};
use std::fs;
use std::process::{Command, Stdio, Output};
use std::io;
pub struct Maven {
sandbox: PathBuf
@@ -37,6 +39,29 @@ impl Maven {
let source_path = self.source_path();
if source_path.exists() {
fs::remove_dir_all(self.source_path()).unwrap();
fs::remove_dir_all(self.sandbox.join("target/")).unwrap();
}
}
// mvn compile
pub fn compile_sandbox(&self) -> io::Result<Output> {
let child = Command::new("mvn")
.arg("compile")
.current_dir(self.sandbox.clone())
.stdout(Stdio::piped())
.spawn()?;
child.wait_with_output()
}
// mvn -B -q exec:java -Dexec.mainClass="test.<class_name>"
pub fn execute_sandbox(&self, main_class: String) -> io::Result<Output> {
let main_class_arg = format!("-Dexec.mainClass=test.{}", main_class);
let child = Command::new("mvn")
.args(&["-B", "-q", "exec:java", &main_class_arg])
.current_dir(self.sandbox.clone())
.stdout(Stdio::piped())
.spawn()?;
child.wait_with_output()
}
}
Oops, something went wrong.

0 comments on commit 40183ee

Please sign in to comment.