/*
* #%L
* ACS AEM Commons Bundle
* %%
* Copyright (C) 2013 Adobe
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
package com.adobe.acs.commons.rewriter.impl;
import static org.mockito.AdditionalMatchers.not;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Matchers.isNull;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.io.InputStream;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.rewriter.ProcessingComponentConfiguration;
import org.apache.sling.rewriter.ProcessingContext;
import org.apache.sling.rewriter.Transformer;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;
import com.adobe.granite.ui.clientlibs.HtmlLibrary;
import com.adobe.granite.ui.clientlibs.HtmlLibraryManager;
import com.adobe.granite.ui.clientlibs.LibraryType;
import junitx.util.PrivateAccessor;
@RunWith(MockitoJUnitRunner.class)
public class StylesheetInlinerTransformerFactoryTest {
@Mock
private HtmlLibraryManager htmlLibraryManager;
@Mock
private HtmlLibrary htmlLibrary;
@Mock
private ContentHandler handler;
@Mock
private ProcessingContext processingContext;
@Mock
private SlingHttpServletRequest slingRequest;
@Mock
private ResourceResolver resourceResolver;
@Mock
private Resource resource;
private StylesheetInlinerTransformerFactory factory;
private Transformer transformer;
private Attributes empty = new AttributesImpl();
private final String CLIENTLIB_PATH = "/etc/clientlibs/test";
private final String CSS_RESOURCE_PATH = "/etc/assets/somecss";
private final String NON_EXISTING_PATH = "/etc/assets/doesntexist";
private static final String CSS_CONTENTS = "div {display:block;}";
private static final String NEWLINE = "\n";
private static final String TEST_DATA = "some test data";
@Before
public void setUp() throws Throwable {
factory = new StylesheetInlinerTransformerFactory();
PrivateAccessor.setField(factory, "htmlLibraryManager", htmlLibraryManager);
when(htmlLibrary.getInputStream()).thenReturn(new java.io.ByteArrayInputStream(CSS_CONTENTS.getBytes()));
when(htmlLibraryManager.getLibrary(eq(LibraryType.CSS), eq(CLIENTLIB_PATH))).thenReturn(htmlLibrary);
when(htmlLibraryManager.getLibrary(eq(LibraryType.CSS), not(eq(CLIENTLIB_PATH)))).thenReturn(null);
when( slingRequest.getRequestURL()).thenReturn(new StringBuffer("testing"));
when(resource.adaptTo(eq(InputStream.class))).thenReturn(new java.io.ByteArrayInputStream(CSS_CONTENTS.getBytes()));
when(resourceResolver.getResource(eq(CSS_RESOURCE_PATH + ".css" ))).thenReturn(resource);
when(resourceResolver.getResource(eq(NON_EXISTING_PATH))).thenReturn(null);
when(slingRequest.getResourceResolver()).thenReturn(resourceResolver);
when(processingContext.getRequest()).thenReturn(slingRequest);
transformer = factory.createTransformer();
PrivateAccessor.invoke(transformer, "init",
new Class[] {ProcessingContext.class, ProcessingComponentConfiguration.class},
new Object[] {processingContext, null} );
transformer.setContentHandler(handler);
}
@After
public void tearDown() throws Exception {
reset(htmlLibraryManager, htmlLibrary, handler);
transformer = null;
}
@Test
public void testNoop() throws Exception {
startHeadSection(empty);
startBodySection(empty);
endBodySection();
verify(handler).startElement(isNull(String.class), eq("html"), isNull(String.class), eq(empty));
verify(handler).startElement(isNull(String.class), eq("head"), isNull(String.class), eq(empty));
verify(handler).endElement(isNull(String.class), eq("head"), isNull(String.class));
verify(handler).startElement(isNull(String.class), eq("body"), isNull(String.class), eq(empty));
verify(handler).endElement(isNull(String.class), eq("body"), isNull(String.class));
verify(handler).endElement(isNull(String.class), eq("html"), isNull(String.class));
}
@Test
public void testClientLibReferenceInHead() throws Exception {
startHeadSection(empty);
addStylesheetLink(CLIENTLIB_PATH);
startBodySection(empty);
endBodySection();
verify(handler).startElement(isNull(String.class), eq("html"), isNull(String.class), eq(empty));
verify(handler).startElement(isNull(String.class), eq("head"), isNull(String.class), eq(empty));
verifyInlineStyle();
verify(handler).endElement(isNull(String.class), eq("head"), isNull(String.class));
verify(handler).startElement(isNull(String.class), eq("body"), isNull(String.class), eq(empty));
verify(handler).endElement(isNull(String.class), eq("body"), isNull(String.class));
verify(handler).endElement(isNull(String.class), eq("html"), isNull(String.class));
}
@Test
public void testClientLibReferenceInBody() throws Exception {
startHeadSection(empty);
startBodySection(empty);
addDiv(empty);
addStylesheetLink(CLIENTLIB_PATH);
endBodySection();
verify(handler).startElement(isNull(String.class), eq("html"), isNull(String.class), eq(empty));
verify(handler).startElement(isNull(String.class), eq("head"), isNull(String.class), eq(empty));
verify(handler).endElement(isNull(String.class), eq("head"), isNull(String.class));
verify(handler).startElement(isNull(String.class), eq("body"), isNull(String.class), eq(empty));
verifyDiv();
verifyInlineStyle();
verify(handler).endElement(isNull(String.class), eq("body"), isNull(String.class));
verify(handler).endElement(isNull(String.class), eq("html"), isNull(String.class));
}
@Test
public void testResourceReferenceInHead() throws Exception {
startHeadSection(empty);
addStylesheetLink(CSS_RESOURCE_PATH);
startBodySection(empty);
endBodySection();
verify(handler).startElement(isNull(String.class), eq("html"), isNull(String.class), eq(empty));
verify(handler).startElement(isNull(String.class), eq("head"), isNull(String.class), eq(empty));
verifyInlineStyle();
verify(handler).endElement(isNull(String.class), eq("head"), isNull(String.class));
verify(handler).startElement(isNull(String.class), eq("body"), isNull(String.class), eq(empty));
verify(handler).endElement(isNull(String.class), eq("body"), isNull(String.class));
verify(handler).endElement(isNull(String.class), eq("html"), isNull(String.class));
}
@Test
public void testResourceReferenceInBody() throws Exception {
startHeadSection(empty);
startBodySection(empty);
addDiv(empty);
addStylesheetLink(CSS_RESOURCE_PATH);
endBodySection();
verify(handler).startElement(isNull(String.class), eq("html"), isNull(String.class), eq(empty));
verify(handler).startElement(isNull(String.class), eq("head"), isNull(String.class), eq(empty));
verify(handler).endElement(isNull(String.class), eq("head"), isNull(String.class));
verify(handler).startElement(isNull(String.class), eq("body"), isNull(String.class), eq(empty));
verifyDiv();
verifyInlineStyle();
verify(handler).endElement(isNull(String.class), eq("body"), isNull(String.class));
verify(handler).endElement(isNull(String.class), eq("html"), isNull(String.class));
}
@Test
public void testNonExistingResource() throws Exception {
startHeadSection(empty);
addStylesheetLink(NON_EXISTING_PATH);
startBodySection(empty);
endBodySection();
verify(handler).startElement(isNull(String.class), eq("html"), isNull(String.class), eq(empty));
verify(handler).startElement(isNull(String.class), eq("head"), isNull(String.class), eq(empty));
verify(handler).endElement(isNull(String.class), eq("head"), isNull(String.class));
verify(handler).startElement(isNull(String.class), eq("body"), isNull(String.class), eq(empty));
verify(handler).endElement(isNull(String.class), eq("body"), isNull(String.class));
verify(handler).endElement(isNull(String.class), eq("html"), isNull(String.class));
}
private void endBodySection() throws SAXException {
transformer.endElement(null, "body", null);
transformer.endElement(null, "html", null);
}
private void startBodySection(Attributes atts) throws SAXException {
transformer.endElement(null, "head", null);
transformer.startElement(null, "body", null, atts);
}
private void addDiv(Attributes atts) throws SAXException {
transformer.startElement(null, "div", null, atts);
transformer.characters( TEST_DATA.toCharArray(), 0, TEST_DATA.length());
transformer.endElement(null, "div", null);
}
private void verifyDiv() throws SAXException {
verify(handler).startElement(isNull(String.class), eq("div"), isNull(String.class), eq(empty));
verify(handler).characters(TEST_DATA.toCharArray(), 0, TEST_DATA.length());
verify(handler).endElement(isNull(String.class), eq("div"), isNull(String.class));
}
private void verifyInlineStyle() throws SAXException {
verify(handler).startElement(isNull(String.class), eq("style"), isNull(String.class), any(org.xml.sax.Attributes.class));
verify(handler).characters(NEWLINE.toCharArray(), 0, NEWLINE.length());
verify(handler).characters(CSS_CONTENTS.toCharArray(), 0, CSS_CONTENTS.length());
verify(handler).endElement(isNull(String.class), eq("style"), isNull(String.class));
}
private void startHeadSection(Attributes atts) throws SAXException {
transformer.startElement(null, "html", null, atts);
transformer.startElement(null, "head", null, atts);
}
private void addStylesheetLink(String path) throws SAXException {
final AttributesImpl in = new AttributesImpl();
in.addAttribute("", "href", "", "CDATA", path + ".css");
in.addAttribute("", "type", "", "CDATA", "text/css");
in.addAttribute("", "rel", "", "CDATA", "stylesheet");
transformer.startElement(null, "link", null, in);
transformer.endElement(null, "link", null);
}
}