4chan-XZ/src/General/Test.ts
2023-05-05 14:42:32 +02:00

258 lines
7.5 KiB
TypeScript

/*
* decaffeinate suggestions:
* DS101: Remove unnecessary use of Array.from
* DS102: Remove unnecessary code created because of implicit returns
* DS205: Consider reworking code to avoid use of IIFEs
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md
*/
import Notice from "../classes/Notice"
import Post from "../classes/Post"
import Config from "../config/Config"
import Filter from "../Filtering/Filter"
import { c, Conf, g } from "../globals/globals"
import ImageHost from "../Images/ImageHost"
import Menu from "../Menu/Menu"
import Keybinds from "../Miscellaneous/Keybinds"
import Unread from "../Monitoring/Unread"
import $ from "../platform/$"
import $$ from "../platform/$$"
import Header from "./Header"
const Test = {
init() {
if ((g.SITE.software !== 'yotsuba') || !['index', 'thread'].includes(g.VIEW)) { return }
if (Conf['Menu']) {
const a = $.el('a',
{ textContent: 'Test HTML building' })
$.on(a, 'click', this.cb.testOne)
Menu.menu.addEntry({
el: a,
open(post) {
a.dataset.fullID = post.fullID
return true
}
})
}
const a2 = $.el('a',
{ textContent: 'Test HTML building' })
$.on(a2, 'click', this.cb.testAll)
Header.menu.addEntry({
el: a2
})
if (Unread.posts) {
const testOrderLink = $.el('a',
{ textContent: 'Test Post Order' })
$.on(testOrderLink, 'click', this.cb.testOrder)
Header.menu.addEntry({
el: testOrderLink
})
}
return $.on(d, 'keydown', this.cb.keydown)
},
assert(condition) {
if (!condition()) {
return new Notice('warning', `Assertion failed: ${condition}`, 30)
}
},
normalize(root) {
let el, i
let node
const root2 = root.cloneNode(true)
for (el of $$('.mobile', root2)) {
$.rm(el)
}
for (el of $$('a[href]', root2)) {
let {
href
} = el
href = href.replace(/(^\w+:\/\/boards\.4chan(?:nel)?\.org\/[^\/]+\/thread\/\d+)\/.*/, '$1')
el.setAttribute('href', href)
}
ImageHost.fixLinks($$('.fileText > a, a.fileThumb', root2))
for (el of $$('img[src]', root2)) {
el.src = el.src.replace(/(spoiler-\w+)\d(\.png)$/, '$11$2')
}
for (el of $$('pre.prettyprinted', root2)) {
let nodes = $.X('.//br|.//wbr|.//text()', el)
i = 0
nodes = ((() => {
const result = []
while (node = nodes.snapshotItem(i++)) {
result.push(node)
}
return result
})())
$.rmAll(el)
$.add(el, nodes)
el.normalize()
$.rmClass(el, 'prettyprinted')
}
for (el of $$('pre[style=""]', root2)) {
el.removeAttribute('style')
}
// XXX https://bugzilla.mozilla.org/show_bug.cgi?id=1021289
$('.fileInfo[data-md5]', root2)?.removeAttribute('data-md5')
const textNodes = $.X('.//text()', root2)
i = 0
while (node = textNodes.snapshotItem(i++)) {
node.data = node.data.replace(/\ +/g, ' ')
// XXX https://a.4cdn.org/sci/thread/5942502.json, https://a.4cdn.org/news/thread/6.json, https://a.4cdn.org/wsg/thread/957536.json
if (node.previousSibling?.nodeName === 'BR') { node.data = node.data.replace(/^\n+/g, '') }
if (node.nextSibling?.nodeName === 'BR') { node.data = node.data.replace(/\n+$/g, '') }
if (node.data === '') { $.rm(node) }
}
return root2
},
firstDiff(x, y) {
let x2 = x.cloneNode(false)
let y2 = y.cloneNode(false)
if (!x2.isEqualNode(y2)) { return [x2, y2] }
let i = 0
while (true) {
x2 = x.childNodes[i]
y2 = y.childNodes[i]
if (!x2 || !y2) { return [x2, y2] }
if (!x2.isEqualNode(y2)) { return Test.firstDiff(x2, y2) }
i++
}
},
testOne(post) {
Test.postsRemaining++
return $.cache(g.SITE.urls.threadJSON({ boardID: post.boardID, threadID: post.threadID }), function () {
if (!this.response) { return }
const { posts } = this.response
g.SITE.Build.spoilerRange[post.board.ID] = posts[0].custom_spoiler
for (const postData of posts) {
if (postData.no === post.ID) {
const t1 = new Date().getTime()
const obj = g.SITE.Build.parseJSON(postData, post.board)
const root = g.SITE.Build.post(obj)
const t2 = new Date().getTime()
Test.time += t2 - t1
const post2 = new Post(root, post.thread, post.board, { forBuildTest: true })
let fail = false
const x = post.normalizedOriginal
const y = post2.normalizedOriginal
if (!x.isEqualNode(y)) {
fail = true
c.log(`${post.fullID} differs`)
const [x2, y2] = Array.from(Test.firstDiff(x, y))
c.log(x2)
c.log(y2)
c.log(x.outerHTML)
c.log(y.outerHTML)
}
for (const key in Config.filter) {
if ((!key === 'General') && !((key === 'MD5') && (post.board.ID === 'f'))) {
const val1 = Filter.values(key, obj)
const val2 = Filter.values(key, post2)
if ((val1.length !== val2.length) || !val1.every((x, i) => x === val2[i])) {
fail = true
c.log(`${post.fullID} has filter bug in ${key}`)
c.log(val1)
c.log(val2)
}
}
}
if (fail) {
Test.postsFailed++
} else {
c.log(`${post.fullID} correct`)
}
Test.postsRemaining--
if (Test.postsRemaining === 0) { Test.report() }
}
}
})
},
testAll() {
g.posts.forEach(function (post) {
if (!post.isClone && !post.isFetchedQuote) {
let abbr
if (!((abbr = $('.abbr', post.nodes.comment)) && /Comment too long\./.test(abbr.textContent))) {
return Test.testOne(post)
}
}
})
},
postsRemaining: 0,
postsFailed: 0,
time: 0,
report() {
if (Test.postsFailed) {
new Notice('warning', `${Test.postsFailed} post(s) differ (${Test.time} ms)`, 30)
} else {
new Notice('success', `All correct (${Test.time} ms)`, 5)
}
return Test.postsFailed = (Test.time = 0)
},
cb: {
testOne() {
Test.testOne(g.posts.get(this.dataset.fullID))
return Menu.menu.close()
},
testAll() {
Test.testAll()
return Header.menu.close()
},
testOrder() {
let x
const list1 = ((() => {
const result = []
for (x of Unread.order.order()) {
result.push(x.ID)
}
return result
})())
const list2 = ((() => {
const result1 = []
for (x of ($$((g.SITE.isOPContainerThread ? `${g.SITE.selectors.thread}, ` : '') + g.SITE.selectors.postContainer))) {
result1.push(+x.id.match(/\d*$/)[0])
}
return result1
})())
const pass = (function () {
if (list1.length !== list2.length) { return false }
for (let i = 0, end = list1.length; i < end; i++) {
if (list1[i] !== list2[i]) { return false }
}
return true
})()
if (pass) {
return new Notice('success', `Orders same (${list1.length} posts)`, 5)
} else {
new Notice('warning', 'Orders differ.', 30)
c.log(list1)
return c.log(list2)
}
},
keydown(e) {
if (Keybinds.keyCode(e) !== 'v') { return }
if (['INPUT', 'TEXTAREA'].includes(e.target.nodeName)) { return }
Test.testAll()
e.preventDefault()
return e.stopPropagation()
}
}
}
export default Test