/*
* Copyright 2013 eXo Platform SAS
*
* 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.
*/
package juzu.test;
import junit.framework.Assert;
import junit.framework.AssertionFailedError;
import juzu.impl.common.Name;
import juzu.impl.fs.spi.disk.DiskFileSystem;
import juzu.impl.fs.spi.url.URLFileSystem;
import juzu.impl.inject.spi.InjectorProvider;
import juzu.impl.common.JSON;
import juzu.impl.common.Tools;
import juzu.test.protocol.mock.MockApplication;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.rules.TestName;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
/** @author <a href="mailto:julien.viet@exoplatform.com">Julien Viet</a> */
//@RunWith(JUnit38ClassRunner.class)
public abstract class AbstractTestCase extends Assert {
/** Encoding proof euro sign. */
public static final String EURO = "\u20AC";
@Before
public void setUp() throws Exception {
Registry.clear();
}
@After
public void tearDown() {
if (application != null) {
Tools.safeClose(application);
application = null;
}
}
/**
* Wait for at least one millisecond, based on the current time clock.
*
* @return the time captured after the wait
*/
public static long waitForOneMillis() {
long snapshot = System.currentTimeMillis();
while (true) {
try {
long now = System.currentTimeMillis();
if (snapshot < now) {
return now;
}
else {
snapshot = now;
Thread.sleep(1);
}
}
catch (InterruptedException e) {
AssertionFailedError afe = new AssertionFailedError("Was not expecting interruption");
afe.initCause(e);
throw afe;
}
}
}
public static void fail(Throwable t) {
throw failure(t);
}
public static AssertionFailedError failure(Throwable t) {
AssertionFailedError afe = new AssertionFailedError();
afe.initCause(t);
return afe;
}
public static AssertionFailedError failure(String msg, Throwable t) {
AssertionFailedError afe = new AssertionFailedError(msg);
afe.initCause(t);
return afe;
}
public static AssertionFailedError failure(String msg) {
return new AssertionFailedError(msg);
}
public static <T> T assertInstanceOf(Class<T> expectedInstance, Object o) {
if (expectedInstance.isInstance(o)) {
return expectedInstance.cast(o);
}
else {
throw failure("Was expecting " + o + " to be an instance of " + expectedInstance.getName());
}
}
public static <T> T assertNotInstanceOf(Class<?> expectedInstance, T o) {
if (expectedInstance.isInstance(o)) {
throw failure("Was expecting " + o + " not to be an instance of " + expectedInstance.getName());
}
else {
return o;
}
}
public static void assertDelete(File f) {
if (!f.exists()) {
throw failure("Was expecting file " + f.getAbsolutePath() + " to exist");
}
if (!f.delete()) {
throw failure("Was expecting file " + f.getAbsolutePath() + " to be deleted");
}
}
public static DiskFileSystem diskFS(Name packageName) {
File root = new File(System.getProperty("juzu.test.resources.path"));
return new DiskFileSystem(root, packageName);
}
public static DiskFileSystem diskFS(String packageName) {
File root = new File(System.getProperty("juzu.test.resources.path"));
return new DiskFileSystem(root, packageName);
}
@Rule
public TestName name = new TestName();
/** The currently deployed mock application. */
private MockApplication<File> application;
public final String getName() {
return name.getMethodName();
}
public static final CompilerAssert<File, File> compiler(String packageName, String... qualifiers) {
return compiler(false, Name.parse(packageName));
}
public final CompilerAssert<File, File> incrementalCompiler(String packageName) {
return compiler(true, packageName);
}
private CompilerAssert<File, File> compiler(boolean incremental, String packageName) {
return compiler(incremental, Name.parse(packageName), getQualifiers());
}
/**
* Override to append additional qualifiers.
*
* @return the qualifiers
*/
protected ArrayList<String> getQualifiers() {
ArrayList<String> qualifiers = new ArrayList<String>();
String methodName = name.getMethodName();
if (methodName != null) {
qualifiers.add(methodName);
}
return qualifiers;
}
public static CompilerAssert<File, File> compiler(boolean incremental, Name packageName, String... qualifiers) {
return compiler(incremental, packageName, Arrays.asList(qualifiers));
}
private static CompilerAssert<File, File> compiler(boolean incremental, Name packageName, List<String> qualifiers) {
if (packageName.isEmpty()) {
throw failure("Cannot compile empty package");
}
//
String outputPath = System.getProperty("juzu.test.workspace.path");
File a = new File(outputPath);
if (a.exists()) {
if (a.isFile()) {
throw failure("File " + outputPath + " already exist and is a file");
}
}
else {
if (!a.mkdirs()) {
throw failure("Could not create test generated source directory " + outputPath);
}
}
// Find
StringBuilder pkg = Tools.join(new StringBuilder(), '_', packageName);
if (qualifiers != null) {
for (String qualifier : qualifiers) {
pkg.append('#').append(qualifier);
}
}
File f2 = new File(a, pkg.toString());
for (int count = 0;;count++) {
if (!f2.exists()) {
break;
}
else {
f2 = new File(a, pkg + "-" + count);
}
}
//
if (!f2.mkdirs()) {
throw failure("Could not create test generated source directory " + f2.getAbsolutePath());
}
//
File sourceOutputDir = new File(f2, "source-output");
assertTrue(sourceOutputDir.mkdir());
DiskFileSystem sourceOutput = new DiskFileSystem(sourceOutputDir);
//
File classOutputDir = new File(f2, "class-output");
assertTrue(classOutputDir.mkdir());
DiskFileSystem classOutput = new DiskFileSystem(classOutputDir);
//
File sourcePathDir = new File(f2, "source-path");
String relativePath = packageName.toString().replace('.', '/') + '/';
assertTrue(new File(sourcePathDir, relativePath).mkdirs());
DiskFileSystem sourcePath = new DiskFileSystem(sourcePathDir);
URL url = Thread.currentThread().getContextClassLoader().getResource(relativePath);
if (url == null) {
throw failure("Could not resolve resource " + relativePath);
}
try {
URLFileSystem fs = new URLFileSystem();
fs.add(url);
fs.copy(sourcePath, sourcePath.getPath(packageName));
}
catch (Exception e) {
throw failure(e);
}
//
return new CompilerAssert<File, File>(incremental, sourcePath, sourceOutput, classOutput);
}
public MockApplication<File> application(InjectorProvider injectorProvider, String packageName) {
if (application != null) {
throw failure("An application is already deployed");
}
CompilerAssert<File, File> compiler = compiler(packageName);
try {
return application = new MockApplication<File>(compiler, injectorProvider, Name.parse(packageName));
}
catch (Exception e) {
throw AbstractTestCase.failure(e);
}
}
public static void assertEquals(JSON expected, JSON test) {
if (expected != null) {
if (test == null) {
throw failure("Was expected " + expected + " to be not null");
}
else if (!equalsIgnoreNull(expected, test)) {
StringBuilder sb;
try {
sb = new StringBuilder("expected <");
expected.toString(sb, 2);
sb.append("> but was:<");
test.toString(sb, 2);
sb.append(">");
throw failure(sb.toString());
}
catch (IOException e) {
throw failure("Unexpected", e);
}
}
}
else {
if (test != null) {
throw failure("Was expected " + test + " to be null");
}
}
}
private static boolean equalsIgnoreNull(Object o1, Object o2) {
if (o1 == null || o2 == null) {
return true;
} else if (o1 instanceof List && o2 instanceof List) {
Iterator i1 = ((List)o1).iterator();
Iterator i2 = ((List)o2).iterator();
while (true) {
boolean n1 = i1.hasNext();
boolean n2 = i2.hasNext();
if (n1 && n2) {
if (!equalsIgnoreNull(i1.next(), i2.next())) {
return false;
}
} else {
return n1 == n2;
}
}
} else {
if (o1 instanceof JSON && o2 instanceof JSON) {
JSON js1 = (JSON)o1;
JSON js2 = (JSON)o2;
HashSet<String> names = new HashSet<String>(js1.names());
names.addAll(js2.names());
for (String name : names) {
js1.getArray("", Object.class);
Object v1 = js1.get(name);
Object v2 = js2.get(name);
if (!equalsIgnoreNull(v1, v2)) {
return false;
}
}
return true;
} else {
return o1.equals(o2);
}
}
}
public static void assertNoSuchElement(Iterator<?> iterator) {
try {
Object next = iterator.next();
fail("Was not expecting to obtain " + next + " element from an iterator");
}
catch (NoSuchElementException expected) {
}
}
public static <E> void assertEquals(List<? extends E> expected, Iterable<? extends E> test) {
int index = 0;
Iterator<? extends E> expectedIterator = expected.iterator();
Iterator<? extends E> testIterator = test.iterator();
while (true) {
if (expectedIterator.hasNext()) {
if (testIterator.hasNext()) {
E expectedNext = expectedIterator.next();
E testNext = testIterator.next();
if (!Tools.safeEquals(expectedNext, testNext)) {
throw failure("Elements at index " + index + " are not equals: " + expectedNext + "!=" + testNext);
} else {
index++;
}
} else {
StringBuilder buffer = new StringBuilder("Expected iterable has more elements (");
while (expectedIterator.hasNext()) {
buffer.append(expectedIterator.next());
buffer.append(',');
}
buffer.setCharAt(buffer.length() - 1, ')');
buffer.append(" than the tested iterable at index ").append(index);
throw failure(buffer.toString());
}
} else {
if (testIterator.hasNext()) {
StringBuilder buffer = new StringBuilder("Tested iterable has more elements (");
while (testIterator.hasNext()) {
buffer.append(testIterator.next());
buffer.append(',');
}
buffer.setCharAt(buffer.length() - 1, ')');
buffer.append(" than the expected iterable at index ").append(index);
throw failure(buffer.toString());
} else {
break;
}
}
}
}
public static void assertEndsWith(String suffix, String test) {
if (!test.endsWith(suffix)) {
throw failure("Was expecting " + test + " to end with " + suffix);
}
}
}