Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
XWiki
xwiki-rendering
Commits
38c9b46e
Unverified
Commit
38c9b46e
authored
Jan 10, 2022
by
Thomas Mortagne
Committed by
GitHub
Jan 10, 2022
Browse files
Merge pull request #193 from michitux/XRENDERING-636
parents
0bae09bd
854115dc
Changes
3
Hide whitespace changes
Inline
Side-by-side
xwiki-rendering-api/pom.xml
View file @
38c9b46e
...
@@ -32,7 +32,7 @@
...
@@ -32,7 +32,7 @@
<packaging>
jar
</packaging>
<packaging>
jar
</packaging>
<description>
XWiki Rendering - Api
</description>
<description>
XWiki Rendering - Api
</description>
<properties>
<properties>
<xwiki.jacoco.instructionRatio>
0.
33
</xwiki.jacoco.instructionRatio>
<xwiki.jacoco.instructionRatio>
0.
4
</xwiki.jacoco.instructionRatio>
<!-- Skipping revapi since xwiki-rendering-legacy-api wraps this module and runs checks on it -->
<!-- Skipping revapi since xwiki-rendering-legacy-api wraps this module and runs checks on it -->
<xwiki.revapi.skip>
true
</xwiki.revapi.skip>
<xwiki.revapi.skip>
true
</xwiki.revapi.skip>
</properties>
</properties>
...
...
xwiki-rendering-api/src/main/java/org/xwiki/rendering/listener/chaining/BlockStateChainingListener.java
View file @
38c9b46e
...
@@ -72,7 +72,9 @@ public class BlockStateChainingListener extends AbstractChainingListener impleme
...
@@ -72,7 +72,9 @@ public class BlockStateChainingListener extends AbstractChainingListener impleme
VERBATIM_STANDALONE
,
VERBATIM_STANDALONE
,
WORD
,
WORD
,
FIGURE
,
FIGURE
,
FIGURE_CAPTION
FIGURE_CAPTION
,
META_DATA
,
GROUP
}
}
private
Event
previousEvent
=
Event
.
NONE
;
private
Event
previousEvent
=
Event
.
NONE
;
...
@@ -439,9 +441,9 @@ public void endDefinitionTerm()
...
@@ -439,9 +441,9 @@ public void endDefinitionTerm()
@Override
@Override
public
void
endDocument
(
MetaData
metadata
)
public
void
endDocument
(
MetaData
metadata
)
{
{
this
.
previousEvent
=
Event
.
DOCUMENT
;
super
.
endDocument
(
metadata
);
super
.
endDocument
(
metadata
);
this
.
previousEvent
=
Event
.
DOCUMENT
;
}
}
@Override
@Override
...
@@ -491,7 +493,7 @@ public void endListItem(Map<String, String> parameters)
...
@@ -491,7 +493,7 @@ public void endListItem(Map<String, String> parameters)
super
.
endListItem
(
parameters
);
super
.
endListItem
(
parameters
);
--
this
.
inlineDepth
;
--
this
.
inlineDepth
;
this
.
previousEvent
=
Event
.
LIST_ITEM
;
this
.
previousEvent
=
Event
.
LIST_ITEM
;
}
}
@Override
@Override
...
@@ -503,6 +505,32 @@ public void endMacroMarker(String name, Map<String, String> parameters, String c
...
@@ -503,6 +505,32 @@ public void endMacroMarker(String name, Map<String, String> parameters, String c
--
this
.
macroDepth
;
--
this
.
macroDepth
;
}
}
/**
* {@inheritDoc}
*
* @since 14.0RC1
*/
@Override
public
void
endMetaData
(
MetaData
metadata
)
{
super
.
endMetaData
(
metadata
);
this
.
previousEvent
=
Event
.
META_DATA
;
}
/**
* {@inheritDoc}
*
* @since 14.0RC1
*/
@Override
public
void
endGroup
(
Map
<
String
,
String
>
parameters
)
{
super
.
endGroup
(
parameters
);
this
.
previousEvent
=
Event
.
GROUP
;
}
@Override
@Override
public
void
endParagraph
(
Map
<
String
,
String
>
parameters
)
public
void
endParagraph
(
Map
<
String
,
String
>
parameters
)
{
{
...
@@ -628,25 +656,25 @@ public void onRawText(String text, Syntax syntax)
...
@@ -628,25 +656,25 @@ public void onRawText(String text, Syntax syntax)
@Override
@Override
public
void
onEmptyLines
(
int
count
)
public
void
onEmptyLines
(
int
count
)
{
{
this
.
previousEvent
=
Event
.
EMPTY_LINES
;
super
.
onEmptyLines
(
count
);
super
.
onEmptyLines
(
count
);
this
.
previousEvent
=
Event
.
EMPTY_LINES
;
}
}
@Override
@Override
public
void
onHorizontalLine
(
Map
<
String
,
String
>
parameters
)
public
void
onHorizontalLine
(
Map
<
String
,
String
>
parameters
)
{
{
this
.
previousEvent
=
Event
.
HORIZONTAL_LINE
;
super
.
onHorizontalLine
(
parameters
);
super
.
onHorizontalLine
(
parameters
);
this
.
previousEvent
=
Event
.
HORIZONTAL_LINE
;
}
}
@Override
@Override
public
void
onId
(
String
name
)
public
void
onId
(
String
name
)
{
{
this
.
previousEvent
=
Event
.
ID
;
super
.
onId
(
name
);
super
.
onId
(
name
);
this
.
previousEvent
=
Event
.
ID
;
}
}
/**
/**
...
@@ -657,57 +685,61 @@ public void onId(String name)
...
@@ -657,57 +685,61 @@ public void onId(String name)
@Override
@Override
public
void
onImage
(
ResourceReference
reference
,
boolean
freestanding
,
Map
<
String
,
String
>
parameters
)
public
void
onImage
(
ResourceReference
reference
,
boolean
freestanding
,
Map
<
String
,
String
>
parameters
)
{
{
this
.
previousEvent
=
Event
.
IMAGE
;
super
.
onImage
(
reference
,
freestanding
,
parameters
);
super
.
onImage
(
reference
,
freestanding
,
parameters
);
this
.
previousEvent
=
Event
.
IMAGE
;
}
}
@Override
@Override
public
void
onNewLine
()
public
void
onNewLine
()
{
{
this
.
previousEvent
=
Event
.
NEW_LINE
;
super
.
onNewLine
();
super
.
onNewLine
();
this
.
previousEvent
=
Event
.
NEW_LINE
;
}
}
@Override
@Override
public
void
onSpace
()
public
void
onSpace
()
{
{
this
.
previousEvent
=
Event
.
SPACE
;
super
.
onSpace
();
super
.
onSpace
();
this
.
previousEvent
=
Event
.
SPACE
;
}
}
@Override
@Override
public
void
onSpecialSymbol
(
char
symbol
)
public
void
onSpecialSymbol
(
char
symbol
)
{
{
this
.
previousEvent
=
Event
.
SPECIAL_SYMBOL
;
super
.
onSpecialSymbol
(
symbol
);
super
.
onSpecialSymbol
(
symbol
);
this
.
previousEvent
=
Event
.
SPECIAL_SYMBOL
;
}
}
@Override
@Override
public
void
onVerbatim
(
String
content
,
boolean
inline
,
Map
<
String
,
String
>
parameters
)
public
void
onVerbatim
(
String
content
,
boolean
inline
,
Map
<
String
,
String
>
parameters
)
{
{
this
.
previousEvent
=
Event
.
VERBATIM_STANDALONE
;
super
.
onVerbatim
(
content
,
inline
,
parameters
);
super
.
onVerbatim
(
content
,
inline
,
parameters
);
if
(
inline
)
{
this
.
previousEvent
=
Event
.
VERBATIM_INLINE
;
}
else
{
this
.
previousEvent
=
Event
.
VERBATIM_STANDALONE
;
}
}
}
@Override
@Override
public
void
onWord
(
String
word
)
public
void
onWord
(
String
word
)
{
{
this
.
previousEvent
=
Event
.
WORD
;
super
.
onWord
(
word
);
super
.
onWord
(
word
);
this
.
previousEvent
=
Event
.
WORD
;
}
}
@Override
@Override
public
void
onMacro
(
String
id
,
Map
<
String
,
String
>
parameters
,
String
content
,
boolean
inline
)
public
void
onMacro
(
String
id
,
Map
<
String
,
String
>
parameters
,
String
content
,
boolean
inline
)
{
{
this
.
previousEvent
=
Event
.
MACRO
;
super
.
onMacro
(
id
,
parameters
,
content
,
inline
);
super
.
onMacro
(
id
,
parameters
,
content
,
inline
);
this
.
previousEvent
=
Event
.
MACRO
;
}
}
private
static
class
ListState
private
static
class
ListState
...
...
xwiki-rendering-api/src/test/java/org/xwiki/rendering/listener/chaining/BlockStateChainingListenerTest.java
0 → 100644
View file @
38c9b46e
/*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package
org.xwiki.rendering.listener.chaining
;
import
java.lang.reflect.InvocationTargetException
;
import
java.lang.reflect.Method
;
import
java.util.Arrays
;
import
java.util.stream.Collectors
;
import
java.util.stream.Stream
;
import
org.apache.commons.text.CaseUtils
;
import
org.junit.jupiter.api.BeforeEach
;
import
org.junit.jupiter.api.DynamicTest
;
import
org.junit.jupiter.api.TestFactory
;
import
org.mockito.stubbing.Stubber
;
import
org.xwiki.rendering.listener.Format
;
import
org.xwiki.rendering.listener.HeaderLevel
;
import
org.xwiki.rendering.listener.ListType
;
import
org.xwiki.rendering.listener.Listener
;
import
org.xwiki.rendering.listener.MetaData
;
import
static
org
.
junit
.
jupiter
.
api
.
Assertions
.
assertEquals
;
import
static
org
.
junit
.
jupiter
.
api
.
Assertions
.
fail
;
import
static
org
.
mockito
.
Mockito
.
doAnswer
;
import
static
org
.
mockito
.
Mockito
.
mock
;
import
static
org
.
mockito
.
Mockito
.
verify
;
/**
* Unit tests for {@link BlockStateChainingListener}.
*
* @version $Id$
* @since 14.0RC1
*/
public
class
BlockStateChainingListenerTest
{
private
BlockStateChainingListener
listener
;
private
ChainingListener
mockListener
;
@BeforeEach
void
setUpChain
()
{
ListenerChain
chain
=
new
ListenerChain
();
this
.
listener
=
new
BlockStateChainingListener
(
chain
);
chain
.
addListener
(
this
.
listener
);
this
.
mockListener
=
mock
(
ChainingListener
.
class
);
chain
.
addListener
(
this
.
mockListener
);
}
/**
* Tests for all "begin/end"-methods if the previous event is correctly set, but only after the end event has been
* forwarded in the chain.
*/
@TestFactory
Stream
<
DynamicTest
>
beginEndMethods
()
{
return
Arrays
.
stream
(
Listener
.
class
.
getMethods
())
.
filter
(
m
->
m
.
getName
().
startsWith
(
"begin"
))
.
map
(
beginMethod
->
DynamicTest
.
dynamicTest
(
getTestName
(
beginMethod
),
()
->
testBeginEndMethod
(
beginMethod
)));
}
/**
* Tests for all "on..." methods if the previous event is correctly set, but only after the event has been forwarded
* in the chain.
*/
@TestFactory
Stream
<
DynamicTest
>
onMethods
()
{
return
Arrays
.
stream
(
Listener
.
class
.
getMethods
())
.
filter
(
m
->
m
.
getName
().
startsWith
(
"on"
))
.
map
(
beginMethod
->
DynamicTest
.
dynamicTest
(
getTestName
(
beginMethod
),
()
->
testOnMethod
(
beginMethod
)));
}
private
String
getTestName
(
Method
method
)
{
return
method
.
getName
()
+
"("
+
Arrays
.
stream
(
method
.
getParameterTypes
()).
map
(
Class:
:
getName
)
.
collect
(
Collectors
.
joining
(
", "
))
+
")"
;
}
private
void
testBeginEndMethod
(
Method
beginMethod
)
{
String
endMethodName
=
beginMethod
.
getName
().
replace
(
"begin"
,
"end"
);
Class
<?>[]
parameterClasses
=
beginMethod
.
getParameterTypes
();
try
{
Method
endMethod
=
Listener
.
class
.
getMethod
(
endMethodName
,
parameterClasses
);
boolean
isListItem
=
beginMethod
.
getName
().
equals
(
"beginListItem"
);
boolean
isDefinitionItem
=
beginMethod
.
getName
().
equals
(
"beginDefinitionTerm"
)
||
beginMethod
.
getName
().
equals
(
"beginDefinitionDescription"
);
if
(
isListItem
)
{
this
.
listener
.
beginList
(
ListType
.
NUMBERED
,
Listener
.
EMPTY_PARAMETERS
);
}
else
if
(
isDefinitionItem
)
{
this
.
listener
.
beginDefinitionList
(
Listener
.
EMPTY_PARAMETERS
);
}
Object
[]
parameters
=
Arrays
.
stream
(
parameterClasses
).
map
(
this
::
mockParameter
).
toArray
();
this
.
listener
.
onId
(
"MockID"
);
Stubber
verifyPreviousAndParentEventStubber
=
doAnswer
(
invocation
->
{
assertEquals
(
BlockStateChainingListener
.
Event
.
ID
,
this
.
listener
.
getPreviousEvent
());
return
null
;
}).
doNothing
();
// Assert that in the begin method, the previous event are unchanged
beginMethod
.
invoke
(
verifyPreviousAndParentEventStubber
.
when
(
this
.
mockListener
),
parameters
);
// Actually call the begin method.
beginMethod
.
invoke
(
this
.
listener
,
parameters
);
// Verify the mock listener in the chain has been called.
beginMethod
.
invoke
(
verify
(
this
.
mockListener
),
parameters
);
// Assert that in the end method, the previous event is unchanged
endMethod
.
invoke
(
verifyPreviousAndParentEventStubber
.
when
(
this
.
mockListener
),
parameters
);
// Actually call the end method.
endMethod
.
invoke
(
this
.
listener
,
parameters
);
// Verify the mock listener in the chain has been called.
endMethod
.
invoke
(
verify
(
this
.
mockListener
),
parameters
);
// Verify that the previous event has been set to the event corresponding to the current methods.
String
previousEventName
=
this
.
listener
.
getPreviousEvent
().
name
();
String
previousEventCamelCase
=
CaseUtils
.
toCamelCase
(
previousEventName
,
true
,
'_'
);
assertEquals
(
beginMethod
.
getName
(),
"begin"
+
previousEventCamelCase
,
"Wrong event "
+
previousEventName
+
" generated for "
+
beginMethod
.
getName
());
if
(
isDefinitionItem
)
{
this
.
listener
.
endDefinitionList
(
Listener
.
EMPTY_PARAMETERS
);
}
else
if
(
isListItem
)
{
this
.
listener
.
endList
(
ListType
.
NUMBERED
,
Listener
.
EMPTY_PARAMETERS
);
}
}
catch
(
NoSuchMethodException
e
)
{
fail
(
"Expected end method "
+
endMethodName
+
" for "
+
beginMethod
.
getName
()
+
" not found: "
+
e
.
getMessage
());
}
catch
(
InvocationTargetException
e
)
{
fail
(
"Listener method has thrown exception: "
+
e
.
getMessage
());
}
catch
(
IllegalAccessException
e
)
{
fail
(
"Listener method not callable: "
+
e
.
getMessage
());
}
}
private
void
testOnMethod
(
Method
method
)
{
this
.
listener
.
beginDocument
(
MetaData
.
EMPTY
);
// Make sure the previous event is one that we never trigger.
this
.
listener
.
beginParagraph
(
Listener
.
EMPTY_PARAMETERS
);
this
.
listener
.
endParagraph
(
Listener
.
EMPTY_PARAMETERS
);
Object
[]
parameters
=
Arrays
.
stream
(
method
.
getParameterTypes
()).
map
(
this
::
mockParameter
).
toArray
();
try
{
// Verify that the next in the chain still gets the old previous event.
method
.
invoke
(
doAnswer
(
invocationOnMock
->
{
assertEquals
(
BlockStateChainingListener
.
Event
.
PARAGRAPH
,
this
.
listener
.
getPreviousEvent
());
return
null
;
})
.
doThrow
(
new
AssertionError
(
"Listener must only be called once"
))
.
when
(
this
.
mockListener
),
parameters
);
// Actually call the listener method.
method
.
invoke
(
this
.
listener
,
parameters
);
// Verify that the call has been correctly forwarded.
method
.
invoke
(
verify
(
this
.
mockListener
),
parameters
);
}
catch
(
InvocationTargetException
e
)
{
fail
(
"Listener method has thrown exception: "
+
e
.
getMessage
());
}
catch
(
IllegalAccessException
e
)
{
fail
(
"Listener method not callable: "
+
e
.
getMessage
());
}
// Check if the previous event is the expected event.
String
previousEventName
=
this
.
listener
.
getPreviousEvent
().
name
();
// Verbatim has two events, as our mock boolean is true we always get the inline event.
if
(
this
.
listener
.
getPreviousEvent
().
equals
(
BlockStateChainingListener
.
Event
.
VERBATIM_INLINE
))
{
previousEventName
=
"VERBATIM"
;
}
String
eventCamelCaseName
=
CaseUtils
.
toCamelCase
(
previousEventName
,
true
,
'_'
);
assertEquals
(
method
.
getName
(),
"on"
+
eventCamelCaseName
,
"Previous event "
+
previousEventName
+
" "
+
"does not match method name "
+
method
.
getName
());
this
.
listener
.
endDocument
(
MetaData
.
EMPTY
);
}
/**
* @param classToMock The class to return a mock object for.
* @return Either a mock object or in the case of an enum or primitive type a concrete value.
*/
private
Object
mockParameter
(
Class
<?>
classToMock
)
{
if
(
classToMock
.
equals
(
Format
.
class
))
{
return
Format
.
BOLD
;
}
if
(
classToMock
.
equals
(
ListType
.
class
))
{
return
ListType
.
BULLETED
;
}
if
(
classToMock
.
equals
(
HeaderLevel
.
class
))
{
return
HeaderLevel
.
LEVEL1
;
}
if
(
classToMock
.
equals
(
String
.
class
))
{
return
"Mock"
;
}
if
(
classToMock
.
equals
(
boolean
.
class
))
{
return
true
;
}
if
(
classToMock
.
equals
(
char
.
class
))
{
return
'{'
;
}
if
(
classToMock
.
equals
(
int
.
class
))
{
return
42
;
}
return
mock
(
classToMock
);
}
}
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment