Skip to content

Commit 3f7ab2d

Browse files
authored
Merge pull request #211 from rage/msg
Fix serialization issue and improve error message
2 parents bed9b98 + 74ce239 commit 3f7ab2d

File tree

12 files changed

+406
-357
lines changed

12 files changed

+406
-357
lines changed

Diff for: Cargo.lock

+269-289
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: Cargo.toml

+2-2
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ authors = [
2222
edition = "2021"
2323
license = "MIT OR Apache-2.0"
2424
rust-version = "1.70.0"
25-
version = "0.33.0"
25+
version = "0.34.0"
2626

2727
[workspace.dependencies]
2828
mooc-langs-api = { git = "https://github.com/rage/secret-project-331.git", rev = "778a5820a8b7422cbf9f1c786da437833ced5ae9" }
@@ -39,7 +39,7 @@ tmc-langs-util = { path = "crates/tmc-langs-util" }
3939
tmc-mooc-client = { path = "crates/tmc-mooc-client" }
4040
tmc-server-mock = { path = "crates/helpers/tmc-server-mock" }
4141
tmc-testmycode-client = { path = "crates/tmc-testmycode-client" }
42-
ts-rs = { git = "https://github.com/Heliozoa/ts-rs.git", rev = "07712bf04007472aeeb065091261b3b64c019381" }
42+
ts-rs = { git = "https://github.com/Heliozoa/ts-rs.git", rev = "a08135ffad38a8fce2b9501b344d96e609f2c46f" }
4343

4444
# [patch.'https://github.com/Heliozoa/ts-rs.git']
4545
# ts-rs = { path = "../ts-rs/ts-rs" }

Diff for: crates/plugins/java/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ tmc-langs-util.workspace = true
1212

1313
dirs = "5.0.1"
1414
flate2 = "1.0.22"
15-
j4rs = "=0.16.0" # specific version to match the jar
15+
j4rs = "=0.17.1" # specific version to match the jar
1616
log = "0.4.14"
1717
once_cell = "1.9.0"
1818
serde = { version = "1.0.136", features = ["derive"] }

Diff for: crates/plugins/java/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ const SEPARATOR: &str = ":";
2929
const TMC_JUNIT_RUNNER_BYTES: &[u8] = include_bytes!("../deps/tmc-junit-runner-0.2.8.jar");
3030
const TMC_CHECKSTYLE_RUNNER_BYTES: &[u8] =
3131
include_bytes!("../deps/tmc-checkstyle-runner-3.0.3-20200520.064542-3.jar");
32-
const J4RS_BYTES: &[u8] = include_bytes!("../deps/j4rs-0.16.0-jar-with-dependencies.jar");
32+
const J4RS_BYTES: &[u8] = include_bytes!("../deps/j4rs-0.17.1-jar-with-dependencies.jar");
3333

3434
struct JvmWrapper {
3535
jvm: Jvm,

Diff for: crates/plugins/make/src/plugin.rs

+42-34
Original file line numberDiff line numberDiff line change
@@ -163,52 +163,61 @@ impl LanguagePlugin for MakePlugin {
163163
});
164164
}
165165

166+
// try to clean old log file if any
167+
let base_test_path = path.join("test");
168+
let valgrind_log_path = base_test_path.join("valgrind.log");
169+
let _ = file_util::remove_file(&valgrind_log_path);
170+
166171
// try to run valgrind
167172
let mut ran_valgrind = true;
168173
let valgrind_run = self.run_tests_with_valgrind(path, true);
169174
let output = match valgrind_run {
170175
Ok(output) => output,
171-
Err(error) => match error {
172-
MakeError::Tmc(TmcError::Command(command_error)) => {
173-
match command_error {
174-
CommandError::Popen(_, PopenError::IoError(io_error))
175-
| CommandError::FailedToRun(_, PopenError::IoError(io_error))
176-
if io_error.kind() == io::ErrorKind::PermissionDenied =>
177-
{
178-
// failed due to lacking permissions, try to clean and rerun
179-
self.clean(path)?;
180-
match self.run_tests_with_valgrind(path, false) {
181-
Ok(output) => output,
182-
Err(err) => {
183-
log::error!(
176+
Err(error) => {
177+
if let Ok(valgrind_log) = file_util::read_file_to_string_lossy(&valgrind_log_path) {
178+
log::warn!("Failed to run valgrind but a valgrind.log exists: {valgrind_log}");
179+
}
180+
match error {
181+
MakeError::Tmc(TmcError::Command(command_error)) => {
182+
match command_error {
183+
CommandError::Popen(_, PopenError::IoError(io_error))
184+
| CommandError::FailedToRun(_, PopenError::IoError(io_error))
185+
if io_error.kind() == io::ErrorKind::PermissionDenied =>
186+
{
187+
// failed due to lacking permissions, try to clean and rerun
188+
self.clean(path)?;
189+
match self.run_tests_with_valgrind(path, false) {
190+
Ok(output) => output,
191+
Err(err) => {
192+
log::error!(
184193
"Running with valgrind failed after trying to clean! {}",
185194
err
186195
);
187-
ran_valgrind = false;
188-
log::info!("Running without valgrind");
189-
self.run_tests_with_valgrind(path, false)?
196+
ran_valgrind = false;
197+
log::info!("Running without valgrind");
198+
self.run_tests_with_valgrind(path, false)?
199+
}
190200
}
191201
}
192-
}
193-
_ => {
194-
ran_valgrind = false;
195-
log::info!("Running without valgrind");
196-
self.run_tests_with_valgrind(path, false)?
202+
_ => {
203+
ran_valgrind = false;
204+
log::info!("Running without valgrind");
205+
self.run_tests_with_valgrind(path, false)?
206+
}
197207
}
198208
}
209+
MakeError::RunningTestsWithValgrind(..) => {
210+
ran_valgrind = false;
211+
log::info!("Running without valgrind");
212+
self.run_tests_with_valgrind(path, false)?
213+
}
214+
err => {
215+
log::warn!("unexpected error {:?}", err);
216+
return Err(err.into());
217+
}
199218
}
200-
MakeError::RunningTestsWithValgrind(..) => {
201-
ran_valgrind = false;
202-
log::info!("Running without valgrind");
203-
self.run_tests_with_valgrind(path, false)?
204-
}
205-
err => {
206-
log::warn!("unexpected error {:?}", err);
207-
return Err(err.into());
208-
}
209-
},
219+
}
210220
};
211-
let base_test_path = path.join("test");
212221

213222
// fails on valgrind by default
214223
let fail_on_valgrind_error = match TmcProjectYml::load_or_default(path) {
@@ -218,8 +227,7 @@ impl LanguagePlugin for MakePlugin {
218227

219228
// valgrind logs are only interesting if fail on valgrind error is on
220229
let valgrind_log = if ran_valgrind && fail_on_valgrind_error {
221-
let valgrind_path = base_test_path.join("valgrind.log");
222-
Some(ValgrindLog::from(&valgrind_path)?)
230+
Some(ValgrindLog::from(&valgrind_log_path)?)
223231
} else {
224232
None
225233
};

Diff for: crates/tmc-langs-cli/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ serde = "1.0.136"
2525
serde_json = "1.0.78"
2626
tempfile = "3.3.0"
2727
thiserror = "1.0.30"
28-
toml = "0.7.2"
28+
toml = "0.8.2"
2929
url = "2.2.2"
3030
uuid = { version = "1.3.4", features = ["v4"] }
3131
walkdir = "2.3.2"

Diff for: crates/tmc-langs-util/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ serde_path_to_error = "0.1.7"
2020
serde_yaml = "0.9.10"
2121
tempfile = "3.3.0"
2222
thiserror = "1.0.30"
23-
toml = "0.7.2"
23+
toml = "0.8.2"
2424
type-map = "0.5.0"
2525
walkdir = "2.3.2"
2626

Diff for: crates/tmc-langs/Cargo.toml

+2-2
Original file line numberDiff line numberDiff line change
@@ -38,15 +38,15 @@ shellwords = "1.1.0"
3838
tar = "0.4.38"
3939
tempfile = "3.3.0"
4040
thiserror = "1.0.30"
41-
toml = "0.7.2"
41+
toml = "0.8.2"
4242
url = "2.2.2"
4343
uuid = { version = "1.3.4", features = ["v4"] }
4444
walkdir = "2.3.2"
4545
zip = "0.6.3"
4646
zstd = "0.12.3"
4747

4848
[target.'cfg(unix)'.dependencies]
49-
nix = "0.26.2"
49+
nix = { version = "0.27.1", features = ["fs"] }
5050

5151
[dev-dependencies]
5252
chrono = "0.4.19"

Diff for: crates/tmc-testmycode-client/src/client.rs

+3-5
Original file line numberDiff line numberDiff line change
@@ -126,11 +126,9 @@ impl TestMyCodeClient {
126126
return Err(TestMyCodeClientError::AlreadyAuthenticated);
127127
}
128128

129-
let auth_url = self
130-
.0
131-
.root_url
132-
.join("/oauth/token")
133-
.map_err(|e| TestMyCodeClientError::UrlParse("oauth/token".to_string(), e))?;
129+
let auth_url = self.0.root_url.join("/oauth/token").map_err(|e| {
130+
TestMyCodeClientError::UrlParse(self.0.root_url.to_string() + "/oauth/token", e)
131+
})?;
134132

135133
let credentials = api_v8::get_credentials(self, client_name)?;
136134

Diff for: crates/tmc-testmycode-client/src/response.rs

+82-19
Original file line numberDiff line numberDiff line change
@@ -437,7 +437,7 @@ pub struct SubmissionFeedbackQuestion {
437437
pub kind: SubmissionFeedbackKind,
438438
}
439439

440-
#[derive(Debug, PartialEq, Eq, JsonSchema)]
440+
#[derive(Debug, Clone, Copy, PartialEq, Eq, JsonSchema)]
441441
#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
442442
pub enum SubmissionFeedbackKind {
443443
Text,
@@ -449,7 +449,22 @@ impl<'de> Deserialize<'de> for SubmissionFeedbackKind {
449449
where
450450
D: Deserializer<'de>,
451451
{
452-
deserializer.deserialize_string(SubmissionFeedbackKindVisitor {})
452+
let wrapper = SubmissionFeedbackKindWrapper::deserialize(deserializer)?;
453+
let kind = match wrapper {
454+
SubmissionFeedbackKindWrapper::String(string) => match string {
455+
SubmissionFeedbackKindString::Text => Self::Text,
456+
SubmissionFeedbackKindString::IntRange { lower, upper } => {
457+
Self::IntRange { lower, upper }
458+
}
459+
},
460+
SubmissionFeedbackKindWrapper::Derived(derived) => match derived {
461+
SubmissionFeedbackKindDerived::Text => Self::Text,
462+
SubmissionFeedbackKindDerived::IntRange { lower, upper } => {
463+
Self::IntRange { lower, upper }
464+
}
465+
},
466+
};
467+
Ok(kind)
453468
}
454469
}
455470

@@ -458,19 +473,53 @@ impl Serialize for SubmissionFeedbackKind {
458473
where
459474
S: Serializer,
460475
{
461-
let s = match self {
462-
Self::Text => "text".to_string(),
463-
Self::IntRange { lower, upper } => format!("intrange[{lower}..{upper}]"),
476+
let derived = match self {
477+
Self::Text => SubmissionFeedbackKindDerived::Text,
478+
Self::IntRange { lower, upper } => SubmissionFeedbackKindDerived::IntRange {
479+
lower: *lower,
480+
upper: *upper,
481+
},
464482
};
465-
serializer.serialize_str(&s)
483+
derived.serialize(serializer)
484+
}
485+
}
486+
487+
// wraps the two stringly typed and rusty versions of the kind
488+
#[derive(Debug, Clone, Copy, Deserialize)]
489+
#[serde(untagged)]
490+
enum SubmissionFeedbackKindWrapper {
491+
Derived(SubmissionFeedbackKindDerived),
492+
String(SubmissionFeedbackKindString),
493+
}
494+
495+
// uses derived serde impls
496+
#[derive(Debug, Clone, Copy, Deserialize, Serialize)]
497+
enum SubmissionFeedbackKindDerived {
498+
Text,
499+
IntRange { lower: u32, upper: u32 },
500+
}
501+
502+
// the stringly typed "text" or "intrange" that comes from the server
503+
#[derive(Debug, Clone, Copy)]
504+
enum SubmissionFeedbackKindString {
505+
Text,
506+
IntRange { lower: u32, upper: u32 },
507+
}
508+
509+
impl<'de> Deserialize<'de> for SubmissionFeedbackKindString {
510+
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
511+
where
512+
D: Deserializer<'de>,
513+
{
514+
deserializer.deserialize_string(SubmissionFeedbackKindStringVisitor {})
466515
}
467516
}
468517

469-
struct SubmissionFeedbackKindVisitor {}
518+
struct SubmissionFeedbackKindStringVisitor {}
470519

471520
// parses "text" into Text, and "intrange[x..y]" into IntRange {lower: x, upper: y}
472-
impl<'de> Visitor<'de> for SubmissionFeedbackKindVisitor {
473-
type Value = SubmissionFeedbackKind;
521+
impl<'de> Visitor<'de> for SubmissionFeedbackKindStringVisitor {
522+
type Value = SubmissionFeedbackKindString;
474523

475524
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
476525
formatter.write_str("\"text\" or \"intrange[x..y]\"")
@@ -485,7 +534,7 @@ impl<'de> Visitor<'de> for SubmissionFeedbackKindVisitor {
485534
Lazy::new(|| Regex::new(r#"intrange\[(\d+)\.\.(\d+)\]"#).unwrap());
486535

487536
if value == "text" {
488-
Ok(SubmissionFeedbackKind::Text)
537+
Ok(SubmissionFeedbackKindString::Text)
489538
} else if let Some(captures) = RANGE.captures(value) {
490539
let lower = &captures[1];
491540
let lower = u32::from_str(lower).map_err(|e| {
@@ -495,7 +544,7 @@ impl<'de> Visitor<'de> for SubmissionFeedbackKindVisitor {
495544
let upper = u32::from_str(upper).map_err(|e| {
496545
E::custom(format!("error parsing intrange upper bound {upper}: {e}"))
497546
})?;
498-
Ok(SubmissionFeedbackKind::IntRange { lower, upper })
547+
Ok(SubmissionFeedbackKindString::IntRange { lower, upper })
499548
} else {
500549
Err(E::custom("expected \"text\" or \"intrange[x..y]\""))
501550
}
@@ -601,7 +650,7 @@ mod test {
601650
}
602651

603652
#[test]
604-
fn feedback_kind_de() {
653+
fn feedback_kind_de_server() {
605654
init();
606655

607656
let text = serde_json::json!("text");
@@ -619,17 +668,31 @@ mod test {
619668
}
620669
}
621670

671+
#[test]
672+
fn feedback_kind_de_rust() {
673+
init();
674+
675+
let original = SubmissionFeedbackKind::Text;
676+
let json = serde_json::to_string(&original).unwrap();
677+
let deserialized: SubmissionFeedbackKind = deserialize::json_from_str(&json).unwrap();
678+
assert_eq!(deserialized, original);
679+
680+
let original = SubmissionFeedbackKind::IntRange { lower: 1, upper: 5 };
681+
let json = serde_json::to_string(&original).unwrap();
682+
let deserialized: SubmissionFeedbackKind = deserialize::json_from_str(&json).unwrap();
683+
assert_eq!(deserialized, original);
684+
}
685+
622686
#[test]
623687
fn feedback_kind_se() {
624688
init();
625-
use serde_json::Value;
626689

627-
let text = SubmissionFeedbackKind::Text;
628-
let text = serde_json::to_value(&text).unwrap();
629-
assert_eq!(text, Value::String("text".to_string()));
690+
let original = SubmissionFeedbackKind::Text;
691+
let json = serde_json::to_string(&original).unwrap();
692+
assert_eq!(json, r#""Text""#);
630693

631-
let range = SubmissionFeedbackKind::IntRange { lower: 1, upper: 5 };
632-
let range = serde_json::to_value(&range).unwrap();
633-
assert_eq!(range, Value::String("intrange[1..5]".to_string()));
694+
let original = SubmissionFeedbackKind::IntRange { lower: 1, upper: 5 };
695+
let json = serde_json::to_string(&original).unwrap();
696+
assert_eq!(json, r#"{"IntRange":{"lower":1,"upper":5}}"#);
634697
}
635698
}

Diff for: docker.sh

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ CMD="${*:-cargo build && cp /build/target/debug/tmc-langs-cli /build/out/}"
44
export DOCKER_BUILDKIT=1
55
docker build . -f docker/Dockerfile -t tmc-langs-rust
66
if [ "$CMD" = "interactive" ]; then
7-
docker run -it --rm -v "$PWD":/build/out tmc-langs-rust bash
7+
docker run --ulimit nofile=1024:1024 -it --rm -v "$PWD":/build/out tmc-langs-rust bash
88
else
9-
docker run --rm -v "$PWD":/build/out tmc-langs-rust bash -c "$CMD"
9+
docker run --ulimit nofile=1024:1024 --rm -v "$PWD":/build/out tmc-langs-rust bash -c "$CMD"
1010
fi;

0 commit comments

Comments
 (0)