Mw_parse: Add merge_attributes

pull/620/head
gnosygnu 8 years ago
parent 78526c00c6
commit 32b4fafe10

@ -18,7 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
package gplx.xowa.files; import gplx.*; import gplx.xowa.*;
import org.junit.*;
public class Xof_file_wkr__tst {
private final Xof_file_wkr___fxt fxt = new Xof_file_wkr___fxt();
private final Xof_file_wkr___fxt fxt = new Xof_file_wkr___fxt();
@Test public void Ttl_standardize() {
fxt.Test__ttl_standardize("Abc.png" , "Abc.png"); // basic
fxt.Test__ttl_standardize("A b.png" , "A_b.png"); // spaces -> unders

@ -19,6 +19,12 @@ package gplx.xowa.mws; import gplx.*; import gplx.xowa.*;
import gplx.core.btries.*;
import gplx.xowa.mws.htmls.*;
import gplx.xowa.mws.linkers.*;
/* TODO.XO
* titleFormatter->gePrefixedTex
* $html = HtmlArmor::getHtml($text);
* Get_link_url
* Get_link_classes
*/
public class Xomw_linker {
private final Bry_bfr tmp = Bry_bfr_.New();
private final Linker_rel_splitter splitter = new Linker_rel_splitter();

@ -28,7 +28,7 @@ public class Xomw_linker__normalize_subpage_link__tst {
@Test public void Dot2__trailing() {fxt.Test__normalize_subpage_link("A/B/C" , "../../Z/" , "" , "A/Z" , "Z");}
}
class Xomw_linker__normalize_subpage_link__fxt {
private final Xomw_linker mgr = new Xomw_linker(new gplx.xowa.mws.linkers.Xomw_link_renderer());
private final Xomw_linker mgr = new Xomw_linker(new gplx.xowa.mws.linkers.Xomw_link_renderer(new Xomw_sanitizer()));
private final Xowe_wiki wiki;
private final Xomw_linker__normalize_subpage_link normalize_subpage_link = new Xomw_linker__normalize_subpage_link();
public Xomw_linker__normalize_subpage_link__fxt() {

@ -23,7 +23,7 @@ public class Xomw_linker__split_trail__tst {
@Test public void None() {fxt.Test__split_trail(" abc" , null , " abc");}
}
class Xomw_linker__split_trail__fxt {
private final Xomw_linker linker = new Xomw_linker(new gplx.xowa.mws.linkers.Xomw_link_renderer());
private final Xomw_linker linker = new Xomw_linker(new gplx.xowa.mws.linkers.Xomw_link_renderer(new Xomw_sanitizer()));
private final Btrie_slim_mgr trie = Btrie_slim_mgr.cs();
public Xomw_linker__split_trail__fxt() {
String[] ary = new String[] {"a", "b", "c", "d", "e", "f"};

@ -18,7 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
package gplx.xowa.mws; import gplx.*; import gplx.xowa.*;
import gplx.core.brys.*; import gplx.core.btries.*; import gplx.core.encoders.*; import gplx.core.primitives.*; import gplx.langs.htmls.entitys.*;
import gplx.xowa.parsers.htmls.*;
import gplx.xowa.mws.parsers.*; import gplx.langs.phps.utls.*;
import gplx.langs.htmls.*; import gplx.xowa.mws.htmls.*; import gplx.xowa.mws.parsers.*; import gplx.langs.phps.utls.*;
public class Xomw_sanitizer {
private final Mwh_doc_wkr__atr_bldr atr_bldr = new Mwh_doc_wkr__atr_bldr();
private final Mwh_atr_parser atr_parser = new Mwh_atr_parser();
@ -91,6 +91,50 @@ public class Xomw_sanitizer {
}
}
// Merge two sets of HTML attributes. Conflicting items in the second set
// will override those in the first, except for 'class' attributes which
// will be combined (if they're both strings).
// XO.MW: XO does src += trg; MW does rv = src + trg;
public void Merge_attributes(Xomw_atr_mgr src, Xomw_atr_mgr trg) {
int trg_len = trg.Len();
for (int i = 0; i < trg_len; i++) {
Xomw_atr_itm trg_atr = trg.Get_at(i);
// merge trg and src
byte[] atr_cls = Gfh_atr_.Bry__class;
if (Bry_.Eq(trg_atr.Key_bry(), atr_cls)) {
Xomw_atr_itm src_atr = src.Get_by_or_null(atr_cls);
if (src_atr != null) {
// NOTE: need byte[]-creation is unavoidable b/c src_atr and trg_atr are non-null
Merge_atrs_combine(tmp_bfr, src_atr.Val(), Byte_ascii.Space);
tmp_bfr.Add_byte_space();
Merge_atrs_combine(tmp_bfr, trg_atr.Val(), Byte_ascii.Space);
src_atr.Val_(tmp_bfr.To_bry_and_clear());
continue;
}
}
src.Add_or_set(trg_atr);
}
}
private void Merge_atrs_combine(Bry_bfr trg, byte[] src, byte sep) {
int src_len = src.length;
for (int i = 0; i < src_len; i++) {
byte b = src[i];
if (b == sep) {
// gobble ws; EX: "a b"
int space_bgn = i;
int space_end = Bry_find_.Find_fwd_while(src, i, src_len, sep);
i = space_end - 1; // -1 b/c i++ above
// ignore ws at BOS; EX: " a"
if (space_bgn == 0)
continue;
// ignore ws at EOS; EX: "a "
if (space_end == src_len)
break;
}
trg.Add_byte(b);
}
}
public byte[] Clean_url(byte[] url) {
// Normalize any HTML entities in input. They will be
// re-escaped by makeExternalLink().

@ -16,7 +16,7 @@ You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.mws; import gplx.*; import gplx.xowa.*;
import org.junit.*; import gplx.core.tests.*; import gplx.core.btries.*;
import org.junit.*; import gplx.core.tests.*; import gplx.core.btries.*; import gplx.xowa.mws.htmls.*;
public class Xomw_sanitizer__tst {
private final Xomw_sanitizer__fxt fxt = new Xomw_sanitizer__fxt();
@Test public void Normalize__text() {fxt.Test__normalize_char_references("abc" , "abc");}
@ -107,6 +107,22 @@ public class Xomw_sanitizer__tst {
// ipv6_brack
fxt.Test__clean_url("http://[0a.1b:12]:123/cd" , "http://[0a.1b:12]:123/cd");
}
@Test public void Merge_atrs() {
Xomw_atr_mgr src_atrs = new Xomw_atr_mgr();
Xomw_atr_mgr trg_atrs = new Xomw_atr_mgr();
Xomw_atr_mgr expd_atrs = new Xomw_atr_mgr();
String cls = "class";
// basic: k1 + k2
fxt.Test__merge_attributes(src_atrs.Clear().Add_many("k1", "v1"), trg_atrs.Clear().Add_many("k2", "v2"), expd_atrs.Clear().Add_many("k1", "v1", "k2", "v2"));
// overwrite: k1 + k1
fxt.Test__merge_attributes(src_atrs.Clear().Add_many("k1", "v1"), trg_atrs.Clear().Add_many("k1", "v1a"), expd_atrs.Clear().Add_many("k1", "v1a"));
// cls: many
fxt.Test__merge_attributes(src_atrs.Clear().Add_many(cls, "v1 v2"), trg_atrs.Clear().Add_many(cls, "v3 v4"), expd_atrs.Clear().Add_many(cls, "v1 v2 v3 v4"));
// cls: src.empty
fxt.Test__merge_attributes(src_atrs.Clear(), trg_atrs.Clear().Add_many(cls, "v1"), expd_atrs.Clear().Add_many(cls, "v1"));
// cls: ws
fxt.Test__merge_attributes(src_atrs.Clear().Add_many(cls, " v1 v2 "), trg_atrs.Clear().Add_many(cls, " v3 v4 "), expd_atrs.Clear().Add_many(cls, "v1 v2 v3 v4"));
}
}
class Xomw_sanitizer__fxt {
private final Xomw_sanitizer sanitizer = new Xomw_sanitizer();
@ -145,4 +161,8 @@ class Xomw_sanitizer__fxt {
byte[] src_bry = Bry_.new_u8(src_str);
Gftest.Eq__str(expd, sanitizer.Clean_url(src_bry));
}
public void Test__merge_attributes(Xomw_atr_mgr src, Xomw_atr_mgr trg, Xomw_atr_mgr expd) {
sanitizer.Merge_attributes(src, trg);
Gftest.Eq__ary__lines(expd.To_str(tmp), src.To_str(tmp), "merge_atrs");
}
}

@ -17,17 +17,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.mws.htmls; import gplx.*; import gplx.xowa.*; import gplx.xowa.mws.*;
public class Xomw_atr_mgr {
private final Ordered_hash hash = Ordered_hash_.New();
public int Len() {return hash.Len();}
public Xomw_atr_itm Get_at(int i) {return (Xomw_atr_itm)hash.Get_at(i);}
public Xomw_atr_mgr Clear() {hash.Clear(); return this;}
public void Add(byte[] key, byte[] val) {hash.Add(key, new Xomw_atr_itm(-1, key, val));}
public void Add(Xomw_atr_itm itm) {hash.Add(itm.Key_bry(), itm);}
public void Del(byte[] key) {hash.Del(key);}
public void Set(byte[] key, byte[] val) {
Xomw_atr_itm atr = Get_by_or_make(key);
atr.Val_(val);
}
private final Ordered_hash hash = Ordered_hash_.New_bry();
public int Len() {return hash.Len();}
public Xomw_atr_itm Get_at(int i) {return (Xomw_atr_itm)hash.Get_at(i);}
public Xomw_atr_itm Get_by_or_null(byte[] k) {return (Xomw_atr_itm)hash.Get_by(k);}
public Xomw_atr_mgr Clear() {hash.Clear(); return this;}
public void Del(byte[] key) {hash.Del(key);}
public void Add(Xomw_atr_itm itm) {hash.Add(itm.Key_bry(), itm);}
public void Add(byte[] key, byte[] val) {this.Add(new Xomw_atr_itm(-1, key, val));}
public void Add_or_set(Xomw_atr_itm src) {
Xomw_atr_itm trg = (Xomw_atr_itm)hash.Get_by(src.Key_bry());
if (trg == null)
@ -35,8 +32,9 @@ public class Xomw_atr_mgr {
else
trg.Val_(src.Val());
}
public Xomw_atr_itm Get_by_or_null(byte[] k) {
return (Xomw_atr_itm)hash.Get_by(k);
public void Set(byte[] key, byte[] val) {
Xomw_atr_itm atr = Get_by_or_make(key);
atr.Val_(val);
}
public Xomw_atr_itm Get_by_or_make(byte[] k) {
Xomw_atr_itm rv = (Xomw_atr_itm)hash.Get_by(k);
@ -50,11 +48,22 @@ public class Xomw_atr_mgr {
Xomw_atr_itm atr = (Xomw_atr_itm)hash.Get_by(k);
return atr == null ? null : atr.Val();
}
public void Merge(Xomw_atr_mgr src) {
int src_len = src.Len();
for (int i = 0; i < src_len; i++) {
Xomw_atr_itm src_atr = src.Get_at(i);
this.Add(src_atr);
public Xomw_atr_mgr Add_many(String... kvs) {// TEST
int len = kvs.length;
for (int i = 0; i < len; i += 2) {
byte[] key = Bry_.new_u8(kvs[i]);
byte[] val = Bry_.new_u8(kvs[i + 1]);
Add(key, val);
}
return this;
}
public String To_str(Bry_bfr tmp) { // TEST
int len = this.Len();
for (int i = 0; i < len; i++) {
Xomw_atr_itm itm = this.Get_at(i);
tmp.Add(itm.Key_bry()).Add_byte_eq();
tmp.Add(itm.Val()).Add_byte_nl();
}
return tmp.To_str_and_clear();
}
}

@ -19,18 +19,20 @@ package gplx.xowa.mws.linkers; import gplx.*; import gplx.xowa.*; import gplx.xo
import gplx.langs.htmls.*;
import gplx.xowa.mws.htmls.*;
/* TODO.XO
* titleFormatter->gePrefixedTex
* $html = HtmlArmor::getHtml($text);
* Get_link_url
* Normalise_special_page
* Merge_attribs
* Get_link_classes
* P7: $html = HtmlArmor::getHtml($text);
* P3: Get_link_url [alternate urls? EX: mw/wiki/index.php/title?]
* P2: titleFormatter->getPrefixedText [depends on redlinks]
* P1: Get_link_classes [depends on redlinks]
*/
public class Xomw_link_renderer {
private boolean expand_urls = false;
private final Xomw_html_utl html_utl = new Xomw_html_utl();
private final Xomw_atr_mgr attribs = new Xomw_atr_mgr();
private final List_adp tmp_merge_deleted = List_adp_.New();
private final Xomw_sanitizer sanitizer;
public Xomw_link_renderer(Xomw_sanitizer sanitizer) {
this.sanitizer = sanitizer;
}
// XO.MW:SYNC:1.29; DATE:2017-01-31
public void Make_link(Bry_bfr bfr, Xoa_ttl target, byte[] text, byte[] classes, Xomw_atr_mgr extra_atrs, Xomw_qry_mgr query) {
if (target.Is_known()) {
@ -57,7 +59,7 @@ public class Xomw_link_renderer {
attribs.Add(Gfh_atr_.Bry__title, prefixed_text);
}
attribs.Merge(extra_atrs);
Merge_attribs(attribs, extra_atrs);
if (text == null) {
text = this.Get_link_text(target);
@ -99,7 +101,7 @@ public class Xomw_link_renderer {
attribs.Clear();
attribs.Add(Gfh_atr_.Bry__href, url); // $attribs = ['href' => $url,] + $this->mergeAttribs($attribs, $extraAttribs);
attribs.Add(Gfh_atr_.Bry__class, Bry_.new_a7("new"));
attribs.Merge(extra_atrs);
Merge_attribs(attribs, extra_atrs);
// $prefixedText = $this->titleFormatter->getPrefixedText($target);
// if ($prefixedText !== '') {
@ -157,22 +159,35 @@ public class Xomw_link_renderer {
private Xoa_ttl Normalize_target(Xoa_ttl target) {
return Xomw_linker.Normalise_special_page(target);
}
// private function mergeAttribs( $defaults, $attribs ) {
// if ( !$attribs ) {
// return $defaults;
// }
// // Merge the custom attribs with the default ones, and iterate
// // over that, deleting all "false" attributes.
// $ret = [];
// $merged = Sanitizer::mergeAttributes( $defaults, $attribs );
// foreach ( $merged as $key => $val ) {
// # A false value suppresses the attribute
// if ( $val !== false ) {
// $ret[$key] = $val;
// }
// }
// return $ret;
// }
// XO.MW:SYNC:1.29; DATE:2017-02-01
private void Merge_attribs(Xomw_atr_mgr src, Xomw_atr_mgr trg) {
// XO.MW: ignore; src is always non-null and empty; if trg exists, it will be merged below
// if (!$attribs) {return $defaults;}
// Merge the custom attribs with the default ones, and iterate
// over that, deleting all "false" attributes.
sanitizer.Merge_attributes(src, trg);
// XO.MW:MW removes "false" values; XO removes "null" values
boolean deleted = false;
int len = trg.Len();
for (int i = 0; i < len; i++) {
Xomw_atr_itm trg_atr = trg.Get_at(i);
// A false value suppresses the attribute
if (trg_atr.Val() == null) {
tmp_merge_deleted.Add(trg_atr);
deleted = true;
}
}
if (deleted) {
len = tmp_merge_deleted.Len();
for (int i = 0; i < len; i++) {
Xomw_atr_itm atr = (Xomw_atr_itm)trg.Get_at(i);
trg.Del(atr.Key_bry());
}
tmp_merge_deleted.Clear();
}
}
public byte[] Get_link_classes(Xoa_ttl target) {
// Make sure the target is in the cache
// $id = $this->linkCache->addLinkObj($target);

@ -26,7 +26,7 @@ public class Xomw_link_holders__tst {
}
}
class Xomw_link_holders__fxt {
private final Xomw_link_holders holders = new Xomw_link_holders(new Xomw_link_renderer(), Bry_bfr_.New());
private final Xomw_link_holders holders = new Xomw_link_holders(new Xomw_link_renderer(new Xomw_sanitizer()), Bry_bfr_.New());
private final Xomw_parser_bfr pbfr = new Xomw_parser_bfr();
private final Xowe_wiki wiki;
private boolean apos = true;

@ -32,7 +32,7 @@ public class Xomw_parser {
private final Xomw_heading_wkr heading_wkr = new Xomw_heading_wkr();
private final Xomw_magiclinks_wkr magiclinks_wkr;
private final Xomw_doubleunder_wkr doubleunder_wkr = new Xomw_doubleunder_wkr();
private final Xomw_link_renderer link_renderer = new Xomw_link_renderer();
private final Xomw_link_renderer link_renderer;
private final Xomw_link_holders holders;
private final Xomw_heading_cbk__html heading_wkr_cbk;
private final Btrie_slim_mgr protocols_trie;
@ -61,6 +61,7 @@ public class Xomw_parser {
}
}
this.link_renderer = new Xomw_link_renderer(sanitizer);
this.linker = new Xomw_linker(link_renderer);
this.protocols_trie = Xomw_parser.Protocols__dflt();
this.holders = new Xomw_link_holders(link_renderer, tmp);

@ -51,9 +51,9 @@ public class Xomw_parser__tst {
, "</td></tr></table>"
, "<p><i>italics</i>"
, "<!--MWTOC-->"
, "<a class=\"external text\" rel=\"nofollow\" href=\"https://a.org\">b</a>"
, "<a rel=\"nofollow\" class=\"external text\" href=\"https://a.org\">b</a>"
, "<a href=\"/wiki/A\" title=\"A\">abc</a>"
, "<a class=\"external free\" rel=\"nofollow\" href=\"https://c.org\">https://c.org</a>"
, "<a rel=\"nofollow\" class=\"external free\" href=\"https://c.org\">https://c.org</a>"
, "a&#160;»b«&#160; !important c"
, "</p>"
));

@ -19,7 +19,7 @@ package gplx.xowa.mws.parsers.lnkes; import gplx.*; import gplx.xowa.*; import g
import org.junit.*;
public class Xomw_lnke_wkr__tst {
private final Xomw_lnke_wkr__fxt fxt = new Xomw_lnke_wkr__fxt();
@Test public void Basic() {fxt.Test__parse("[https://a.org b]" , "<a class='external text' rel='nofollow' href='https://a.org'>b</a>");}
@Test public void Basic() {fxt.Test__parse("[https://a.org b]" , "<a rel='nofollow' class='external text' href='https://a.org'>b</a>");}
@Test public void Invaild__protocol() {fxt.Test__parse("[httpz:a.org]" , "[httpz:a.org]");}
@Test public void Invaild__protocol_slash() {fxt.Test__parse("[https:a.org]" , "[https:a.org]");}
@Test public void Invaild__urlchars__0() {fxt.Test__parse("[https://]" , "[https://]");}
@ -33,9 +33,9 @@ public class Xomw_lnke_wkr__tst {
, "g"
), String_.Concat_lines_nl_apos_skip_last
( "a"
, "<a class='external text' rel='nofollow' href='https://b.org'>c</a>"
, "<a rel='nofollow' class='external text' href='https://b.org'>c</a>"
, "d"
, "<a class='external text' rel='nofollow' href='https://e.org'>f</a>"
, "<a rel='nofollow' class='external text' href='https://e.org'>f</a>"
, "g"
));
}

@ -19,51 +19,51 @@ package gplx.xowa.mws.parsers.magiclinks; import gplx.*; import gplx.xowa.*; imp
import org.junit.*;
public class Xomw_magiclinks_wkr__tst {
private final Xomw_magiclinks_wkr__fxt fxt = new Xomw_magiclinks_wkr__fxt();
@Test public void Basic() {fxt.Test__parse("a https://b.org z", "a <a class='external free' rel='nofollow' href='https://b.org'>https://b.org</a> z");}
@Test public void Basic() {fxt.Test__parse("a https://b.org z", "a <a rel='nofollow' class='external free' href='https://b.org'>https://b.org</a> z");}
@Test public void Invalid() {fxt.Test__parse("a _https://b.org z", "a _https://b.org z");}
@Test public void Tag__anch() {fxt.Test__parse("a <a title=\"https://b.org\">b</a> z", "a <a title=\"https://b.org\">b</a> z");}
@Test public void Tag__misc() {fxt.Test__parse("a <div title=\"https://b.org\">b</div> z", "a <div title=\"https://b.org\">b</div> z");}
@Test public void Interrupt() {
// ent
fxt.Test__parse("a https://b.org&lt;z" , "a <a class='external free' rel='nofollow' href='https://b.org'>https://b.org</a>&lt;z");
fxt.Test__parse("a https://b.org&lt;z" , "a <a rel='nofollow' class='external free' href='https://b.org'>https://b.org</a>&lt;z");
// hex
fxt.Test__parse("a https://b.org&#x3c;z" , "a <a class='external free' rel='nofollow' href='https://b.org'>https://b.org</a>&#x3c;z");
fxt.Test__parse("a https://b.org&#x3c;z" , "a <a rel='nofollow' class='external free' href='https://b.org'>https://b.org</a>&#x3c;z");
// dec
fxt.Test__parse("a https://b.org&#60;z" , "a <a class='external free' rel='nofollow' href='https://b.org'>https://b.org</a>&#60;z");
fxt.Test__parse("a https://b.org&#60;z" , "a <a rel='nofollow' class='external free' href='https://b.org'>https://b.org</a>&#60;z");
// num_post_proto rule
fxt.Test__parse("a https://&lt; z" , "a https://&lt; z");
}
@Test public void Interrupt__hex_dec() {// implementation specific test for mixed hex / dec
// dec-hex
fxt.Test__parse("a https://b.org&#3c;z" , "a <a class='external free' rel='nofollow' href='https://b.org&amp;#3c;z'>https://b.org&amp;#3c;z</a>");
fxt.Test__parse("a https://b.org&#3c;z" , "a <a rel='nofollow' class='external free' href='https://b.org&amp;#3c;z'>https://b.org&amp;#3c;z</a>");
}
@Test public void Separator() {
// basic; ,;.:!?
fxt.Test__parse("a https://b.org,;.:!? z" , "a <a class='external free' rel='nofollow' href='https://b.org'>https://b.org</a>,;.:!? z");
fxt.Test__parse("a https://b.org,;.:!? z" , "a <a rel='nofollow' class='external free' href='https://b.org'>https://b.org</a>,;.:!? z");
// ")" excluded
fxt.Test__parse("a https://b.org).:!? z" , "a <a class='external free' rel='nofollow' href='https://b.org'>https://b.org</a>).:!? z");
fxt.Test__parse("a https://b.org).:!? z" , "a <a rel='nofollow' class='external free' href='https://b.org'>https://b.org</a>).:!? z");
// ")" included b/c "(" exists
fxt.Test__parse("a https://b.org().:!? z" , "a <a class='external free' rel='nofollow' href='https://b.org()'>https://b.org()</a>.:!? z");
fxt.Test__parse("a https://b.org().:!? z" , "a <a rel='nofollow' class='external free' href='https://b.org()'>https://b.org()</a>.:!? z");
// ";" excluded
fxt.Test__parse("a https://b.org;.:!? z" , "a <a class='external free' rel='nofollow' href='https://b.org'>https://b.org</a>;.:!? z");
fxt.Test__parse("a https://b.org;.:!? z" , "a <a rel='nofollow' class='external free' href='https://b.org'>https://b.org</a>;.:!? z");
// ";" included b/c of ent
fxt.Test__parse("a https://b.org&abc;.:!? z" , "a <a class='external free' rel='nofollow' href='https://b.org&amp;abc;'>https://b.org&amp;abc;</a>.:!? z");
fxt.Test__parse("a https://b.org&abc;.:!? z" , "a <a rel='nofollow' class='external free' href='https://b.org&amp;abc;'>https://b.org&amp;abc;</a>.:!? z");
// ";" included b/c of hex; note that Clean_url changes "&#xB1;" to "±"
fxt.Test__parse("a https://b.org&#xB1;.:!? z", "a <a class='external free' rel='nofollow' href='https://b.org±'>https://b.org±</a>.:!? z");
fxt.Test__parse("a https://b.org&#xB1;.:!? z", "a <a rel='nofollow' class='external free' href='https://b.org±'>https://b.org±</a>.:!? z");
// ";" included b/c of dec; note that Clean_url changes "&#123;" to "{"
fxt.Test__parse("a https://b.org&#123;.:!? z", "a <a class='external free' rel='nofollow' href='https://b.org{'>https://b.org{</a>.:!? z");
fxt.Test__parse("a https://b.org&#123;.:!? z", "a <a rel='nofollow' class='external free' href='https://b.org{'>https://b.org{</a>.:!? z");
// ";" excluded b/c of invalid.ent
fxt.Test__parse("a https://b.org&a1b;.:!? z" , "a <a class='external free' rel='nofollow' href='https://b.org&amp;a1b'>https://b.org&amp;a1b</a>;.:!? z");
fxt.Test__parse("a https://b.org&a1b;.:!? z" , "a <a rel='nofollow' class='external free' href='https://b.org&amp;a1b'>https://b.org&amp;a1b</a>;.:!? z");
// ";" excluded b/c of invalid.hex
fxt.Test__parse("a https://b.org&#x;.:!? z" , "a <a class='external free' rel='nofollow' href='https://b.org&amp;#x'>https://b.org&amp;#x</a>;.:!? z");
fxt.Test__parse("a https://b.org&#x;.:!? z" , "a <a rel='nofollow' class='external free' href='https://b.org&amp;#x'>https://b.org&amp;#x</a>;.:!? z");
// ";" excluded b/c of invalid.dec
fxt.Test__parse("a https://b.org&#a;.:!? z" , "a <a class='external free' rel='nofollow' href='https://b.org&amp;#a'>https://b.org&amp;#a</a>;.:!? z");
fxt.Test__parse("a https://b.org&#a;.:!? z" , "a <a rel='nofollow' class='external free' href='https://b.org&amp;#a'>https://b.org&amp;#a</a>;.:!? z");
// num_post_proto rule
fxt.Test__parse("a https://.:!? z" , "a https://.:!? z");
}
@Test public void Clean_url() {
// basic
fxt.Test__parse("http://a᠆b.org/c᠆d" , "<a class='external free' rel='nofollow' href='http://ab.org/c᠆d'>http://ab.org/c᠆d</a>");
fxt.Test__parse("http://a᠆b.org/c᠆d" , "<a rel='nofollow' class='external free' href='http://ab.org/c᠆d'>http://ab.org/c᠆d</a>");
}
}
class Xomw_magiclinks_wkr__fxt {

Loading…
Cancel
Save