package org.nuunframework.universalvisitor; import static org.assertj.core.api.Assertions.assertThat; import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import org.junit.Before; import org.junit.Test; import org.nuunframework.universalvisitor.api.Filter; import org.nuunframework.universalvisitor.api.MapReduce; import org.nuunframework.universalvisitor.api.Mapper; import org.nuunframework.universalvisitor.api.Metadata; import org.nuunframework.universalvisitor.api.Node; import org.nuunframework.universalvisitor.api.Reducer; import org.nuunframework.universalvisitor.core.MapReduceDefault; import org.nuunframework.universalvisitor.sample.Alphabet; import org.nuunframework.universalvisitor.sample.collections.H; import org.nuunframework.universalvisitor.sample.collections.I; import org.nuunframework.universalvisitor.sample.collections.J; import org.nuunframework.universalvisitor.sample.collections.K; import org.nuunframework.universalvisitor.sample.collections.L; import org.nuunframework.universalvisitor.sample.issues.Issue1; import org.nuunframework.universalvisitor.sample.issues.Issue2; import org.nuunframework.universalvisitor.sample.levels.L1; import org.nuunframework.universalvisitor.sample.multiplereducers.D; import org.nuunframework.universalvisitor.sample.multiplereducers.E; import org.nuunframework.universalvisitor.sample.multiplereducers.F; import org.nuunframework.universalvisitor.sample.multiplereducers.G; import org.nuunframework.universalvisitor.sample.mutatormapper.M; import org.nuunframework.universalvisitor.sample.nulls.N; import org.nuunframework.universalvisitor.sample.simple.A; import org.nuunframework.universalvisitor.sample.simple.B; import org.nuunframework.universalvisitor.sample.simple.C; /** * * */ public class UniversalVisitorTest { UniversalVisitor underTest; A a; D d; H h; M m; N n; Issue1 issue1; Issue2 issue2; L1 l1; @SuppressWarnings("serial") @Before public void init () { underTest = new UniversalVisitor(); a = new A(); B b = new B(); C c = new C(); a.name = "zob"; a.b = b; b.c = c; c.a = a; d = new D(); D dNew = new D(); E e = new E(); F f = new F(); G g = new G(); d.e = e; d.dValue = 10; dNew.dValue = 100000; e.f = f; e.eValue = 100; f.g = g; f.fValue = 1000; g.dCycle = d; g.dNew = dNew; g.gValue = 10000; /////////////////// h = new H(); h.is = new ArrayList<I>(){{ add(new I()); add(new I()); add(new I()); }}; h.js = new HashMap<String, J>(){{ put("k0", new J()); put("k1", new J()); put("k2", new J()); }}; h.ks = new K[]{new K() , new K() , new K()}; h.ls = new ArrayList<L>() {{ L l = new L(); l.ks = new HashSet<K>(){{ add(new K()); add(new K()); add(new K()); }}; add(l); l = new L(); l.ks = new HashSet<K>(){{ add(new K()); add(new K()); add(new K()); }}; add(l); l = new L(); l.ks = new HashSet<K>(){{ add(new K()); add(new K()); add(new K()); }}; add(l); }}; ///// m = new M(); // n = new N(); // issue1 = new Issue1(); // issue2 = new Issue2(); // l1 = new L1(); } @Test public void simple_case() { MyPredicate predicate = new MyPredicate(); MyMapper mapper = new MyMapper(); SumReducer reducer = new SumReducer(); underTest.visit(a,predicate, mapper , reducer); assertThat(mapper.getCount()).isEqualTo(3); assertThat(reducer.reduce()).isEqualTo(3); assertThat(mapper.getMaxLevel()).isEqualTo(2); } @Test public void nullity_case() { MyPredicate predicate = new MyPredicate(); MyMapper mapper = new MyMapper(); underTest.visit(String.class,predicate, mapper); underTest.visit(n,predicate, mapper); } @Test public void multiple_reducer () { MyMapper2 mapper = new MyMapper2(); SumReducer sumReducer = new SumReducer(); MeanReducer meanReducer = new MeanReducer(); MyPredicate2 predicate = new MyPredicate2(); MapReduce<Integer> mapReduce = new MapReduceDefault <Integer>(mapper ,sumReducer, meanReducer); underTest.visit(d, predicate , mapReduce); assertThat(sumReducer.reduce()).isEqualTo(111110); assertThat(meanReducer.reduce()).isEqualTo(22222); } @Test public void collections_reducers () { MyPredicate predicate = new MyPredicate(); MyMapper2 mapper = new MyMapper2(); SumReducer sumReducer = new SumReducer(); underTest.visit(h,predicate, mapper , sumReducer); assertThat(sumReducer.reduce()).isEqualTo(1233); } @Test public void mutator_mapper () { UniversalVisitor underTest2 = new UniversalVisitor(); MyPredicate predicate = new MyPredicate(); MutatorMapper mapper = new MutatorMapper(); assertThat(m.getSalary()).isEqualTo(10000); underTest2.visit(m,predicate, mapper ); assertThat(m.getSalary()).isEqualTo(100000); } @Test public void issue1 () { NopMap nopMap = new NopMap(); underTest.visit(issue1, nopMap); } @Test public void issue2 () { CountMapper nopMap = new CountMapper(); // System.out.println("============================== ISSUE2 ==================================="); underTest.visit(issue2, nopMap); assertThat(nopMap.methods).contains("interface1M","interface2M","interface3M","issue2Private" , "issue2Package", "issue2Protected" , "issue2Public" , "parentPrivate" , "parentProtected", "parentPackage" , "parentPublic"); // System.out.println(nopMap.methods); assertThat(nopMap.fields).contains("interface1F","interface2F","interface3F", "issue2Private" , "issue2Package", "issue2Protected" , "issue2Public" , "parentPrivate" , "parentProtected", "parentPackage" , "parentPublic"); // System.out.println(nopMap.fields); System.out.println(nopMap.node); } @Test public void checkLevel () { CheckLevelMap mapper = new CheckLevelMap(); underTest.visit(l1, mapper); } class CheckLevelMap implements Mapper<Void> { @Override public boolean handle(AnnotatedElement object) { return object instanceof Field /*|| object instanceof Constructor*/; } @Override public Void map(Node node) { String indentation = ""; for (int i = 0; i < node.level(); i++) { indentation += "\t"; } if (node.annotatedElement() instanceof Field) { Field f = (Field) node.annotatedElement(); String value = ""; if (f.getType().equals(String.class) || f.getType().equals(Integer.class)) { value = " = \"" + readField(f, node.instance()) + "\""; } Metadata metadata = node.metadata(); if (metadata == null) { metadata = new Metadata(); } System.out.println(indentation + "|" +node.level() + "|"+" " +f.getName() + metadata + value + " from " + f.getDeclaringClass().getSimpleName()) ; } if (node.annotatedElement() instanceof Constructor) { Constructor c = (Constructor) node.annotatedElement(); System.out.println(indentation + "|" + node.level() + "|"+ node.metadata()+" " +c.getDeclaringClass().getSimpleName() + "()"); } return null; } } static class NopMap implements Mapper<Void> { @Override public boolean handle(AnnotatedElement object) { return true; } @Override public Void map(Node node) { System.out.println("Current Node : " + node.annotatedElement()); return null; } } static class CountMapper implements Mapper<Void> { List<String> fields = new ArrayList<String>(); List<String> methods = new ArrayList<String>(); List<String> constructors = new ArrayList<String>(); Node node = null; @Override public boolean handle(AnnotatedElement object) { return true; } @Override public Void map(Node node) { if (this.node == null) { this.node = node; } if (node.annotatedElement() instanceof Field) { fields.add(((Field) node.annotatedElement()).getName() ); } if (node.annotatedElement() instanceof Method) { methods.add(((Method) node.annotatedElement()).getName() ); } if (node.annotatedElement() instanceof Constructor) { constructors.add(((Constructor) node.annotatedElement()).getName() ); } return null; } } static class MutatorMapper implements Mapper<Void> { @Override public boolean handle(AnnotatedElement object) { return object instanceof Field && ((Field) object).getType().equals(Integer.class); } @Override public Void map(Node node) { Field f = (Field) node.annotatedElement(); Integer value = null; try { value = (Integer) f.get(node.instance()); System.out.println("value " + value); f.set(node.instance(), value * 10); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } return null; } } static class MyMapper2 implements Mapper<Integer> { @Override public Integer map(Node node) { Field f = (Field) node.annotatedElement(); Integer value = null; try { value = (Integer) f.get(node.instance()); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } return value; } @Override public boolean handle(AnnotatedElement object) { return object instanceof Field && ((Field) object).getType().equals(Integer.class); } } static class MyMapper implements Mapper<Integer> { int counter = 0; int maxLevel = 0; @Override public Integer map(Node node) { System.out.println("node " + node.annotatedElement() + " -> " + node.instance() + " type = " + node.instance().getClass()); counter ++; maxLevel = Math.max(maxLevel, node.level()); return new Integer(1); } public int getCount() { return counter; } public int getMaxLevel() { return maxLevel; } @Override public boolean handle(AnnotatedElement object) { return object instanceof Field && ((Field) object) .getType(). getAnnotation(Alphabet.class) != null; } } static class SumReducer implements Reducer<Integer, Integer> { int counter = 0; @Override public void collect(Integer input) { counter = counter + input; } @Override public Integer reduce() { return counter; } } static class MeanReducer implements Reducer<Integer, Integer> { int counter = 0; int sum =0; @Override public void collect(Integer input) { counter++; sum += input; } @Override public Integer reduce() { return sum / counter; } } static class MyPredicate implements Filter { @Override public boolean retains(Field input) { return true ; } } static class MyPredicate2 implements Filter { @Override public boolean retains(Field input) { return input.getType().getAnnotation(Alphabet.class) != null; } } public Object readField(Field f, Object instance) { Object o = null; try { f.setAccessible(true); o = f.get(instance); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } return o; } }