use crate::prelude::*;
use crate::tests::test_client;
use crate::{map::IndexMap, Result};
#[tokio::test]
async fn test_templates() -> Result<()> {
let client = test_client::testwp_client();
let code = client.get("Main Page").await?.into_mutable();
let mut found = false;
for template in code.filter_templates()? {
if template.name_in_wikitext() == "Wikipedia:What we do on this wiki" {
found = true;
}
}
assert!(found);
Ok(())
}
#[tokio::test]
async fn test_more_cases() -> Result<()> {
let client = test_client::testwp_client();
let code = client
.transform_to_html(
"{{1x|param<!--comment-->name=value|normal=value2}}{{#if:{{{1}}}|foo|bar}}",
)
.await?.into_mutable();
let templates = code.filter_templates()?;
assert_eq!(templates.len(), 1);
let temp = &templates[0];
assert!(temp.is_template());
assert!(!temp.is_parser_function());
assert_eq!(temp.raw_name(), "./Template:1x");
assert_eq!(temp.name(), "Template:1x");
let mut params = IndexMap::new();
params.insert("normal".to_string(), "value2".to_string());
params.insert("paramname".to_string(), "value".to_string());
assert_eq!(temp.params(), params);
assert_eq!(temp.param("paramname"), Some("value".to_string()));
assert_eq!(temp.param("notset"), None);
assert_eq!(
temp.param_in_wikitext("paramname"),
Some("param<!--comment-->name".to_string())
);
assert_eq!(temp.param_in_wikitext("normal"), Some("normal".to_string()));
assert_eq!(temp.param_in_wikitext("notset"), None);
let pfs = code.filter_parser_functions()?;
assert_eq!(pfs.len(), 1);
let pf = &pfs[0];
assert!(pf.is_parser_function());
assert!(!pf.is_template());
assert_eq!(pf.raw_name(), "if");
Ok(())
}
#[tokio::test]
async fn test_template_mutation() -> Result<()> {
let client = test_client::testwp_client();
let original = "{{1x|foo=bar}}";
let code = client.transform_to_html(original).await?.into_mutable();
let mut templates = code.filter_templates()?;
let temp = &mut templates[0];
temp.set_param("new", "placeholder")?;
let previous = temp.set_param("new", "wikitext")?;
assert_eq!(previous, Some("placeholder".to_string()));
let html = client.transform_to_wikitext(&code).await?;
assert_eq!(html, "{{1x|foo=bar|new=wikitext}}".to_string());
let value = temp.remove_param("new")?;
assert_eq!(value, Some("wikitext".to_string()));
let new_html = client.transform_to_wikitext(&code).await?;
assert_eq!(new_html, original.to_string());
temp.set_params([
("baz".to_string(), "blah".to_string()),
("1".to_string(), "what".to_string()),
])?;
let html = client.transform_to_wikitext(&code).await?;
assert_eq!(&html, "{{1x|baz=blah|what}}");
temp.set_name("2x".to_string())?;
let html = client.transform_to_wikitext(&code).await?;
println!("{}", temp);
assert_eq!(&html, "{{2x|baz=blah|what}}");
Ok(())
}
#[tokio::test]
async fn test_text_contents() -> Result<()> {
let client = test_client::testwp_client();
let code = client.get("Mwbot-rs/Strip code").await?.into_mutable();
assert_eq!(
code.text_contents(),
"This is some formatted code. Also a link.".to_string()
);
Ok(())
}
#[tokio::test]
async fn test_wikilinks() -> Result<()> {
let client = test_client::testwp_client();
let code = client
.transform_to_html("[[Home Page#some fragment|link text]]")
.await?
.into_mutable()
.without_parsoid_data();
let links = code.filter_links();
let link = &links[0];
assert_eq!(link.raw_target(), "./Home_Page#some_fragment".to_string());
assert_eq!(link.target(), "Home Page#some fragment".to_string());
assert_eq!(link.text_contents(), "link text".to_string());
assert!(link.is_redirect());
if link.to_string() != "<a rel=\"mw:WikiLink\" href=\"./Home_Page#some_fragment\" title=\"Home Page\" class=\"mw-redirect\" id=\"mwAw\">link text</a>"
&& link.to_string() != "<a rel=\"mw:WikiLink\" href=\"./Home_Page#some_fragment\" class=\"mw-selflink-fragment mw-redirect\" id=\"mwAw\">link text</a>" {
assert_eq!(link.to_string(), "");
}
link.set_target("MediaWiki");
assert_eq!(link.raw_target(), "./MediaWiki".to_string());
assert_eq!(link.target(), "MediaWiki".to_string());
assert!(code.to_string().contains("href=\"./MediaWiki\""));
let wikitext = client.transform_to_wikitext(&code).await?;
assert_eq!(wikitext, "[[MediaWiki|link text]]".to_string());
let code = client
.transform_to_html("[[Mwbot-rs/Question?#some fragment with ö and ?]]")
.await?
.into_mutable();
let links = code.filter_links();
let link = &links[0];
assert_eq!(
link.raw_target(),
"./Mwbot-rs/Question%3F#some_fragment_with_ö_and_?".to_string()
);
assert_eq!(
link.target(),
"Mwbot-rs/Question?#some fragment with ö and ?".to_string()
);
Ok(())
}
#[tokio::test]
async fn test_redlinks() -> Result<()> {
let client = test_client::testwp_client();
let code = client
.transform_to_html("[[Page does not exist#Section heading]]")
.await?
.into_mutable();
let links = code.filter_links();
let link = &links[0];
assert_eq!(
link.target(),
"Page does not exist#Section heading".to_string()
);
Ok(())
}
#[tokio::test]
async fn test_new_link() -> Result<()> {
let client = test_client::testwp_client();
let link = WikiLink::new("Foo", &Wikicode::new_text("bar"));
assert_eq!(
&link.to_string(),
"<a href=\"./Foo\" rel=\"mw:WikiLink\">bar</a>"
);
let code = Wikicode::new("");
code.append(&link);
let new_wikitext = client.transform_to_wikitext(&code).await?;
assert_eq!(new_wikitext, "[[Foo|bar]]".to_string());
Ok(())
}
#[tokio::test]
async fn test_external_links() -> Result<()> {
let client = test_client::testwp_client();
let code = client
.transform_to_html("[https://example.com Link content] ")
.await?
.into_mutable()
.without_parsoid_data();
println!("{}", *code);
let links = code.filter_external_links();
let link = &links[0];
assert_eq!(link.target(), "https://example.com".to_string());
assert_eq!(link.text_contents(), "Link content".to_string());
assert_eq!(
&link.to_string(),
"<a rel=\"mw:ExtLink nofollow\" href=\"https://example.com\" class=\"external text\" id=\"mwAw\">Link content</a>"
);
let found_links = code.inclusive_descendants().any(|node| {
dbg!(&node);
matches!(node, Wikinode::ExtLink(_))
});
assert!(found_links);
link.set_target("https://wiki.example.org/foo?query=1");
assert_eq!(
link.target(),
"https://wiki.example.org/foo?query=1".to_string()
);
let wikitext = client.transform_to_wikitext(&code).await?;
assert_eq!(
wikitext,
"[https://wiki.example.org/foo?query=1 Link content] ".to_string()
);
Ok(())
}
#[tokio::test]
async fn test_comments() -> Result<()> {
let client = test_client::testwp_client();
let code = client
.transform_to_html("<!--comment-->")
.await?
.into_mutable();
let comments = code.filter_comments();
let comment = &comments[0];
assert_eq!(comment.text(), "comment".to_string());
comment.set_text(" new ");
assert_eq!(comment.text(), " new ".to_string());
assert!(code.to_string().contains("<!-- new -->"));
Ok(())
}
#[tokio::test]
async fn test_properties() -> Result<()> {
let client = test_client::testwp_client();
let code = client.get("Mwbot-rs/Stable").await?.into_mutable();
assert_eq!(code.revision_id(), Some(635905));
assert_eq!(code.title(), Some("Mwbot-rs/Stable".to_string()));
Ok(())
}
#[tokio::test]
async fn test_iterators() -> Result<()> {
let client = test_client::testwp_client();
let code = client
.transform_to_html("This is a [[PageThatDoesntExist|sentence]].")
.await?
.into_mutable();
let link = code
.descendants()
.filter_map(|node| {
dbg!(&node);
node.as_wikilink()
})
.next()
.unwrap();
assert_eq!(
link.raw_target(),
"./PageThatDoesntExist?action=edit&redlink=1".to_string()
);
assert_eq!(link.target(), "PageThatDoesntExist".to_string());
assert_eq!(link.text_contents(), "sentence".to_string());
Ok(())
}
#[tokio::test]
async fn test_title() -> Result<()> {
let client = test_client::testwp_client();
let code = client.get("Mwbot-rs/DISPLAYTITLE").await?.into_mutable();
assert_eq!(code.title().unwrap(), "Mwbot-rs/DISPLAYTITLE".to_string());
let wikitext = client.transform_to_wikitext(&code).await?;
assert!(wikitext.starts_with("{{DISPLAYTITLE"));
Ok(())
}
#[tokio::test]
async fn test_sections() -> Result<()> {
let client = test_client::testwp_client();
let wikitext = r#"
...lead section contents...
== foo=bar ==
...section contents...
=== nested ===
...section contents...
"#;
let code = client
.transform_to_html(wikitext)
.await?
.into_mutable()
.without_parsoid_data();
let sections = code.iter_sections();
{
let section = §ions[0];
assert!(section.is_pseudo_section());
assert_eq!(section.section_id(), 0);
assert!(section.heading().is_none());
assert!(section.is_editable());
}
{
let section = §ions[1];
assert!(!section.is_pseudo_section());
assert_eq!(section.section_id(), 1);
let heading = section.heading().unwrap();
assert_eq!(heading.text_contents(), "foo=bar");
assert_eq!(heading.level(), 2);
assert!(section.is_editable());
}
{
let section = §ions[2];
assert!(!section.is_pseudo_section());
assert_eq!(section.section_id(), 2);
let heading = section.heading().unwrap();
assert_eq!(heading.text_contents(), "nested");
assert_eq!(heading.level(), 3);
assert!(section.is_editable());
}
let new_heading = Heading::new(3, &Wikicode::new_text("inserted"))?;
sections[2].insert_before(&new_heading);
assert_eq!(
r#"
...lead section contents...
== foo=bar ==
...section contents...
=== inserted ===
=== nested ===
...section contents...
"#,
client.transform_to_wikitext(&code).await?
);
Ok(())
}
#[tokio::test]
async fn test_heading() -> Result<()> {
let client = test_client::testwp_client();
let heading = Heading::new(2, &Wikicode::new_text("Some text"))?;
let code = Wikicode::new("");
code.append(&heading);
let wikitext = client.transform_to_wikitext(&code).await?;
assert_eq!(&wikitext, "== Some text ==\n");
Ok(())
}
#[test]
fn test_invalid_heading() {
let err = Heading::new(7, &Wikicode::new_text("foo")).unwrap_err();
assert_eq!(
err.to_string(),
"Heading levels must be between 1 and 6, '7' was provided"
);
}
#[tokio::test]
async fn test_category() -> Result<()> {
let client = test_client::testwp_client();
let category = Category::new("Category:Foo bar", Some("Bar baz#quux"));
let code = Wikicode::new("");
code.append(&category);
let wikitext = client.transform_to_wikitext(&code).await?;
assert_eq!(&wikitext, "[[Category:Foo bar|Bar baz#quux]]");
let cats: Vec<_> = code
.inclusive_descendants()
.filter_map(|node| node.as_category())
.collect();
let cat = &cats[0];
assert_eq!(&cat.category(), "Category:Foo bar");
assert_eq!(cat.sort_key(), Some("Bar baz#quux".to_string()));
cat.set_category("Category:Bar baz");
cat.set_sort_key(None);
assert_eq!(cat.sort_key(), None);
assert_eq!(
&cat.to_string(),
"<link href=\"./Category:Bar_baz\" rel=\"mw:PageProp/Category\">"
);
let new_wikitext = client.transform_to_wikitext(&code).await?;
assert_eq!(&new_wikitext, "[[Category:Bar baz]]");
Ok(())
}
#[tokio::test]
async fn test_language_link() -> Result<()> {
let client = test_client::testwp_client();
let link = LanguageLink::new("https://en.wikipedia.org/wiki/Foo");
let code = Wikicode::new("");
code.append(&link);
let wikitext = client.transform_to_wikitext(&code).await?;
assert_eq!(&wikitext, "[[en:Foo]]");
link.set_target("https://de.wikipedia.org/wiki/Foo");
assert_eq!(&link.target(), "https://de.wikipedia.org/wiki/Foo");
let wikitext2 = client.transform_to_wikitext(&code).await?;
assert_eq!(&wikitext2, "[[de:Foo]]");
Ok(())
}
#[tokio::test]
async fn test_behavior_switch() -> Result<()> {
let client = test_client::testwp_client();
let code = Wikicode::new("");
code.append(&BehaviorSwitch::new("toc"));
let wikitext = client.transform_to_wikitext(&code).await?;
assert_eq!(&wikitext, "__TOC__\n");
let switches: Vec<_> = code
.inclusive_descendants()
.filter_map(|node| node.as_behavior_switch())
.collect();
let switch = &switches[0];
assert_eq!(&switch.property(), "toc");
Ok(())
}
#[tokio::test]
async fn test_redirect() -> Result<()> {
let client = test_client::testwp_client();
let code = Wikicode::new("");
code.append(&Redirect::new("Foo"));
let redirect = code.redirect().unwrap();
assert_eq!(redirect.target(), "Foo".to_string());
assert_eq!(redirect.raw_target(), "./Foo".to_string());
assert!(!redirect.is_external());
let wikitext = client.transform_to_wikitext(&code).await?;
assert_eq!(&wikitext, "#REDIRECT [[Foo]]");
assert_eq!(
client
.get("Mwbot-rs/RedirectSym")
.await?
.into_mutable()
.redirect()
.unwrap()
.target(),
"Mwbot-rs/RedirectSym?"
);
Ok(())
}
#[tokio::test]
async fn test_external_redirect() -> Result<()> {
let client = test_client::testwp_client();
let code = client
.transform_to_html("#REDIRECT [[w:Main Page]]")
.await?
.into_mutable();
dbg!(&code.to_string());
dbg!(&code.redirect());
let redirect = code.redirect().expect("not a redirect");
assert!(redirect.is_external());
assert_eq!(
redirect.target(),
"https://en.wikipedia.org/wiki/Main%20Page".to_string()
);
assert_eq!(
redirect.raw_target(),
"https://en.wikipedia.org/wiki/Main%20Page".to_string()
);
Ok(())
}
#[tokio::test]
async fn test_detach() -> Result<()> {
let client = test_client::testwp_client();
let code = client
.transform_to_html("This is a [[link]].")
.await?
.into_mutable();
for link in code.filter_links() {
link.detach();
}
let wikitext = client.transform_to_wikitext(&code).await?;
assert_eq!(&wikitext, "This is a .");
Ok(())
}
#[tokio::test]
async fn test_section_prepend() -> Result<()> {
let client = test_client::testwp_client();
let code = client
.transform_to_html("== Section ==\n[[foo]]")
.await?
.into_mutable()
.without_parsoid_data();
let section = code.iter_sections()[1].clone();
section
.heading()
.unwrap()
.insert_after(&WikiLink::new("./Bar", &Wikicode::new_text("Bar")));
let wikitext = client.transform_to_wikitext(&code).await?;
assert_eq!(&wikitext, "== Section ==\n[[Bar]]\n[[foo]]");
Ok(())
}
#[tokio::test]
async fn test_parser_functions() -> Result<()> {
let client = test_client::testwp_client();
let code = client.get("Mwbot-rs/Parser function").await?.into_mutable();
let templates = code.filter_parser_functions()?;
let temp = &templates[0];
assert!(temp.is_parser_function());
assert_eq!(
temp.name_in_wikitext(),
"#expr:{{formatnum:{{NUMBEROFUSERS}}|R}}+100"
);
assert_eq!(temp.raw_name(), "expr");
assert_eq!(temp.name(), "expr");
Ok(())
}
#[tokio::test]
async fn test_question() -> Result<()> {
let client = test_client::testwp_client();
let code = client
.get("Mwbot-rs/Question template")
.await?
.into_mutable();
let templates = code.filter_templates()?;
let temp = &templates[0];
assert_eq!(&temp.name(), "Template:But why?");
Ok(())
}
#[tokio::test]
async fn test_includeonly() -> Result<()> {
let client = test_client::testwp_client();
let wikitext = "foo<includeonly>bar</includeonly>baz";
let code = client.transform_to_html(wikitext).await?.into_mutable();
let includeonlys: Vec<_> = code
.descendants()
.filter_map(|node| node.as_includeonly())
.collect();
assert_eq!(includeonlys.len(), 1);
let includeonly = includeonlys[0].clone();
assert_eq!(includeonly.wikitext()?, "bar");
includeonly.set_wikitext("yay!")?;
let new = client.transform_to_wikitext(&code).await?;
assert_eq!(&new, "foo<includeonly>yay!</includeonly>baz");
includeonly.detach();
let detached = client.transform_to_wikitext(&code).await?;
assert_eq!(&detached, "foobaz");
let node = IncludeOnly::new("included")?;
code.append(&node);
let appended = client.transform_to_wikitext(&code).await?;
assert_eq!(&appended, "foobaz<includeonly>included</includeonly>");
Ok(())
}
#[tokio::test]
async fn test_noinclude() -> Result<()> {
let client = test_client::testwp_client();
let code = client
.transform_to_html("foo<noinclude>bar</noinclude>baz")
.await?
.into_mutable();
let noincludes = code.filter_noinclude();
assert_eq!(noincludes.len(), 1);
let noinclude = noincludes[0].clone();
let text_contents = {
let text: Vec<_> = noinclude
.inclusive_descendants()
.iter()
.map(|node| node.text_contents())
.collect();
text.join("")
};
assert_eq!(&text_contents, "bar");
noinclude.detach();
assert_eq!(&client.transform_to_wikitext(&code).await?, "foobaz");
let new = NoInclude::new(&WikiLink::new(
"Main Page",
&Wikicode::new_text("text"),
));
code.append(&new);
assert_eq!(
&client.transform_to_wikitext(&code).await?,
"foobaz<noinclude>[[Main Page|text]]</noinclude>"
);
Ok(())
}
#[tokio::test]
async fn test_noinclude_children() -> Result<()> {
let client = test_client::testwp_client();
let code = client
.transform_to_html("foo<noinclude>[[bar]] baz</noinclude>!")
.await?
.into_mutable();
let noinclude = code.filter_noinclude()[0].clone();
let links: Vec<WikiLink> = noinclude
.inclusive_descendants()
.iter()
.filter_map(|node| node.as_wikilink())
.collect();
assert_eq!(&links[0].target(), "Bar");
Ok(())
}
#[tokio::test]
async fn test_onlyinclude() -> Result<()> {
let client = test_client::testwp_client();
let code = client
.transform_to_html("foo<onlyinclude>bar</onlyinclude>baz")
.await?
.into_mutable();
let onlyincludes = code.filter_onlyinclude();
assert_eq!(onlyincludes.len(), 1);
let onlyinclude = onlyincludes[0].clone();
let text_contents = {
let text: Vec<_> = onlyinclude
.inclusive_descendants()
.iter()
.map(|node| node.text_contents())
.collect();
text.join("")
};
assert_eq!(&text_contents, "bar");
onlyinclude.detach();
assert_eq!(&client.transform_to_wikitext(&code).await?, "foobaz");
let new = OnlyInclude::new(&WikiLink::new(
"Main Page",
&Wikicode::new_text("text"),
));
code.append(&new);
assert_eq!(
&client.transform_to_wikitext(&code).await?,
"foobaz<onlyinclude>[[Main Page|text]]</onlyinclude>"
);
Ok(())
}
#[tokio::test]
async fn test_placeholder() -> Result<()> {
let client = test_client::testwp_client();
let code = client
.transform_to_html(";one</b>two :bad tag fun")
.await?
.into_mutable();
let placeholders: Vec<_> = code
.descendants()
.filter_map(|node| node.as_placeholder())
.collect();
assert_eq!(placeholders.len(), 1);
Ok(())
}
#[tokio::test]
async fn test_displayspace() -> Result<()> {
let client = test_client::testwp_client();
let code = client
.transform_to_html("<nowiki>test : 123</nowiki>")
.await?
.into_mutable();
let displayspaces: Vec<_> = code
.inclusive_descendants()
.filter_map(|node| node.as_displayspace())
.collect();
assert_eq!(displayspaces.len(), 1);
Ok(())
}
#[tokio::test]
async fn test_spec_version() -> Result<()> {
let client = test_client::testwp_client();
let code = client.get("Main Page").await?.into_mutable();
let version = code.spec_version().unwrap();
assert!(version.starts_with("2."));
let sp: Vec<_> = version.split('.').collect();
assert_eq!(sp.len(), 3);
Ok(())
}
#[tokio::test]
async fn test_extension_sections() -> Result<()> {
let client = test_client::mw_client();
let code = client.get("Help:TemplateData").await?.into_mutable();
for section in code.iter_sections() {
section.section_id();
section.is_pseudo_section();
section.heading();
}
for section in code
.inclusive_descendants()
.filter_map(|node| node.as_section())
{
section.section_id();
section.is_pseudo_section();
section.heading();
}
Ok(())
}
#[tokio::test]
async fn test_magic_links() -> Result<()> {
let client = test_client::testwp_client();
let code = client
.transform_to_html(
r#"
PMID 1234
ISBN 978-0-307-26395-7
RFC 4321
"#,
)
.await?
.into_mutable();
let links = code.filter_links();
assert!(links[0].is_isbn_magic_link());
let extlinks = code.filter_external_links();
assert!(extlinks[0].is_magic_link());
assert!(extlinks[1].is_magic_link());
let code = client
.transform_to_html(
r#"
[[pmid:1234|PMID 1234]]
[[Special:BookSources/9780307263957|ISBN 978-0-307-26395-7]]
[[rfc:4321|RFC 4321]]
"#,
)
.await?
.into_mutable();
let links = code.filter_links();
assert!(!links[0].is_isbn_magic_link());
assert_eq!(code.filter_external_links().len(), 0);
assert_eq!(
code.descendants()
.filter_map(|node| node.as_interwiki_link())
.count(),
2
);
Ok(())
}
#[tokio::test]
async fn test_templatearg() -> Result<()> {
let client = test_client::enwp_client();
let wikitext = "{{discussion-top}}{{{1|}}}{{discussion-bottom}}";
let code = client.transform_to_html(wikitext).await?.into_mutable();
code.filter_templates()?;
let converted = client.transform_to_wikitext(&code).await?;
assert_eq!(converted, wikitext);
let code = client
.get_revision("Talk:Signaling of the New York City Subway", 1095492368)
.await?
.into_mutable();
code.filter_templates()?;
Ok(())
}