Skip to content

Commit 892b97a

Browse files
committed
Merge branch 'master' of github.com:rage/tmc-langs-rust
2 parents cf08c7d + df9d509 commit 892b97a

File tree

5 files changed

+67
-39
lines changed

5 files changed

+67
-39
lines changed

plugins/java/src/maven.rs

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -228,27 +228,28 @@ impl JavaPlugin for MavenPlugin {
228228
#[cfg(test)]
229229
#[cfg(not(target_os = "macos"))] // issues with maven dependencies
230230
mod test {
231+
//! Maven doesn't like being run in parallel, at least on Windows.
232+
//! For now the tests access the MavenPlugin with a function that locks a mutex.
233+
231234
use super::super::{TestCase, TestCaseStatus};
232235
use super::*;
233236
use std::fs::{self, File};
237+
use std::sync::{Mutex, MutexGuard};
234238
use tempfile::{tempdir, TempDir};
235239
use tmc_langs_framework::domain::Strategy;
236240
use tmc_langs_framework::zip::ZipArchive;
237241
use walkdir::WalkDir;
238242

239-
#[cfg(windows)]
240-
use std::sync::Once;
241-
#[cfg(windows)]
242-
static INIT_MAVEN: Once = Once::new();
243+
lazy_static::lazy_static! {
244+
static ref MAVEN_LOCK: Mutex<()> = Mutex::new(());
245+
}
243246

244247
fn init() {
245248
let _ = env_logger::builder().is_test(true).try_init();
249+
}
246250

247-
// initializes maven in a synchronized manner for all tests
248-
#[cfg(windows)]
249-
INIT_MAVEN.call_once(|| {
250-
MavenPlugin::new().expect("failed to instantiate maven");
251-
});
251+
fn get_maven() -> (MavenPlugin, MutexGuard<'static, ()>) {
252+
(MavenPlugin::new().unwrap(), MAVEN_LOCK.lock().unwrap())
252253
}
253254

254255
fn copy_test_dir(path: &str) -> TempDir {
@@ -273,13 +274,12 @@ mod test {
273274
}
274275

275276
#[test]
276-
#[cfg(not(target_os = "windows"))] // CI problems
277277
fn gets_project_class_path() {
278278
init();
279279

280280
let temp_dir = copy_test_dir("tests/data/maven_exercise");
281281
let test_path = temp_dir.path();
282-
let plugin = MavenPlugin::new().unwrap();
282+
let (plugin, _lock) = get_maven();
283283
let class_path = plugin.get_project_class_path(test_path).unwrap();
284284
log::debug!("{}", class_path);
285285
let expected = format!("{0}junit{0}", std::path::MAIN_SEPARATOR);
@@ -295,19 +295,18 @@ mod test {
295295

296296
let temp_dir = copy_test_dir("tests/data/maven_exercise");
297297
let test_path = temp_dir.path();
298-
let plugin = MavenPlugin::new().unwrap();
298+
let (plugin, _lock) = get_maven();
299299
let compile_result = plugin.build(test_path).unwrap();
300300
assert!(compile_result.status_code.success());
301301
}
302302

303303
#[test]
304-
#[cfg(not(target_os = "windows"))] // CI problems
305304
fn creates_run_result_file() {
306305
init();
307306

308307
let temp_dir = copy_test_dir("tests/data/maven_exercise");
309308
let test_path = temp_dir.path();
310-
let plugin = MavenPlugin::new().unwrap();
309+
let (plugin, _lock) = get_maven();
311310
let compile_result = plugin.build(test_path).unwrap();
312311
let test_run = plugin
313312
.create_run_result_file(test_path, compile_result)
@@ -338,7 +337,7 @@ mod test {
338337

339338
let temp_dir = copy_test_dir("tests/data/maven_exercise");
340339
let test_path = temp_dir.path();
341-
let plugin = MavenPlugin::new().unwrap();
340+
let (plugin, _lock) = get_maven();
342341
let exercises = plugin
343342
.scan_exercise(&test_path, "test".to_string(), &mut vec![])
344343
.unwrap();
@@ -357,7 +356,7 @@ mod test {
357356

358357
let temp_dir = copy_test_dir("tests/data/maven_exercise");
359358
let test_path = temp_dir.path();
360-
let plugin = MavenPlugin::new().unwrap();
359+
let (plugin, _lock) = get_maven();
361360
let checkstyle_result = plugin
362361
.check_code_style(test_path, Language::from_639_3("fin").unwrap())
363362
.unwrap()

plugins/python3/src/policy.rs

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,21 @@ impl StudentFilePolicy for Python3StudentFilePolicy {
2222
}
2323

2424
fn is_student_source_file(&self, path: &Path) -> bool {
25-
// .py files in exercise root, and all non-pyc or __pycache__ files in src
26-
match path.parent() {
27-
Some(parent) => {
28-
parent == OsStr::new("src")
29-
&& path.extension() != Some(OsStr::new("pyc"))
30-
&& !path
31-
.components()
32-
.any(|c| c.as_os_str() == OsStr::new("__pycache__"))
33-
}
34-
None => path.extension() == Some(OsStr::new("py")),
35-
}
25+
// all non-pyc or __pycache__ files in src are student source files
26+
let in_src = path.starts_with("src");
27+
let is_cache_file = path.extension() == Some(OsStr::new("pyc"))
28+
|| path
29+
.components()
30+
.any(|c| c.as_os_str() == OsStr::new("__pycache__"));
31+
32+
// .py files in exercise root are student source files
33+
let is_in_project_root = match path.parent() {
34+
Some(s) => s.as_os_str().is_empty(),
35+
None => true,
36+
};
37+
let is_py_file = path.extension() == Some(OsStr::new("py"));
38+
39+
in_src && !is_cache_file || is_in_project_root && is_py_file
3640
}
3741
}
3842

tmc-langs-framework/src/io/tmc_zip.rs

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,19 +21,20 @@ pub fn zip<P: StudentFilePolicy>(policy: P, root_directory: &Path) -> Result<Vec
2121
.filter_entry(|e| !contains_tmcnosubmit(e))
2222
.filter_map(|e| e.ok())
2323
{
24-
log::trace!("processing {:?}", entry.path());
24+
log::trace!("processing {}", entry.path().display());
2525
if policy.is_student_file(entry.path(), &root_directory, &tmc_project_yml)? {
2626
let path = root_directory
2727
.parent()
2828
.map(|p| entry.path().strip_prefix(p).unwrap())
2929
.unwrap_or_else(|| entry.path());
3030
if entry.path().is_dir() {
3131
log::trace!("adding directory {}", path.display());
32-
writer.add_directory(path.to_string_lossy(), FileOptions::default())?;
32+
writer
33+
.add_directory(path_to_zip_compatible_string(path), FileOptions::default())?;
3334
} else {
3435
let bytes = file_util::read_file(entry.path())?;
3536
log::trace!("writing file {}", path.display());
36-
writer.start_file(path.to_string_lossy(), FileOptions::default())?;
37+
writer.start_file(path_to_zip_compatible_string(path), FileOptions::default())?;
3738
writer
3839
.write_all(&bytes)
3940
.map_err(|e| TmcError::ZipWrite(path.to_path_buf(), e))?;
@@ -44,6 +45,18 @@ pub fn zip<P: StudentFilePolicy>(policy: P, root_directory: &Path) -> Result<Vec
4445
Ok(cursor.into_inner())
4546
}
4647

48+
// ensures the / separator is used
49+
fn path_to_zip_compatible_string(path: &Path) -> String {
50+
let mut string = String::new();
51+
for component in path.components() {
52+
if !string.is_empty() {
53+
string.push('/');
54+
}
55+
string.push_str(&*component.as_os_str().to_string_lossy());
56+
}
57+
string
58+
}
59+
4760
// todo: remove
4861
/// Finds a project directory in the given zip and unzips it according to the given student policy. Also cleans unnecessary non-student files.
4962
///
@@ -210,10 +223,10 @@ fn contains_tmcnosubmit(entry: &DirEntry) -> bool {
210223

211224
#[cfg(test)]
212225
mod test {
213-
/*
214226
use super::*;
215227
use crate::policy::EverythingIsStudentFilePolicy;
216228
use std::collections::HashSet;
229+
use std::fs::{self, *};
217230
use tempfile::tempdir;
218231

219232
fn init() {
@@ -245,12 +258,9 @@ mod test {
245258
File::create(missing_file_path).unwrap();
246259

247260
let path = temp.path().join("exercise-name");
248-
let zipped = zip(
249-
Box::new(EverythingIsStudentFilePolicy::new(path.clone())),
250-
&path,
251-
)
252-
.unwrap();
261+
let zipped = zip(EverythingIsStudentFilePolicy::new(path.clone()), &path).unwrap();
253262
let mut archive = ZipArchive::new(Cursor::new(zipped)).unwrap();
263+
assert!(archive.len() > 0);
254264
for i in 0..archive.len() {
255265
log::debug!("{:?}", archive.by_index(i).unwrap().name());
256266
}
@@ -319,5 +329,21 @@ mod test {
319329
.unwrap();
320330
assert!(temp.path().join("src").exists());
321331
}
322-
*/
332+
333+
#[cfg(windows)]
334+
#[test]
335+
fn windows_paths_get_converted() {
336+
let win_path = PathBuf::from(r"tests\data\dir");
337+
let zipped = zip(
338+
EverythingIsStudentFilePolicy::new(win_path.clone()),
339+
&win_path,
340+
)
341+
.unwrap();
342+
let mut ziparch = ZipArchive::new(Cursor::new(zipped)).unwrap();
343+
assert!(ziparch.len() > 0);
344+
for i in 0..ziparch.len() {
345+
let file = ziparch.by_index(i).unwrap();
346+
assert!(file.name().chars().find(|c| c == &'\\').is_none())
347+
}
348+
}
323349
}

tmc-langs-framework/src/policy.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ pub trait StudentFilePolicy {
4141
let root_canon = project_root_path
4242
.canonicalize()
4343
.map_err(|e| TmcError::Canonicalize(project_root_path.to_path_buf(), e))?;
44-
log::debug!("{} {}", path_canon.display(), root_canon.display());
4544

4645
// the project root path should be considered a student file
4746
if path_canon == root_canon {
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
@points("test_point")
2-
@points("ex_and_test_point")
2+
@points("ex_and_test_point")

0 commit comments

Comments
 (0)