/**
* Copyright 2015 Nabarun Mondal
* 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
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* 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 com.noga.njexl.testing.api.junit;
import com.noga.njexl.lang.extension.TypeUtility;
import com.noga.njexl.testing.api.*;
import com.noga.njexl.testing.api.Annotations.* ;
import com.noga.njexl.testing.api.ServiceCreatorFactory.ServiceCreator ;
import com.noga.njexl.testing.dataprovider.collection.XStreamIterator;
import org.junit.runner.JUnitCore;
import org.junit.runner.Request;
import org.junit.runner.Result;
import org.junit.runner.Runner;
import org.junit.runners.Suite;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* jUnit class runner to run a standard POJO as Test
*/
public class JClassRunner extends Suite {
/**
* Runs a nApi Class using jUnit
* @param clazz the class implementing nApi
* @return result
* @throws Exception in case of error
*/
public static Result run(Class<?> clazz) throws Exception {
JUnitCore c = new JUnitCore();
JClassRunner suite = new JClassRunner( clazz );
Result r = c.run(Request.runner(suite));
return r;
}
protected final List<Runner> children;
/**
* Creates a runner from a class
* @param clazz the class to wrap into multiple tests
* @throws Exception if fails to do so
*/
public JClassRunner(Class<?> clazz) throws Exception {
super(clazz, Collections.<Runner>emptyList());
children = new ArrayList<>();
createRunners();
}
/**
* Creates a service object from a creator
* @param creator the creator to take definition from
* @param clazz the class to create
* @return instance of a service object
* @throws Exception if fails to do so
*/
public Object service(NApiServiceCreator creator, Class clazz) throws Exception{
ServiceCreator serviceCreator = ServiceCreatorFactory.creator(creator);
Object service = serviceCreator.create(clazz);
return service;
}
/**
* Creates a dict entry x:y
* @param s a string with x=y
* @return a dict entry x:y format
*/
public static String dictEntry(String s){
String[] pairs = s.split("=");
if ( pairs.length != 2 ){
return "null:null" ; // defaults
}
String ret = String.format("'%s' : '%s'", pairs[0],pairs[1]);
return ret;
}
/**
* Get the global variable
* @param arr the array of the global variables
* @return a dict in nJexl string
*/
public static String globals(String[] arr){
StringBuffer buffer = new StringBuffer();
buffer.append("{");
if ( arr.length > 0 ) {
buffer.append(dictEntry(arr[0]));
for (int i = 1; i < arr.length; i++) {
buffer.append(",");
buffer.append(dictEntry(arr[i]));
}
}
buffer.append("}");
return buffer.toString();
}
protected List<JApiRunner> runners(MethodRunInformation mi, Object service) throws Exception{
ArgConverter converter = new ArgConverter(mi);
String globals = globals(mi.nApi.globals());
CallContainer[] containers = converter.allContainers();
// update these containers with ready to run data
for ( int i = 0 ; i < containers.length; i++ ){
containers[i].service = service ;
containers[i].pre = mi.base + "/" + mi.nApi.before() ;
containers[i].post = mi.base + "/" + mi.nApi.after() ;
containers[i].globals = globals ;
}
if ( mi.nApi.randomize() ){
TypeUtility.shuffle(containers);
}
/*
Now what is our strategy?
How many runners are required?
[1] All runners gets different Call Container
: DTD : they gets executed one test data after another
[2] All threads gets different Call Container
: DCD : Every Call will get different input
*/
// now create an iterator
XStreamIterator<CallContainer> iterator = new XStreamIterator<>(containers);
ArrayList l = new ArrayList();
if ( mi.nApiThread.use() && mi.nApiThread.dcd() ){
// do not worry, rewind if need be
iterator.setMode(false);
// no of tests are strictly the no of threads to spawn
int totCalls = mi.nApiThread.numThreads() * mi.nApiThread.numCallPerThread() ;
int tests = iterator.size() / totCalls ;
if ( iterator.size() % totCalls > 0 ) {
tests += 1;
}
for ( int i = 0 ; i < tests ; i++ ){
JApiRunner jApiRunner = JApiRunner.createRunner(-1, iterator, mi);
l.add(jApiRunner);
}
}
else{
// tests are strictly the no of data rows
for ( int i = 0 ; i < containers.length ; i++ ){
JApiRunner jApiRunner = JApiRunner.createRunner(i, iterator, mi);
l.add(jApiRunner);
}
}
return l;
}
protected void createRunners() throws Exception{
Class clazz = super.getTestClass().getJavaClass();
NApiServiceCreator creator = Annotations.NApiServiceCreator(clazz);
Object service = service(creator,clazz);
List<MethodRunInformation> l = Annotations.runs(clazz);
for ( MethodRunInformation mi : l ){
List<JApiRunner> runners = runners( mi , service);
children.addAll(runners);
}
}
@Override
protected List<Runner> getChildren() {
return children;
}
}