Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,10 @@ public void beginDocument(MetaData metadata)
public void beginDefinitionDescription()
{
++this.inlineDepth;
if (this.definitionListDepth.isEmpty()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not encapsulating the content of the method in an if (!this.definitionListDepth.isEmpty()) { instead of adding artificially an element? Would that break something else?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, I thought so, but now I'm not so sure anymore. It seems that getListItemIndex already checks if the stack is non-empty, so this might actually be a better solution... It will break the printing of the list items in both XWiki syntax and plain text, but it might be cleaner.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And +1 for having a warning in the else branch then.

Copy link
Contributor Author

@michitux michitux Feb 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've adjusted the code. I've decided not to log a warning as it is hard to provide relevant information for admins to perform any actions, in particular without a stack trace. For now, I'm just logging a debug message. A possibility could also be to make this a warning when deprecation logging is enabled as in https://github.com/xwiki/xwiki-platform/blob/05d353688490b416a90fcf9ba116cca04e8a9b06/xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/doc/XWikiDocument.java#L2434-L2437 but to me that doesn't really seem fitting, what do you think?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to me that doesn't really seem fitting

Yeah, does not feel like a deprecation. In the case of cache document modification, I used it because modifying directly the cached document used to be kind of officially OK.

// Avoid a null pointer exception. The result might be wrong but at least it won't break.
this.definitionListDepth.push(new DefinitionListState());
}
++this.definitionListDepth.peek().definitionListItemIndex;

super.beginDefinitionDescription();
Expand All @@ -304,6 +308,10 @@ public void beginDefinitionList(Map<String, String> parameters)
public void beginDefinitionTerm()
{
++this.inlineDepth;
if (this.definitionListDepth.isEmpty()) {
// Avoid a null pointer exception. The result might be wrong but at least it won't break.
this.definitionListDepth.push(new DefinitionListState());
}
++this.definitionListDepth.peek().definitionListItemIndex;

super.beginDefinitionTerm();
Expand Down Expand Up @@ -340,6 +348,10 @@ public void beginList(ListType type, Map<String, String> parameters)
public void beginListItem()
{
++this.inlineDepth;
if (this.listDepth.isEmpty()) {
// Avoid a null pointer exception. The result might be wrong but at least it won't break.
this.listDepth.push(new ListState());
}
++this.listDepth.peek().listItemIndex;

super.beginListItem();
Expand All @@ -351,6 +363,10 @@ public void beginListItem()
public void beginListItem(Map<String, String> parameters)
{
++this.inlineDepth;
if (this.listDepth.isEmpty()) {
// Avoid a null pointer exception. The result might be wrong but at least it won't break.
this.listDepth.push(new ListState());
}
++this.listDepth.peek().listItemIndex;

super.beginListItem(parameters);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,13 @@

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;

import org.apache.commons.text.CaseUtils;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import org.junit.jupiter.params.provider.ValueSource;
import org.mockito.stubbing.Stubber;
import org.xwiki.rendering.listener.ListType;
import org.xwiki.rendering.listener.Listener;
Expand All @@ -34,6 +36,7 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
Expand Down Expand Up @@ -188,4 +191,47 @@ void testOnMethod(Method method, Object[] parameters) throws InvocationTargetExc

this.listener.endDocument(MetaData.EMPTY);
}

@ParameterizedTest
@ValueSource(booleans = { true, false })
void testListItemWithoutParent(boolean withParameter) throws Exception
{
Class<?>[] parameterTypes = withParameter ? new Class<?>[] { Map.class } : new Class<?>[0];
Method beginMethod = BlockStateChainingListener.class.getDeclaredMethod("beginListItem", parameterTypes);
Method endMethod = BlockStateChainingListener.class.getDeclaredMethod("endListItem", parameterTypes);
Object[] parameters = withParameter ? new Object[] { Listener.EMPTY_PARAMETERS } : new Object[0];

this.listener.beginDocument(MetaData.EMPTY);
beginMethod.invoke(this.listener, parameters);
assertEquals(0, this.listener.getListItemIndex());
assertTrue(this.listener.isInList());
assertEquals(1, this.listener.getListDepth());
endMethod.invoke(this.listener, parameters);
beginMethod.invoke(this.listener, parameters);
assertEquals(1, this.listener.getListItemIndex());
assertTrue(this.listener.isInList());
assertEquals(1, this.listener.getListDepth());
endMethod.invoke(this.listener, parameters);
this.listener.endDocument(MetaData.EMPTY);
}

@ParameterizedTest
@ValueSource(strings = { "Term", "Description" })
void testDefinitionListItemWithoutParent(String methodSuffix) throws Exception
{
Method beginMethod = BlockStateChainingListener.class.getDeclaredMethod("beginDefinition" + methodSuffix);
Method endMethod = BlockStateChainingListener.class.getDeclaredMethod("endDefinition" + methodSuffix);
this.listener.beginDocument(MetaData.EMPTY);
beginMethod.invoke(this.listener);
assertTrue(this.listener.isInDefinitionList());
assertEquals(0, this.listener.getDefinitionListItemIndex());
assertEquals(1, this.listener.getDefinitionListDepth());
endMethod.invoke(this.listener);
beginMethod.invoke(this.listener);
assertTrue(this.listener.isInDefinitionList());
assertEquals(1, this.listener.getDefinitionListItemIndex());
assertEquals(1, this.listener.getDefinitionListDepth());
endMethod.invoke(this.listener);
this.listener.endDocument(MetaData.EMPTY);
}
}