Page Menu
Home
WickedGov Phorge
Search
Configure Global Search
Log In
Files
F4074844
ReferenceStackTest.php
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
23 KB
Referenced Files
None
Subscribers
None
ReferenceStackTest.php
View Options
<?php
namespace
Cite\Tests\Unit
;
use
Cite\ReferenceStack
;
use
Cite\Tests\TestUtils
;
use
LogicException
;
use
MediaWiki\Parser\StripState
;
use
Wikimedia\TestingAccessWrapper
;
/**
* @covers \Cite\ReferenceStack
* @license GPL-2.0-or-later
*/
class
ReferenceStackTest
extends
\MediaWikiUnitTestCase
{
public
function
testPushInvalidRef
()
{
$stack
=
$this
->
newStack
();
$stack
->
pushInvalidRef
();
$this
->
assertSame
(
[
false
],
$stack
->
refCallStack
);
}
/**
* @dataProvider providePushRef
*/
public
function
testPushRefs
(
array
$refs
,
array
$expectedOutputs
,
array
$finalRefs
,
array
$finalCallStack
)
{
$mockStripState
=
$this
->
createMock
(
StripState
::
class
);
$mockStripState
->
method
(
'unstripBoth'
)->
willReturnArgument
(
0
);
$stack
=
$this
->
newStack
();
for
(
$i
=
0
;
$i
<
count
(
$refs
);
$i
++
)
{
$result
=
$stack
->
pushRef
(
$mockStripState
,
...
$refs
[
$i
]
);
$this
->
assertArrayHasKey
(
$i
,
$expectedOutputs
,
'Bad test, not enough expected outputs in fixture.'
);
$expectedRef
=
TestUtils
::
refFromArray
(
$expectedOutputs
[
$i
]
);
$this
->
assertEquals
(
$expectedRef
,
$result
);
}
$finalRefs
=
TestUtils
::
refGroupsFromArray
(
$finalRefs
);
$this
->
assertEquals
(
$finalRefs
,
$stack
->
refs
);
$this
->
assertSame
(
$finalCallStack
,
$stack
->
refCallStack
);
}
public
static
function
providePushRef
()
{
return
[
'Anonymous ref in default group'
=>
[
'refs'
=>
[
[
'text'
,
[],
''
,
null
,
null
,
null
,
'rtl'
]
],
'expectedOutputs'
=>
[
[
'count'
=>
1
,
'dir'
=>
'rtl'
,
'key'
=>
1
,
'group'
=>
''
,
'name'
=>
null
,
'text'
=>
'text'
,
'number'
=>
1
,
]
],
'finalRefs'
=>
[
''
=>
[
[
'count'
=>
1
,
'dir'
=>
'rtl'
,
'key'
=>
1
,
'group'
=>
''
,
'name'
=>
null
,
'text'
=>
'text'
,
'number'
=>
1
,
]
]
],
'finalCallStack'
=>
[
[
'new'
,
1
,
''
,
null
,
'text'
,
[]
],
]
],
'Anonymous ref in named group'
=>
[
'refs'
=>
[
[
'text'
,
[],
'foo'
,
null
,
null
,
null
,
'rtl'
]
],
'expectedOutputs'
=>
[
[
'count'
=>
1
,
'dir'
=>
'rtl'
,
'key'
=>
1
,
'group'
=>
'foo'
,
'name'
=>
null
,
'text'
=>
'text'
,
'number'
=>
1
,
]
],
'finalRefs'
=>
[
'foo'
=>
[
[
'count'
=>
1
,
'dir'
=>
'rtl'
,
'key'
=>
1
,
'group'
=>
'foo'
,
'name'
=>
null
,
'text'
=>
'text'
,
'number'
=>
1
,
]
]
],
'finalCallStack'
=>
[
[
'new'
,
1
,
'foo'
,
null
,
'text'
,
[]
],
]
],
'Ref with text'
=>
[
'refs'
=>
[
[
'text'
,
[],
'foo'
,
null
,
null
,
null
,
'rtl'
]
],
'expectedOutputs'
=>
[
[
'count'
=>
1
,
'dir'
=>
'rtl'
,
'key'
=>
1
,
'group'
=>
'foo'
,
'name'
=>
null
,
'text'
=>
'text'
,
'number'
=>
1
,
]
],
'finalRefs'
=>
[
'foo'
=>
[
[
'count'
=>
1
,
'dir'
=>
'rtl'
,
'key'
=>
1
,
'group'
=>
'foo'
,
'name'
=>
null
,
'text'
=>
'text'
,
'number'
=>
1
,
]
]
],
'finalCallStack'
=>
[
[
'new'
,
1
,
'foo'
,
null
,
'text'
,
[]
],
]
],
'Named ref with text'
=>
[
'refs'
=>
[
[
'text'
,
[],
'foo'
,
'name'
,
null
,
null
,
'rtl'
]
],
'expectedOutputs'
=>
[
[
'count'
=>
1
,
'dir'
=>
'rtl'
,
'key'
=>
1
,
'group'
=>
'foo'
,
'name'
=>
'name'
,
'text'
=>
'text'
,
'number'
=>
1
,
],
],
'finalRefs'
=>
[
'foo'
=>
[
'name'
=>
[
'count'
=>
1
,
'dir'
=>
'rtl'
,
'key'
=>
1
,
'group'
=>
'foo'
,
'name'
=>
'name'
,
'text'
=>
'text'
,
'number'
=>
1
,
]
]
],
'finalCallStack'
=>
[
[
'new'
,
1
,
'foo'
,
'name'
,
'text'
,
[]
],
]
],
'Follow after base'
=>
[
'refs'
=>
[
[
'text-a'
,
[],
'foo'
,
'a'
,
null
,
null
,
'rtl'
],
[
'text-b'
,
[],
'foo'
,
'b'
,
null
,
'a'
,
'rtl'
]
],
'expectedOutputs'
=>
[
[
'count'
=>
1
,
'dir'
=>
'rtl'
,
'key'
=>
1
,
'group'
=>
'foo'
,
'name'
=>
'a'
,
'text'
=>
'text-a'
,
'number'
=>
1
,
],
null
],
'finalRefs'
=>
[
'foo'
=>
[
'a'
=>
[
'count'
=>
1
,
'dir'
=>
'rtl'
,
'key'
=>
1
,
'group'
=>
'foo'
,
'name'
=>
'a'
,
'text'
=>
'text-a text-b'
,
'number'
=>
1
,
]
]
],
'finalCallStack'
=>
[
[
'new'
,
1
,
'foo'
,
'a'
,
'text-a'
,
[]
],
]
],
'Follow with no base'
=>
[
'refs'
=>
[
[
'text'
,
[],
'foo'
,
null
,
null
,
'a'
,
'rtl'
]
],
'expectedOutputs'
=>
[
null
],
'finalRefs'
=>
[
'foo'
=>
[
[
'count'
=>
1
,
'dir'
=>
'rtl'
,
'key'
=>
1
,
'group'
=>
'foo'
,
'name'
=>
null
,
'text'
=>
'text'
,
'follow'
=>
'a'
,
]
]
],
'finalCallStack'
=>
[
[
'new'
,
1
,
'foo'
,
null
,
'text'
,
[]
],
]
],
'Follow pointing to later ref'
=>
[
'refs'
=>
[
[
'text-a'
,
[],
'foo'
,
'a'
,
null
,
null
,
'rtl'
],
[
'text-b'
,
[],
'foo'
,
null
,
null
,
'c'
,
'rtl'
],
[
'text-c'
,
[],
'foo'
,
'c'
,
null
,
null
,
'rtl'
]
],
'expectedOutputs'
=>
[
[
'count'
=>
1
,
'dir'
=>
'rtl'
,
'key'
=>
1
,
'group'
=>
'foo'
,
'name'
=>
'a'
,
'text'
=>
'text-a'
,
'number'
=>
1
,
],
null
,
[
'count'
=>
1
,
'dir'
=>
'rtl'
,
'key'
=>
3
,
'group'
=>
'foo'
,
'name'
=>
'c'
,
'text'
=>
'text-c'
,
'number'
=>
2
,
]
],
'finalRefs'
=>
[
'foo'
=>
[
'a'
=>
[
'count'
=>
1
,
'dir'
=>
'rtl'
,
'key'
=>
1
,
'group'
=>
'foo'
,
'name'
=>
'a'
,
'text'
=>
'text-a'
,
'number'
=>
1
,
],
0
=>
[
'count'
=>
1
,
'dir'
=>
'rtl'
,
'key'
=>
2
,
'group'
=>
'foo'
,
'name'
=>
null
,
'text'
=>
'text-b'
,
'follow'
=>
'c'
,
],
'c'
=>
[
'count'
=>
1
,
'dir'
=>
'rtl'
,
'key'
=>
3
,
'group'
=>
'foo'
,
'name'
=>
'c'
,
'text'
=>
'text-c'
,
'number'
=>
2
,
]
]
],
'finalCallStack'
=>
[
[
'new'
,
1
,
'foo'
,
'a'
,
'text-a'
,
[]
],
[
'new'
,
2
,
'foo'
,
null
,
'text-b'
,
[]
],
[
'new'
,
3
,
'foo'
,
'c'
,
'text-c'
,
[]
],
]
],
'Repeated ref, text in first tag'
=>
[
'refs'
=>
[
[
'text'
,
[],
'foo'
,
'a'
,
null
,
null
,
'rtl'
],
[
null
,
[],
'foo'
,
'a'
,
null
,
null
,
'rtl'
]
],
'expectedOutputs'
=>
[
[
'count'
=>
1
,
'dir'
=>
'rtl'
,
'key'
=>
1
,
'group'
=>
'foo'
,
'name'
=>
'a'
,
'text'
=>
'text'
,
'number'
=>
1
,
],
[
'count'
=>
2
,
'dir'
=>
'rtl'
,
'key'
=>
1
,
'group'
=>
'foo'
,
'name'
=>
'a'
,
'text'
=>
'text'
,
'number'
=>
1
,
],
],
'finalRefs'
=>
[
'foo'
=>
[
'a'
=>
[
'count'
=>
2
,
'dir'
=>
'rtl'
,
'key'
=>
1
,
'group'
=>
'foo'
,
'name'
=>
'a'
,
'text'
=>
'text'
,
'number'
=>
1
,
]
]
],
'finalCallStack'
=>
[
[
'new'
,
1
,
'foo'
,
'a'
,
'text'
,
[]
],
[
'increment'
,
1
,
'foo'
,
'a'
,
null
,
[]
],
]
],
'Repeated ref, text in second tag'
=>
[
'refs'
=>
[
[
null
,
[],
'foo'
,
'a'
,
null
,
null
,
'rtl'
],
[
'text'
,
[],
'foo'
,
'a'
,
null
,
null
,
'rtl'
]
],
'expectedOutputs'
=>
[
[
'count'
=>
1
,
'dir'
=>
'rtl'
,
'key'
=>
1
,
'group'
=>
'foo'
,
'name'
=>
'a'
,
'text'
=>
null
,
'number'
=>
1
,
],
[
'count'
=>
2
,
'dir'
=>
'rtl'
,
'key'
=>
1
,
'group'
=>
'foo'
,
'name'
=>
'a'
,
'text'
=>
'text'
,
'number'
=>
1
,
]
],
'finalRefs'
=>
[
'foo'
=>
[
'a'
=>
[
'count'
=>
2
,
'dir'
=>
'rtl'
,
'key'
=>
1
,
'group'
=>
'foo'
,
'name'
=>
'a'
,
'text'
=>
'text'
,
'number'
=>
1
,
]
]
],
'finalCallStack'
=>
[
[
'new'
,
1
,
'foo'
,
'a'
,
null
,
[]
],
[
'assign'
,
1
,
'foo'
,
'a'
,
'text'
,
[]
],
]
],
'Repeated ref, mismatched text'
=>
[
'refs'
=>
[
[
'text-1'
,
[],
'foo'
,
'a'
,
null
,
null
,
'rtl'
],
[
'text-2'
,
[],
'foo'
,
'a'
,
null
,
null
,
'rtl'
]
],
'expectedOutputs'
=>
[
[
'count'
=>
1
,
'dir'
=>
'rtl'
,
'key'
=>
1
,
'group'
=>
'foo'
,
'name'
=>
'a'
,
'text'
=>
'text-1'
,
'number'
=>
1
,
],
[
'count'
=>
2
,
'dir'
=>
'rtl'
,
'key'
=>
1
,
'group'
=>
'foo'
,
'name'
=>
'a'
,
'text'
=>
'text-1'
,
'number'
=>
1
,
'warnings'
=>
[
[
'cite_error_references_duplicate_key'
,
'a'
]
],
]
],
'finalRefs'
=>
[
'foo'
=>
[
'a'
=>
[
'count'
=>
2
,
'dir'
=>
'rtl'
,
'key'
=>
1
,
'group'
=>
'foo'
,
'name'
=>
'a'
,
'text'
=>
'text-1'
,
'number'
=>
1
,
'warnings'
=>
[
[
'cite_error_references_duplicate_key'
,
'a'
]
],
]
]
],
'finalCallStack'
=>
[
[
'new'
,
1
,
'foo'
,
'a'
,
'text-1'
,
[]
],
[
'increment'
,
1
,
'foo'
,
'a'
,
'text-2'
,
[]
],
]
],
'Named extends with no parent'
=>
[
'refs'
=>
[
[
'text-a'
,
[],
'foo'
,
'a'
,
'b'
,
null
,
'rtl'
],
],
'expectedOutputs'
=>
[
[
'count'
=>
1
,
'dir'
=>
'rtl'
,
'key'
=>
1
,
'group'
=>
'foo'
,
'name'
=>
'a'
,
'text'
=>
'text-a'
,
'number'
=>
1
,
'extends'
=>
'b'
,
'extendsIndex'
=>
1
,
],
],
'finalRefs'
=>
[
'foo'
=>
[
'a'
=>
[
'count'
=>
1
,
'dir'
=>
'rtl'
,
'key'
=>
1
,
'group'
=>
'foo'
,
'name'
=>
'a'
,
'text'
=>
'text-a'
,
'number'
=>
1
,
'extends'
=>
'b'
,
'extendsIndex'
=>
1
,
],
'b'
=>
[
'count'
=>
0
,
'extendsCount'
=>
1
,
'name'
=>
'b'
,
'number'
=>
1
,
'placeholder'
=>
true
,
]
]
],
'finalCallStack'
=>
[
[
'new'
,
1
,
'foo'
,
'a'
,
'text-a'
,
[]
],
]
],
'Named extends before parent'
=>
[
'refs'
=>
[
[
'text-a'
,
[],
'foo'
,
'a'
,
'b'
,
null
,
'rtl'
],
[
'text-b'
,
[],
'foo'
,
'b'
,
null
,
null
,
'rtl'
],
],
'expectedOutputs'
=>
[
[
'count'
=>
1
,
'dir'
=>
'rtl'
,
'key'
=>
1
,
'group'
=>
'foo'
,
'name'
=>
'a'
,
'text'
=>
'text-a'
,
'number'
=>
1
,
'extends'
=>
'b'
,
'extendsIndex'
=>
1
,
],
[
'count'
=>
1
,
'dir'
=>
'rtl'
,
'extendsCount'
=>
1
,
'key'
=>
2
,
'group'
=>
'foo'
,
'name'
=>
'b'
,
'text'
=>
'text-b'
,
'number'
=>
1
,
]
],
'finalRefs'
=>
[
'foo'
=>
[
'a'
=>
[
'count'
=>
1
,
'dir'
=>
'rtl'
,
'key'
=>
1
,
'group'
=>
'foo'
,
'name'
=>
'a'
,
'text'
=>
'text-a'
,
'number'
=>
1
,
'extends'
=>
'b'
,
'extendsIndex'
=>
1
,
],
'b'
=>
[
'count'
=>
1
,
'dir'
=>
'rtl'
,
'extendsCount'
=>
1
,
'key'
=>
2
,
'group'
=>
'foo'
,
'name'
=>
'b'
,
'text'
=>
'text-b'
,
'number'
=>
1
,
]
]
],
'finalCallStack'
=>
[
[
'new'
,
1
,
'foo'
,
'a'
,
'text-a'
,
[]
],
[
'new-from-placeholder'
,
2
,
'foo'
,
'b'
,
'text-b'
,
[]
],
]
],
'Named extends after parent'
=>
[
'refs'
=>
[
[
'text-a'
,
[],
'foo'
,
'a'
,
null
,
null
,
'rtl'
],
[
'text-b'
,
[],
'foo'
,
'b'
,
'a'
,
null
,
'rtl'
],
],
'expectedOutputs'
=>
[
[
'count'
=>
1
,
'dir'
=>
'rtl'
,
'key'
=>
1
,
'group'
=>
'foo'
,
'name'
=>
'a'
,
'text'
=>
'text-a'
,
'number'
=>
1
,
],
[
'count'
=>
1
,
'dir'
=>
'rtl'
,
'key'
=>
2
,
'group'
=>
'foo'
,
'name'
=>
'b'
,
'text'
=>
'text-b'
,
'number'
=>
1
,
'extends'
=>
'a'
,
'extendsIndex'
=>
1
,
]
],
'finalRefs'
=>
[
'foo'
=>
[
'a'
=>
[
'count'
=>
1
,
'dir'
=>
'rtl'
,
'extendsCount'
=>
1
,
'key'
=>
1
,
'group'
=>
'foo'
,
'name'
=>
'a'
,
'text'
=>
'text-a'
,
'number'
=>
1
,
],
'b'
=>
[
'count'
=>
1
,
'dir'
=>
'rtl'
,
'key'
=>
2
,
'group'
=>
'foo'
,
'name'
=>
'b'
,
'text'
=>
'text-b'
,
'number'
=>
1
,
'extends'
=>
'a'
,
'extendsIndex'
=>
1
,
]
]
],
'finalCallStack'
=>
[
[
'new'
,
1
,
'foo'
,
'a'
,
'text-a'
,
[]
],
[
'new'
,
2
,
'foo'
,
'b'
,
'text-b'
,
[]
],
]
],
'Anonymous extends with no parent'
=>
[
'refs'
=>
[
[
'text-a'
,
[],
'foo'
,
null
,
'b'
,
null
,
'rtl'
],
],
'expectedOutputs'
=>
[
[
'count'
=>
1
,
'dir'
=>
'rtl'
,
'key'
=>
1
,
'group'
=>
'foo'
,
'name'
=>
null
,
'text'
=>
'text-a'
,
'number'
=>
1
,
'extends'
=>
'b'
,
'extendsIndex'
=>
1
,
]
],
'finalRefs'
=>
[
'foo'
=>
[
0
=>
[
'count'
=>
1
,
'dir'
=>
'rtl'
,
'key'
=>
1
,
'group'
=>
'foo'
,
'name'
=>
null
,
'text'
=>
'text-a'
,
'number'
=>
1
,
'extends'
=>
'b'
,
'extendsIndex'
=>
1
,
],
'b'
=>
[
'count'
=>
0
,
'extendsCount'
=>
1
,
'name'
=>
'b'
,
'number'
=>
1
,
'placeholder'
=>
true
,
]
],
],
'finalCallStack'
=>
[
[
'new'
,
1
,
'foo'
,
null
,
'text-a'
,
[]
],
]
],
'Anonymous extends before parent'
=>
[
'refs'
=>
[
[
'text-a'
,
[],
'foo'
,
null
,
'b'
,
null
,
'rtl'
],
[
'text-b'
,
[],
'foo'
,
'b'
,
null
,
null
,
'rtl'
],
],
'expectedOutputs'
=>
[
[
'count'
=>
1
,
'dir'
=>
'rtl'
,
'key'
=>
1
,
'group'
=>
'foo'
,
'name'
=>
null
,
'text'
=>
'text-a'
,
'number'
=>
1
,
'extends'
=>
'b'
,
'extendsIndex'
=>
1
,
],
[
'count'
=>
1
,
'dir'
=>
'rtl'
,
'extendsCount'
=>
1
,
'key'
=>
2
,
'group'
=>
'foo'
,
'name'
=>
'b'
,
'text'
=>
'text-b'
,
'number'
=>
1
,
]
],
'finalRefs'
=>
[
'foo'
=>
[
0
=>
[
'count'
=>
1
,
'dir'
=>
'rtl'
,
'key'
=>
1
,
'group'
=>
'foo'
,
'name'
=>
null
,
'text'
=>
'text-a'
,
'number'
=>
1
,
'extends'
=>
'b'
,
'extendsIndex'
=>
1
,
],
'b'
=>
[
'count'
=>
1
,
'dir'
=>
'rtl'
,
'extendsCount'
=>
1
,
'key'
=>
2
,
'group'
=>
'foo'
,
'name'
=>
'b'
,
'text'
=>
'text-b'
,
'number'
=>
1
,
]
]
],
'finalCallStack'
=>
[
[
'new'
,
1
,
'foo'
,
null
,
'text-a'
,
[]
],
[
'new-from-placeholder'
,
2
,
'foo'
,
'b'
,
'text-b'
,
[]
],
]
],
'Anonymous extends after parent'
=>
[
'refs'
=>
[
[
'text-a'
,
[],
'foo'
,
'a'
,
null
,
null
,
'rtl'
],
[
'text-b'
,
[],
'foo'
,
null
,
'a'
,
null
,
'rtl'
],
],
'expectedOutputs'
=>
[
[
'count'
=>
1
,
'dir'
=>
'rtl'
,
'key'
=>
1
,
'group'
=>
'foo'
,
'name'
=>
'a'
,
'text'
=>
'text-a'
,
'number'
=>
1
,
],
[
'count'
=>
1
,
'dir'
=>
'rtl'
,
'key'
=>
2
,
'group'
=>
'foo'
,
'name'
=>
null
,
'text'
=>
'text-b'
,
'number'
=>
1
,
'extends'
=>
'a'
,
'extendsIndex'
=>
1
,
]
],
'finalRefs'
=>
[
'foo'
=>
[
'a'
=>
[
'count'
=>
1
,
'dir'
=>
'rtl'
,
'extendsCount'
=>
1
,
'key'
=>
1
,
'group'
=>
'foo'
,
'name'
=>
'a'
,
'text'
=>
'text-a'
,
'number'
=>
1
,
],
0
=>
[
'count'
=>
1
,
'dir'
=>
'rtl'
,
'key'
=>
2
,
'group'
=>
'foo'
,
'name'
=>
null
,
'text'
=>
'text-b'
,
'number'
=>
1
,
'extends'
=>
'a'
,
'extendsIndex'
=>
1
,
]
]
],
'finalCallStack'
=>
[
[
'new'
,
1
,
'foo'
,
'a'
,
'text-a'
,
[]
],
[
'new'
,
2
,
'foo'
,
null
,
'text-b'
,
[]
],
]
],
'Normal after extends'
=>
[
'refs'
=>
[
[
'text-a'
,
[],
'foo'
,
'a'
,
null
,
null
,
'rtl'
],
[
'text-b'
,
[],
'foo'
,
null
,
'a'
,
null
,
'rtl'
],
[
'text-c'
,
[],
'foo'
,
'c'
,
null
,
null
,
'rtl'
],
],
'expectedOutputs'
=>
[
[
'count'
=>
1
,
'dir'
=>
'rtl'
,
'key'
=>
1
,
'group'
=>
'foo'
,
'name'
=>
'a'
,
'text'
=>
'text-a'
,
'number'
=>
1
,
],
[
'count'
=>
1
,
'dir'
=>
'rtl'
,
'key'
=>
2
,
'group'
=>
'foo'
,
'name'
=>
null
,
'text'
=>
'text-b'
,
'number'
=>
1
,
'extends'
=>
'a'
,
'extendsIndex'
=>
1
,
],
[
'count'
=>
1
,
'dir'
=>
'rtl'
,
'key'
=>
3
,
'group'
=>
'foo'
,
'name'
=>
'c'
,
'text'
=>
'text-c'
,
'number'
=>
2
,
],
],
'finalRefs'
=>
[
'foo'
=>
[
'a'
=>
[
'count'
=>
1
,
'dir'
=>
'rtl'
,
'extendsCount'
=>
1
,
'key'
=>
1
,
'group'
=>
'foo'
,
'name'
=>
'a'
,
'text'
=>
'text-a'
,
'number'
=>
1
,
],
0
=>
[
'count'
=>
1
,
'dir'
=>
'rtl'
,
'key'
=>
2
,
'group'
=>
'foo'
,
'name'
=>
null
,
'text'
=>
'text-b'
,
'number'
=>
1
,
'extends'
=>
'a'
,
'extendsIndex'
=>
1
,
],
'c'
=>
[
'count'
=>
1
,
'dir'
=>
'rtl'
,
'key'
=>
3
,
'group'
=>
'foo'
,
'name'
=>
'c'
,
'text'
=>
'text-c'
,
'number'
=>
2
,
],
]
],
'finalCallStack'
=>
[
[
'new'
,
1
,
'foo'
,
'a'
,
'text-a'
,
[]
],
[
'new'
,
2
,
'foo'
,
null
,
'text-b'
,
[]
],
[
'new'
,
3
,
'foo'
,
'c'
,
'text-c'
,
[]
],
]
],
'Two incomplete follows'
=>
[
'refs'
=>
[
[
'text-a'
,
[],
'foo'
,
'a'
,
null
,
null
,
'rtl'
],
[
'text-b'
,
[],
'foo'
,
null
,
null
,
'd'
,
'rtl'
],
[
'text-c'
,
[],
'foo'
,
null
,
null
,
'd'
,
'rtl'
],
],
'expectedOutputs'
=>
[
[
'count'
=>
1
,
'dir'
=>
'rtl'
,
'key'
=>
1
,
'group'
=>
'foo'
,
'name'
=>
'a'
,
'text'
=>
'text-a'
,
'number'
=>
1
,
],
null
,
null
],
'finalRefs'
=>
[
'foo'
=>
[
'a'
=>
[
'count'
=>
1
,
'dir'
=>
'rtl'
,
'key'
=>
1
,
'group'
=>
'foo'
,
'name'
=>
'a'
,
'text'
=>
'text-a'
,
'number'
=>
1
,
],
0
=>
[
'count'
=>
1
,
'dir'
=>
'rtl'
,
'key'
=>
2
,
'group'
=>
'foo'
,
'name'
=>
null
,
'text'
=>
'text-b'
,
'follow'
=>
'd'
,
],
1
=>
[
'count'
=>
1
,
'dir'
=>
'rtl'
,
'key'
=>
3
,
'group'
=>
'foo'
,
'name'
=>
null
,
'text'
=>
'text-c'
,
'follow'
=>
'd'
,
],
]
],
'finalCallStack'
=>
[
[
'new'
,
1
,
'foo'
,
'a'
,
'text-a'
,
[]
],
[
'new'
,
2
,
'foo'
,
null
,
'text-b'
,
[]
],
[
'new'
,
3
,
'foo'
,
null
,
'text-c'
,
[]
],
]
],
];
}
/**
* @dataProvider provideRollbackRefs
*/
public
function
testRollbackRefs
(
array
$initialCallStack
,
array
$initialRefs
,
int
$rollbackCount
,
$expectedResult
,
array
$expectedRefs
=
[]
)
{
$stack
=
$this
->
newStack
();
$stack
->
refCallStack
=
$initialCallStack
;
$stack
->
refs
=
TestUtils
::
refGroupsFromArray
(
$initialRefs
);
if
(
is_string
(
$expectedResult
)
)
{
$this
->
expectException
(
LogicException
::
class
);
$this
->
expectExceptionMessage
(
$expectedResult
);
}
$redoStack
=
$stack
->
rollbackRefs
(
$rollbackCount
);
$this
->
assertSame
(
$expectedResult
,
$redoStack
);
$expectedRefs
=
TestUtils
::
refGroupsFromArray
(
$expectedRefs
);
$this
->
assertEquals
(
$expectedRefs
,
$stack
->
refs
);
}
public
static
function
provideRollbackRefs
()
{
return
[
'Empty stack'
=>
[
'initialCallStack'
=>
[],
'initialRefs'
=>
[],
'rollbackCount'
=>
0
,
'expectedResult'
=>
[],
'expectedRefs'
=>
[],
],
'Attempt to overflow stack bounds'
=>
[
'initialCallStack'
=>
[],
'initialRefs'
=>
[],
'rollbackCount'
=>
1
,
'expectedResult'
=>
[],
'expectedRefs'
=>
[],
],
'Skip invalid refs'
=>
[
'initialCallStack'
=>
[
false
],
'initialRefs'
=>
[],
'rollbackCount'
=>
1
,
'expectedResult'
=>
[],
'expectedRefs'
=>
[],
],
'Missing group'
=>
[
'initialCallStack'
=>
[
[
'new'
,
1
,
'foo'
,
null
,
'text'
,
[]
],
],
'initialRefs'
=>
[],
'rollbackCount'
=>
1
,
'expectedResult'
=>
'Cannot roll back ref with unknown group "foo".'
,
],
'Find anonymous ref by key'
=>
[
'initialCallStack'
=>
[
[
'new'
,
1
,
'foo'
,
null
,
'text'
,
[]
],
],
'initialRefs'
=>
[
'foo'
=>
[
[
'key'
=>
1
,
],
]
],
'rollbackCount'
=>
1
,
'expectedResult'
=>
[
[
'text'
,
[]
],
],
'expectedRefs'
=>
[],
],
'Missing anonymous ref'
=>
[
'initialCallStack'
=>
[
[
'new'
,
1
,
'foo'
,
null
,
'text'
,
[]
],
],
'initialRefs'
=>
[
'foo'
=>
[
[
'key'
=>
2
,
],
]
],
'rollbackCount'
=>
1
,
'expectedResult'
=>
'Cannot roll back unknown ref by key 1.'
,
],
'Assign text'
=>
[
'initialCallStack'
=>
[
[
'assign'
,
1
,
'foo'
,
null
,
'text-2'
,
[]
],
],
'initialRefs'
=>
[
'foo'
=>
[
[
'count'
=>
2
,
'key'
=>
1
,
'text'
=>
'text-1'
,
],
]
],
'rollbackCount'
=>
1
,
'expectedResult'
=>
[
[
'text-2'
,
[]
],
],
'expectedRefs'
=>
[
'foo'
=>
[
[
'count'
=>
1
,
'key'
=>
1
,
'text'
=>
null
,
],
]
],
],
'Increment'
=>
[
'initialCallStack'
=>
[
[
'increment'
,
1
,
'foo'
,
null
,
null
,
[]
],
],
'initialRefs'
=>
[
'foo'
=>
[
[
'count'
=>
2
,
'key'
=>
1
,
],
]
],
'rollbackCount'
=>
1
,
'expectedResult'
=>
[
[
null
,
[]
],
],
'expectedRefs'
=>
[
'foo'
=>
[
[
'count'
=>
1
,
'key'
=>
1
,
],
]
],
],
'Safely ignore placeholder'
=>
[
'initialCallStack'
=>
[
[
'increment'
,
2
,
'foo'
,
null
,
null
,
[]
],
],
'initialRefs'
=>
[
'foo'
=>
[
[
'count'
=>
0
,
'key'
=>
1
,
'placeholder'
=>
true
,
'number'
=>
10
,
],
[
'count'
=>
3
,
'key'
=>
2
,
],
]
],
'rollbackCount'
=>
1
,
'expectedResult'
=>
[
[
null
,
[]
],
],
'expectedRefs'
=>
[
'foo'
=>
[
[
'count'
=>
0
,
'key'
=>
1
,
'placeholder'
=>
true
,
'number'
=>
10
,
],
[
'count'
=>
2
,
'key'
=>
2
,
],
]
],
],
];
}
public
function
testRollbackRefs_extends
()
{
$stack
=
$this
->
newStack
();
$mockStripState
=
$this
->
createMock
(
StripState
::
class
);
$mockStripState
->
method
(
'unstripBoth'
)->
willReturnArgument
(
0
);
$stack
->
pushRef
(
$mockStripState
,
'text'
,
[],
'foo'
,
null
,
'a'
,
null
,
'rtl'
);
$stack
->
rollbackRefs
(
1
);
$this
->
assertEquals
(
TestUtils
::
refFromArray
(
[
'count'
=>
0
,
'extendsCount'
=>
0
,
'name'
=>
'a'
,
'number'
=>
1
,
'placeholder'
=>
true
,
'warnings'
=>
[]
]
),
$stack
->
refs
[
'foo'
][
'a'
]
);
}
public
function
testRemovals
()
{
$stack
=
$this
->
newStack
();
$stack
->
refs
=
[
'group1'
=>
[],
'group2'
=>
[]
];
$this
->
assertSame
(
[],
$stack
->
popGroup
(
'group1'
)
);
$this
->
assertSame
(
[
'group2'
=>
[]
],
$stack
->
refs
);
}
public
function
testGetGroups
()
{
$stack
=
$this
->
newStack
();
$stack
->
refs
=
[
'havenot'
=>
[],
'have'
=>
[
[
'ref etc'
]
]
];
$this
->
assertSame
(
[
'have'
],
$stack
->
getGroups
()
);
}
public
function
testHasGroup
()
{
$stack
=
$this
->
newStack
();
$stack
->
refs
=
[
'present'
=>
[
[
'ref etc'
]
],
'empty'
=>
[]
];
$this
->
assertFalse
(
$stack
->
hasGroup
(
'absent'
)
);
$this
->
assertTrue
(
$stack
->
hasGroup
(
'present'
)
);
$this
->
assertFalse
(
$stack
->
hasGroup
(
'empty'
)
);
}
public
function
testGetGroupRefs
()
{
$stack
=
$this
->
newStack
();
$stack
->
refs
=
[
'present'
=>
[
[
'ref etc'
]
],
'empty'
=>
[]
];
$this
->
assertSame
(
[],
$stack
->
getGroupRefs
(
'absent'
)
);
$this
->
assertSame
(
[
[
'ref etc'
]
],
$stack
->
getGroupRefs
(
'present'
)
);
$this
->
assertSame
(
[],
$stack
->
getGroupRefs
(
'empty'
)
);
}
/**
* @return ReferenceStack
*/
private
function
newStack
()
{
return
TestingAccessWrapper
::
newFromObject
(
new
ReferenceStack
()
);
}
}
File Metadata
Details
Attached
Mime Type
text/x-php
Expires
Aug 17 2026, 16:59 (10 w, 2 d ago)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
22/71/ea7313518599960c825d2440b15b
Default Alt Text
ReferenceStackTest.php (23 KB)
Attached To
Mode
rMWPROD MediaWiki Production
Attached
Detach File
Event Timeline
Log In to Comment