package org.molgenis.js;
import org.molgenis.data.Entity;
import org.molgenis.data.meta.model.Attribute;
import org.molgenis.data.meta.model.EntityType;
import org.molgenis.data.support.DynamicEntity;
import org.molgenis.js.magma.JsMagmaScriptEvaluator;
import org.molgenis.js.nashorn.NashornScriptEngine;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.Date;
import java.util.Locale;
import static java.util.Arrays.asList;
import static java.util.Collections.singletonList;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.molgenis.data.meta.AttributeType.*;
import static org.testng.Assert.assertEquals;
public class JsMagmaScriptEvaluatorTest
{
private static EntityType personWeightEntityType;
private static EntityType personHeightEntityType;
private static EntityType personWeightAndHeightEntityType;
private static EntityType personBirthDateMeta;
private static EntityType personAgeEntityType;
private static EntityType genderEntityType;
private static EntityType personGenderEntityType;
private static JsMagmaScriptEvaluator jsMagmaScriptEvaluator;
@BeforeClass
protected static void beforeClass()
{
Attribute weightAttr = when(mock(Attribute.class).getName()).thenReturn("weight").getMock();
when(weightAttr.getDataType()).thenReturn(INT);
personWeightEntityType = when(mock(EntityType.class).getName()).thenReturn("person").getMock();
when(personWeightEntityType.getAttribute("weight")).thenReturn(weightAttr);
when(personWeightEntityType.getAtomicAttributes()).thenReturn(singletonList(weightAttr));
Attribute heightAttr = when(mock(Attribute.class).getName()).thenReturn("height").getMock();
when(heightAttr.getDataType()).thenReturn(INT);
personHeightEntityType = when(mock(EntityType.class).getName()).thenReturn("person").getMock();
when(personHeightEntityType.getAttribute("height")).thenReturn(heightAttr);
when(personHeightEntityType.getAtomicAttributes()).thenReturn(singletonList(heightAttr));
personWeightAndHeightEntityType = when(mock(EntityType.class).getName()).thenReturn("person").getMock();
when(personWeightAndHeightEntityType.getAttribute("weight")).thenReturn(weightAttr);
when(personWeightAndHeightEntityType.getAttribute("height")).thenReturn(heightAttr);
when(personWeightAndHeightEntityType.getAtomicAttributes()).thenReturn(asList(weightAttr, heightAttr));
Attribute birthDateAttr = when(mock(Attribute.class).getName()).thenReturn("birthdate").getMock();
when(birthDateAttr.getDataType()).thenReturn(DATE);
personBirthDateMeta = when(mock(EntityType.class).getName()).thenReturn("person").getMock();
when(personBirthDateMeta.getAttribute("birthdate")).thenReturn(birthDateAttr);
when(personBirthDateMeta.getAtomicAttributes()).thenReturn(singletonList(birthDateAttr));
Attribute ageAttr = when(mock(Attribute.class).getName()).thenReturn("age").getMock();
when(ageAttr.getDataType()).thenReturn(INT);
personAgeEntityType = when(mock(EntityType.class).getName()).thenReturn("person").getMock();
when(personAgeEntityType.getAttribute("age")).thenReturn(ageAttr);
when(personAgeEntityType.getAtomicAttributes()).thenReturn(singletonList(ageAttr));
Attribute idAttr = when(mock(Attribute.class).getName()).thenReturn("id").getMock();
when(idAttr.getDataType()).thenReturn(STRING);
genderEntityType = when(mock(EntityType.class).getName()).thenReturn("gender").getMock();
when(genderEntityType.getIdAttribute()).thenReturn(idAttr);
when(genderEntityType.getAttribute("id")).thenReturn(idAttr);
when(genderEntityType.getAtomicAttributes()).thenReturn(singletonList(idAttr));
Attribute genderAttr = when(mock(Attribute.class).getName()).thenReturn("gender").getMock();
when(genderAttr.getDataType()).thenReturn(CATEGORICAL);
personGenderEntityType = when(mock(EntityType.class).getName()).thenReturn("person").getMock();
when(personGenderEntityType.getAttribute("gender")).thenReturn(genderAttr);
when(personGenderEntityType.getAtomicAttributes()).thenReturn(singletonList(genderAttr));
jsMagmaScriptEvaluator = new JsMagmaScriptEvaluator(new NashornScriptEngine());
}
@Test
public void test$()
{
Entity person = new DynamicEntity(personWeightEntityType);
person.set("weight", 82);
Object weight = jsMagmaScriptEvaluator.eval("$('weight').value()", person);
assertEquals(weight, 82);
}
@Test
public void testUnitConversion()
{
Entity person = new DynamicEntity(personWeightEntityType);
person.set("weight", 82);
Object weight = jsMagmaScriptEvaluator.eval("$('weight').unit('kg').toUnit('poundmass').value()", person);
assertEquals(weight, 180.7790549915996);
}
@Test
public void mapSimple()
{
Entity gender = new DynamicEntity(genderEntityType);
gender.set("id", "B");
Entity person = new DynamicEntity(personGenderEntityType);
person.set("gender", gender);
Object result = jsMagmaScriptEvaluator.eval("$('gender').map({'20':'2','B':'B2'}).value()", person);
assertEquals(result.toString(), "B2");
}
@Test
public void mapDefault()
{
Entity gender = new DynamicEntity(genderEntityType);
gender.set("id", "B");
Entity person = new DynamicEntity(personGenderEntityType);
person.set("gender", gender);
Object result = jsMagmaScriptEvaluator.eval("$('gender').map({'20':'2'}, 'B2').value()", person);
assertEquals(result.toString(), "B2");
}
@Test
public void mapNull()
{
Object result = jsMagmaScriptEvaluator
.eval("$('gender').map({'20':'2'}, 'B2', 'B3').value()", new DynamicEntity(personGenderEntityType));
assertEquals(result.toString(), "B3");
}
@Test
public void testAverageValueOfMultipleNumericAttributes()
{
Attribute sbp1Attr = when(mock(Attribute.class).getName()).thenReturn("SBP_1").getMock();
when(sbp1Attr.getDataType()).thenReturn(DECIMAL);
Attribute sbp2Attr = when(mock(Attribute.class).getName()).thenReturn("SBP_2").getMock();
when(sbp2Attr.getDataType()).thenReturn(DECIMAL);
EntityType sbpPersonEntityType = when(mock(EntityType.class).getName()).thenReturn("person").getMock();
when(sbpPersonEntityType.getAttribute("SBP_1")).thenReturn(sbp1Attr);
when(sbpPersonEntityType.getAttribute("SBP_2")).thenReturn(sbp2Attr);
when(sbpPersonEntityType.getAtomicAttributes()).thenReturn(asList(sbp1Attr, sbp2Attr));
Entity entity0 = new DynamicEntity(sbpPersonEntityType);
entity0.set("SBP_1", 120d);
entity0.set("SBP_2", 124d);
Entity entity1 = new DynamicEntity(sbpPersonEntityType);
entity1.set("SBP_1", 120d);
Entity entity2 = new DynamicEntity(sbpPersonEntityType);
String script = "var counter = 0;\nvar SUM=newValue(0);\nif(!$('SBP_1').isNull().value()){\n\tSUM.plus($('SBP_1').value());\n\tcounter++;\n}\nif(!$('SBP_2').isNull().value()){\n\tSUM.plus($('SBP_2').value());\n\tcounter++;\n}\nif(counter !== 0){\n\tSUM.div(counter);\nSUM.value();\n}\nelse{\n\tnull;\n}";
Object result1 = jsMagmaScriptEvaluator.eval(script, entity0);
assertEquals(result1.toString(), "122.0");
Object result2 = jsMagmaScriptEvaluator.eval(script, entity1);
assertEquals(result2.toString(), "120.0");
Object result3 = jsMagmaScriptEvaluator.eval(script, entity2);
assertEquals(result3, null);
}
@Test
public void testGroup()
{
Entity entity1 = new DynamicEntity(personAgeEntityType);
entity1.set("age", 29);
Object result1 = jsMagmaScriptEvaluator.eval("$('age').group([18, 35, 56]).value();", entity1);
assertEquals(result1.toString(), "18-35");
Entity entity2 = new DynamicEntity(personAgeEntityType);
entity2.set("age", 999);
Object result2 = jsMagmaScriptEvaluator.eval("$('age').group([18, 35, 56], [888, 999]).value();", entity2);
assertEquals(result2.toString(), "999");
Entity entity3 = new DynamicEntity(personAgeEntityType);
entity3.set("age", 47);
Object result3 = jsMagmaScriptEvaluator.eval("$('age').group([18, 35, 56]).value();", entity3);
assertEquals(result3.toString(), "35-56");
}
@Test
public void testGroupNull()
{
Entity entity4 = new DynamicEntity(personAgeEntityType);
entity4.set("age", 47);
Object result4 = jsMagmaScriptEvaluator.eval("$('age').group().value();", entity4);
assertEquals(result4, null);
Object result5 = jsMagmaScriptEvaluator.eval("$('age').group([56, 18, 35]).value();", entity4);
assertEquals(result5, null);
Object result6 = jsMagmaScriptEvaluator.eval("$('age').group([56, 18, 35], null,'123456').value();", entity4);
assertEquals(result6.toString(), "123456");
}
@Test
public void testGroupConstantValue()
{
Entity entity4 = new DynamicEntity(personAgeEntityType);
entity4.set("age", 47);
Object result4 = jsMagmaScriptEvaluator
.eval("var age_variable=new newValue(45);age_variable.group([18, 35, 56]).value();", entity4);
assertEquals(result4.toString(), "35-56");
}
@Test
public void combineGroupMapFunctions()
{
Entity entity1 = new DynamicEntity(personAgeEntityType);
entity1.set("age", 29);
Object result1 = jsMagmaScriptEvaluator
.eval("$('age').group([18, 35, 56]).map({'-18':'0','18-35':'1','35-56':'2','56+':'3'}).value();",
entity1);
assertEquals(result1.toString(), "1");
Entity entity2 = new DynamicEntity(personAgeEntityType);
entity2.set("age", 17);
Object result2 = jsMagmaScriptEvaluator
.eval("$('age').group([18, 35, 56]).map({'-18':'0','18-35':'1','35-56':'2','56+':'3'}).value();",
entity2);
assertEquals(result2.toString(), "0");
Entity entity3 = new DynamicEntity(personAgeEntityType);
entity3.set("age", 40);
Object result3 = jsMagmaScriptEvaluator
.eval("$('age').group([18, 35, 56]).map({'-18':'0','18-35':'1','35-56':'2','56+':'3'}).value();",
entity3);
assertEquals(result3.toString(), "2");
Entity entity4 = new DynamicEntity(personAgeEntityType);
entity4.set("age", 70);
Object result4 = jsMagmaScriptEvaluator
.eval("$('age').group([18, 35, 56]).map({'-18':'0','18-35':'1','35-56':'2','56+':'3'}).value();",
entity4);
assertEquals(result4.toString(), "3");
Entity entity5 = new DynamicEntity(personAgeEntityType);
entity5.set("age", 999);
Object result5 = jsMagmaScriptEvaluator
.eval("$('age').group([18, 35, 56], [999]).map({'-18':0,'18-35':1,'35-56':2,'56+':3,'999':'9'}).value();",
entity5);
assertEquals(result5.toString(), "9");
}
@Test
public void combinePlusGroupMapFunctions()
{
Attribute food59Attr = when(mock(Attribute.class).getName()).thenReturn("FOOD59A1").getMock();
when(food59Attr.getDataType()).thenReturn(INT);
Attribute food60Attr = when(mock(Attribute.class).getName()).thenReturn("FOOD60A1").getMock();
when(food60Attr.getDataType()).thenReturn(INT);
EntityType foodPersonEntityType = when(mock(EntityType.class).getName()).thenReturn("person").getMock();
when(foodPersonEntityType.getAttribute("FOOD59A1")).thenReturn(food59Attr);
when(foodPersonEntityType.getAttribute("FOOD60A1")).thenReturn(food60Attr);
when(foodPersonEntityType.getAtomicAttributes()).thenReturn(asList(food59Attr, food60Attr));
Entity entity0 = new DynamicEntity(foodPersonEntityType);
entity0.set("FOOD59A1", 7);
entity0.set("FOOD60A1", 6);
Object result1 = jsMagmaScriptEvaluator
.eval("var SUM_WEIGHT = new newValue(0);SUM_WEIGHT.plus($('FOOD59A1').map({\"1\":0,\"2\":0.2,\"3\":0.6,\"4\":1,\"5\":2.5,\"6\":4.5,\"7\":6.5}, null, null).value());SUM_WEIGHT.plus($('FOOD60A1').map({\"1\":0,\"2\":0.2,\"3\":0.6,\"4\":1,\"5\":2.5,\"6\":4.5,\"7\":6.5}, null, null).value());SUM_WEIGHT.group([0,1,2,6,7]).map({\"0-1\":\"4\",\"1-2\":\"3\",\"2-6\":\"2\",\"6-7\":\"1\", \"7+\" : \"1\"},null,null).value();",
entity0);
assertEquals(result1.toString(), "1");
}
@Test
public void testPlusValue()
{
Entity entity0 = new DynamicEntity(personHeightEntityType);
entity0.set("height", 180);
Object result = jsMagmaScriptEvaluator.eval("$('height').plus(100).value()", entity0);
assertEquals(result, (double) 280);
}
@Test
public void testPlusObject()
{
Entity entity0 = new DynamicEntity(personHeightEntityType);
entity0.set("height", 180);
Object result1 = jsMagmaScriptEvaluator.eval("$('height').plus(new newValue(100)).value()", entity0);
assertEquals(result1, (double) 280);
}
@Test
public void testPlusNullValue()
{
Entity entity0 = new DynamicEntity(personHeightEntityType);
entity0.set("height", 180);
Object result1 = jsMagmaScriptEvaluator.eval("$('height').plus(null).value()", entity0);
assertEquals(result1, 180);
}
@Test
public void testTimes()
{
Entity entity0 = new DynamicEntity(personHeightEntityType);
entity0.set("height", 2);
Object result = jsMagmaScriptEvaluator.eval("$('height').times(100).value()", entity0);
assertEquals(result, (double) 200);
}
@Test
public void div()
{
Entity entity0 = new DynamicEntity(personHeightEntityType);
entity0.set("height", 200);
Object result = jsMagmaScriptEvaluator.eval("$('height').div(100).value()", entity0);
assertEquals(result, 2d);
}
@Test
public void pow()
{
Entity entity0 = new DynamicEntity(personHeightEntityType);
entity0.set("height", 20);
Object result = jsMagmaScriptEvaluator.eval("$('height').pow(2).value()", entity0);
assertEquals(result, 400d);
}
@Test
public void testBmi()
{
Entity person = new DynamicEntity(personWeightAndHeightEntityType);
person.set("weight", 82);
person.set("height", 189);
Object bmi = jsMagmaScriptEvaluator.eval("$('weight').div($('height').div(100).pow(2)).value()", person);
DecimalFormat df = new DecimalFormat("#.####", new DecimalFormatSymbols(Locale.ENGLISH));
assertEquals(df.format(bmi), df.format(82.0 / (1.89 * 1.89)));
}
@Test
public void testGlucose()
{
Attribute gluc1Attr = when(mock(Attribute.class).getName()).thenReturn("GLUC_1").getMock();
when(gluc1Attr.getDataType()).thenReturn(DECIMAL);
EntityType personGlucoseMeta = when(mock(EntityType.class).getName()).thenReturn("glucose").getMock();
when(personGlucoseMeta.getAttribute("GLUC_1")).thenReturn(gluc1Attr);
when(personGlucoseMeta.getAtomicAttributes()).thenReturn(singletonList(gluc1Attr));
Entity glucose = new DynamicEntity(personGlucoseMeta);
glucose.set("GLUC_1", 4.1);
Object bmi = jsMagmaScriptEvaluator.eval("$('GLUC_1').div(100).value()", glucose);
DecimalFormat df = new DecimalFormat("#.####", new DecimalFormatSymbols(Locale.ENGLISH));
assertEquals(df.format(bmi), df.format(4.1 / 100));
}
@Test
public void age()
{
Entity person = new DynamicEntity(personBirthDateMeta);
person.set("birthdate", new Date());
Object result = jsMagmaScriptEvaluator.eval("$('birthdate').age().value()", person);
assertEquals(result, 0d);
}
@Test
public void testNull()
{
Entity person0 = new DynamicEntity(personBirthDateMeta);
person0.set("birthdate", new Date());
String script = "$('birthdate').age().value() < 18 || $('birthdate').value() != null";
Object result = jsMagmaScriptEvaluator.eval(script, person0);
assertEquals(result, true);
Entity person1 = new DynamicEntity(personBirthDateMeta);
person1.set("birthdate", null);
result = jsMagmaScriptEvaluator.eval(script, person1);
assertEquals(result, false);
}
@Test
public void testEq()
{
Entity person0 = new DynamicEntity(personWeightEntityType);
person0.set("weight", 100);
String script = "$('weight').eq(100).value()";
Object result = jsMagmaScriptEvaluator.eval(script, person0);
assertEquals(result, true);
Entity person1 = new DynamicEntity(personWeightEntityType);
person1.set("weight", 99);
result = jsMagmaScriptEvaluator.eval(script, person1);
assertEquals(result, false);
}
@Test
public void testIsNull()
{
Entity person0 = new DynamicEntity(personWeightEntityType);
person0.set("weight", null);
String script = "$('weight').isNull().value()";
Object result = jsMagmaScriptEvaluator.eval(script, person0);
assertEquals(result, true);
Entity person1 = new DynamicEntity(personWeightEntityType);
person1.set("weight", 99);
result = jsMagmaScriptEvaluator.eval(script, person1);
assertEquals(result, false);
}
@Test
public void testNot()
{
Entity person0 = new DynamicEntity(personWeightEntityType);
person0.set("weight", null);
String script = "$('weight').isNull().not().value()";
Object result = jsMagmaScriptEvaluator.eval(script, person0);
assertEquals(result, false);
Entity person1 = new DynamicEntity(personWeightEntityType);
person1.set("weight", 99);
result = jsMagmaScriptEvaluator.eval(script, person1);
assertEquals(result, true);
}
@Test
public void testOr()
{
Entity person0 = new DynamicEntity(personWeightEntityType);
person0.set("weight", null);
String script = "$('weight').eq(99).or($('weight').eq(100)).value()";
Object result = jsMagmaScriptEvaluator.eval(script, person0);
assertEquals(result, false);
Entity person1 = new DynamicEntity(personWeightEntityType);
person1.set("weight", 99);
result = jsMagmaScriptEvaluator.eval(script, person1);
assertEquals(result, true);
Entity person2 = new DynamicEntity(personWeightEntityType);
person2.set("weight", 100);
result = jsMagmaScriptEvaluator.eval(script, person2);
assertEquals(result, true);
Entity person3 = new DynamicEntity(personWeightEntityType);
person3.set("weight", 99);
result = jsMagmaScriptEvaluator.eval(script, person3);
assertEquals(result, true);
}
@Test
public void testGt()
{
Entity person0 = new DynamicEntity(personWeightEntityType);
person0.set("weight", null);
String script = "$('weight').gt(100).value()";
Object result = jsMagmaScriptEvaluator.eval(script, person0);
assertEquals(result, false);
Entity person1 = new DynamicEntity(personWeightEntityType);
person1.set("weight", 99);
result = jsMagmaScriptEvaluator.eval(script, person1);
assertEquals(result, false);
Entity person2 = new DynamicEntity(personWeightEntityType);
person2.set("weight", 100);
result = jsMagmaScriptEvaluator.eval(script, person2);
assertEquals(result, false);
Entity person3 = new DynamicEntity(personWeightEntityType);
person3.set("weight", 101);
result = jsMagmaScriptEvaluator.eval(script, person3);
assertEquals(result, true);
}
@Test
public void testLt()
{
Entity person0 = new DynamicEntity(personWeightEntityType);
person0.set("weight", null);
String script = "$('weight').lt(100).value()";
Object result = jsMagmaScriptEvaluator.eval(script, person0);
assertEquals(result, false);
Entity person1 = new DynamicEntity(personWeightEntityType);
person1.set("weight", 99);
result = jsMagmaScriptEvaluator.eval(script, person1);
assertEquals(result, true);
Entity person2 = new DynamicEntity(personWeightEntityType);
person2.set("weight", 100);
result = jsMagmaScriptEvaluator.eval(script, person2);
assertEquals(result, false);
Entity person3 = new DynamicEntity(personWeightEntityType);
person3.set("weight", 101);
result = jsMagmaScriptEvaluator.eval(script, person3);
assertEquals(result, false);
}
@Test
public void testGe()
{
Entity person0 = new DynamicEntity(personWeightEntityType);
person0.set("weight", null);
String script = "$('weight').ge(100).value()";
Object result = jsMagmaScriptEvaluator.eval(script, person0);
assertEquals(result, false);
Entity person1 = new DynamicEntity(personWeightEntityType);
person1.set("weight", 99);
result = jsMagmaScriptEvaluator.eval(script, person1);
assertEquals(result, false);
Entity person2 = new DynamicEntity(personWeightEntityType);
person2.set("weight", 100);
result = jsMagmaScriptEvaluator.eval(script, person2);
assertEquals(result, true);
Entity person3 = new DynamicEntity(personWeightEntityType);
person3.set("weight", 101);
result = jsMagmaScriptEvaluator.eval(script, person3);
assertEquals(result, true);
}
@Test
public void testLe()
{
Entity person0 = new DynamicEntity(personWeightEntityType);
person0.set("weight", null);
String script = "$('weight').le(100).value()";
Object result = jsMagmaScriptEvaluator.eval(script, person0);
assertEquals(result, false);
Entity person1 = new DynamicEntity(personWeightEntityType);
person1.set("weight", 99);
result = jsMagmaScriptEvaluator.eval(script, person1);
assertEquals(result, true);
Entity person2 = new DynamicEntity(personWeightEntityType);
person2.set("weight", 100);
result = jsMagmaScriptEvaluator.eval(script, person2);
assertEquals(result, true);
Entity person3 = new DynamicEntity(personWeightEntityType);
person3.set("weight", 101);
result = jsMagmaScriptEvaluator.eval(script, person3);
assertEquals(result, false);
}
}