From 755f323a1da2259a39d0bc5746a6d24c91ec4f15 Mon Sep 17 00:00:00 2001
From: "robinwilliam.hundt" <robinwilliam.hundt@stud.uni-goettingen.de>
Date: Tue, 5 Nov 2019 15:10:47 +0100
Subject: [PATCH] Interactive notebook fixing, latex rendering, change to
 output schema concerning tests

---
 Cargo.lock                          | 138 ++++++++++++++++++++++++----
 Cargo.toml                          |   1 +
 src/lib.rs                          |  25 ++++-
 src/main.rs                         |  46 +++-------
 src/parser/ipynb_parser/notebook.rs |  53 ++++++++++-
 src/parser/mod.rs                   |   6 +-
 src/parser/xml_parser.rs            |  38 +++++---
 src/submission.rs                   |  16 +---
 src/submission_type.rs              |  41 ++++++++-
 src/test_output.rs                  |   2 +-
 tests/test_xml_parser.rs            |   8 +-
 11 files changed, 277 insertions(+), 97 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index d0040d4..db758d0 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -34,7 +34,7 @@ name = "atty"
 version = "0.2.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
  "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -50,7 +50,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "backtrace-sys 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)",
  "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -60,7 +60,7 @@ version = "0.1.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "cc 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -97,7 +97,7 @@ version = "0.3.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "bzip2-sys 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -106,7 +106,16 @@ version = "0.1.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "cc 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "c2-chacha"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -140,7 +149,7 @@ name = "chrono"
 version = "0.4.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
  "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
  "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -349,7 +358,7 @@ version = "1.0.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
  "miniz_oxide_c_api 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -391,6 +400,16 @@ dependencies = [
  "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
+[[package]]
+name = "getrandom"
+version = "0.1.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
+ "wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "h2"
 version = "0.1.26"
@@ -515,7 +534,7 @@ name = "iovec"
 version = "0.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
  "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -548,7 +567,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "libc"
-version = "0.2.61"
+version = "0.2.62"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
@@ -626,7 +645,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "cc 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
  "crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
  "miniz_oxide 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -639,7 +658,7 @@ dependencies = [
  "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -664,7 +683,7 @@ version = "0.2.33"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
  "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -695,7 +714,7 @@ name = "num_cpus"
 version = "1.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -720,7 +739,7 @@ name = "parking_lot_core"
 version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
  "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -742,6 +761,11 @@ name = "podio"
 version = "0.1.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
+[[package]]
+name = "ppv-lite86"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
 [[package]]
 name = "proc-macro2"
 version = "0.4.30"
@@ -798,7 +822,7 @@ version = "0.6.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
  "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -810,6 +834,18 @@ dependencies = [
  "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
+[[package]]
+name = "rand"
+version = "0.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "rand_chacha"
 version = "0.1.1"
@@ -819,6 +855,15 @@ dependencies = [
  "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
+[[package]]
+name = "rand_chacha"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "rand_core"
 version = "0.3.1"
@@ -832,6 +877,14 @@ name = "rand_core"
 version = "0.4.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
+[[package]]
+name = "rand_core"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "rand_hc"
 version = "0.1.0"
@@ -840,6 +893,14 @@ dependencies = [
  "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
+[[package]]
+name = "rand_hc"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "rand_isaac"
 version = "0.1.1"
@@ -853,7 +914,7 @@ name = "rand_jitter"
 version = "0.1.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
  "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
@@ -865,7 +926,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
  "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -917,6 +978,14 @@ name = "regex-syntax"
 version = "0.6.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
+[[package]]
+name = "remove_dir_all"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "reqwest"
 version = "0.9.19"
@@ -959,7 +1028,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "cc 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
  "spin 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1019,6 +1088,7 @@ dependencies = [
  "structopt 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
  "sxd-document 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "sxd-xpath 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "zip 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
@@ -1245,6 +1315,19 @@ name = "take_mut"
 version = "0.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
+[[package]]
+name = "tempfile"
+version = "3.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
+ "remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "termcolor"
 version = "1.0.5"
@@ -1274,7 +1357,7 @@ name = "time"
 version = "0.1.42"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
  "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
  "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
@@ -1518,6 +1601,11 @@ dependencies = [
  "try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
+[[package]]
+name = "wasi"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
 [[package]]
 name = "webpki"
 version = "0.19.1"
@@ -1626,6 +1714,7 @@ dependencies = [
 "checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c"
 "checksum bzip2 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "42b7c3cbf0fa9c1b82308d57191728ca0256cb821220f4e2fd410a72ade26e3b"
 "checksum bzip2-sys 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6584aa36f5ad4c9247f5323b0a42f37802b37a836f0ad87084d7a33961abe25f"
+"checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101"
 "checksum calamine 0.15.5 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3ab74871ccd5a5b62749ec8b8a43c8dedc5e325ee16d6def84bcad8b449726"
 "checksum cc 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "b548a4ee81fccb95919d4e22cfea83c7693ebfd78f0495493178db20b3139da7"
 "checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33"
@@ -1658,6 +1747,7 @@ dependencies = [
 "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
 "checksum futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "45dc39533a6cae6da2b56da48edae506bb767ec07370f86f70fc062e9d435869"
 "checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4"
+"checksum getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "473a1265acc8ff1e808cd0a1af8cee3c2ee5200916058a2ca113c29f2d903571"
 "checksum h2 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)" = "a5b34c246847f938a410a03c5458c7fee2274436675e76d8b903c08efc29c462"
 "checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
 "checksum http 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "372bcb56f939e449117fb0869c2e8fd8753a8223d92a172c6e808cf123a5b6e4"
@@ -1673,7 +1763,7 @@ dependencies = [
 "checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f"
 "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
 "checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14"
-"checksum libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)" = "c665266eb592905e8503ba3403020f4b8794d26263f412ca33171600eca9a6fa"
+"checksum libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba"
 "checksum libflate 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)" = "45c97cf62125b79dcac52d506acdc4799f21a198597806947fd5f40dc7b93412"
 "checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c"
 "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
@@ -1697,6 +1787,7 @@ dependencies = [
 "checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831"
 "checksum peresil 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f658886ed52e196e850cfbbfddab9eaa7f6d90dd0929e264c31e5cec07e09e57"
 "checksum podio 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "780fb4b6698bbf9cf2444ea5d22411cef2953f0824b98f33cf454ec5615645bd"
+"checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b"
 "checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
 "checksum publicsuffix 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5afecba86dcf1e4fd610246f89899d1924fe12e1e89f555eb7c7f710f3c5ad1d"
 "checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0"
@@ -1704,10 +1795,14 @@ dependencies = [
 "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
 "checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1"
 "checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca"
+"checksum rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3ae1b169243eaf61759b8475a998f0a385e42042370f3a7dbaf35246eacc8412"
 "checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef"
+"checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853"
 "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
 "checksum rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
+"checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
 "checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4"
+"checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
 "checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08"
 "checksum rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b"
 "checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071"
@@ -1717,6 +1812,7 @@ dependencies = [
 "checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
 "checksum regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88c3d9193984285d544df4a30c23a4e62ead42edf70a4452ceb76dac1ce05c26"
 "checksum regex-syntax 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b143cceb2ca5e56d5671988ef8b15615733e7ee16cd348e064333b251b89343f"
+"checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e"
 "checksum reqwest 0.9.19 (registry+https://github.com/rust-lang/crates.io-index)" = "1d0777154c2c3eb54f5c480db01de845652d941e47191277cc673634c3853939"
 "checksum ring 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)" = "426bc186e3e95cac1e4a4be125a4aca7e84c2d616ffc02244eef36e2a60a093c"
 "checksum rle-decode-fast 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cabe4fa914dec5870285fa7f71f602645da47c486e68486d2b4ceb4a343e90ac"
@@ -1751,6 +1847,7 @@ dependencies = [
 "checksum synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "02353edf96d6e4dc81aea2d8490a7e9db177bf8acb0e951c24940bf866cb313f"
 "checksum synstructure 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3a761d12e6d8dcb4dcf952a7a89b475e3a9d69e4a69307e01a470977642914bd"
 "checksum take_mut 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60"
+"checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
 "checksum termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "96d6098003bde162e4277c70665bd87c326f5a0c3f3fbfb285787fa482d54e6e"
 "checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
 "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
@@ -1782,6 +1879,7 @@ dependencies = [
 "checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
 "checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
 "checksum want 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b6395efa4784b027708f7451087e647ec73cc74f5d9bc2e418404248d679a230"
+"checksum wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b89c3ce4ce14bdc6fb6beaf9ec7928ca331de5df7e5ea278375642a2f478570d"
 "checksum webpki 0.19.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4f7e1cd7900a3a6b65a3e8780c51a3e6b59c0e2c55c6dc69578c288d69f7d082"
 "checksum webpki-roots 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c10fa4212003ba19a564f25cd8ab572c6791f99a03cc219c13ed35ccab00de0e"
 "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
diff --git a/Cargo.toml b/Cargo.toml
index 8810160..f957040 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -33,3 +33,4 @@ chrono = {version = "0.4.6", features = ["serde"]}
 semver = {version = "0.9.0", features = ["serde"]}
 display_derive = "0.0.0"
 snafu = "0.5.0"
+tempfile = "3.1.0"
diff --git a/src/lib.rs b/src/lib.rs
index 830efc9..f41a59b 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -67,6 +67,27 @@ where
     }
 }
 
+pub fn yes_or_no(prompt: &str) -> bool {
+    let mut buffer = String::new();
+    let allowed_responses = vec!["y", "Y", "n", "N", ""];
+
+    // this is a do-while loop! :D
+    while {
+        buffer.clear();
+        print!("{} (Y/n):", prompt);
+        io::stdout().flush().expect("Io error");
+        io::stdin().read_line(&mut buffer).expect("Io error");
+        buffer = buffer.trim().to_owned();
+
+        !allowed_responses.contains(&buffer.as_str())
+    } {}
+    match buffer.as_str() {
+        "y" | "Y" | "" => true,
+        "n" | "N" => false,
+        &_ => unreachable!(),
+    }
+}
+
 pub fn run_test(test: Box<dyn Test>, students: &mut [StudentSerializable]) {
     for student in students {
         student.submissions = student
@@ -75,9 +96,7 @@ pub fn run_test(test: Box<dyn Test>, students: &mut [StudentSerializable]) {
             .into_iter()
             .map(|mut submission| {
                 let test_output = test.run(&submission);
-                submission
-                    .tests
-                    .insert(test_output.name.clone(), test_output);
+                submission.tests.push(test_output);
                 submission
             })
             .collect()
diff --git a/src/main.rs b/src/main.rs
index 2b0eba7..fefc489 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,7 +1,6 @@
 use std::error::Error;
 use std::ffi::OsStr;
 use std::fs;
-use std::io::{self, Write};
 use std::ops::Not;
 use std::path::PathBuf;
 
@@ -20,7 +19,7 @@ use rusty_hektor::student::StudentSerializable;
 use rusty_hektor::submission_type::{ProgrammingLang, SubmissionType};
 use rusty_hektor::testrunner::empty_test::EmptyTest;
 use rusty_hektor::testrunner::Test;
-use rusty_hektor::{anonymizer, run_test};
+use rusty_hektor::{anonymizer, run_test, yes_or_no};
 use ParsedData::*;
 
 /// Parse ILIAS exam export for importing into Grady
@@ -47,6 +46,10 @@ struct Opt {
     #[structopt(long = "skip-text")]
     skip_text: bool,
 
+    /// Disable latex rendering
+    #[structopt(long = "no-latex")]
+    no_latex: bool,
+
     /// Tests to run on the the submissions, the default (and only available option at
     /// the moment) is "empty" to check for empty submissions
     #[structopt(short, name = "TEST", parse(from_os_str), default_value = "empty")]
@@ -82,13 +85,6 @@ impl From<&OsStr> for TestEnum {
             _ => panic!("Unable to parse test. Allowed values: empty"),
         }
     }
-
-    //    fn from_str(s: &str) -> Result<Self, Self::Err> {
-    //        match s {
-    //            "empty" => Ok(Self::Empty),
-    //            _ => Err("Unable to parse test. Allowed values: empty")?
-    //        }
-    //    }
 }
 
 enum ParsedData {
@@ -102,13 +98,14 @@ fn main() -> Result<(), Box<dyn Error>> {
             "Unable to check for a new Rusty-Hektor version.\n\
              Please check manually at https://gitlab.gwdg.de/robinwilliam.hundt/rusty-hektor"
         );
-        if yes_or_no("Exit?")? {
+        if yes_or_no("Exit?") {
             std::process::exit(0)
         }
     }
     let opt = Opt::from_args();
 
     let parse_text = opt.skip_text.not();
+    let render_latex = opt.no_latex.not();
 
     let parsed_data: Result<Vec<ParsedData>, Box<dyn Error>> = opt
         .in_files
@@ -124,7 +121,7 @@ fn main() -> Result<(), Box<dyn Error>> {
                 );
                 std::process::exit(1)
             } else if extension == "zip" {
-                Ok(XML(XMLParser::parse(path, parse_text)?))
+                Ok(XML(XMLParser::parse(path, parse_text, render_latex)?))
             } else {
                 Err(ParserError::new(format!(
                     "Unsupported filetype: {:?}",
@@ -186,8 +183,8 @@ fn interactive_annotate(mut data: ExamSerializable) -> Result<ExamSerializable,
             if sub_type
                 .programming_language
                 .as_ref()
-                .expect("Programming lan must not be None after annote")
-                == &ProgrammingLang::ipynb
+                .expect("Programming lang must not be None after annotate")
+                == &ProgrammingLang::python
             {
                 for student in data.students.iter_mut() {
                     render_student_notebooks(student, &sub_type)?;
@@ -242,30 +239,9 @@ fn check_for_new_version() -> Result<(), Box<dyn Error>> {
              Please download the latest version from https://gitlab.gwdg.de/robinwilliam.hundt/rusty-hektor",
             current_version, latest_version
         );
-        if yes_or_no("Exit?")? {
+        if yes_or_no("Exit?") {
             std::process::exit(0);
         }
     }
     Ok(())
 }
-
-fn yes_or_no(prompt: &str) -> io::Result<bool> {
-    let mut buffer = String::new();
-    let allowed_responses = vec!["y", "Y", "n", "N", ""];
-
-    // this is a do-while loop! :D
-    while {
-        buffer.clear();
-        print!("{} (Y/n):", prompt);
-        io::stdout().flush()?;
-        io::stdin().read_line(&mut buffer)?;
-        buffer = buffer.trim().to_owned();
-
-        !allowed_responses.contains(&buffer.as_str())
-    } {}
-    Ok(match buffer.as_str() {
-        "y" | "Y" | "" => true,
-        "n" | "N" => false,
-        &_ => unreachable!(),
-    })
-}
diff --git a/src/parser/ipynb_parser/notebook.rs b/src/parser/ipynb_parser/notebook.rs
index 93421ae..ee19dc4 100644
--- a/src/parser/ipynb_parser/notebook.rs
+++ b/src/parser/ipynb_parser/notebook.rs
@@ -4,8 +4,12 @@ use std::error::Error;
 use std::fmt::{Display, Formatter};
 use std::str::FromStr;
 
+use crate::{input, yes_or_no};
 use lazy_static::lazy_static;
 use regex::Regex;
+use std::io::{Read, Write};
+use std::path::PathBuf;
+use std::process::Command;
 
 /// Media attachments (e.g. inline images), stored as mimebundle keyed by filename.
 #[derive(Clone, PartialEq, Debug, Deserialize, Serialize)]
@@ -74,10 +78,45 @@ impl FromStr for Notebook {
     type Err = NotebookParseError;
 
     fn from_str(s: &str) -> Result<Self, Self::Err> {
-        Ok(serde_json::from_str(s)?)
+        match serde_json::from_str(s) {
+            Err(err) => {
+                println!(
+                    "An error has been encountered while parsing a notebook:\n{}",
+                    err
+                );
+                let edit = yes_or_no("Edit the file in an editor to fix the json?:");
+                if !edit {
+                    Err(err)?;
+                }
+                let fixed_json = edit_json(s);
+                fixed_json.parse()
+            }
+            Ok(notebook) => return Ok(notebook),
+        }
     }
 }
 
+fn edit_json(s: &str) -> String {
+    let editor = get_editor();
+    let mut file = tempfile::NamedTempFile::new().expect("Unable to create temp file");
+    file.write_all(s.as_bytes())
+        .expect("Unable to write json to temp file");
+    Command::new(editor)
+        .arg(file.as_ref())
+        .status()
+        .expect("Unable to start editor");
+    let mut buf = String::new();
+    let mut file = file.reopen().expect("Unable to reopen temp file");
+    file.read_to_string(&mut buf)
+        .expect("Unable to read from temp file");
+    buf
+}
+
+fn get_editor() -> PathBuf {
+    let editor: PathBuf = input("Please enter a name or a path to a terminal editor");
+    editor
+}
+
 impl Display for Notebook {
     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
         for cell in &self.cells {
@@ -123,12 +162,12 @@ impl Display for CodeCell {
             .execution_count
             .and_then(|count| Some(count.to_string()))
             .unwrap_or(" ".into());
-        writeln!(f, "# In[{}]:\n", exec_count_as_str)?;
+        writeln!(f, "\n# In[{}]:\n", exec_count_as_str)?;
         writeln!(f, "{}\n", self.source)?;
 
         writeln!(f, "# Out[{}]:\n", exec_count_as_str)?;
         for output in &self.outputs {
-            write!(f, "{}", comment_out(output.to_string()))?;
+            write!(f, "{}\n", comment_out(output.to_string()))?;
         }
         Ok(())
     }
@@ -144,7 +183,11 @@ pub struct MarkdownCell {
 
 impl Display for MarkdownCell {
     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
-        writeln!(f, "# Markdown:\n{}", comment_out(self.source.to_string()))?;
+        writeln!(
+            f,
+            "\n# MarkdownCell:\n{}",
+            comment_out(self.source.to_string())
+        )?;
         if self.attachments.is_some() {
             write!(
                 f,
@@ -165,7 +208,7 @@ pub struct RawCell {
 
 impl Display for RawCell {
     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
-        writeln!(f, "# RawCell:\n{}", comment_out(self.source.to_string()))?;
+        writeln!(f, "\n# RawCell:\n{}", comment_out(self.source.to_string()))?;
         if self.attachments.is_some() {
             writeln!(
                 f,
diff --git a/src/parser/mod.rs b/src/parser/mod.rs
index ee2a313..e9dba4b 100644
--- a/src/parser/mod.rs
+++ b/src/parser/mod.rs
@@ -7,7 +7,11 @@ pub mod ipynb_parser;
 pub mod xml_parser;
 
 pub trait Parser {
-    fn parse<'a>(path: &Path, parse_text_questions: bool) -> result::Result<Exam, Box<dyn Error>>;
+    fn parse<'a>(
+        path: &Path,
+        parse_text_questions: bool,
+        render_latex: bool,
+    ) -> result::Result<Exam, Box<dyn Error>>;
 }
 
 #[derive(Debug)]
diff --git a/src/parser/xml_parser.rs b/src/parser/xml_parser.rs
index f4eb9a7..bac3926 100644
--- a/src/parser/xml_parser.rs
+++ b/src/parser/xml_parser.rs
@@ -1,11 +1,3 @@
-use crate::errors::{
-    EmptyFieldError, InvalidMatrNumber, InvalidStringLengthError, ValidationError,
-};
-use crate::student::Student;
-use crate::submission::Submission;
-use crate::submission_type::SubmissionType;
-
-use regex::Regex;
 use std::collections::{BTreeSet, HashMap};
 use std::error::Error;
 use std::fs::File;
@@ -15,14 +7,22 @@ use std::result;
 
 use base64::decode;
 use itertools::Itertools;
-use lazy_static::lazy_static;
 use log::warn;
+use regex::Regex;
 use sxd_document::{dom::Document, parser, Package};
 use sxd_xpath::{nodeset::Nodeset, Context, Factory, Value};
 use zip::ZipArchive;
 
+use lazy_static::lazy_static;
+
+use crate::errors::{
+    EmptyFieldError, InvalidMatrNumber, InvalidStringLengthError, ValidationError,
+};
 use crate::exam::Exam;
 use crate::parser::{Parser, ParserError};
+use crate::student::Student;
+use crate::submission::Submission;
+use crate::submission_type::SubmissionType;
 
 #[derive(Debug, Default)]
 struct PartialXMLFiles {
@@ -86,7 +86,11 @@ impl XMLFiles {
 pub struct XMLParser {}
 
 impl Parser for XMLParser {
-    fn parse(path: &Path, parse_text_questions: bool) -> result::Result<Exam, Box<dyn Error>> {
+    fn parse(
+        path: &Path,
+        parse_text_questions: bool,
+        render_latex: bool,
+    ) -> result::Result<Exam, Box<dyn Error>> {
         let file = File::open(path)?;
         let mut archive = ZipArchive::new(file)?;
 
@@ -96,7 +100,7 @@ impl Parser for XMLParser {
         } else {
             &["assSourceCode"]
         };
-        let sub_types = extract_submission_types(&xml_files, allowed_question_types)?;
+        let sub_types = extract_submission_types(&xml_files, allowed_question_types, render_latex)?;
         let students = extract_students(&xml_files, &sub_types)?;
 
         Ok(Exam {
@@ -110,6 +114,7 @@ impl Parser for XMLParser {
 fn extract_submission_types(
     xml_files: &XMLFiles,
     allowed_types: &[&str],
+    render_latex: bool,
 ) -> result::Result<HashMap<String, SubmissionType>, Box<dyn Error>> {
     let context = Context::new();
     let xp_factory = Factory::new();
@@ -154,7 +159,16 @@ fn extract_submission_types(
 
         let name = name_xp.evaluate(&context, item)?.into_string();
         let text = text_xp.evaluate(&context, item)?.into_string();
-        let sub_type = SubmissionType::new(name).add_description(text);
+        let mut sub_type = SubmissionType::new(name.clone()).add_description(text);
+        if render_latex {
+            sub_type.enable_latex_rendering().unwrap_or_else(|err| {
+                warn!(
+                    "Unable to render latex for submission type {}.\
+                     To disable latex rendering, run program with --no-latex.\n{}",
+                    name, err
+                )
+            });
+        }
         results.insert(id, sub_type);
     }
     Ok(results)
diff --git a/src/submission.rs b/src/submission.rs
index 37e90a2..38f27d5 100644
--- a/src/submission.rs
+++ b/src/submission.rs
@@ -1,11 +1,9 @@
 use crate::test_output::TestOutput;
 use serde::export::fmt::Display;
-use std::collections::BTreeMap;
 use std::error::Error;
-use std::hash::{Hash, Hasher};
 use std::str::FromStr;
 
-#[derive(Debug, Eq, PartialEq, Serialize, Default, Clone, PartialOrd, Ord)]
+#[derive(Debug, Eq, PartialEq, Serialize, Default, Clone, Hash, PartialOrd, Ord)]
 pub struct Submission {
     pub code: String,
     /// This field is populated if the displayed source code differs from the
@@ -13,7 +11,7 @@ pub struct Submission {
     /// into a python script to display but want to keep the original notebook as json
     pub source_code: Option<String>,
     pub r#type: String,
-    pub tests: BTreeMap<String, TestOutput>,
+    pub tests: Vec<TestOutput>,
 }
 
 impl Submission {
@@ -22,7 +20,7 @@ impl Submission {
             code,
             source_code: None,
             r#type,
-            tests: BTreeMap::new(),
+            tests: vec![],
         }
     }
 
@@ -37,11 +35,3 @@ impl Submission {
         Ok(())
     }
 }
-
-impl Hash for Submission {
-    fn hash<H: Hasher>(&self, state: &mut H) {
-        self.code.hash(state);
-        self.source_code.hash(state);
-        self.r#type.hash(state);
-    }
-}
diff --git a/src/submission_type.rs b/src/submission_type.rs
index 147f13e..e5b36a3 100644
--- a/src/submission_type.rs
+++ b/src/submission_type.rs
@@ -6,6 +6,8 @@ use std::str::FromStr;
 use crate::input;
 
 use display_derive::Display;
+use sxd_document::{parser, writer::format_document};
+use sxd_xpath::{Context, Factory, Value};
 
 #[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Default, PartialOrd, Ord)]
 pub struct SubmissionType {
@@ -70,6 +72,39 @@ impl SubmissionType {
 
         Ok(())
     }
+
+    pub fn enable_latex_rendering(&mut self) -> Result<(), Box<dyn Error>> {
+        if self.description.is_none() {
+            panic!("enable_latex_rendering must be called after description is set");
+        }
+        let context = Context::new();
+        let factory = Factory::new();
+        let latex_xp = factory.build("//span[@class='latex']").unwrap().unwrap();
+        let wrapped_description = format!("<div>{}</div>", self.description.as_ref().unwrap());
+        let package = parser::parse(&wrapped_description)?;
+        let doc = package.as_document();
+        let items = match latex_xp.evaluate(&context, doc.root())? {
+            Value::Nodeset(nodes) => nodes,
+            _ => Err("latex xpath didn't return nodeset")?,
+        };
+        for item in items.iter() {
+            match item.element() {
+                Some(el) => {
+                    el.set_text(&format!("\\({}\\)", item.string_value()));
+                }
+                None => log::warn!(
+                    "Encountered Node without Element during Latex preprocessing.\
+                     Output may not be able to be rendered"
+                ),
+            }
+        }
+
+        let mut description = vec![];
+        format_document(&doc, &mut description)?;
+        self.description = Some(String::from_utf8(description)?);
+
+        Ok(())
+    }
 }
 
 #[allow(non_camel_case_types)]
@@ -79,13 +114,13 @@ pub enum ProgrammingLang {
     java,
     mipsasm,
     haskell,
-    ipynb,
+    python,
     plaintext,
 }
 
 #[derive(Debug, Display)]
 #[display(
-    fmt = "Unparseable programming language: {}. Allowed: c, java, mipsasm, haskell, ipynb, plaintext",
+    fmt = "Unparseable programming language: {}. Allowed: c, java, mipsasm, haskell, python, plaintext",
     input
 )]
 pub struct ParseProgrammingLangError {
@@ -104,7 +139,7 @@ impl FromStr for ProgrammingLang {
             "mipsasm" => ProgrammingLang::mipsasm,
             "haskell" => ProgrammingLang::haskell,
             "plaintext" => ProgrammingLang::plaintext,
-            "ipynb" => ProgrammingLang::ipynb,
+            "python" => ProgrammingLang::python,
             _ => Err(ParseProgrammingLangError {
                 input: s.to_owned(),
             })?,
diff --git a/src/test_output.rs b/src/test_output.rs
index 62bc933..6fb0df5 100644
--- a/src/test_output.rs
+++ b/src/test_output.rs
@@ -1,4 +1,4 @@
-#[derive(Debug, Eq, PartialEq, Serialize, Default, Clone, PartialOrd, Ord)]
+#[derive(Debug, Eq, PartialEq, Serialize, Default, Clone, PartialOrd, Hash, Ord)]
 pub struct TestOutput {
     pub name: String,
     pub annotation: String,
diff --git a/tests/test_xml_parser.rs b/tests/test_xml_parser.rs
index b534c46..788edd6 100644
--- a/tests/test_xml_parser.rs
+++ b/tests/test_xml_parser.rs
@@ -7,7 +7,7 @@ use std::collections::{BTreeSet, HashSet};
 
 #[test]
 fn can_parse_zipped_xml_data() -> Result<(), Box<dyn Error>> {
-    let parsed = XMLParser::parse(Path::new("tests/test.zip"), false)?;
+    let parsed = XMLParser::parse(Path::new("tests/test.zip"), false, true)?;
     let serializable = parsed.into_serializable()?;
     assert_eq!(1, serializable.submission_types.len());
     assert_eq!(1, serializable.students.len());
@@ -16,7 +16,7 @@ fn can_parse_zipped_xml_data() -> Result<(), Box<dyn Error>> {
 
 #[test]
 fn parsed_xml_contains_correct_submission_types() -> Result<(), Box<dyn Error>> {
-    let parsed = XMLParser::parse(Path::new("tests/test.zip"), false)?;
+    let parsed = XMLParser::parse(Path::new("tests/test.zip"), false, true)?;
     let serializable = parsed.into_serializable()?;
 
     let submission_type_names: HashSet<String> = serializable
@@ -37,7 +37,7 @@ fn parsed_xml_contains_correct_submission_types() -> Result<(), Box<dyn Error>>
 
 #[test]
 fn parsed_xls_contains_correct_students() -> Result<(), Box<dyn Error>> {
-    let parsed = XMLParser::parse(Path::new("tests/test.zip"), false)?;
+    let parsed = XMLParser::parse(Path::new("tests/test.zip"), false, true)?;
     let serializable = parsed.into_serializable()?;
 
     let students: BTreeSet<StudentSerializable> = serializable
@@ -68,7 +68,7 @@ fn parsed_xls_contains_correct_students() -> Result<(), Box<dyn Error>> {
 fn correct_mapping_is_generated() -> Result<(), Box<dyn Error>> {
     use rusty_hektor::anonymizer;
 
-    let parsed = XMLParser::parse(Path::new("tests/test.zip"), false)?;
+    let parsed = XMLParser::parse(Path::new("tests/test.zip"), false, true)?;
     let mut serializable = parsed.into_serializable()?;
 
     let map = anonymizer::replace_students(&mut serializable.students);
-- 
GitLab