Skip to content

Commit

Permalink
Test fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
phax committed Sep 23, 2024
1 parent ba313bd commit 268da6f
Show file tree
Hide file tree
Showing 7 changed files with 204 additions and 56 deletions.
147 changes: 137 additions & 10 deletions ph-css/src/main/java/com/helger/css/decl/CSSSelectorMemberPseudoHas.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,12 @@

import com.helger.commons.ValueEnforcer;
import com.helger.commons.annotation.Nonempty;
import com.helger.commons.annotation.ReturnsMutableCopy;
import com.helger.commons.collection.impl.CommonsArrayList;
import com.helger.commons.collection.impl.ICommonsList;
import com.helger.commons.equals.EqualsHelper;
import com.helger.commons.hashcode.HashCodeGenerator;
import com.helger.commons.state.EChange;
import com.helger.commons.string.ToStringGenerator;
import com.helger.css.CSSSourceLocation;
import com.helger.css.ECSSVersion;
Expand All @@ -33,27 +38,133 @@

/**
* Represents a single, simple CSS selector as used for the ":has()" CSS pseudo
* element.<br>
* element.
*
* @author Philip Helger
* @since 7.0.3
*/
@NotThreadSafe
public class CSSSelectorMemberPseudoHas implements ICSSSelectorMember, ICSSVersionAware, ICSSSourceLocationAware
{
private final CSSSelector m_aSelector;
private final ECSSSelectorCombinator m_eCombinator;
private final ICommonsList <CSSSelector> m_aNestedSelectors;
private CSSSourceLocation m_aSourceLocation;

public CSSSelectorMemberPseudoHas (@Nonnull final CSSSelector aSelector)
public CSSSelectorMemberPseudoHas (@Nullable final ECSSSelectorCombinator eCombinator,
@Nonnull final CSSSelector aNestedSelector)
{
ValueEnforcer.notNull (aNestedSelector, "NestedSelector");
m_eCombinator = eCombinator;
m_aNestedSelectors = new CommonsArrayList <> (aNestedSelector);
}

public CSSSelectorMemberPseudoHas (@Nullable final ECSSSelectorCombinator eCombinator,
@Nonnull final CSSSelector... aNestedSelectors)
{
ValueEnforcer.notNull (aNestedSelectors, "NestedSelectors");
m_eCombinator = eCombinator;
m_aNestedSelectors = new CommonsArrayList <> (aNestedSelectors);
}

public CSSSelectorMemberPseudoHas (@Nullable final ECSSSelectorCombinator eCombinator,
@Nonnull final Iterable <CSSSelector> aNestedSelectors)
{
ValueEnforcer.notNull (aNestedSelectors, "NestedSelectors");
m_eCombinator = eCombinator;
m_aNestedSelectors = new CommonsArrayList <> (aNestedSelectors);
}

@Nullable
public ECSSSelectorCombinator getCombinator ()
{
return m_eCombinator;
}

public boolean hasSelectors ()
{
return m_aNestedSelectors.isNotEmpty ();
}

@Nonnegative
public int getSelectorCount ()
{
return m_aNestedSelectors.size ();
}

@Nonnull
public CSSSelectorMemberPseudoHas addSelector (@Nonnull final ICSSSelectorMember aSingleSelectorMember)
{
ValueEnforcer.notNull (aSingleSelectorMember, "SingleSelectorMember");

return addSelector (new CSSSelector ().addMember (aSingleSelectorMember));
}

@Nonnull
public CSSSelectorMemberPseudoHas addSelector (@Nonnull final CSSSelector aSelector)
{
ValueEnforcer.notNull (aSelector, "Selector");
m_aSelector = aSelector;

m_aNestedSelectors.add (aSelector);
return this;
}

@Nonnull
public final CSSSelector getSelector ()
public CSSSelectorMemberPseudoHas addSelector (@Nonnegative final int nIndex,
@Nonnull final ICSSSelectorMember aSingleSelectorMember)
{
return m_aSelector;
ValueEnforcer.notNull (aSingleSelectorMember, "SingleSelectorMember");

return addSelector (nIndex, new CSSSelector ().addMember (aSingleSelectorMember));
}

@Nonnull
public CSSSelectorMemberPseudoHas addSelector (@Nonnegative final int nIndex, @Nonnull final CSSSelector aSelector)
{
ValueEnforcer.isGE0 (nIndex, "Index");
ValueEnforcer.notNull (aSelector, "Selector");

if (nIndex >= getSelectorCount ())
m_aNestedSelectors.add (aSelector);
else
m_aNestedSelectors.add (nIndex, aSelector);
return this;
}

@Nonnull
public EChange removeSelector (@Nonnull final CSSSelector aSelector)
{
return m_aNestedSelectors.removeObject (aSelector);
}

@Nonnull
public EChange removeSelector (@Nonnegative final int nSelectorIndex)
{
return m_aNestedSelectors.removeAtIndex (nSelectorIndex);
}

/**
* Remove all selectors.
*
* @return {@link EChange#CHANGED} if any selector was removed,
* {@link EChange#UNCHANGED} otherwise. Never <code>null</code>.
*/
@Nonnull
public EChange removeAllSelectors ()
{
return m_aNestedSelectors.removeAll ();
}

@Nullable
public CSSSelector getSelectorAtIndex (@Nonnegative final int nSelectorIndex)
{
return m_aNestedSelectors.getAtIndex (nSelectorIndex);
}

@Nonnull
@ReturnsMutableCopy
public ICommonsList <CSSSelector> getAllSelectors ()
{
return m_aNestedSelectors.getClone ();
}

@Nonnull
Expand All @@ -62,8 +173,23 @@ public String getAsCSSString (@Nonnull final ICSSWriterSettings aSettings, @Nonn
{
aSettings.checkVersionRequirements (this);

aSettings.checkVersionRequirements (this);

final boolean bOptimizedOutput = aSettings.isOptimizedOutput ();
final StringBuilder aSB = new StringBuilder (":has(");
aSB.append (m_aSelector.getAsCSSString (aSettings, 0));

if (m_eCombinator != null)
aSB.append (m_eCombinator.getAsCSSString (aSettings));

boolean bFirst = true;
for (final CSSSelector aNestedSelector : m_aNestedSelectors)
{
if (bFirst)
bFirst = false;
else
aSB.append (bOptimizedOutput ? "," : ", ");
aSB.append (aNestedSelector.getAsCSSString (aSettings, 0));
}
return aSB.append (')').toString ();
}

Expand Down Expand Up @@ -92,19 +218,20 @@ public boolean equals (final Object o)
if (o == null || !getClass ().equals (o.getClass ()))
return false;
final CSSSelectorMemberPseudoHas rhs = (CSSSelectorMemberPseudoHas) o;
return m_aSelector.equals (rhs.m_aSelector);
return EqualsHelper.equals (m_eCombinator, rhs.m_eCombinator) && m_aNestedSelectors.equals (rhs.m_aNestedSelectors);
}

@Override
public int hashCode ()
{
return new HashCodeGenerator (this).append (m_aSelector).getHashCode ();
return new HashCodeGenerator (this).append (m_eCombinator).append (m_aNestedSelectors).getHashCode ();
}

@Override
public String toString ()
{
return new ToStringGenerator (null).append ("Selector", m_aSelector)
return new ToStringGenerator (null).append ("Combinator", m_eCombinator)
.append ("NestedSelectors", m_aNestedSelectors)
.appendIfNotNull ("SourceLocation", m_aSourceLocation)
.getToString ();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,15 @@ private CSSSelectorAttribute _createSelectorAttribute (@Nonnull final CSSNode aN
return ret;
}

@Nullable
private ECSSSelectorCombinator _createSelectorCombinator (final String sText)
{
final ECSSSelectorCombinator eCombinator = ECSSSelectorCombinator.getFromNameOrNull (sText);
if (eCombinator == null)
m_aErrorHandler.onCSSInterpretationError ("Failed to parse CSS selector combinator '" + sText + "'");
return eCombinator;
}

@Nullable
private ICSSSelectorMember _createSelectorMember (final CSSNode aNode)
{
Expand All @@ -224,13 +233,7 @@ private ICSSSelectorMember _createSelectorMember (final CSSNode aNode)
return _createSelectorAttribute (aNode);

if (ECSSNodeType.SELECTORCOMBINATOR.isNode (aNode, m_eVersion))
{
final String sText = aNode.getText ();
final ECSSSelectorCombinator eCombinator = ECSSSelectorCombinator.getFromNameOrNull (sText);
if (eCombinator == null)
m_aErrorHandler.onCSSInterpretationError ("Failed to parse CSS selector combinator '" + sText + "'");
return eCombinator;
}
return _createSelectorCombinator (aNode.getText ());

if (ECSSNodeType.NEGATION.isNode (aNode, m_eVersion))
{
Expand Down Expand Up @@ -318,11 +321,30 @@ private ICSSSelectorMember _createSelectorMember (final CSSNode aNode)

if (ECSSNodeType.PSEUDO_HAS.isNode (aChildNode, m_eVersion))
{
final CSSSelector aSelector = new CSSSelector ();
ECSSSelectorCombinator eSelectorCombinator = null;

final int nChildChildCount = aChildNode.jjtGetNumChildren ();
for (int j = 0; j < nChildChildCount; ++j)
aSelector.addMember (_createSelectorMember (aChildNode.jjtGetChild (j)));
final CSSSelectorMemberPseudoHas ret = new CSSSelectorMemberPseudoHas (aSelector);
int i = 0;
CSSNode aChildChildNode = aChildNode.jjtGetChild (i);
if (ECSSNodeType.SELECTORCOMBINATOR.isNode (aChildChildNode, m_eVersion))
{
eSelectorCombinator = _createSelectorCombinator (aChildChildNode.getText ());
if (eSelectorCombinator != null)
{
// Skip the first elements as selector
i++;
}
}

final ICommonsList <CSSSelector> aNestedSelectors = new CommonsArrayList <> ();
for (; i < nChildChildCount; ++i)
{
aChildChildNode = aChildNode.jjtGetChild (i);
final CSSSelector aSelector = _createSelector (aChildChildNode);
aNestedSelectors.add (aSelector);
}

final CSSSelectorMemberPseudoHas ret = new CSSSelectorMemberPseudoHas (eSelectorCombinator, aNestedSelectors);
if (m_bUseSourceLocation)
ret.setSourceLocation (aNode.getSourceLocation ());
return ret;
Expand Down Expand Up @@ -380,6 +402,7 @@ private ICSSSelectorMember _createSelectorMember (final CSSNode aNode)
private CSSSelector _createSelector (@Nonnull final CSSNode aNode)
{
_expectNodeType (aNode, ECSSNodeType.SELECTOR);

final CSSSelector ret = new CSSSelector ();
if (m_bUseSourceLocation)
ret.setSourceLocation (aNode.getSourceLocation ());
Expand Down
22 changes: 3 additions & 19 deletions ph-css/src/main/jjtree/ParserCSS30.jjt
Original file line number Diff line number Diff line change
Expand Up @@ -1098,15 +1098,11 @@ void pseudoWhere() #where : {}
selector()
}

void pseudoElementSelector() : {}
{
<COLON> { jjtThis.setText (":"); }
pseudoClassSelector()
}

void pseudoClassSelector() : {}
{
<COLON> { jjtThis.setText (":"); }
// For pseudo elements
( <COLON> { jjtThis.appendText (":"); } )?
( <FUNCTION_NTH> { jjtThis.appendText (token.image); }
pseudoNth()
<RROUND> // do not append because of expression!
Expand Down Expand Up @@ -1154,33 +1150,21 @@ void funcNot() : {}

void simpleSelectorSequence() #void : {}
{
LOOKAHEAD(2)
LOOKAHEAD(4)
( typeSelector()
( idSelector()
| classSelector()
| attributeSelector()
| pseudoClassSelector()
| funcNot()
)*
( LOOKAHEAD(2)
pseudoElementSelector()
( pseudoClassSelector() )*
)*
)
| ( idSelector()
| classSelector()
| attributeSelector()
| pseudoClassSelector()
| funcNot()
)+
( LOOKAHEAD(2)
pseudoElementSelector()
( pseudoClassSelector() )*
)*
| LOOKAHEAD(2)
( pseudoElementSelector()
( pseudoClassSelector() )*
)+
// Extension for CSS animations (e.g. 50%)
| <PERCENTAGE>
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@ public abstract class AbstractFuncTestCSSReader
private final CSSReaderSettings m_aReaderSettings;
private final CSSWriterSettings m_aWriterSettings;

protected AbstractFuncTestCSSReader (@Nonnull final Charset aCharset, final boolean bDebug, final boolean bBrowserCompliantMode)
protected AbstractFuncTestCSSReader (@Nonnull final Charset aCharset,
final boolean bDebug,
final boolean bBrowserCompliantMode)
{
m_bDebug = bDebug;
m_aReaderSettings = new CSSReaderSettings ().setFallbackCharset (aCharset)
Expand All @@ -76,40 +78,41 @@ protected final void testReadGood (@Nonnull final String sBaseDir)

for (final File aFile : new FileSystemRecursiveIterator (aBaseDir).withFilter (IFileFilter.filenameEndsWith (".css")))
{
final String sKey = aFile.getAbsolutePath ();
final String sFilename = aFile.getAbsolutePath ();
if (m_bDebug)
m_aLogger.info ("Filename: " + sKey);
m_aLogger.info ("Filename: " + sFilename);
final CollectingCSSParseErrorHandler aErrorHdl = new CollectingCSSParseErrorHandler ();
m_aReaderSettings.setCustomErrorHandler (aErrorHdl.and (new LoggingCSSParseErrorHandler ()));
final CascadingStyleSheet aCSS = CSSReader.readFromFile (aFile, m_aReaderSettings);
assertNotNull (sKey, aCSS);
assertNotNull (sFilename, aCSS);

// May have errors or not
if (m_bDebug)
m_aLogger.info ("Parse errors: " + aErrorHdl.getAllParseErrors ().toString ());

// Write optimized version and compare it
String sCSS = new CSSWriter (m_aWriterSettings.setOptimizedOutput (true)).getCSSAsString (aCSS);
assertNotNull (sKey, sCSS);
assertNotNull (sFilename, sCSS);
if (m_bDebug)
m_aLogger.info ("Created CSS: " + sCSS);

final CascadingStyleSheet aCSSReRead = CSSReader.readFromStringReader (sCSS, m_aReaderSettings);
assertNotNull ("Failed to parse " + sKey + ":\n" + sCSS, aCSSReRead);
assertEquals (sKey + "\n" + sCSS, aCSS, aCSSReRead);
assertNotNull ("Failed to parse " + sFilename + ":\n" + sCSS, aCSSReRead);
assertEquals ("Differences in " + sFilename + "\n" + sCSS + "\n" + aCSS + "\n" + aCSSReRead, aCSS, aCSSReRead);

// Write non-optimized version and compare it
sCSS = new CSSWriter (m_aWriterSettings.setOptimizedOutput (false)).getCSSAsString (aCSS);
assertNotNull (sKey, sCSS);
assertNotNull (sFilename, sCSS);
if (m_bDebug)
m_aLogger.info ("Read and re-created CSS: " + sCSS);
assertEquals (sKey, aCSS, CSSReader.readFromStringReader (sCSS, m_aReaderSettings));
assertEquals (sFilename, aCSS, CSSReader.readFromStringReader (sCSS, m_aReaderSettings));

// Write non-optimized and code-removed version and ensure it is not
// null
sCSS = new CSSWriter (m_aWriterSettings.setOptimizedOutput (false).setRemoveUnnecessaryCode (true)).getCSSAsString (aCSS);
assertNotNull (sKey, sCSS);
assertNotNull (sKey, CSSReader.readFromStringReader (sCSS, m_aReaderSettings));
sCSS = new CSSWriter (m_aWriterSettings.setOptimizedOutput (false)
.setRemoveUnnecessaryCode (true)).getCSSAsString (aCSS);
assertNotNull (sFilename, sCSS);
assertNotNull (sFilename, CSSReader.readFromStringReader (sCSS, m_aReaderSettings));

// Restore value :)
m_aWriterSettings.setRemoveUnnecessaryCode (false);
Expand Down
Loading

0 comments on commit 268da6f

Please sign in to comment.