create test for full urhg for builder parsing
This commit is contained in:
208
src/law.rs
208
src/law.rs
@ -1,27 +1,23 @@
|
||||
use log::{debug, error};
|
||||
use std::{
|
||||
borrow::BorrowMut,
|
||||
fmt,
|
||||
rc::{Rc, Weak},
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
use log::debug;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::overview;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
||||
pub(crate) struct Law {
|
||||
name: String, //ABGB, UrhG
|
||||
header: Vec<Heading>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
||||
struct Heading {
|
||||
name: String, //1. Hauptstück; 3. Theil; ...
|
||||
desc: Option<String>,
|
||||
content: HeadingContent, // 1. Theil; 1. Subtheil; ...
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
||||
enum HeadingContent {
|
||||
Paragraph(Vec<Section>),
|
||||
Heading(Vec<Box<Heading>>),
|
||||
@ -97,6 +93,9 @@ pub(crate) struct LawBuilder {
|
||||
|
||||
/// Stores the header of the next paragraph
|
||||
pub(crate) next_para_header: Option<String>,
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) history: Vec<String>,
|
||||
}
|
||||
|
||||
impl LawBuilder {
|
||||
@ -138,6 +137,8 @@ impl LawBuilder {
|
||||
classifiers,
|
||||
next_para_header: None,
|
||||
last_header_index,
|
||||
#[cfg(test)]
|
||||
history: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -177,6 +178,8 @@ impl LawBuilder {
|
||||
classifiers,
|
||||
next_para_header: None,
|
||||
last_header_index: None,
|
||||
#[cfg(test)]
|
||||
history: Vec::new(),
|
||||
};
|
||||
|
||||
overview::parse(law_id.unwrap()).unwrap();
|
||||
@ -186,6 +189,8 @@ impl LawBuilder {
|
||||
|
||||
/// Sets a new header.
|
||||
pub(crate) fn new_header(&mut self, name: &str) {
|
||||
#[cfg(test)]
|
||||
self.history.push(format!("New_header: {name}"));
|
||||
debug!("new_header={name}");
|
||||
let classifier_index = self
|
||||
.classifiers
|
||||
@ -238,6 +243,9 @@ impl LawBuilder {
|
||||
|
||||
/// Sets a new description for the last classifier.
|
||||
pub(crate) fn new_desc(&mut self, desc: &str) {
|
||||
#[cfg(test)]
|
||||
self.history.push(format!("New desc: {desc}"));
|
||||
|
||||
debug!("new_desc={desc}");
|
||||
if let Some(index) = self.last_header_index {
|
||||
self.classifiers[index].set_desc(desc);
|
||||
@ -248,6 +256,11 @@ impl LawBuilder {
|
||||
|
||||
/// Adds a new paragraph.
|
||||
pub(crate) fn new_par(&mut self, par: String, content: Content) {
|
||||
#[cfg(test)]
|
||||
self.history.push(format!(
|
||||
"New_par: {par};{}",
|
||||
serde_json::to_string(&content).unwrap()
|
||||
));
|
||||
debug!("new_par=par:{par};content:{content:#?}");
|
||||
if let Some(index) = self.last_header_index {
|
||||
let section = Section {
|
||||
@ -264,6 +277,8 @@ impl LawBuilder {
|
||||
|
||||
/// Next paragraph has a header, store its name.
|
||||
pub(crate) fn new_next_para_header(&mut self, header: &str) {
|
||||
#[cfg(test)]
|
||||
self.history.push(format!("New_new_para_header: {header}"));
|
||||
debug!("new_next_para_header={header}");
|
||||
self.next_para_header = Some(header.into());
|
||||
}
|
||||
@ -285,7 +300,7 @@ impl LawBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub(crate) struct Section {
|
||||
pub(crate) symb: String, // §"1", §"2", ...
|
||||
pub(crate) par_header: Option<String>,
|
||||
@ -414,73 +429,132 @@ impl Classifier {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub(crate) enum Content {
|
||||
Text(String), //This is my direct law text
|
||||
Item(Vec<Box<Content>>), //(1) This is general law. (2) This is more specific law
|
||||
List(Vec<Box<Content>>),
|
||||
}
|
||||
|
||||
//#[cfg(test)]
|
||||
//mod tests {
|
||||
// use super::*;
|
||||
//
|
||||
// //#[test]
|
||||
// //fn atest() {
|
||||
// // let mut builder = LawBuilder::test("test");
|
||||
// // builder.new_header("h11");
|
||||
// // builder.new_par("§11".into(), Content::Text("hi".into()));
|
||||
// // builder.new_header("h21");
|
||||
// // builder.new_header("h31");
|
||||
// // builder.new_par("§211".into(), Content::Text("hi".into()));
|
||||
// // builder.new_par("§212".into(), Content::Text("hi".into()));
|
||||
// // builder.new_header("h22");
|
||||
// // builder.new_par("§22".into(), Content::Text("hi".into()));
|
||||
//
|
||||
// // let law: Law = builder.into();
|
||||
//
|
||||
// // println!("{law:#?}");
|
||||
// // assert!(false);
|
||||
// //}
|
||||
//
|
||||
// // #[test]
|
||||
// // fn test() {
|
||||
// // let mut builder = LawBuilder::test("UrhG");
|
||||
// //
|
||||
// // builder.new_header("1. Hauptstück");
|
||||
// // builder.new_header("2. Abschnitt");
|
||||
// //
|
||||
// // builder.new_par(Content::Text("Mein erster Paragraph".into()));
|
||||
// //
|
||||
// // let expected = LawBuilder {
|
||||
// // name: "UrhG".into(),
|
||||
// // classifiers: vec![
|
||||
// // Classifier {
|
||||
// // name: "Hauptstück".into(),
|
||||
// // parent: None,
|
||||
// // instances: vec![ClassifierInstance {
|
||||
// // name: "1. Hauptstück".into(),
|
||||
// // desc: None,
|
||||
// // content: vec![],
|
||||
// // }],
|
||||
// // },
|
||||
// // Classifier {
|
||||
// // name: "Abschnitt".into(),
|
||||
// // parent: Some(Box::new(Classifier {
|
||||
// // name: "Hauptstück".into(),
|
||||
// // parent: None,
|
||||
// // instances: vec![],
|
||||
// // })),
|
||||
// // instances: vec![ClassifierInstance {
|
||||
// // name: "2. Abschnitt".into(),
|
||||
// // desc: None,
|
||||
// // content: vec![Content::Text("Mein erster Paragraph".into())],
|
||||
// // }],
|
||||
// // },
|
||||
// // ],
|
||||
// // next_para_header: None,
|
||||
// // last_header_index: Some(1),
|
||||
// // };
|
||||
// // assert_eq!(builder, expected);
|
||||
// // }
|
||||
//}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use pretty_assertions::assert_eq;
|
||||
use std::{
|
||||
fs::{self, File},
|
||||
io::{self, BufRead, Read},
|
||||
path::Path,
|
||||
};
|
||||
|
||||
use super::*;
|
||||
|
||||
//#[test]
|
||||
//fn atest() {
|
||||
// let mut builder = LawBuilder::test("test");
|
||||
// builder.new_header("h11");
|
||||
// builder.new_par("§11".into(), Content::Text("hi".into()));
|
||||
// builder.new_header("h21");
|
||||
// builder.new_header("h31");
|
||||
// builder.new_par("§211".into(), Content::Text("hi".into()));
|
||||
// builder.new_par("§212".into(), Content::Text("hi".into()));
|
||||
// builder.new_header("h22");
|
||||
// builder.new_par("§22".into(), Content::Text("hi".into()));
|
||||
fn read_lines<P>(filename: P) -> io::Result<Vec<String>>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
let file = File::open(filename)?;
|
||||
let buf_reader = io::BufReader::new(file);
|
||||
buf_reader.lines().collect()
|
||||
}
|
||||
|
||||
// let law: Law = builder.into();
|
||||
#[test]
|
||||
fn test_builder_full_urhg() {
|
||||
let mut builder = LawBuilder::test("UrhG");
|
||||
|
||||
// println!("{law:#?}");
|
||||
// assert!(false);
|
||||
//}
|
||||
let path = Path::new("./data/urhg/par");
|
||||
let input = read_lines(path.join("../par.result")).unwrap();
|
||||
|
||||
// #[test]
|
||||
// fn test() {
|
||||
// let mut builder = LawBuilder::test("UrhG");
|
||||
//
|
||||
// builder.new_header("1. Hauptstück");
|
||||
// builder.new_header("2. Abschnitt");
|
||||
//
|
||||
// builder.new_par(Content::Text("Mein erster Paragraph".into()));
|
||||
//
|
||||
// let expected = LawBuilder {
|
||||
// name: "UrhG".into(),
|
||||
// classifiers: vec![
|
||||
// Classifier {
|
||||
// name: "Hauptstück".into(),
|
||||
// parent: None,
|
||||
// instances: vec![ClassifierInstance {
|
||||
// name: "1. Hauptstück".into(),
|
||||
// desc: None,
|
||||
// content: vec![],
|
||||
// }],
|
||||
// },
|
||||
// Classifier {
|
||||
// name: "Abschnitt".into(),
|
||||
// parent: Some(Box::new(Classifier {
|
||||
// name: "Hauptstück".into(),
|
||||
// parent: None,
|
||||
// instances: vec![],
|
||||
// })),
|
||||
// instances: vec![ClassifierInstance {
|
||||
// name: "2. Abschnitt".into(),
|
||||
// desc: None,
|
||||
// content: vec![Content::Text("Mein erster Paragraph".into())],
|
||||
// }],
|
||||
// },
|
||||
// ],
|
||||
// next_para_header: None,
|
||||
// last_header_index: Some(1),
|
||||
// };
|
||||
// assert_eq!(builder, expected);
|
||||
// }
|
||||
for i in input {
|
||||
let (command, content) = i.split_once(":").unwrap();
|
||||
|
||||
match command {
|
||||
"New_header" => builder.new_header(content),
|
||||
"New desc" => builder.new_desc(content),
|
||||
"New_new_para_header" => builder.new_next_para_header(content),
|
||||
"New_par" => {
|
||||
let (par, real_content) = i.split_once(";").unwrap();
|
||||
let real_content: Content = serde_json::from_str(real_content).unwrap();
|
||||
builder.new_par(par.into(), real_content);
|
||||
}
|
||||
_ => {
|
||||
panic!("Don't know command '{command}'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let actual: Law = builder.into();
|
||||
|
||||
//println!("{}", serde_json::to_string(&law).unwrap());
|
||||
|
||||
let mut file = File::open(path.join("../builder.result")).unwrap();
|
||||
let mut json = String::new();
|
||||
file.read_to_string(&mut json).unwrap();
|
||||
|
||||
let expected = serde_json::from_str(&json).unwrap();
|
||||
|
||||
assert_eq!(actual, expected);
|
||||
}
|
||||
}
|
||||
|
@ -55,3 +55,55 @@ pub(crate) fn parse_from_str(xml: &str, builder: &mut LawBuilder) -> Result<bool
|
||||
|
||||
Ok(continue_parsing)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use pretty_assertions::assert_eq;
|
||||
use std::{
|
||||
fs::{self, File},
|
||||
io::{self, BufRead, Read},
|
||||
path::Path,
|
||||
};
|
||||
|
||||
use super::*;
|
||||
|
||||
fn read_lines<P>(filename: P) -> io::Result<Vec<String>>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
let file = File::open(filename)?;
|
||||
let buf_reader = io::BufReader::new(file);
|
||||
buf_reader.lines().collect()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_par_full_urhg() {
|
||||
let mut builder = LawBuilder::test("UrhG");
|
||||
|
||||
let path = Path::new("./data/urhg/par");
|
||||
let mut entries: Vec<_> = fs::read_dir(path)
|
||||
.unwrap()
|
||||
.filter_map(|entry| entry.ok())
|
||||
.collect();
|
||||
|
||||
entries.sort_by_key(|entry| entry.file_name());
|
||||
|
||||
for entry in entries {
|
||||
println!("{entry:?}");
|
||||
let mut file = File::open(path.join(entry.file_name())).unwrap();
|
||||
let mut json = String::new();
|
||||
file.read_to_string(&mut json).unwrap();
|
||||
|
||||
let cont = parse_from_str(&json, &mut builder).unwrap();
|
||||
if !cont {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let expected = read_lines(path.join("../par.result")).unwrap();
|
||||
|
||||
for (actual, expected) in builder.history.iter().zip(&expected) {
|
||||
assert_eq!(actual, expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -145,7 +145,7 @@ impl Abschnitt {
|
||||
if Liste::test(child) {
|
||||
let liste = Liste::parse(c.next().unwrap());
|
||||
absatze.push(Content::List(vec![
|
||||
Content::Text(absatz.content).into(),
|
||||
Content::Text(absatz.content.replace("\u{a0}", " ")).into(),
|
||||
liste.get_content().into(),
|
||||
]));
|
||||
} else if Table::test(child) {
|
||||
@ -155,22 +155,22 @@ impl Abschnitt {
|
||||
if Absatz::test_with_typ(child, "erltext") {
|
||||
let after_absatz = Absatz::parse(c.next().unwrap());
|
||||
absatze.push(Content::List(vec![
|
||||
Content::Text(absatz.content).into(),
|
||||
Content::Text(absatz.content.replace("\u{a0}", " ")).into(),
|
||||
Content::List(table.get_list()).into(),
|
||||
Content::Text(after_absatz.content).into(),
|
||||
]))
|
||||
} else {
|
||||
absatze.push(Content::List(vec![
|
||||
Content::Text(absatz.content).into(),
|
||||
Content::Text(absatz.content.replace("\u{a0}", " ")).into(),
|
||||
Content::List(table.get_list()).into(),
|
||||
]));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
absatze.push(Content::Text(absatz.content.clone()));
|
||||
absatze.push(Content::Text(absatz.content.replace("\u{a0}", " ").clone()));
|
||||
}
|
||||
} else {
|
||||
absatze.push(Content::Text(absatz.content.clone()));
|
||||
absatze.push(Content::Text(absatz.content.replace("\u{a0}", " ").clone()));
|
||||
}
|
||||
|
||||
//TODO: Continue here, (2) and (3) is somehow skipped
|
||||
@ -187,14 +187,14 @@ impl Abschnitt {
|
||||
if Liste::test(&child) {
|
||||
let liste = Liste::parse(c.next().unwrap());
|
||||
absatze.push(Content::List(vec![
|
||||
Content::Text(abs.content).into(),
|
||||
Content::Text(abs.content.replace("\u{a0}", " ")).into(),
|
||||
liste.get_content().into(),
|
||||
]));
|
||||
} else {
|
||||
absatze.push(Content::Text(abs.content));
|
||||
absatze.push(Content::Text(abs.content.replace("\u{a0}", " ")));
|
||||
}
|
||||
} else {
|
||||
absatze.push(Content::Text(abs.content));
|
||||
absatze.push(Content::Text(abs.content.replace("\u{a0}", " ")));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@ -308,7 +308,12 @@ impl Ziffernliste {
|
||||
let mut elems = Vec::new();
|
||||
|
||||
for elem in &self.listelems {
|
||||
elems.push(Content::Text(format!("{} {}", elem.symbol.content, elem.text)).into());
|
||||
elems.push(
|
||||
Content::Text(
|
||||
format!("{} {}", elem.symbol.content, elem.text).replace("\u{a0}", " "),
|
||||
)
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
|
||||
Content::List(elems)
|
||||
@ -380,7 +385,9 @@ impl Table {
|
||||
txt.push_str(&format!("{} ", td.absatz.content));
|
||||
}
|
||||
|
||||
ret.push(Box::new(Content::Text(format!("- {txt}",))));
|
||||
ret.push(Box::new(Content::Text(
|
||||
format!("- {txt}",).replace("\u{a0}", " "),
|
||||
)));
|
||||
}
|
||||
|
||||
ret
|
||||
@ -429,7 +436,11 @@ impl Liste {
|
||||
if Ziffernliste::test(child) {
|
||||
content.push(Ziffernliste::parse(c.next().unwrap()).get_content().into());
|
||||
} else if Schlussteil::test(child) {
|
||||
content.push(Content::Text(Schlussteil::parse(c.next().unwrap()).content));
|
||||
content.push(Content::Text(
|
||||
Schlussteil::parse(c.next().unwrap())
|
||||
.content
|
||||
.replace("\u{a0}", " "),
|
||||
));
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
@ -586,119 +597,3 @@ impl Layoutdaten {
|
||||
Self {}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::{fs::File, io::Read, sync::Arc};
|
||||
|
||||
use log::error;
|
||||
|
||||
use crate::law::{contains, Classifier, ClassifierInstance, Section};
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn deserialize_wucher1_success() {
|
||||
let mut file = File::open("data/par/wucher1.xml").unwrap();
|
||||
let mut xml = String::new();
|
||||
file.read_to_string(&mut xml).unwrap();
|
||||
|
||||
let mut builder = LawBuilder::test("no-headers");
|
||||
let risdok = Risdok::from_str(&xml, &mut builder);
|
||||
if risdok.is_err() {
|
||||
error!("{:#?}", risdok.as_ref().err());
|
||||
}
|
||||
assert!(risdok.is_ok());
|
||||
let expected = LawBuilder {
|
||||
name: "no-headers".into(),
|
||||
classifiers: vec![
|
||||
Classifier {
|
||||
used_for_fn: Arc::new(&contains),
|
||||
name: "".into(),
|
||||
parent_index: None,
|
||||
instances: vec![
|
||||
ClassifierInstance {
|
||||
name: "".into(),
|
||||
desc: None,
|
||||
sections: vec![
|
||||
Section {
|
||||
symb: "§ 1.".into(),
|
||||
par_header: Some(
|
||||
"Nichtigkeit eines wucherischen Vertrages.".into(),
|
||||
),
|
||||
content: Content::Text(
|
||||
"Ein Vertrag ist nichtig, wenn jemand den Leichtsinn, die Zwangslage, Verstandesschwäche, Unerfahrenheit oder Gemütsaufregung eines anderen dadurch ausbeutet, daß er sich oder einem Dritten für eine Leistung eine Gegenleistung versprechen oder gewähren läßt, deren Vermögenswert zu dem Werte seiner Leistung in auffallendem Mißverhältnis steht.".into(),
|
||||
),
|
||||
},
|
||||
],
|
||||
parent: None,
|
||||
idx: 0,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
last_header_index: Some(
|
||||
0,
|
||||
),
|
||||
next_para_header: None,
|
||||
};
|
||||
assert_eq!(builder, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deserialize_wucher2_success() {
|
||||
let mut file = File::open("data/par/wucher7.xml").unwrap();
|
||||
let mut xml = String::new();
|
||||
file.read_to_string(&mut xml).unwrap();
|
||||
let mut builder = LawBuilder::test("no-headers");
|
||||
|
||||
let risdok = Risdok::from_str(&xml, &mut builder);
|
||||
if risdok.is_err() {
|
||||
println!("{:#?}", risdok.as_ref().err());
|
||||
}
|
||||
assert!(risdok.is_ok());
|
||||
|
||||
let expected = LawBuilder {
|
||||
name: "no-headers".into(),
|
||||
classifiers: vec![
|
||||
Classifier {
|
||||
used_for_fn: Arc::new(&contains),
|
||||
name: "".into(),
|
||||
parent_index: None,
|
||||
instances: vec![
|
||||
ClassifierInstance {
|
||||
name: "".into(),
|
||||
desc: None,
|
||||
sections: vec![
|
||||
Section {
|
||||
symb: "§ 7.".into(),
|
||||
par_header: Some(
|
||||
"Rechtsfolgen der Nichtigkeit eines wucherischen Vertrages.".into(),
|
||||
),
|
||||
content: Content::Item(
|
||||
vec![
|
||||
Box::new(Content::Text(
|
||||
"(1) Ist ein Vertrag nach den vorstehenden Bestimmungen nichtig, so hat jeder der beiden Teile alles zurückzustellen, was er aus dem nichtigen Geschäfte zu seinem Vorteil erhalten hat. Insbesondere sind Geldzahlungen mit den gesetzlichen Zinsen vom Empfangstage zurückzuerstatten, die übergebenen Sachen zurückzustellen oder deren Wert zur Zeit des Empfanges zu ersetzen, die auf die Sache gemachten notwendigen und nützlichen Verwendungen zu ersetzen und für die Benützung und die Entwertung der Sache in der Zwischenzeit eine angemessene Vergütung zu leisten. Ergibt sich aus der Berechnung der beiderseitigen Ansprüche ein Mehranspruch für einen der Vertragsteile, so haftet hiefür die für den vertragsmäßigen Anspruch erworbene Sicherstellung.".into(),
|
||||
)),
|
||||
Box::new(Content::Text(
|
||||
"(2) Ist jedoch die Gewährung oder Verlängerung von Kredit nach den vorstehenden Bestimmungen nichtig, so hat der Benachteiligte für den erhaltenen Kreditbetrag vom Empfangstag bis zur Rückzahlung – sofern im Vertrag nicht eine geringere Verzinsung vorgesehen ist –- Zinsen in der Höhe des Zweifachen des im Zeitpunkt der Schließung des Vertrags geltenden Basiszinssatzes zu vergüten. Er kann für die Rückzahlung des Erhaltenen die im Vertrag vorgesehenen Zahlungsfristen in Anspruch nehmen. Bestimmungen, nach denen der Benachteiligte in besonderen Fällen weitergehende Rechte hat, bleiben unberührt.".into(),
|
||||
)),
|
||||
],
|
||||
),
|
||||
},
|
||||
],
|
||||
parent: None,
|
||||
idx: 0,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
last_header_index: Some(
|
||||
0,
|
||||
),
|
||||
next_para_header: None,
|
||||
};
|
||||
|
||||
assert_eq!(builder, expected);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user