Commit graph

217 commits

Author SHA1 Message Date
Ed Sanders da64c43ccc Show thread metadata in section headers
Bug: T269950
Change-Id: Ifa47ddcbccf288be0bbecd5961eab7c5122aab7b
2022-06-23 17:17:09 +01:00
Ed Sanders 1f002f812f Convert more self:: to static::
These are from patches that were already in progress before
we did the first run of conversions.

Change-Id: Id883e693a518130cfcc80bfd0f2874cbd9593446
2022-06-14 22:53:00 +01:00
jenkins-bot cb17181fa4 Merge "Prefer late static binding over self::" 2022-06-09 16:29:48 +00:00
Ed Sanders af54bae2ec Prefer late static binding over self::
While in many cases the class will never be sub-classed, it's easier
just to always use static:: and not worry about predicting which
classes might have problems in the future.

Change-Id: I23072a1701b5acf62bb3379a877de97627d8fcf3
2022-06-09 15:12:48 +01:00
Ed Sanders c96c076a4e Follow-up I46a58f6a: Add missing test runner
Change-Id: I17438cf55959d146265f3aafa5940f7fe0de19e1
2022-06-07 16:09:04 +01:00
Bartosz Dziewoński c7723baf72 CommentParser: Replace uses of Title with TitleValue
Another small step towards removing the reliance on global state.

Change-Id: Ifb4a5bcbef6606d02f1c7aa7385d72822cb0bad0
2022-03-18 18:24:34 +00:00
Bartosz Dziewoński b68832ace0 Fix parsing of non-English titles in tests
We were calling Title::newFromText() before setupEnv(), which meant
that the title for each test case was parsed using the default rules
for English, rather than the rules for the specified wiki.

This only makes a practical difference for tests with self-links.
Changed the only such test to demonstrate the fix.

Change-Id: I45561f1c9f0d149e2b743f0000b742bf6fc014af
2022-03-18 18:24:07 +00:00
Bartosz Dziewoński 77614a2d02 tests: Fix root node / container handling
Since times immemorial, and for reasons lost to history, our test code
was adding an extra <div> wrapper before parsing the HTML used for
tests. This wasn't a problem, until now, because I want to add some
tests for T303396 that need to check that the *real* wrappers present
in some test cases are handled correctly.

Changes to test cases mostly remove a leading "0/" from serialized
ranges, corresponding to removing the extra wrapper.

Change-Id: Ia50e3590538c8cd274b02d2a937ba1a3fbb4ac89
2022-03-10 18:43:58 +01:00
Bartosz Dziewoński 4c29304484 CommentParser: Avoid using a dynamic undeclared property
Change-Id: Iefa8dea83bc0d31b9c6b3509189eeaa652dd9ea0
2022-03-08 23:30:11 +00:00
Bartosz Dziewoński 063174e71c Use instanceof for checking for text/element nodes in PHP
It is friendlier for static analysis tools like Phan, which can't
infer anything from the `->nodeType === …` checks, and we were already
using it in most places.

Fix newly revealed Phan failures (and one unneeded suppression).

Change-Id: Id789f05e16a210f7ba22ca7514587c392fac0741
2022-03-08 23:28:39 +00:00
jenkins-bot 3c91a800ed Merge "Improve detecting already signed comments" 2022-03-02 14:14:13 +00:00
Ed Sanders dc8b4e8d4f Highlight all comments since the oldest in a thread bundle
For topic subscriptions, further restrict this to comments
in the same thread.

Bug: T302014
Change-Id: Ifba218871122901031a891034e709b886fc406da
2022-02-28 21:58:10 +00:00
Bartosz Dziewoński 0ecc8a4c05 Improve detecting already signed comments
Previously, we required a signature at the end of the comment.
This was a pretty rough heuristic that did not correctly handle
many comments that we would consider entirely properly signed
in CommentParser (e.g. comments wrapped in formatting like
<small>…</small>, comments with a post-scriptum or in parentheses,
or comments generated by various templates).

Now we process the user input using the same code that adds reply
links, and only add a signature when we detect that there really
isn't a signature (including template-generated), or if the signature
is in the wrong place and would result in the reply link showing up
in the wrong place as well (not at the end of the comment).

Bug: T278442
Bug: T268558
Bug: T278355
Bug: T291421
Bug: T282983
Change-Id: I46b6110af328ebdf93b7dfc2bd941e04391a1599
2022-02-21 21:21:26 +00:00
Bartosz Dziewoński 85165543f4 CommentParser: Inject a forgotten service
Also sort alphabetically.

Change-Id: I9e77c4aa1fba930f382e3c4f17ac0504c2f06668
2022-02-21 20:15:54 +01:00
Bartosz Dziewoński 8e44b43df0 Split off ThreadItemSet from CommentParser
Goal:
-----
Finishing the work from Iadb7757debe000025e52770ca51ebcf24ca8ee66
by changing CommentParser::parse() to return a data object, instead of
the whole parser.

Changes:
--------
ThreadItemSet.php:
ThreadItemSet.js:
* New data class to access the results of parsing a discussion. Most
  methods and properties are moved from CommentParser with no changes.

CommentParser.php:
Parser.js:
* parse() returns a new ThreadItemSet.
* Remove methods moved to ThreadItemSet.
* Placeholder headings are generated slightly differently, as we process
  things in a different order.
* Grouping threads and computing IDs/names is no longer lazy. We always
  needed IDs/names anyway.
* computeId() explicitly uses a ThreadItemSet to check the existing IDs
  when de-duplicating.

controller.js:
* Move the code for turning some nodes annotated by CommentFormatter
  into a ThreadItemSet (previously a Parser) from controller#init to
  ThreadItemSet.static.newFromAnnotatedNodes, and rewrite it to handle
  assigning parents/replies and recalculating legacy IDs more nicely.
* mw.dt.pageThreads is now a ThreadItemSet.

Change-Id: I49bfe019aa460651447fd383f73eafa9d7180a92
2022-02-21 16:22:32 +00:00
Bartosz Dziewoński 4613ae78e7 Change CommentParser into a service
Goal:
-----
To have a method like CommentParser::parse(), which just takes a node
to parse and a title and returns plain data, so that we don't need to
keep track of the config to construct a CommentParser object (the
required config like content language is provided by services) and
we don't need to keep that object around after parsing.

Changes:
--------
CommentParser.php:
* …is now a service. Constructor only takes services as arguments.
  The node and title are passed to a new parse() method.
* parse() should return plain data, but I split this part to a separate
  patch for ease of review: I49bfe019aa460651447fd383f73eafa9d7180a92.
* CommentParser still cheats and accesses global state in a few places,
  e.g. calling Title::makeTitleSafe or CommentUtils::getTitleFromUrl,
  so we can't turn its tests into true unit tests. This work is left
  for future commits.

LanguageData.php:
* …is now a service, instead of a static class.

Parser.js:
* …is not a real service, but it's changed to behave in a similar way.
  Constructor takes only the required config as argument,
  and node and title are instead passed to a new parse() method.

CommentParserTest.php:
parser.test.js:
* Can be simplified, now that we don't need a useless node and title
  to test internal methods that don't use them.

testUtils.js:
* Can be simplified, now that we don't need to override internal
  ResourceLoader stuff just to change the parser config.

Change-Id: Iadb7757debe000025e52770ca51ebcf24ca8ee66
2022-02-19 19:51:57 +01:00
Bartosz Dziewoński 99b5de8038 Split Data class into ResourceLoaderData and LanguageData
The Data class contained utilities for two unrelated purposes.
Split each half to a separate class.

Notably, this improves the signature of the getLocalData() function.

Change-Id: Icde615fb9d483fee1f352c34909b37f8ffde8081
2022-02-19 19:37:34 +01:00
Bartosz Dziewoński ae9f26a9e5 Various code quality tweaks
(suggested by PhpStorm)

composer.json:
* Document required PHP extensions

Parser.js:
* Remove incorrect param documentation
* Fix some typos in comments (missing parentheses)

CommentParser.php:
* Fix some typos in comments (missing parentheses)

ImmutableRange.php:
* Remove unused property
* Add a `throw` to indicate that code path is unreachable

SubscribedNewCommentPresentationModel.php:
* Add missing `return false`

CommentParserTest.php:
* Remove unnecessary pass-by-reference

CommentModifierTest.php:
* Remove unused variable

CommentParserTest.php:
* Don't construct Element objects directly. PHP's DOMElement allows
  it, but Parsoid/Dodo's doesn't, and we use the latter for static
  analysis. This generates all kinds of confusing warnings.

Change-Id: Ia9598ebea0e99830dd485296e94a9d96acc4b258
2022-02-19 19:36:52 +01:00
Bartosz Dziewoński 165ca9b847 Improve CommentModifier::addReply() API for re-use and testing
Goal: To be able to re-use or test the transformations we previously
  performed in addWikitextReply() / addHtmlReply(), without requiring
  a Comment object or adding the result as a reply.

Change-Id: I040c4be9b6b9bddba661f30fd0566f8850673074
2022-02-03 21:12:48 +00:00
Bartosz Dziewoński b7cbd714ca Add tests for bullet indentation
Bug: T259864
Change-Id: If38016564b67ee7217fe7328b40973aa244ff467
2022-01-14 00:27:04 +00:00
jenkins-bot 7f329ca9a2 Merge "Enable wikis to customize the syntax used for replies" 2022-01-12 21:32:49 +00:00
Ed Sanders 34011b7a07 Parser: Pass in title of page being parsed
Will be used to parse selflinks in the future.

Change-Id: I2bc29d1c5c69cb6309f582f162f9af7d96ce8913
2022-01-12 21:17:59 +00:00
Ed Sanders 1fed7115f4 Tests: Add original titles to test cases
These are not used for anything yet, but soon the parser will
want to know the title of the page it is parsing.

Change-Id: I02fa5d63fae78f3e92032d93bc27ac5c744faecb
2022-01-12 22:16:03 +01:00
Bartosz Dziewoński 7b1053300a Enable wikis to customize the syntax used for replies
The following values for configuration variables are supported:
$wgDiscussionToolsReplyIndentation = 'invisible'; (default)
$wgDiscussionToolsReplyIndentation = 'bullet';

Bug: T259864
Change-Id: Icefad79630adc6ed35687498614e6a03ede1451b
2022-01-12 20:54:04 +00:00
jenkins-bot cd8f426ad4 Merge "Add missing typehints" 2021-12-02 21:13:49 +00:00
Bartosz Dziewoński f68f91e883 Set $wgUsePigLatinVariant = false while running tests
Data used for the tests assumes there are no variants for English,
and some tests fail when there are. Correct behavior with language
variants is tested using other languages.

Change-Id: I348a0ba0389c2a18644ce5e05c7f37d8f26a8c55
2021-12-01 23:25:30 +01:00
Ed Sanders 8e4f08182e Add missing typehints
Change-Id: Ia25c5bea1834a3fdd26f32a9d5ed097789329824
2021-12-01 14:57:09 +00:00
Bartosz Dziewoński 0d57aa9762 Automatic topic subscriptions (on any edit)
Bug: T284836
Change-Id: Ia42ad087218fd91a0cdd1664157d1049738e3c01
2021-11-15 22:45:42 +01:00
Ed Sanders 0fba9b0048 Suppress events from comments that are more than 10 minutes old
Bug: T290803
Change-Id: Ic0e23f439eef8a1b785f408d4557bec0abe9104b
2021-11-09 16:37:46 +00:00
Ed Sanders a86d308d66 CommentItem.php: Store timestamp object instead of string
We do something similar in CommentItem.js with a moment object.
The object can be converted to a string when required.

Change-Id: Id7221e9201db0d89c3b771574634c878c9515ca0
2021-11-09 16:37:45 +00:00
Alexander Vorwerk 0935bb1271 MediaWikiTestCase -> MediaWikiIntegrationTestCase
MediaWikiTestCase has been renamed to MediaWikiIntegrationTestCase in 1.34.

Bug: T293043
Change-Id: I485c5c5f0376ab60cdec49e934c6e7eea8c9feb5
2021-10-12 00:40:27 +02:00
Bartosz Dziewoński c1f4668806 Change CommentParser and ImmutableRange to use offsets in codepoints instead of bytes
The PHP DOM extension measures lengths and offsets in Unicode codepoints.
Our PHP code used UTF-8 bytes, causing some offsets to be slightly off.
Now it mostly uses Unicode codepoints as well (we're forced to use bytes
in a few places, because preg_match returns offsets in bytes).

In practice, this had no visible effect to the user. It caused the
markers `<span data-mw-comment-end="..."></span>` to be placed at
the end of their container instead of the correct position when the
timestamp contained multibyte characters (e.g. "ź" in Polish); but
the correct position is usually at the end of the container anyway.

In the test cases, the only difference is placing these markers before
a trailing line break inside `<p>...</p>` tags rather than before it.

The patch also accidentally fixes another bug, where element nodes
with no children (mostly <img>) were incorrectly excluded when calling
cloneContents(), because they were treated as if they were text nodes.

Change-Id: Iccdccf1078598f4b62cab96225e9c85a4c0e93ee
2021-09-27 19:04:16 +00:00
Bartosz Dziewoński a6a547f2b2 Add some tests covering ThreadItem::getHTML() and related methods
* ThreadItem::getText
* CommentItem::getBodyText (used when generating notifications)
* ThreadItem::getHTML (may soon be used in API)
* CommentItem::getBodyHTML (may soon be used in API)
* ImmutableRange::cloneContents (the common implementation for all
  of the above)

The outputs are only lightly reviewed. This is mostly meant to
document the current behavior rather than the expected behavior,
to avoid making unintentional changes while refactoring.

Change-Id: I14471ee4969aa3d0b5577d9de2a6d4462fab4d09
2021-08-24 07:54:09 +02:00
Bartosz Dziewoński ad04b24ffd Create a hidden revision tag for talk page comments
Bug: T262107
Depends-On: I21159d03eebaf46ad94f4273ba698a59b8019185
Change-Id: Iceddfaf6a4bcc5e8b5c85c8cd5638bf14aa7db03
2021-08-16 15:42:51 +00:00
Bartosz Dziewoński 47510a22f3 EventDispatcher: Fix ignoring level 3+ headings
The code (prior to d25825a754) assumed
that level 3+ headings would always follow a level 2 heading or the
placeholder heading, but we don't generate a placeholder heading if
there are no comments in section zero.

Add more tests to confirm that comments under level 3+ headings (that
are not sub-headings of level 2), and level 1 headings, are ignored
when generating notifications, and do not mess with normal headings.

Bug: T288775
Change-Id: Ic57b56752a4797cb01234f66e0ed7b849752bd70
2021-08-16 15:42:06 +00:00
Bartosz Dziewoński b46893eb7d Remove pointless uses of preserveWhiteSpace property
This DOMDocument property has no effect, because we do not use
DOMDocument methods for parsing HTML, but rather DOMUtils::parseHTML()
provided by Parsoid.

Change-Id: I1d9e73e53f2d44f41cf9dcda4f06ac8647671096
2021-08-09 23:45:48 +02:00
jenkins-bot 10c23d0eb1 Merge "Deal with document body consistently" 2021-08-06 03:08:28 +00:00
Bartosz Dziewoński 8de8d80cde Deal with document body consistently
Use `DOMCompat::getBody( ... )` as a nicer getter than
`->getElementsByTagName( 'body' )->item( 0 )`.

Remove overly defensive checks and redundant annotations on its
return value. Since we're dealing with HTML documents throughout,
the document body is guaranteed to exist.

We previously needed some of them to convince Phan when it thought
the body may be null, but this seems to no longer be needed.

Change-Id: If7aee7b6adbfa78269c7ba28b26a6eaa21fe935b
2021-08-03 15:12:55 +02:00
Bartosz Dziewoński 80704b6e80 Test cases for interactions with events generated by base Echo
Adding test cases in a separate commit to make it easier to review how
the test results change after I98fbca8e.

* For mentions, the 'mentioned-users' extra parameter is copied to our
  event (which is then used to avoid duplicate notifications).
* For user talk page edit, nothing special happens right now (we use
  the target page title to avoid duplicate notifications, but this is
  not apparent from the test case, since page titles are not present).

Bug: T281590
Bug: T253082
Change-Id: I153e7735f63f1e2643ed881281d807313cd699c3
2021-08-01 12:27:33 +02:00
Bartosz Dziewoński 78cb03c471 Test cases for comments posted in close succession
Adding test cases in a separate commit to make it easier to review how
the test results change.

As expected, in every case, no notifications are generated right now.

Bug: T285528
Change-Id: I25308754112c521d2db8c54ef0c82373456d9e31
2021-08-01 12:27:33 +02:00
C. Scott Ananian 25272e7a4a Don't refer directly to PHP dom extension classes; avoid nonstandard behavior
These changes ensure that DiscussionTools is independent of DOM
library choice, and will not break if/when Parsoid switches to an
alternate (more standards-compliant) DOM library.

We run `phan` against the Dodo standards-compliant DOM library,
so this ends up flagging uses of non-standard PHP extensions to
the DOM.  These will be suppressed for now with a "Nonstandard DOM"
comment that can be grepped for, since they will eventually
will need to be rewritten or worked around.

Most frequent issues:

* Node::nodeValue and Node::textContent and Element::getAttribute()
can return null in a spec-compliant implementation.  Add `?? ''` to
make spec-compliant results consistent w/ what PHP returns.

* DOMXPath doesn't accept anything except DOMDocument.  These uses
should be replaced with DOMCompat::querySelectorAll() or similar
(which end up using DOMXPath under the covers for DOMDocument any way,
but are implemented more efficiently in a spec-compliant
implementation).

* A couple of times we have code like:
  `while ($node->firstChild!==null) { $node = $node->firstChild; }`
and phan's analysis isn't strong enough to determine that $node is still
non-null after the while.  This same issue should appear with DOMDocument
but phan doesn't complain for some reason.

One apparently legit issue:

* Node::insertBefore() is once called in a funny way which leans on
the fact that the second option is optional in PHP.  This seems to be
a workaround for an ancient PHP bug, and can probably be safely
removed.

Bug: T287611
Bug: T217867
Change-Id: I3c4f41c3819770f85d68157c9f690d650b7266a3
2021-07-30 18:15:40 -04:00
C. Scott Ananian 5203d30ea6 Use DOMCompat::newDocument() to create a new Document
For compatibility with Parsoid's document abstraction (Parsoid may
switch to an alternate DOM library in the future), don't explicitly
create a new document object using `new DOMDocument`; instead use
the Parsoid wrapper `DOMCompat::newDocument()`.  This ensures that
the Document object created will be compatible with Parsoid.

There are a number of other subtle dependencies on the PHP `dom`
extension in DiscussionTools, like explicit `instanceof` tests; those
will be tweaked in a follow-up patch
(I3c4f41c3819770f85d68157c9f690d650b7266a3) since they do not affect
correctness so long as Parsoid is aliasing Document to a subclass of
the built-in DOMDocument.  Similarly, the Phan warnings we suppress
do not cause runtime errors (because of the fixes included in
c5265341afd9efde6b54ba56dc009aab88eff83c) but phan will be happier
once the follow-up patch lands and aligns all the DOM types.

Bug: T287611
Depends-On: If0671255779571a91d3472a9d90d0f2d69dd1f7d
Change-Id: Ib98bd5b76de7a0d32a29840d1ce04379c72ef486
2021-07-30 18:15:11 -04:00
Bartosz Dziewoński d0e4aeaecb Fix notifications when new comment is under subheading
The user interface only allows you to subscribe to level 2 headings.
But we would generate events for whatever heading was the closest,
If it was e.g. level 3, no one would receive that notification.

Now we generate events for the closest level 2 heading, or we don't
generate the event at all if there isn't one (if the only headings are
of level 3 and below, or level 1, or if the comment is added before
the first heading on the page).

Bug: T286736
Change-Id: Iae99853070e353ab81c9cc29ef1d53c877adfc66
2021-07-24 05:28:10 +02:00
Bartosz Dziewoński 801b57b0f4 Add PHPUnit integration tests for EventDispatcher
Bug: T286608
Change-Id: I711483be80d455f4439e96d37844ee4552619a92
2021-07-24 05:28:04 +02:00
libraryupgrader b0884b177c build: Updating dependencies
composer:
* mediawiki/mediawiki-codesniffer: 36.0.0 → 37.0.0

npm:
* postcss: 7.0.35 → 7.0.36
  * https://npmjs.com/advisories/1693 (CVE-2021-23368)
* glob-parent: 5.1.1 → 5.1.2
  * https://npmjs.com/advisories/1751 (CVE-2020-28469)
* trim-newlines: 3.0.0 → 3.0.1
  * https://npmjs.com/advisories/1753 (CVE-2021-33623)

Change-Id: I7a71e23da561599da417db3b3077b78d91173bbc
2021-07-22 16:29:04 +00:00
Bartosz Dziewoński 9c8d709b8a Use placeholder localisation messages in CommentFormatter tests
Otherwise they will fail whenever translations are updated
(and they are failing right now).

Change-Id: I849c57b86d36fb6c7739cc31a74df741e08462f4
2021-06-02 21:46:36 +02:00
libraryupgrader 12fb65b9f1 build: Updating composer dependencies
* mediawiki/mediawiki-codesniffer: 35.0.0 → 36.0.0
* php-parallel-lint/php-parallel-lint: 1.2.0 → 1.3.0

Change-Id: I5c152292e83e7f3441e2c08b7d0ad23ac90f194b
2021-05-05 11:14:52 +00:00
Bartosz Dziewoński 475aa80057 Fetch user's topic subscriptions on the page in a single query
Previously, we have made a query per each topic on the page.

Bug: T281000
Change-Id: I1029e62a65fc191ca37e1178ea7ffc55afafa1b9
2021-04-28 21:54:26 +00:00
Ed Sanders 722a4e5198 Avoid splitting ParserCache on user language
Bug: T280295
Change-Id: I87eab83803d24c11db4d723377bf7b40390b2e70
2021-04-21 11:57:30 +00:00
Bartosz Dziewoński 5103e651be Add tests for CommentFormatter::postprocessTopicSubscription
Change-Id: Ief9648b8805fadcc170c54b627eb669cc8b907b6
2021-04-21 11:57:25 +00:00
Bartosz Dziewoński 4bbfe6cb5d Rename CommentFormatter::addReplyLinks
Bug: T280351
Change-Id: I0d7627d63407e11cca6091f78e4d440eec6efa91
2021-04-21 11:24:03 +00:00
Bartosz Dziewoński 42ce942c86 Introduce comment "names" to identify comments across revisions/pages
The existing comment IDs can't be used to find the same comment on
a different revision or page (when it's transcluded), because they
depend on the comment's parent and its position on the page.

Comment names depend only on the author and timestamp. The trade-off
is that they can't distinguish comments posted within the same minute,
or in the same edit, so we will still need the IDs sometimes.

Prefer using comment names when replying, if they're not ambiguous.
This fixes T273413 and T275821.

Heading names depend on the author and timestamp of the oldest comment.
This way we don't have to detect changes to the heading text, but we
can't distinguish headings without any comments.

Bug: T274685
Bug: T273413
Bug: T275821
Change-Id: Id85c50ba38d1e532cec106708c077b908a3fcd49
2021-03-23 16:08:42 +00:00
Bartosz Dziewoński a103abb8ae Ignore warnings about legacy IDs in tests
Change-Id: I3c74b4e65aac9b84494917547cce7eb6a75995b4
2021-03-18 20:42:03 +01:00
Bartosz Dziewoński 44f2209abf Trim signatures when added in an empty existing node, too
Add unit tests for appendSignature().

Bug: T276612
Change-Id: Ic44c52f4d54492e092f9396c626380e2637b6f0f
2021-03-08 23:38:46 +00:00
Bartosz Dziewoński 5a07139249 CommentFormatterTest: Avoid re-serializing the HTML
The code we're testing already produces a string of serialized HTML,
no need to parse and re-serialize it.

Also, we recently learned that the precise format matters here
(T274709), and now this test *actually* covers the fix for that bug.
Follow-up to 5b26e9664b.

As a downside, this test might now spuriously fail if the format of
the output of Parsoid's XMLSerializer changes. Hopefully that won't
happen too often.

Change-Id: I69b514f545e47dcb437fb39a83edb8e2f19ed99b
2021-03-01 21:30:28 +01:00
Bartosz Dziewoński efe95494a8 Improve signature detection to handle formatting on the timestamp
Now it detect signatures generated by en.wp's {{Undated}} template,
and signatures of people who do weird stuff to the timestamps.

Bug: T275938
Change-Id: I27b07f6786ca5433a3c02a5fe68e4716d41401bb
2021-02-27 02:33:30 +01:00
Bartosz Dziewoński 1c3fada1fb Make CommentUtilsTest a proper unit test
Documentation:
https://www.mediawiki.org/wiki/Manual:PHP_unit_testing/Writing_unit_tests_for_extensions#Two_types_of_tests

We can do this because the tested methods do not depend on any globals
or on MediaWiki being installed.

In addition to being the new hotness, MediaWikiUnitTestCase allows the
test classes that use it instead of MediaWikiTestCase to start up much
faster. In my testing, running this test case individually now takes
0.35s, compared to 1.1s before.

Try:
* With new code:
  time php tests/phpunit/phpunit.php extensions/DiscussionTools/tests/phpunit/unit/CommentUtilsTest.php
* With old code:
  time php tests/phpunit/phpunit.php extensions/DiscussionTools/tests/phpunit/CommentUtilsTest.php

Change-Id: I771b1f3d101a394ee869e42547d9ae7839397752
2021-02-02 15:37:17 +01:00
Ed Sanders 2908c2808d Move Hooks::addReplyLinks to CommentFormatter
Change-Id: I9f5483cd801f48efff22cba045ae6851da9719fd
2021-02-01 22:35:04 +00:00
Ed Sanders 47aea0b160 Use tabs for indentation in JSON test files
Change-Id: I1d8f8b33b19bcff249ad08dfe687f87f5e5bf9bf
2021-01-27 00:25:15 +00:00
Bartosz Dziewoński 8f42c74985 Fix skipping to the end of paragraph, now it considers nested tags
Add yet another tree walking utility: CommentUtils::linearWalk().
Unlike TreeWalker, it allows handling the beginnings and ends of nodes
separately – kind of like parsing a XML token stream, or kind of like
VisualEditor's linear model.

(Add unit tests for this utility. The simple.html test case is copied
from [VisualEditor/VisualEditor]/demos/ve/pages/simple.html.)

Use this utility to stop skipping when we reach either a closing or
opening block node tag. Previously we'd skip over such tags inside
nested "transparent" nodes (like <a>, <del>, or apparently <font>).

Bug: T271385
Change-Id: I201a942eb3a56335e84d94e150ec2c33f8b4f4e0
2021-01-18 18:20:20 +00:00
Ed Sanders 8b71a2b5dc Load site config data in CommentFormatter tests
This fixes missing reply links in arwiki test output.

Change-Id: I24d3b8371a8343c4445c716fadf0692be0924eed
2021-01-08 23:03:33 +00:00
Ed Sanders 9ba6c3d159 CommentItem/HeadingItem: Make more constructor args required
This ensures the getters always return the promised types.

Change-Id: I1a3c909f5395463ef7a89d896ead1520b2a17509
2021-01-08 20:45:29 +00:00
Ed Sanders 0d2d3b16b8 Pass interface language object to addReplyLinks
Change-Id: I8a5562e11df3ad6430db48020d6005d0c4fd6834
2021-01-08 21:43:21 +01:00
Ed Sanders 32cd64ec6a Use Parsoid DOMCompat/DOMUtils in CommentFormatter
As CommentFormatter no longer needs HTMLFormatter, remove
the inheritance and make addReplyLinks a static method.

Testing locally this is marginally slower, going from 2.55s
to 2.9s for the CommentFormatterTest case.

Bug: T266317
Bug: T267973
Change-Id: If69749cae678a1647a138d782a32032189f55cec
2020-11-16 22:28:07 +00:00
Bartosz Dziewoński 31f6d44bf6 Move warnings stuff from CommentItem to ThreadItem
After recent changes allowing ThreadItems to have IDs, they can now
also have warnings about duplicate IDs.

Bug: T267035
Change-Id: If3edfe34e6e29741e29fac8946a3c88badc4ab7f
2020-11-02 20:07:23 +00:00
Bartosz Dziewoński 044bc50fb6 Fix some TODOs about test data
We avoided fixing these because it causes changes in just about all of
the test data, which is annoying when reviewing or blaming changes.

But the previous several commits also caused changes in just about all
of the test data, so we might as well do this too.

Change-Id: I83b64d83b6f12c04dc06c0cadff7cdd89417e137
2020-10-22 00:21:04 +00:00
Bartosz Dziewoński 3137d76f40 Connect sub-threads to their parent threads
Our threads now also contain all replies to their sub-threads.
This is similar to how sections work in MediaWiki, where the parent
section also contains the content of all the lower-level sections.
We're going to need this for notifications about replies in a thread.

Bug: T264478
Change-Id: I241fc58e2088a7555942824b0f184ed21e3a8b6f
2020-10-22 02:05:02 +02:00
Bartosz Dziewoński 284115a184 Add tests for CommentFormatter
I haven't really reviewed the outputs, but at least a) they don't
crash b) they will fail if the output suddenly changes (which could
cause problems due to caching).

Bug: T252555
Change-Id: I1bbcbc5dd17ce1e24b3622062f5e8df4baf5f389
2020-10-20 04:13:25 +02:00
Bartosz Dziewoński a29c49ae70 Better way to update expected test outputs
Use an environment variable "DISCUSSIONTOOLS_OVERWRITE_TESTS".

Change-Id: I017112b7d6b1df9497f01f3f97f34e0935ca16f8
2020-10-19 23:53:30 +02:00
jenkins-bot a2cf9cc978 Merge "Correctly generate timezone abbreviations for parsing" 2020-10-15 15:24:14 +00:00
Bartosz Dziewoński a1dc3a4896 Correctly generate timezone abbreviations for parsing
Also, add tests covering this and the previous bug fixes in this code
(T259818, T261706).

Note that the test data added in tests/cases/ doesn't exactly match
the entire configuration of the wiki, only the parts we want to cover.
This is unlike the data in tests/data/, which was literally copied
from the relevant wikis, and which is used as input for other tests.

Bug: T265500
Change-Id: I29a59a5952f6dc9fb5910434bb6bcc9dcdaa01a9
2020-10-15 12:11:25 +00:00
Bartosz Dziewoński c464d995c3 tests: Fix some typos
Change-Id: I99b14b8aae7416bd7a25f563fb07e35dc98a39e7
2020-10-14 22:14:59 +02:00
Bartosz Dziewoński 329df8c953 Parsing discussions converted to language variants
* Export parser data (date format, digits, timezone names, and
  messages for weekday/month names) converted to language variants
* Update the parsers to try matching using every variant, in case
  the page is displayed in non-default variant (and to avoid
  problems with incomplete variant conversion)

Bug: T259818
Change-Id: I04d73992cd31ce06fa79f87df0c0a53d7efc3c58
2020-09-16 22:07:07 +00:00
Bartosz Dziewoński 084f45128c Improve and document the files in tests/data/
* Remove 'wgMetaNamespace' and 'wgMetaNamespaceTalk', the same data
  exists in 'wgFormattedNamespaces'.

* Rename 'wgContentLang' to 'wgContentLanguage', to match its real
  name in JS config. MediaWiki doesn't use 'wgContentLang' anywhere,
  although the related PHP global is called $wgContLang.

* Document how I made these files, previously only mentioned in the
  commit message of e9c401e3aa.

Change-Id: I67f962812c155aedf41154e0d837e7feb5af972d
2020-09-01 01:50:33 +02:00
jenkins-bot 4be90d7494 Merge "Re-apply new reply API patches (again)" 2020-08-25 11:11:12 +00:00
jenkins-bot 5f8214a2e4 Merge "parser: Fix comment ranges when timestamp has entities" 2020-08-20 12:10:43 +00:00
Bartosz Dziewoński b706eac8bc Re-apply new reply API patches (again)
This reverts commit 4d7c98b97c.

Change-Id: I4100521efb687ec324d25e273a9c986fd5dac0d0
2020-08-19 20:05:42 +00:00
Bartosz Dziewoński 4d7c98b97c Revert new reply API (again)
Causes page corruption, in a new way we haven't seen before.

* Revert "Move page updating logic to controller.js"
  This reverts commit 54fdc6de06.
* Revert "ReplyWidget: Move clear methods from #teardown to #clear"
  This reverts commit 9b811a94e0.
* Revert "ApiDiscussionToolsEdit: Do not pass 'basetimestamp'"
  This reverts commit 7de5938a6f.
* Revert "Use DOMCompat::getOuterHTML instead of doc->saveHTML()"
  This reverts commit 7b2448d2f0.
* Revert "CommentController: Remove remains of client-side edit conflict handling"
  This reverts commit 2d038af705.
* Revert "Restore error message for when comment is deleted while replying"
  This reverts commit 655c0526d6.
* Revert "Use transcluded from API to avoid ever fetching Parsoid DOM in client"
  This reverts commit 9d0fc184fe.
* Revert "Create a 'transcludedfrom' API endpoint"
  This reverts commit 5d8f3b9051.
* Revert "Edit API for replies"
  This reverts commit 8829a1a412.

Bug: T259855
Change-Id: I6419408c6194ec0afa6b8ee604b12c1a24c6ac7b
2020-08-13 20:19:29 +02:00
Bartosz Dziewoński 375bfe028e parser: Fix comment ranges when timestamp has entities
Previously, parser would output offsets that don't exist in their
containers, because we were pretending that entities are parts of
their neighboring text nodes.

Turns out it's much easier to do it right when going backwards.

Change-Id: I9bccca2d403f1a976ae517449989170cdd99721e
2020-08-11 20:41:06 +02:00
Bartosz Dziewoński f0225243e0 tests: Fix some issues with overwriting outputs from PHP tests
Follow-up to ccd9e411d2.

* Fix variable name in CommentTestCase::overwriteHtmlFile()
* Overwrite before assertions, because they abort execution if they fail

Change-Id: I5bba016ba93f9dd1994325ae82c3105ba11cf033
2020-08-11 06:45:45 +02:00
Ed Sanders 7b2448d2f0 Use DOMCompat::getOuterHTML instead of doc->saveHTML()
The latter results in lots of extra HTML entity encoding.

The former is built by the Parsing team and appears to result
in no unexpected changes elsewhere in the document.

As Parsoid's selser relies on HTML fragments being byte-for-byte
equal, these changes were resulting in wikitext normalisations
in untouched parts of the document ("dirty diffs").

Bug: T259855
Change-Id: Ib3cb605911e690ec3e8c2f9df25fd1a2e2849d7e
2020-08-07 21:31:38 +02:00
Bartosz Dziewoński ccd9e411d2 Allow updating the expected results when running PHP tests
This is similar to the code we already have in JS tests, but instead
of printing to the console where you have to copy-paste from, it just
overwrites the files.

Also, update all of the expected results by this method.

Changes in the expected outputs:
* In JSON files, the "warnings" are now always in the same place
  regardless of the type of the warning.
* In all HTML files, self-closing tags now include the trailing slash,
  some characters are no longer encoded as entities when not necessary,
  and attributes may be single-quoted when that makes them shorter.
* In Parsoid HTML files, the header is no longer terribly mangled.

Other notes:
* CommentParserTest.php: Change the output of serializeComments()
  to be in similar order as in JS, to reduce the diffs in this commit
  and because it's a better order for humans.
* modifier.test.js: Remove some hacks that were working around small
  inconsistencies between the previous expected outputs and the actual
  outputs.

Change-Id: I9f764640dae823321c0ac35898fa4db03f1ca364
2020-08-04 03:05:28 +02:00
jenkins-bot 889de1bcdf Merge "Improve detecting typed signatures" 2020-07-22 01:43:40 +00:00
Bartosz Dziewoński 80e52e1155 Improve detecting typed signatures
* Remove the existing approach for detecting signatures that only
  worked in source mode; remove autoSignWikitext()

* Use the same approach for auto-signing in source mode as we have
  already used in visual

* In both modes, detect whether the user has already typed a signature
  at the end of their comment in the modifier, and if so, don't add a
  signature

* Add test cases for the detection

Bug: T255738
Change-Id: I791d3035cb1ffc33ce3966d4617a25d08700c35b
2020-07-22 00:00:53 +02:00
Ed Sanders a2431fe006 Refactor CommentParser
* Pass rootNode to the constructor
* Rename getters to match CommentItem/HeadingItem/ThreadItem
  value classes.
* Always build the thread tree so CommentItem's always have
  and ID and replies/parent.

Change-Id: I508be9534de59016ff806e3d84edcbb1c76cb0c6
2020-07-20 23:38:10 +01:00
Ed Sanders a4636d39fc Move #getTranscludedFrom from parser to ThreadItem
Also requires moving getTitleFromUrl to CommentUtils

Change-Id: I9cb83a3fdd456eba66899433b866ce7a7f00eeb5
2020-07-20 15:56:48 +01:00
Ed Sanders 7ae5bbf384 Move #getAuthors from parser to ThreadItem
Change-Id: I16e513000e5366b3044b17a99da07d8d0f47a61f
2020-07-20 15:13:59 +01:00
Ed Sanders b32f991913 Documentation fixes
Change-Id: I2c7ccecbf8a50bd4d658b0f17f4a21fe90a3c399
2020-07-20 13:34:08 +01:00
Bartosz Dziewoński 08b467bf9f tests: Fix wrong $rootNode in some tests using CommentParser::getComments()
Rather than the <body> node, we were passing <body>'s first child.
Current implementation of CommentParser::getComments() doesn't fail
the tests in spite of this because the XPath query incorrectly returns
results relative to the document's real root node, but these tests
would start failing after I2441f33e6e7bad753ac830d277e6a2e81ee8c93d.

Follow-up to 3e6ab2c4d2.

Change-Id: Ic26e0a1ee4443987e215c5f26ef1f084ccd0b40b
2020-07-15 16:40:30 +00:00
Ed Sanders ed70d49285 CommentParser.php: Fix URL parsing
Change-Id: I406fd98b308dd4d975ea974f2369737a7052b556
2020-07-01 17:06:02 +01:00
Ed Sanders 6459e7dc82 Move wikitext modifiers to modifier.js
Re-create methods in PHP.

Change-Id: Iae6117b65e3b8f50ecc68e1e3ea17c8359bdcb06
2020-07-01 17:06:02 +01:00
Ed Sanders d75a340026 CommentModifierTest: Use DOMCompat::get/setInnerHTML to match JS code
Change-Id: Idd057ff1a5028b377903ff3798ca2bce22535337
2020-06-27 13:13:27 +00:00
Ed Sanders 3e6ab2c4d2 PHP: Use DOMUtils::parseHTML
Change-Id: Ifed0ab99b3da9f8b35ca815ada45f804a8756c1b
2020-06-26 20:06:47 +01:00
Ed Sanders 306faba93d Tests: childNodes[0] -> firstChild
Change-Id: Iae53012f289552d80dad907bfb54a8b5d44cb484
2020-06-12 19:46:08 +00:00
Ed Sanders 7be0cc3209 Create ThreadItem classes
Change-Id: Id2c5324d74eccb1209ccb76768c557722c6d9400
2020-06-12 20:35:59 +01:00
Ed Sanders 0d14fcea6a wt->visual: Don't unwrap template lists
Bug: T253150
Change-Id: I1584d9834e29c38edf4234f2f022c1c48bfd485f
2020-06-01 22:32:23 +01:00
jenkins-bot d8a6362361 Merge "Fix failing test case for PHP modifier" 2020-05-26 03:08:48 +00:00
Bartosz Dziewoński 72c730f6c4 Fix failing test case for PHP modifier
The expected HTML was wrong, a '<br />' tag inside 'data-mw' was
somehow turned into '<br ></span>'. No idea how that happened.
Something must be wrong with the HTML parsing in JS tests, which
were used to generate this file.

Change-Id: I69caa68fe70e706df81e8adf29889254704f601e
2020-05-25 21:09:18 +02:00
Ed Sanders b3ca37c1c5 Create ImmutableRange class in PHP
TODO: Create one in JS as well

Change-Id: I6c9dc2455afcb8d0b68674a2985c5e43dd94b6fb
2020-05-22 15:01:09 +01:00
Bartosz Dziewoński c64bb6b5b7 Add the test for getAuthors() in JS too
Change-Id: Id7dabc535b6bb688602c0d55fc3696f662cb10c7
2020-05-19 21:13:52 +02:00
Bartosz Dziewoński e12aea2f77 Add test case for unwrapParsoidSections()
Covers the bug fixed in I9133d4365a71d6db1fa58b69ae3b970166d15c1e.

Depends-On: I9133d4365a71d6db1fa58b69ae3b970166d15c1e
Bug: T252238
Change-Id: I92831696864e04384eb514ab69f14563cceafc19
2020-05-18 21:36:48 +00:00
Ed Sanders c5d1029b25 Move /cases and /data up to /tests
Theses are no longer QUnit specific.

Change-Id: I5f3cca1ff686922e0cdaaedb80858f37df04799a
2020-05-18 21:47:17 +01:00
Ed Sanders b1427163af Parser.php: Add tests for getTranscludedFrom
Requires an implementation of unwrapParsoidSections

Change-Id: I96c929b1117ba652dbd5af6a1ee37a5f9e87ed1e
2020-05-18 19:53:01 +00:00
Ed Sanders d1e58841af Rename removeListItem to removeAddedListItem and remove in PHP
This method shouldn't be required on the server. Leave comments
relating to it in addListItem so JS & PHP can be kept in sync.

Change-Id: I849fac660faf6e750272c20776f96b9250f96b1b
2020-05-18 19:25:08 +00:00
Reedy 234988155e Add leading \ to covers
Change-Id: I1ed4cd28bf630c6aae238e548410d1293a8b71f1
2020-05-15 22:08:25 +01:00
Ed Sanders e6e0b1ead9 PHP: Add missing typehints
Change-Id: I5639f8cbdae9aaa9cfa06136e19cc94f9fad10ea
2020-05-15 22:04:47 +02:00
Ed Sanders b78fb3f4c1 Move all PHP to the MediaWiki\Extension\DiscussionTools namespace
Change-Id: I654ebb3e646a6d8d62f7bd14d48805e39f836d7e
2020-05-15 21:57:13 +02:00
Ed Sanders 340572bc05 Create a Utils class in PHP
Also move htmlTrim to utils in JS.

Change-Id: Ia5356d713c1c5d521c396cc28bcd4ecc7ee5bbbb
2020-05-15 00:25:32 +01:00
Ed Sanders a3889fd400 Port modifier.js to PHP
Change-Id: I03b9e4377cb3ce6a5ca9d06e49dca9b2516f4979
2020-05-15 00:20:41 +01:00
Bartosz Dziewoński 6f32369b6a tests: Fix comparing PHP and JS ranges
In JS, strings are internally encoded as UTF-16, and properties like
.length return values in UTF-16 code units.

In PHP, strings are internally encoded as UTF-8, and we have the
option of using methods that return bytes like strlen() or UTF-8 code
units like mb_strlen().

However, the values produced by preg_match( …, PREG_OFFSET_CAPTURE )
are in bytes, and there's nothing we can do about that. So let's use
bytes throughout, mixing the two types results in meaningless numbers.

Then in the test code, we have to calculate UTF-16 code units offsets
based on the UTF-8 byte offsets.

We also have to copy the entire workaround for mw:Entity nodes… Maybe
the parser should be fixed to return the real nodes for ranges' ends
in this case.

Change-Id: I05804489d7de0d60be6e9f84e6a49a885e9fb870
2020-05-14 22:37:34 +00:00
Bartosz Dziewoński 33d69e26c9 tests: Fix different whitespace trimming in PHP and JS
Notably, JS trims the no-break space, while PHP doesn't. There are
some other differences that don't come up in our tests. What we really
want is to trim the ASCII whitespace as defined in the HTML spec.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/trim
https://www.php.net/manual/en/function.trim.php
https://infra.spec.whatwg.org/#ascii-whitespace

Change-Id: I95b8fb38878716a2fa7ec84c9f2e8065ebe77c0d
2020-05-14 21:37:26 +00:00
Bartosz Dziewoński c0002be7cd tests: Fix computing ranges in Parsoid documents
In JS tests, we load the documents via mw.template, which apparently
causes the <html>, <head> and <body> tags to disappear, resulting
in the ranges not matching in PHP tests (and the real document).

Put in a big hack that makes them match, and update the JSON files.

Change-Id: I8194752cd5f82c3716c99e76a37226af5d4a0ec1
2020-05-14 01:11:44 +02:00
Bartosz Dziewoński 95a87911eb tests: Check ranges in PHP parser tests
Comment out only the cases that still fail, so it's easier to fix them.

Change-Id: I85d205731d572c93ababa7dd66e674321969edb7
2020-05-13 23:58:37 +02:00
Bartosz Dziewoński b8d7a75c34 Fix performance of DiscussionToolsCommentParser::childIndexOf()
Profiling reveals that >87% of the run time of our test suite is spent
in this tiny method. Apparently, DOMNodeList::item() is extremely slow
(possibly it's linear time instead of constant time?).

Profiled using XDebug and KCacheGrind:
https://phabricator.wikimedia.org/F31815264

We can calculate the child's index in its parent by counting its
precending siblings instead, which turns out to be much faster.

Before:
 1. 275444ms to run DiscussionToolsCommentParserTest:testGetComments with data set #2
 2. 12668ms to run DiscussionToolsCommentParserTest:testGetComments with data set #3
 ...
After:
 1. 9545ms to run DiscussionToolsCommentParserTest:testGetComments with data set #2
 2. 5549ms to run DiscussionToolsCommentParserTest:testGetComments with data set #3
 ...

That's still kind of slow but now it's bearable to run the test suite.

Change-Id: I49155f7aa2e231a9a20bf282cf6aaa28fc902e0b
2020-05-13 02:56:39 +02:00
Ed Sanders 745101c02b PHP tests: Move some test utils to a parent class
Change-Id: I6ae5aa85f8aaa02e1b9323820a841c06c5d62b64
2020-05-12 12:33:04 +01:00
Ed Sanders a000b8c7b1 Add comment tests to PHP
TODO: Make the assertions less slow (currently ~50s)

Change-Id: I1d774e353c070484b5bae18e2ec3e3e41da68202
2020-05-12 12:33:04 +01:00
Roan Kattouw 7b7a2cd69c The Great Parser JS to PHP port of 2020!*
* Not to be confused with the Parsing Team's
"Great Parser JS to PHP port of 2019"

Gasp as OR hacks are changed to null coalescing operators.
Applaud as variable declarations are dropped.
Cheer as parameters and return values are type-hinted.
Shudder as DomNodeLists have no indexOf method.

Moving discussion parsing to the server should allow
us to implement much cleaner APIs for commenting.

Bug: T252252
Co-authored-by: Ed Sanders <esanders@wikimedia.org>
Change-Id: Ic1438d516e223db462cb227f6668e856672f538c
2020-05-12 12:33:04 +01:00