fml 0.6.0

Friendly Markup Language
Documentation
use proc_macros::{make_delimits_tests, make_headings_tests};

use crate::ast::{
	Content,
	FmlValue::{self, *},
	Section,
};

#[test]
fn nonesc_backslash() {
	let txt = r"sample \x text";
	let fml = crate::parse(txt).expect("failed to parse");

	assert_eq!(
		fml,
		Content(vec![Section(vec![Text(r"sample \x text".into())].into())])
	)
}

make_delimits_tests! {
	mod @{Name} {
		use crate::ast::{
			Content,
			FmlValue::{self, *},
			Section,
		};

		#[test]
		fn normal() {
			let txt = "@{Delim}sample text@{Delim}";
			let fml = crate::parse(txt).expect("failed to parse");

			assert_eq!(
				fml,
				Content(vec![Section(
					vec![@{CS}Text("sample text".into())@{CE}].into()
				)])
			)
		}

		#[test]
		fn whitespace() {
			let txt = "@{Delim}	sample text @{Delim}";
			let fml = crate::parse(txt).expect("failed to parse");

			assert_eq!(
				fml,
				Content(vec![Section(
					vec![@{CS}Text("	sample text ".into())@{CE}].into()
				)])
			)
		}

		#[test]
		fn multiline() {
			let txt = r"@{Delim}
sample text
@{Delim}";
			let fml = crate::parse(txt).expect("failed to parse");

			assert_eq!(
				fml,
				Content(vec![Section(
					vec![@{CS}Linebreak, Text("sample text".into()), Linebreak@{CE}].into()
				)])
			)
		}

		#[test]
		fn uses_nearest() {
			let txt = r"@{Delim}@{Delim}sample text@{Delim}@{Delim}";
			let fml = crate::parse(txt).expect("failed to parse");

			assert_eq!(
				fml,
				Content(vec![Section(
					vec![Text("@{Delim}".into()), @{CS}Text("sample text".into())@{CE}, Text("@{Delim}".into())].into()
				)])
			)
		}

		mod esc {
			use super::*;

			#[test]
			fn start() {
				let txt = r"\@{Delim}sample text@{Delim}";
				let fml = crate::parse(txt).expect("failed to parse");

				assert_eq!(
					fml,
					Content(vec![Section(
						vec![Text("@{Delim}sample text@{Delim}".into())].into()
					)])
				)
			}

			#[test]
			fn end() {
				let txt = r"@{Delim}sample text\@{Delim}";
				let fml = crate::parse(txt).expect("failed to parse");

				assert_eq!(
					fml,
					Content(vec![Section(
						vec![Text("@{Delim}sample text@{Delim}".into())].into()
					)])
				)
			}

			#[test]
			fn double_start() {
				let txt = r"\\@{Delim}sample text@{Delim}";
				let fml = crate::parse(txt).expect("failed to parse");

				assert_eq!(
					fml,
					Content(vec![Section(
						vec![Text(r"\".into()), @{CS}Text("sample text".into())@{CE}].into()
					)])
				)
			}

			#[test]
			fn double_end() {
				let txt = r"@{Delim}sample text\\@{Delim}";
				let fml = crate::parse(txt).expect("failed to parse");

				assert_eq!(
					fml,
					Content(vec![Section(
						vec![@{CS}Text(r"sample text\".into())@{CE}].into()
					)])
				)
			}
		}

		mod empty {
			use super::*;

			#[test]
			fn touching() {
				let txt = r"@{Delim}@{Delim}";
				let fml = crate::parse(txt).expect("failed to parse");

				assert_eq!(
					fml,
					Content(vec![Section(
						vec![Text(r"@{Delim}@{Delim}".into())].into()
					)])
				)
			}

			#[test]
			fn whitespace() {
				let txt = r"@{Delim}	 @{Delim}";
				let fml = crate::parse(txt).expect("failed to parse");

				assert_eq!(
					fml,
					Content(vec![Section(
						vec![Text(r"@{Delim}	 @{Delim}".into())].into()
					)])
				)
			}

			#[test]
			fn multiline() {
				let txt = r"@{Delim}
@{Delim}";
				let fml = crate::parse(txt).expect("failed to parse");

				assert_eq!(
					fml,
					Content(vec![Section(
						vec![Text(r"@{Delim}".into()), Linebreak, Text("@{Delim}".into())].into()
					)])
				)
			}
		}
	}
}

make_headings_tests! {
	mod @{Name} {
		use crate::ast::{
			Content,
			FmlValue::{self, *},
			Section,
		};

		#[test]
		fn normal() {
			let txt = r"@{Pat} Lorem ipsum";
			let fml = crate::parse(txt).expect("failed to parse");

			assert_eq!(
					fml,
					Content(vec![Section(vec![
						@{CS}Text("Lorem ipsum".into())@{CE}
					].into())])
				)
		}

		#[test]
		fn normal_alt() {
			let txt = r"Lorem
@{Pat} ipsum";
			let fml = crate::parse(txt).expect("failed to parse");

			assert_eq!(
					fml,
					Content(vec![Section(vec![
						Text("Lorem".into()),
						@{CS}Text("ipsum".into())@{CE}
					].into())])
				)
		}

		#[test]
		fn alternative_whitespace() {
			let txt = r"@{Pat}	  	Lorem ipsum";
			let fml = crate::parse(txt).expect("failed to parse");

			assert_eq!(
					fml,
					Content(vec![Section(vec![
						@{CS}Text("Lorem ipsum".into())@{CE}
					].into())])
				)
		}

		#[test]
		// #[ignore] // FIXME:
		fn explicit_multiline() {
			let txt = r"@{Pat} Lorem\
ipsum";
			let fml = crate::parse(txt).expect("failed to parse");

			assert_eq!(
					fml,
					Content(vec![Section(vec![
						@{CS}Text("Lorem".into()), Linebreak, Text("ipsum".into())@{CE},
					].into())])
				)
		}

		#[test]
		fn esc() {
			let txt = r"\@{Pat} Lorem ipsum";
			let fml = crate::parse(txt).expect("failed to parse");

			assert_eq!(
					fml,
					Content(vec![Section(vec![
						Text("@{Pat} Lorem ipsum".into()),
					].into())])
				)
		}

		#[test]
		fn double_esc_no_sol() {
			let txt = r"\\@{Pat} Lorem ipsum";
			let fml = crate::parse(txt).expect("failed to parse");

			assert_eq!(
					fml,
					Content(vec![Section(vec![
						Text(r"\@{Pat} Lorem ipsum".into()),
					].into())])
				)
		}

		mod fails {
			use super::*;

			#[test]
			fn no_start_of_line() {
				let txt = r"Lorem@{Pat} ipsum";
				let fml = crate::parse(txt).expect("failed to parse");

				assert_eq!(
						fml,
						Content(vec![Section(vec![
							Text("Lorem@{Pat} ipsum".into())
						].into())])
					)
			}

			#[test]
			fn no_start_of_line_alt() {
				// Please mind the space after the newline
				let txt = r"Lorem
 @{Pat} ipsum";
				let fml = crate::parse(txt).expect("failed to parse");

				assert_eq!(
						fml,
						Content(vec![Section(vec![
							Text("Lorem".into()),
							Linebreak,
							Text(" @{Pat} ipsum".into())
						].into())])
					)
			}

			#[test]
			fn no_whitespace() {
				let txt = r"@{Pat}Lorem ipsum";
				let fml = crate::parse(txt).expect("failed to parse");

				assert_eq!(
						fml,
						Content(vec![Section(vec![
							Text("@{Pat}Lorem ipsum".into())
						].into())])
					)
			}

			#[test]
			fn multiline() {
				let txt = r"@{Pat} Lorem
ipsum";
				let fml = crate::parse(txt).expect("failed to parse");

				assert_eq!(
						fml,
						Content(vec![Section(vec![
							@{CS}Text("Lorem".into())@{CE},
							Text("ipsum".into())
						].into())])
					)
			}
		}
	}
}