/**
* Copyright (c) 2000-present Liferay, Inc. All rights reserved.
*
* This library 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 library 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.
*/
package com.liferay.portal.tools.theme.builder;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.FileSystem;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.PathMatcher;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.json.simple.JSONObject;
import org.json.simple.JSONValue;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
* @author Andrea Di Giorgi
*/
@RunWith(Parameterized.class)
public class ThemeBuilderCompareTest {
@Parameters(name = "{1}")
public static Iterable<Object[]> getTestThemes() throws Exception {
Properties properties = new Properties();
try (InputStream inputStream = Files.newInputStream(
Paths.get("build/test-theme-dependencies.properties"))) {
properties.load(inputStream);
}
List<Object[]> testThemes = new ArrayList<>(properties.size());
DocumentBuilderFactory documentBuilderFactory =
DocumentBuilderFactory.newInstance();
for (String dirName : properties.stringPropertyNames()) {
String warFileName = properties.getProperty(dirName);
testThemes.add(
_getTestTheme(dirName, warFileName, documentBuilderFactory));
}
return testThemes;
}
@BeforeClass
public static void setUpClass() throws IOException {
try (BufferedReader bufferedReader = Files.newBufferedReader(
Paths.get("build/parent-theme-dependencies.txt"))) {
String line;
while ((line = bufferedReader.readLine()) != null) {
File jarFile = new File(line);
Assert.assertTrue(jarFile.isFile());
if (line.contains("com.liferay.frontend.theme.styled-")) {
_styledJarFile = jarFile;
}
else if (line.contains(
"com.liferay.frontend.theme.unstyled-")) {
_unstyledJarFile = jarFile;
}
}
}
}
public ThemeBuilderCompareTest(
File diffsDir, String name, String parentName, String templateExtension,
File warFile) {
_diffsDir = diffsDir;
_name = name;
_parentDir = _getParentDir(parentName);
_parentName = parentName;
_templateExtension = templateExtension;
_warFile = warFile;
}
@Test
public void testThemeBuilderCompare() throws Exception {
File outputDir = temporaryFolder.newFolder("output");
ThemeBuilder themeBuilder = new ThemeBuilder(
_diffsDir, _name, outputDir, _parentDir, _parentName,
_templateExtension, _unstyledJarFile);
themeBuilder.build();
File warDir = temporaryFolder.newFolder("war");
_unzip(_warFile, warDir);
String otherTemplateExtension = "vm";
if (_templateExtension.equals("vm")) {
otherTemplateExtension = "ftl";
}
String[] excludePatterns = {
"css/*.css", "images/thumbnail.png",
"templates/*." + otherTemplateExtension, "WEB-INF/**"
};
Map<String, byte[]> outputFileNameDigests = _getFileNameDigests(
outputDir.toPath(), excludePatterns);
Map<String, byte[]> warFileNameDigests = _getFileNameDigests(
warDir.toPath(), excludePatterns);
Assert.assertEquals(
warFileNameDigests.toString(), outputFileNameDigests.size(),
warFileNameDigests.size());
for (Map.Entry<String, byte[]> entry :
outputFileNameDigests.entrySet()) {
String fileName = entry.getKey();
byte[] outputFileDigest = entry.getValue();
byte[] warFileDigest = warFileNameDigests.get(fileName);
Assert.assertArrayEquals(
"File " + fileName + " does not match", outputFileDigest,
warFileDigest);
}
}
@Rule
public final TemporaryFolder temporaryFolder = new TemporaryFolder();
private static Map<String, byte[]> _getFileNameDigests(
final Path dirPath, String... excludePatterns)
throws Exception {
final Map<String, byte[]> fileNameDigests = new HashMap<>();
final MessageDigest messageDigest = MessageDigest.getInstance("MD5");
final List<PathMatcher> excludePathMatchers = new ArrayList<>(
excludePatterns.length);
FileSystem fileSystem = dirPath.getFileSystem();
String dirName = dirPath.toString();
if (File.separatorChar != '/') {
dirName = dirName.replace(File.separatorChar, '/');
}
for (String pattern : excludePatterns) {
PathMatcher pathMatcher = fileSystem.getPathMatcher(
"glob:" + dirName + "/" + pattern);
excludePathMatchers.add(pathMatcher);
}
Files.walkFileTree(
dirPath,
new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(
Path path, BasicFileAttributes basicFileAttributes)
throws IOException {
for (PathMatcher pathMatcher : excludePathMatchers) {
if (pathMatcher.matches(path)) {
return FileVisitResult.CONTINUE;
}
}
Path relativePath = dirPath.relativize(path);
messageDigest.reset();
messageDigest.update(Files.readAllBytes(path));
fileNameDigests.put(
relativePath.toString(), messageDigest.digest());
return FileVisitResult.CONTINUE;
}
});
return fileNameDigests;
}
private static File _getParentDir(String parentName) {
if (parentName.equals(ThemeBuilder.STYLED)) {
return _styledJarFile;
}
if (parentName.equals(ThemeBuilder.UNSTYLED)) {
return _unstyledJarFile;
}
throw new IllegalArgumentException(
"Unsupported parent name " + parentName);
}
private static Object[] _getTestTheme(
String dirName, String warFileName,
DocumentBuilderFactory documentBuilderFactory)
throws Exception {
File dir = new File(dirName);
File diffsDir = new File(dir, "src");
JSONObject packageJSONObject;
try (FileReader fileReader = new FileReader(
new File(dir, "package.json"))) {
packageJSONObject = (JSONObject)JSONValue.parseWithException(
fileReader);
}
String name = (String)packageJSONObject.get("name");
JSONObject liferayThemeJSONObject = (JSONObject)packageJSONObject.get(
"liferayTheme");
String parentName = (String)liferayThemeJSONObject.get("baseTheme");
if (parentName.equals("styled")) {
parentName = ThemeBuilder.STYLED;
}
else if (parentName.equals("unstyled")) {
parentName = ThemeBuilder.UNSTYLED;
}
else {
throw new IllegalArgumentException(
"Unsupported base theme " + parentName);
}
DocumentBuilder documentBuilder =
documentBuilderFactory.newDocumentBuilder();
Document document = documentBuilder.parse(
new File(dir, "src/WEB-INF/liferay-look-and-feel.xml"));
NodeList nodeList = document.getElementsByTagName("template-extension");
Node node = nodeList.item(0);
String templateExtension = node.getTextContent();
File warFile = new File(warFileName);
return new Object[] {
diffsDir, name, parentName, templateExtension, warFile
};
}
private static void _unzip(File file, File outputDir) throws IOException {
Path outputDirPath = outputDir.toPath();
try (ZipFile zipFile = new ZipFile(file)) {
Enumeration<? extends ZipEntry> enumeration = zipFile.entries();
while (enumeration.hasMoreElements()) {
ZipEntry zipEntry = enumeration.nextElement();
String name = zipEntry.getName();
if (name.endsWith("/")) {
continue;
}
Path path = outputDirPath.resolve(name);
Files.createDirectories(path.getParent());
Files.copy(zipFile.getInputStream(zipEntry), path);
}
}
}
private static File _styledJarFile;
private static File _unstyledJarFile;
private final File _diffsDir;
private final String _name;
private final File _parentDir;
private final String _parentName;
private final String _templateExtension;
private final File _warFile;
}