1d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar/*
2d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * Copyright (C) 2015 The Android Open Source Project
3d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar *
4d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * Licensed under the Apache License, Version 2.0 (the "License");
5d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * you may not use this file except in compliance with the License.
6d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * You may obtain a copy of the License at
7d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar *
8d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar *      http://www.apache.org/licenses/LICENSE-2.0
9d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar *
10d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * Unless required by applicable law or agreed to in writing, software
11d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * distributed under the License is distributed on an "AS IS" BASIS,
12d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * See the License for the specific language governing permissions and
14d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * limitations under the License.
15d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar */
16d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
17fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountpackage android.databinding.tool.expr;
18d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
19d615f15f0f0cc4c4de7570119d181e13d44e708aGeorge Mountimport android.databinding.Bindable;
20e61d1cc710803cdf0ab4f2aca3d18c46949758a9Yigit Boyarimport android.databinding.Observable;
21fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.LayoutBinder;
22fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.MockLayoutBinder;
23fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.reflection.ModelAnalyzer;
24fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.reflection.ModelClass;
25fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.reflection.java.JavaAnalyzer;
26c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyarimport android.databinding.tool.store.Location;
27fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.util.L;
28e52882df6130221462bf07f5f2b52de5c4b0f8deGeorge Mountimport android.databinding.tool.writer.KCode;
29fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mount
30d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mountimport org.junit.Before;
31d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mountimport org.junit.Rule;
32d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mountimport org.junit.Test;
33d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mountimport org.junit.rules.TestWatcher;
34d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mountimport org.junit.runner.Description;
35d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount
3674f72d77b1db2b78ee6422da2ec94de12edcb6dcYigit Boyarimport java.util.ArrayList;
3774f72d77b1db2b78ee6422da2ec94de12edcb6dcYigit Boyarimport java.util.Arrays;
38d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyarimport java.util.BitSet;
397b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyarimport java.util.Collections;
40d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyarimport java.util.List;
41d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
42fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport static org.junit.Assert.assertEquals;
43fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport static org.junit.Assert.assertFalse;
44fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport static org.junit.Assert.assertNotNull;
45fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport static org.junit.Assert.assertNull;
46fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport static org.junit.Assert.assertSame;
47fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport static org.junit.Assert.assertTrue;
48d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
49d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyarpublic class ExprModelTest {
5074f72d77b1db2b78ee6422da2ec94de12edcb6dcYigit Boyar
51d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    private static class DummyExpr extends Expr {
5274f72d77b1db2b78ee6422da2ec94de12edcb6dcYigit Boyar
53d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        String mKey;
5474f72d77b1db2b78ee6422da2ec94de12edcb6dcYigit Boyar
55d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        public DummyExpr(String key, DummyExpr... children) {
56d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            super(children);
57d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            mKey = key;
58d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
59d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
60d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        @Override
6197d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar        protected ModelClass resolveType(ModelAnalyzer modelAnalyzer) {
6297d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar            return modelAnalyzer.findClass(Integer.class);
63d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
64d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
65d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        @Override
66d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        protected List<Dependency> constructDependencies() {
67d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            return constructDynamicChildrenDependencies();
68d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
69d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
70d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        @Override
71d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        protected String computeUniqueKey() {
72d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            return mKey + super.computeUniqueKey();
73d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
74e52882df6130221462bf07f5f2b52de5c4b0f8deGeorge Mount
75e52882df6130221462bf07f5f2b52de5c4b0f8deGeorge Mount        @Override
76d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        protected KCode generateCode(boolean full) {
77e52882df6130221462bf07f5f2b52de5c4b0f8deGeorge Mount            return new KCode();
78e52882df6130221462bf07f5f2b52de5c4b0f8deGeorge Mount        }
79d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount
80d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        @Override
81d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        protected String getInvertibleError() {
82d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount            return "DummyExpr cannot be 2-way.";
83d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        }
84d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
85d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
86d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    ExprModel mExprModel;
87d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
88d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    @Rule
89d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public TestWatcher mTestWatcher = new TestWatcher() {
90d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        @Override
91d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        protected void failed(Throwable e, Description description) {
92d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            if (mExprModel != null && mExprModel.getFlagMapping() != null) {
93d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                final String[] mapping = mExprModel.getFlagMapping();
9474f72d77b1db2b78ee6422da2ec94de12edcb6dcYigit Boyar                for (int i = 0; i < mapping.length; i++) {
95d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    L.d("flag %d: %s", i, mapping[i]);
96d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                }
97d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            }
98d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
99d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    };
100d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
101d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    @Before
102d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public void setUp() throws Exception {
10397d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar        JavaAnalyzer.initForTests();
104d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        mExprModel = new ExprModel();
105d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
106d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
107d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    @Test
108d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public void testAddNormal() {
109d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        final DummyExpr d = new DummyExpr("a");
110d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        assertSame(d, mExprModel.register(d));
111d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        assertSame(d, mExprModel.register(d));
112d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        assertEquals(1, mExprModel.mExprMap.size());
113d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
11474f72d77b1db2b78ee6422da2ec94de12edcb6dcYigit Boyar
115d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    @Test
116d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public void testAddDupe1() {
117d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        final DummyExpr d = new DummyExpr("a");
118d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        assertSame(d, mExprModel.register(d));
119d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        assertSame(d, mExprModel.register(new DummyExpr("a")));
120d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        assertEquals(1, mExprModel.mExprMap.size());
121d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
122d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
123d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    @Test
124d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public void testAddMultiple() {
125d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        mExprModel.register(new DummyExpr("a"));
126d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        mExprModel.register(new DummyExpr("b"));
127d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        assertEquals(2, mExprModel.mExprMap.size());
128d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
129d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
130d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
131d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    @Test
132d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public void testAddWithChildren() {
133d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        DummyExpr a = new DummyExpr("a");
134d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        DummyExpr b = new DummyExpr("b");
135d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        DummyExpr c = new DummyExpr("c", a, b);
136d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        mExprModel.register(c);
137d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        DummyExpr a2 = new DummyExpr("a");
138d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        DummyExpr b2 = new DummyExpr("b");
139d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        DummyExpr c2 = new DummyExpr("c", a, b);
140d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        assertEquals(c, mExprModel.register(c2));
141d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
142d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
143d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    @Test
144d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public void testShouldRead() {
145eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        MockLayoutBinder lb = new MockLayoutBinder();
146d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        mExprModel = lb.getModel();
147c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        IdentifierExpr a = lb.addVariable("a", "java.lang.String", null);
148c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        IdentifierExpr b = lb.addVariable("b", "java.lang.String", null);
149c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        IdentifierExpr c = lb.addVariable("c", "java.lang.String", null);
150d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        lb.parse("a == null ? b : c", false, null);
15174f72d77b1db2b78ee6422da2ec94de12edcb6dcYigit Boyar        mExprModel.comparison("==", a, mExprModel.symbol("null", Object.class));
152d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        lb.getModel().seal();
1532611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        List<Expr> shouldRead = getShouldRead();
154d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        // a and a == null
1552611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        assertEquals(2, shouldRead.size());
1562611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        final List<Expr> readFirst = getReadFirst(shouldRead, null);
1572611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        assertEquals(1, readFirst.size());
1582611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        final Expr first = readFirst.get(0);
159d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        assertSame(a, first);
160d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        // now , assume we've read this
161d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        final BitSet shouldReadFlags = first.getShouldReadFlags();
162d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        assertNotNull(shouldReadFlags);
163d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
164d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
165d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    @Test
16609aeb26073fc8a98263806f53e44819ebe5046c6Yigit Boyar    public void testReadConstantTernary() {
16709aeb26073fc8a98263806f53e44819ebe5046c6Yigit Boyar        MockLayoutBinder lb = new MockLayoutBinder();
16809aeb26073fc8a98263806f53e44819ebe5046c6Yigit Boyar        mExprModel = lb.getModel();
16909aeb26073fc8a98263806f53e44819ebe5046c6Yigit Boyar        IdentifierExpr a = lb.addVariable("a", "java.lang.String", null);
17009aeb26073fc8a98263806f53e44819ebe5046c6Yigit Boyar        IdentifierExpr b = lb.addVariable("b", "java.lang.String", null);
17109aeb26073fc8a98263806f53e44819ebe5046c6Yigit Boyar        TernaryExpr ternaryExpr = parse(lb, "true ? a : b", TernaryExpr.class);
17209aeb26073fc8a98263806f53e44819ebe5046c6Yigit Boyar        mExprModel.seal();
17309aeb26073fc8a98263806f53e44819ebe5046c6Yigit Boyar        List<Expr> shouldRead = getShouldRead();
17409aeb26073fc8a98263806f53e44819ebe5046c6Yigit Boyar        assertExactMatch(shouldRead, ternaryExpr.getPred());
17509aeb26073fc8a98263806f53e44819ebe5046c6Yigit Boyar        List<Expr> first = getReadFirst(shouldRead);
17609aeb26073fc8a98263806f53e44819ebe5046c6Yigit Boyar        assertExactMatch(first, ternaryExpr.getPred());
17709aeb26073fc8a98263806f53e44819ebe5046c6Yigit Boyar        mExprModel.markBitsRead();
17809aeb26073fc8a98263806f53e44819ebe5046c6Yigit Boyar        shouldRead = getShouldRead();
17909aeb26073fc8a98263806f53e44819ebe5046c6Yigit Boyar        assertExactMatch(shouldRead, a, b, ternaryExpr);
18009aeb26073fc8a98263806f53e44819ebe5046c6Yigit Boyar        first = getReadFirst(shouldRead);
18109aeb26073fc8a98263806f53e44819ebe5046c6Yigit Boyar        assertExactMatch(first, a, b);
1829784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar        List<Expr> justRead = new ArrayList<Expr>();
18309aeb26073fc8a98263806f53e44819ebe5046c6Yigit Boyar        justRead.add(a);
18409aeb26073fc8a98263806f53e44819ebe5046c6Yigit Boyar        justRead.add(b);
18509aeb26073fc8a98263806f53e44819ebe5046c6Yigit Boyar        first = filterOut(getReadFirst(shouldRead, justRead), justRead);
18609aeb26073fc8a98263806f53e44819ebe5046c6Yigit Boyar        assertExactMatch(first, ternaryExpr);
18709aeb26073fc8a98263806f53e44819ebe5046c6Yigit Boyar        assertFalse(mExprModel.markBitsRead());
18809aeb26073fc8a98263806f53e44819ebe5046c6Yigit Boyar    }
18909aeb26073fc8a98263806f53e44819ebe5046c6Yigit Boyar
19009aeb26073fc8a98263806f53e44819ebe5046c6Yigit Boyar    @Test
19174f72d77b1db2b78ee6422da2ec94de12edcb6dcYigit Boyar    public void testTernaryWithPlus() {
192eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        MockLayoutBinder lb = new MockLayoutBinder();
19374f72d77b1db2b78ee6422da2ec94de12edcb6dcYigit Boyar        mExprModel = lb.getModel();
19474f72d77b1db2b78ee6422da2ec94de12edcb6dcYigit Boyar        IdentifierExpr user = lb
195c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar                .addVariable("user", "android.databinding.tool.expr.ExprModelTest.User",
196c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar                        null);
19774f72d77b1db2b78ee6422da2ec94de12edcb6dcYigit Boyar        MathExpr parsed = parse(lb, "user.name + \" \" + (user.lastName ?? \"\")", MathExpr.class);
19874f72d77b1db2b78ee6422da2ec94de12edcb6dcYigit Boyar        mExprModel.seal();
1992611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        List<Expr> toRead = getShouldRead();
2002611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        List<Expr> readNow = getReadFirst(toRead);
2012611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        assertEquals(1, readNow.size());
2022611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        assertSame(user, readNow.get(0));
20374f72d77b1db2b78ee6422da2ec94de12edcb6dcYigit Boyar        List<Expr> justRead = new ArrayList<Expr>();
20474f72d77b1db2b78ee6422da2ec94de12edcb6dcYigit Boyar        justRead.add(user);
20574f72d77b1db2b78ee6422da2ec94de12edcb6dcYigit Boyar        readNow = filterOut(getReadFirst(toRead, justRead), justRead);
2062611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        assertEquals(2, readNow.size()); //user.name && user.lastName
2072611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        justRead.addAll(readNow);
20874f72d77b1db2b78ee6422da2ec94de12edcb6dcYigit Boyar        // user.lastname (T, F), user.name + " "
20974f72d77b1db2b78ee6422da2ec94de12edcb6dcYigit Boyar        readNow = filterOut(getReadFirst(toRead, justRead), justRead);
2102611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        assertEquals(2, readNow.size()); //user.name && user.lastName
2112611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        justRead.addAll(readNow);
21274f72d77b1db2b78ee6422da2ec94de12edcb6dcYigit Boyar        readNow = filterOut(getReadFirst(toRead, justRead), justRead);
2132611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        assertEquals(0, readNow.size());
21474f72d77b1db2b78ee6422da2ec94de12edcb6dcYigit Boyar        mExprModel.markBitsRead();
21574f72d77b1db2b78ee6422da2ec94de12edcb6dcYigit Boyar
21674f72d77b1db2b78ee6422da2ec94de12edcb6dcYigit Boyar        toRead = getShouldRead();
2172611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        assertEquals(2, toRead.size());
21874f72d77b1db2b78ee6422da2ec94de12edcb6dcYigit Boyar        justRead.clear();
21974f72d77b1db2b78ee6422da2ec94de12edcb6dcYigit Boyar        readNow = filterOut(getReadFirst(toRead, justRead), justRead);
2202611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        assertEquals(1, readNow.size());
2212611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        assertSame(parsed.getRight(), readNow.get(0));
2222611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        justRead.addAll(readNow);
22374f72d77b1db2b78ee6422da2ec94de12edcb6dcYigit Boyar
22474f72d77b1db2b78ee6422da2ec94de12edcb6dcYigit Boyar        readNow = filterOut(getReadFirst(toRead, justRead), justRead);
2252611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        assertEquals(1, readNow.size());
2262611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        assertSame(parsed, readNow.get(0));
2272611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        justRead.addAll(readNow);
22874f72d77b1db2b78ee6422da2ec94de12edcb6dcYigit Boyar
22974f72d77b1db2b78ee6422da2ec94de12edcb6dcYigit Boyar        readNow = filterOut(getReadFirst(toRead, justRead), justRead);
2302611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        assertEquals(0, readNow.size());
23174f72d77b1db2b78ee6422da2ec94de12edcb6dcYigit Boyar        mExprModel.markBitsRead();
2322611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        assertEquals(0, getShouldRead().size());
23374f72d77b1db2b78ee6422da2ec94de12edcb6dcYigit Boyar    }
23474f72d77b1db2b78ee6422da2ec94de12edcb6dcYigit Boyar
2352611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar    private List<Expr> filterOut(List<Expr> itr, final List<Expr> exclude) {
2362611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        List<Expr> result = new ArrayList<Expr>();
2372611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        for (Expr expr : itr) {
2382611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar            if (!exclude.contains(expr)) {
2392611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar                result.add(expr);
24074f72d77b1db2b78ee6422da2ec94de12edcb6dcYigit Boyar            }
2412611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        }
2422611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        return result;
24374f72d77b1db2b78ee6422da2ec94de12edcb6dcYigit Boyar    }
24474f72d77b1db2b78ee6422da2ec94de12edcb6dcYigit Boyar
24574f72d77b1db2b78ee6422da2ec94de12edcb6dcYigit Boyar    @Test
2460fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar    public void testTernaryInsideTernary() {
247eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        MockLayoutBinder lb = new MockLayoutBinder();
2480fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar        mExprModel = lb.getModel();
249c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        IdentifierExpr cond1 = lb.addVariable("cond1", "boolean", null);
250c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        IdentifierExpr cond2 = lb.addVariable("cond2", "boolean", null);
2510fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar
252c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        IdentifierExpr a = lb.addVariable("a", "boolean", null);
253c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        IdentifierExpr b = lb.addVariable("b", "boolean", null);
254c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        IdentifierExpr c = lb.addVariable("c", "boolean", null);
2550fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar
2560fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar        final TernaryExpr ternaryExpr = parse(lb, "cond1 ? cond2 ? a : b : c", TernaryExpr.class);
2570fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar        final TernaryExpr innerTernary = (TernaryExpr) ternaryExpr.getIfTrue();
2580fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar        mExprModel.seal();
2590fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar
2602611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        List<Expr> toRead = getShouldRead();
2612611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        assertEquals(1, toRead.size());
2622611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        assertEquals(ternaryExpr.getPred(), toRead.get(0));
2630fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar
2642611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        List<Expr> readNow = getReadFirst(toRead);
2652611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        assertEquals(1, readNow.size());
2662611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        assertEquals(ternaryExpr.getPred(), readNow.get(0));
2670fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar        int cond1True = ternaryExpr.getRequirementFlagIndex(true);
2680fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar        int cond1False = ternaryExpr.getRequirementFlagIndex(false);
2690fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar        // ok, it is read now.
2700fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar        mExprModel.markBitsRead();
2710fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar
2720fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar        // now it should read cond2 or c, depending on the flag from first
2730fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar        toRead = getShouldRead();
2742611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        assertEquals(2, toRead.size());
2750fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar        assertExactMatch(toRead, ternaryExpr.getIfFalse(), innerTernary.getPred());
2760fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar        assertFlags(ternaryExpr.getIfFalse(), cond1False);
2770fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar        assertFlags(ternaryExpr.getIfTrue(), cond1True);
2780fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar
2790fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar        mExprModel.markBitsRead();
2800fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar
2810fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar        // now it should read a or b, innerTernary, outerTernary
2820fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar        toRead = getShouldRead();
2830fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar        assertExactMatch(toRead, innerTernary.getIfTrue(), innerTernary.getIfFalse(), ternaryExpr,
2840fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar                innerTernary);
2850fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar        assertFlags(innerTernary.getIfTrue(), innerTernary.getRequirementFlagIndex(true));
2860fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar        assertFlags(innerTernary.getIfFalse(), innerTernary.getRequirementFlagIndex(false));
2870fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar        assertFalse(mExprModel.markBitsRead());
2880fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar    }
2890fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar
2900fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar    @Test
291d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public void testRequirementFlags() {
292eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        MockLayoutBinder lb = new MockLayoutBinder();
293d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        mExprModel = lb.getModel();
294c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        IdentifierExpr a = lb.addVariable("a", "java.lang.String", null);
295c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        IdentifierExpr b = lb.addVariable("b", "java.lang.String", null);
296c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        IdentifierExpr c = lb.addVariable("c", "java.lang.String", null);
297c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        IdentifierExpr d = lb.addVariable("d", "java.lang.String", null);
298c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        IdentifierExpr e = lb.addVariable("e", "java.lang.String", null);
299d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        final Expr aTernary = lb.parse("a == null ? b == null ? c : d : e", false, null);
300d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        assertTrue(aTernary instanceof TernaryExpr);
30174f72d77b1db2b78ee6422da2ec94de12edcb6dcYigit Boyar        final Expr bTernary = ((TernaryExpr) aTernary).getIfTrue();
302d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        assertTrue(bTernary instanceof TernaryExpr);
30374f72d77b1db2b78ee6422da2ec94de12edcb6dcYigit Boyar        final Expr aIsNull = mExprModel
30474f72d77b1db2b78ee6422da2ec94de12edcb6dcYigit Boyar                .comparison("==", a, mExprModel.symbol("null", Object.class));
30574f72d77b1db2b78ee6422da2ec94de12edcb6dcYigit Boyar        final Expr bIsNull = mExprModel
30674f72d77b1db2b78ee6422da2ec94de12edcb6dcYigit Boyar                .comparison("==", b, mExprModel.symbol("null", Object.class));
307d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        lb.getModel().seal();
3082611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        List<Expr> shouldRead = getShouldRead();
309d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        // a and a == null
3102611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        assertEquals(2, shouldRead.size());
311d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        assertFalse(a.getShouldReadFlags().isEmpty());
312d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        assertTrue(a.getShouldReadFlags().get(a.getId()));
313d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        assertTrue(b.getShouldReadFlags().isEmpty());
314d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        assertTrue(c.getShouldReadFlags().isEmpty());
315d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        assertTrue(d.getShouldReadFlags().isEmpty());
316d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        assertTrue(e.getShouldReadFlags().isEmpty());
317d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
3182611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        List<Expr> readFirst = getReadFirst(shouldRead, null);
3192611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        assertEquals(1, readFirst.size());
3202611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        final Expr first = readFirst.get(0);
321d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        assertSame(a, first);
322d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        assertTrue(mExprModel.markBitsRead());
323d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        for (Expr expr : mExprModel.getPendingExpressions()) {
324d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            assertNull(expr.mShouldReadFlags);
325d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
3260fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar        shouldRead = getShouldRead();
327d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        assertExactMatch(shouldRead, e, b, bIsNull);
328d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
329d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        assertFlags(e, aTernary.getRequirementFlagIndex(false));
330d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
331d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        assertFlags(b, aTernary.getRequirementFlagIndex(true));
332d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        assertFlags(bIsNull, aTernary.getRequirementFlagIndex(true));
333d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        assertTrue(mExprModel.markBitsRead());
3340fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar        shouldRead = getShouldRead();
3352611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        assertEquals(4, shouldRead.size());
3362611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        assertTrue(shouldRead.contains(c));
3372611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        assertTrue(shouldRead.contains(d));
3382611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        assertTrue(shouldRead.contains(aTernary));
3392611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        assertTrue(shouldRead.contains(bTernary));
340d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
341d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        assertTrue(c.getShouldReadFlags().get(bTernary.getRequirementFlagIndex(true)));
342d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        assertEquals(1, c.getShouldReadFlags().cardinality());
343d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
344d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        assertTrue(d.getShouldReadFlags().get(bTernary.getRequirementFlagIndex(false)));
345d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        assertEquals(1, d.getShouldReadFlags().cardinality());
346d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
347d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        assertTrue(bTernary.getShouldReadFlags().get(aTernary.getRequirementFlagIndex(true)));
348d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        assertEquals(1, bTernary.getShouldReadFlags().cardinality());
349019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        // +1 for invalidate all flag
350019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        assertEquals(6, aTernary.getShouldReadFlags().cardinality());
351d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        for (Expr expr : new Expr[]{a, b, c, d, e}) {
352d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            assertTrue(aTernary.getShouldReadFlags().get(expr.getId()));
353d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
354d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
355d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        readFirst = getReadFirst(shouldRead);
3562611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        assertEquals(2, readFirst.size());
3572611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        assertTrue(readFirst.contains(c));
3582611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        assertTrue(readFirst.contains(d));
359d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        assertFalse(mExprModel.markBitsRead());
360d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
361d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
362d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    @Test
363d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public void testPostConditionalDependencies() {
364eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        MockLayoutBinder lb = new MockLayoutBinder();
365d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        mExprModel = lb.getModel();
366d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
367c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        IdentifierExpr u1 = lb.addVariable("u1", User.class.getCanonicalName(), null);
368c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        IdentifierExpr u2 = lb.addVariable("u2", User.class.getCanonicalName(), null);
369c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        IdentifierExpr a = lb.addVariable("a", int.class.getCanonicalName(), null);
370c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        IdentifierExpr b = lb.addVariable("b", int.class.getCanonicalName(), null);
371c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        IdentifierExpr c = lb.addVariable("c", int.class.getCanonicalName(), null);
372c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        IdentifierExpr d = lb.addVariable("d", int.class.getCanonicalName(), null);
373c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        IdentifierExpr e = lb.addVariable("e", int.class.getCanonicalName(), null);
374d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        TernaryExpr abTernary = parse(lb, "a > b ? u1.name : u2.name", TernaryExpr.class);
37574f72d77b1db2b78ee6422da2ec94de12edcb6dcYigit Boyar        TernaryExpr bcTernary = parse(lb, "b > c ? u1.getCond(d) ? u1.lastName : u2.lastName : `xx`"
37674f72d77b1db2b78ee6422da2ec94de12edcb6dcYigit Boyar                + " + u2.getCond(e) ", TernaryExpr.class);
377d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        Expr abCmp = abTernary.getPred();
378d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        Expr bcCmp = bcTernary.getPred();
379d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        Expr u1GetCondD = ((TernaryExpr) bcTernary.getIfTrue()).getPred();
380d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        final MathExpr xxPlusU2getCondE = (MathExpr) bcTernary.getIfFalse();
38197d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar        Expr u2GetCondE = xxPlusU2getCondE.getRight();
382d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        Expr u1Name = abTernary.getIfTrue();
383d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        Expr u2Name = abTernary.getIfFalse();
384d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        Expr u1LastName = ((TernaryExpr) bcTernary.getIfTrue()).getIfTrue();
385d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        Expr u2LastName = ((TernaryExpr) bcTernary.getIfTrue()).getIfFalse();
386d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
387d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        mExprModel.seal();
3882611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        List<Expr> shouldRead = getShouldRead();
389d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
390d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        assertExactMatch(shouldRead, a, b, c, abCmp, bcCmp);
391d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
3922611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        List<Expr> firstRead = getReadFirst(shouldRead);
393d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
394d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        assertExactMatch(firstRead, a, b, c);
395d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
396d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        assertFlags(a, a, b, u1, u2, u1Name, u2Name);
397d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        assertFlags(b, a, b, u1, u2, u1Name, u2Name, c, d, u1LastName, u2LastName, e);
398d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        assertFlags(c, b, c, u1, d, u1LastName, u2LastName, e);
399d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        assertFlags(abCmp, a, b, u1, u2, u1Name, u2Name);
400d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        assertFlags(bcCmp, b, c, u1, d, u1LastName, u2LastName, e);
401d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
402d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        assertTrue(mExprModel.markBitsRead());
403d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
4040fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar        shouldRead = getShouldRead();
405d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        Expr[] batch = {d, e, u1, u2, u1GetCondD, u2GetCondE, xxPlusU2getCondE, abTernary,
406d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                abTernary.getIfTrue(), abTernary.getIfFalse()};
407d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        assertExactMatch(shouldRead, batch);
408d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        firstRead = getReadFirst(shouldRead);
409d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        assertExactMatch(firstRead, d, e, u1, u2);
410d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
411d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        assertFlags(d, bcTernary.getRequirementFlagIndex(true));
412d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        assertFlags(e, bcTernary.getRequirementFlagIndex(false));
41374f72d77b1db2b78ee6422da2ec94de12edcb6dcYigit Boyar        assertFlags(u1, bcTernary.getRequirementFlagIndex(true),
41474f72d77b1db2b78ee6422da2ec94de12edcb6dcYigit Boyar                abTernary.getRequirementFlagIndex(true));
41574f72d77b1db2b78ee6422da2ec94de12edcb6dcYigit Boyar        assertFlags(u2, bcTernary.getRequirementFlagIndex(false),
41674f72d77b1db2b78ee6422da2ec94de12edcb6dcYigit Boyar                abTernary.getRequirementFlagIndex(false));
417d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
418d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        assertFlags(u1GetCondD, bcTernary.getRequirementFlagIndex(true));
419d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        assertFlags(u2GetCondE, bcTernary.getRequirementFlagIndex(false));
420d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        assertFlags(xxPlusU2getCondE, bcTernary.getRequirementFlagIndex(false));
421d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        assertFlags(abTernary, a, b, u1, u2, u1Name, u2Name);
422d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        assertFlags(abTernary.getIfTrue(), abTernary.getRequirementFlagIndex(true));
423d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        assertFlags(abTernary.getIfFalse(), abTernary.getRequirementFlagIndex(false));
424d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
425d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        assertTrue(mExprModel.markBitsRead());
426d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
4270fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar        shouldRead = getShouldRead();
428eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        // FIXME: there is no real case to read u1 anymore because if b>c was not true,
429d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        // u1.getCond(d) will never be set. Right now, we don't have mechanism to figure this out
430d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        // and also it does not affect correctness (just an unnecessary if stmt)
431d615f15f0f0cc4c4de7570119d181e13d44e708aGeorge Mount        assertExactMatch(shouldRead, u1, u2, u1LastName, u2LastName, bcTernary.getIfTrue(), bcTernary);
432d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        firstRead = getReadFirst(shouldRead);
433d615f15f0f0cc4c4de7570119d181e13d44e708aGeorge Mount        assertExactMatch(firstRead, u1, u2);
434eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        assertFlags(u1, bcTernary.getIfTrue().getRequirementFlagIndex(true));
435eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        assertFlags(u2, bcTernary.getIfTrue().getRequirementFlagIndex(false));
436d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        assertFlags(u1LastName, bcTernary.getIfTrue().getRequirementFlagIndex(true));
437d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        assertFlags(u2LastName, bcTernary.getIfTrue().getRequirementFlagIndex(false));
438d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
439d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        assertFlags(bcTernary.getIfTrue(), bcTernary.getRequirementFlagIndex(true));
440d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        assertFlags(bcTernary, b, c, u1, u2, d, u1LastName, u2LastName, e);
441eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar
442eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        assertFalse(mExprModel.markBitsRead());
443d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
444d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
445d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    @Test
446d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public void testCircularDependency() {
447eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        MockLayoutBinder lb = new MockLayoutBinder();
448d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        mExprModel = lb.getModel();
449c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        IdentifierExpr a = lb.addVariable("a", int.class.getCanonicalName(),
450c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar                null);
451c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        IdentifierExpr b = lb.addVariable("b", int.class.getCanonicalName(),
452c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar                null);
453d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        final TernaryExpr abTernary = parse(lb, "a > 3 ? a : b", TernaryExpr.class);
454d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        mExprModel.seal();
4552611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        List<Expr> shouldRead = getShouldRead();
456d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        assertExactMatch(shouldRead, a, abTernary.getPred());
457d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        assertTrue(mExprModel.markBitsRead());
4580fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar        shouldRead = getShouldRead();
459d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        assertExactMatch(shouldRead, b, abTernary);
460d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        assertFalse(mExprModel.markBitsRead());
461d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
462d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
463d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    @Test
464d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    public void testNestedCircularDependency() {
465eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        MockLayoutBinder lb = new MockLayoutBinder();
466d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        mExprModel = lb.getModel();
467c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        IdentifierExpr a = lb.addVariable("a", int.class.getCanonicalName(),
468c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar                null);
469c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        IdentifierExpr b = lb.addVariable("b", int.class.getCanonicalName(),
470c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar                null);
471c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        IdentifierExpr c = lb.addVariable("c", int.class.getCanonicalName(),
472c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar                null);
473d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        final TernaryExpr a3Ternary = parse(lb, "a > 3 ? c > 4 ? a : b : c", TernaryExpr.class);
474d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        final TernaryExpr c4Ternary = (TernaryExpr) a3Ternary.getIfTrue();
475d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        mExprModel.seal();
4762611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        List<Expr> shouldRead = getShouldRead();
477d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        assertExactMatch(shouldRead, a, a3Ternary.getPred());
478d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        assertTrue(mExprModel.markBitsRead());
4790fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar        shouldRead = getShouldRead();
480d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        assertExactMatch(shouldRead, c, c4Ternary.getPred());
481d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        assertFlags(c, a3Ternary.getRequirementFlagIndex(true),
482d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                a3Ternary.getRequirementFlagIndex(false));
483d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        assertFlags(c4Ternary.getPred(), a3Ternary.getRequirementFlagIndex(true));
484d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
485d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
486d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    @Test
487d615f15f0f0cc4c4de7570119d181e13d44e708aGeorge Mount    public void testInterExprDependency() {
488eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        MockLayoutBinder lb = new MockLayoutBinder();
489d615f15f0f0cc4c4de7570119d181e13d44e708aGeorge Mount        mExprModel = lb.getModel();
490d615f15f0f0cc4c4de7570119d181e13d44e708aGeorge Mount        IdentifierExpr u = lb.addVariable("u", User.class.getCanonicalName(),
491d615f15f0f0cc4c4de7570119d181e13d44e708aGeorge Mount                null);
492d615f15f0f0cc4c4de7570119d181e13d44e708aGeorge Mount        final Expr uComment = parse(lb, "u.comment", FieldAccessExpr.class);
493876ba3272f17ed891ea455e7dd526d44e468757cYigit Boyar        final TernaryExpr uTernary = parse(lb, "u.getUseComment ? u.comment : `xx`", TernaryExpr.class);
494d615f15f0f0cc4c4de7570119d181e13d44e708aGeorge Mount        mExprModel.seal();
495eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        assertTrue(uTernary.getPred().canBeInvalidated());
496d615f15f0f0cc4c4de7570119d181e13d44e708aGeorge Mount        List<Expr> shouldRead = getShouldRead();
497d615f15f0f0cc4c4de7570119d181e13d44e708aGeorge Mount        assertExactMatch(shouldRead, u, uComment, uTernary.getPred());
498d615f15f0f0cc4c4de7570119d181e13d44e708aGeorge Mount        assertTrue(mExprModel.markBitsRead());
499d615f15f0f0cc4c4de7570119d181e13d44e708aGeorge Mount        shouldRead = getShouldRead();
500eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        assertExactMatch(shouldRead, uComment, uTernary);
501d615f15f0f0cc4c4de7570119d181e13d44e708aGeorge Mount    }
502d615f15f0f0cc4c4de7570119d181e13d44e708aGeorge Mount
503d615f15f0f0cc4c4de7570119d181e13d44e708aGeorge Mount    @Test
5048533f27db6c31b0c295ae62d314dbf07ea640571Yigit Boyar    public void testInterExprCircularDependency() {
505eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        MockLayoutBinder lb = new MockLayoutBinder();
5068533f27db6c31b0c295ae62d314dbf07ea640571Yigit Boyar        mExprModel = lb.getModel();
507c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        IdentifierExpr a = lb.addVariable("a", int.class.getCanonicalName(),
508c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar                null);
509c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        IdentifierExpr b = lb.addVariable("b", int.class.getCanonicalName(),
510c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar                null);
5118533f27db6c31b0c295ae62d314dbf07ea640571Yigit Boyar        final TernaryExpr abTernary = parse(lb, "a > 3 ? a : b", TernaryExpr.class);
5128533f27db6c31b0c295ae62d314dbf07ea640571Yigit Boyar        final TernaryExpr abTernary2 = parse(lb, "b > 3 ? b : a", TernaryExpr.class);
5138533f27db6c31b0c295ae62d314dbf07ea640571Yigit Boyar        mExprModel.seal();
5142611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        List<Expr> shouldRead = getShouldRead();
5158533f27db6c31b0c295ae62d314dbf07ea640571Yigit Boyar        assertExactMatch(shouldRead, a, b, abTernary.getPred(), abTernary2.getPred());
5168533f27db6c31b0c295ae62d314dbf07ea640571Yigit Boyar        assertTrue(mExprModel.markBitsRead());
5178533f27db6c31b0c295ae62d314dbf07ea640571Yigit Boyar        shouldRead = getShouldRead();
5188533f27db6c31b0c295ae62d314dbf07ea640571Yigit Boyar        assertExactMatch(shouldRead, abTernary, abTernary2);
5198533f27db6c31b0c295ae62d314dbf07ea640571Yigit Boyar    }
5208533f27db6c31b0c295ae62d314dbf07ea640571Yigit Boyar
5218533f27db6c31b0c295ae62d314dbf07ea640571Yigit Boyar    @Test
5227b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar    public void testInterExprCircularDependency2() {
523eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        MockLayoutBinder lb = new MockLayoutBinder();
5247b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar        mExprModel = lb.getModel();
525c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        IdentifierExpr a = lb.addVariable("a", boolean.class.getCanonicalName(),
526c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar                null);
527c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        IdentifierExpr b = lb.addVariable("b", boolean.class.getCanonicalName(),
528c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar                null);
5297b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar        final TernaryExpr abTernary = parse(lb, "a ? b : true", TernaryExpr.class);
5307b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar        final TernaryExpr baTernary = parse(lb, "b ? a : false", TernaryExpr.class);
5317b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar        mExprModel.seal();
5322611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        List<Expr> shouldRead = getShouldRead();
5337b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar        assertExactMatch(shouldRead, a, b);
534eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        assertFlags(a, a, b);
535eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        assertFlags(b, a, b);
5362611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        List<Expr> readFirst = getReadFirst(shouldRead);
5377b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar        assertExactMatch(readFirst, a, b);
5387b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar        assertTrue(mExprModel.markBitsRead());
5397b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar        shouldRead = getShouldRead();
540eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        assertExactMatch(shouldRead, abTernary, baTernary);
5417b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar        readFirst = getReadFirst(shouldRead);
5427b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar        assertExactMatch(readFirst, abTernary, baTernary);
5437b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar        assertFalse(mExprModel.markBitsRead());
5447b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar        shouldRead = getShouldRead();
5452611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        assertEquals(0, shouldRead.size());
5467b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar    }
5477b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar
5487b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar    @Test
5497b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar    public void testInterExprCircularDependency3() {
550eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        MockLayoutBinder lb = new MockLayoutBinder();
5517b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar        mExprModel = lb.getModel();
552c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        IdentifierExpr a = lb.addVariable("a", boolean.class.getCanonicalName(),
553c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar                null);
554c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        IdentifierExpr b = lb.addVariable("b", boolean.class.getCanonicalName(),
555c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar                null);
556c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        IdentifierExpr c = lb.addVariable("c", boolean.class.getCanonicalName(),
557c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar                null);
5587b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar        final TernaryExpr abTernary = parse(lb, "a ? b : c", TernaryExpr.class);
5597b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar        final TernaryExpr abTernary2 = parse(lb, "b ? a : c", TernaryExpr.class);
5607b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar        mExprModel.seal();
5612611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        List<Expr> shouldRead = getShouldRead();
5627b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar        assertExactMatch(shouldRead, a, b);
5637b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar        assertTrue(mExprModel.markBitsRead());
5647b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar        shouldRead = getShouldRead();
5657b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar        // read a and b again, this time for their dependencies and also the rest since everything
5667b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar        // is ready to be read
567eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        assertExactMatch(shouldRead, c, abTernary, abTernary2);
5687b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar        mExprModel.markBitsRead();
5697b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar        shouldRead = getShouldRead();
5702611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        assertEquals(0, shouldRead.size());
5717b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar    }
5727b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar
5737b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar    @Test
5747b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar    public void testInterExprCircularDependency4() {
575eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        MockLayoutBinder lb = new MockLayoutBinder();
5767b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar        mExprModel = lb.getModel();
577c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        IdentifierExpr a = lb.addVariable("a", boolean.class.getCanonicalName(),
578c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar                null);
579c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        IdentifierExpr b = lb.addVariable("b", boolean.class.getCanonicalName(),
580c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar                null);
581c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        IdentifierExpr c = lb.addVariable("c", boolean.class.getCanonicalName(),
582c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar                null);
583c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        IdentifierExpr d = lb.addVariable("d", boolean.class.getCanonicalName(),
584c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar                null);
5857b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar        final TernaryExpr cTernary = parse(lb, "c ? (a ? d : false) : false", TernaryExpr.class);
5867b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar        final TernaryExpr abTernary = parse(lb, "a ? b : true", TernaryExpr.class);
5877b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar        final TernaryExpr baTernary = parse(lb, "b ? a : false", TernaryExpr.class);
5887b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar        mExprModel.seal();
5892611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        List<Expr> shouldRead = getShouldRead();
590eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        // check if a,b or c should be read. these are easily calculated from binding expressions'
591eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        // invalidation
5927b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar        assertExactMatch(shouldRead, c, a, b);
5937b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar
5947b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar        List<Expr> justRead = new ArrayList<Expr>();
5952611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        List<Expr> readFirst = getReadFirst(shouldRead);
5967b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar        assertExactMatch(readFirst, c, a, b);
5977b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar        Collections.addAll(justRead, a, b, c);
5982611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        assertEquals(0, filterOut(getReadFirst(shouldRead, justRead), justRead).size());
5997b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar        assertTrue(mExprModel.markBitsRead());
6007b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar        shouldRead = getShouldRead();
601eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        // if a and b are not invalid, a won't be read in the first step. But if c's expression
602eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        // is invalid and c == true, a must be read. Depending on a, d might be read as well.
603eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        // don't need to read b anymore because `a ? b : true` and `b ? a : false` has the same
604eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        // invalidation flags.
605eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        assertExactMatch(shouldRead, a, abTernary, baTernary);
6067b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar        justRead.clear();
6077b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar
6087b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar        readFirst = getReadFirst(shouldRead);
609eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        // first must read `a`.
610eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        assertExactMatch(readFirst, a);
611eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        Collections.addAll(justRead, a);
6127b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar
6137b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar        readFirst = filterOut(getReadFirst(shouldRead, justRead), justRead);
614eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        assertExactMatch(readFirst, abTernary, baTernary);
615eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        Collections.addAll(justRead, abTernary, baTernary);
616eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar
617eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        readFirst = filterOut(getReadFirst(shouldRead, justRead), justRead);
618eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        assertEquals(0, filterOut(getReadFirst(shouldRead, justRead), justRead).size());
619eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        assertTrue(mExprModel.markBitsRead());
620eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar
621eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        shouldRead = getShouldRead();
622eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        // now we can read adf ternary and c ternary
623eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        justRead.clear();
624eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        assertExactMatch(shouldRead, d, cTernary.getIfTrue(), cTernary);
625eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        readFirst = getReadFirst(shouldRead);
626eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        assertExactMatch(readFirst, d);
627eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        Collections.addAll(justRead, d);
628eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        readFirst = filterOut(getReadFirst(shouldRead, justRead), justRead);
629eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        assertExactMatch(readFirst, cTernary.getIfTrue());
630eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        Collections.addAll(justRead, cTernary.getIfTrue());
6317b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar
6327b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar        readFirst = filterOut(getReadFirst(shouldRead, justRead), justRead);
6337b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar        assertExactMatch(readFirst, cTernary);
6347b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar        Collections.addAll(justRead, cTernary);
6357b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar
6362611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        assertEquals(0, filterOut(getReadFirst(shouldRead, justRead), justRead).size());
6377b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar
6387b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar        assertFalse(mExprModel.markBitsRead());
6397b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar    }
6407b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar
6417b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar    @Test
642eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar    public void testInterExprDeepDependency() {
643eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        MockLayoutBinder lb = new MockLayoutBinder();
644eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        mExprModel = lb.getModel();
645eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        IdentifierExpr a = lb.addVariable("a", boolean.class.getCanonicalName(), null);
646eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        IdentifierExpr b = lb.addVariable("b", boolean.class.getCanonicalName(), null);
647eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        IdentifierExpr c = lb.addVariable("c", boolean.class.getCanonicalName(), null);
648eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        final TernaryExpr t1 = parse(lb, "c ? (a ? b : true) : false", TernaryExpr.class);
649eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        final TernaryExpr t2 = parse(lb, "c ? (b ? a : false) : true", TernaryExpr.class);
650eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        final TernaryExpr abTernary = (TernaryExpr) t1.getIfTrue();
651eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        final TernaryExpr baTernary = (TernaryExpr) t2.getIfTrue();
652eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        mExprModel.seal();
653eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        List<Expr> shouldRead = getShouldRead();
654eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        assertExactMatch(shouldRead, c);
655eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        assertTrue(mExprModel.markBitsRead());
656eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        shouldRead = getShouldRead();
657eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        assertExactMatch(shouldRead, a, b);
658eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        assertTrue(mExprModel.markBitsRead());
659eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        shouldRead = getShouldRead();
660eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        assertExactMatch(shouldRead, a, b, t1.getIfTrue(), t2.getIfTrue(), t1, t2);
661eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        assertFlags(b, abTernary.getRequirementFlagIndex(true));
662eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        assertFlags(a, baTernary.getRequirementFlagIndex(true));
663eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        assertFalse(mExprModel.markBitsRead());
664eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar    }
665eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar
666eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar    @Test
6677b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar    public void testInterExprDependencyNotReadyYet() {
668eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        MockLayoutBinder lb = new MockLayoutBinder();
6697b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar        mExprModel = lb.getModel();
670c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        IdentifierExpr a = lb.addVariable("a", boolean.class.getCanonicalName(), null);
671c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        IdentifierExpr b = lb.addVariable("b", boolean.class.getCanonicalName(), null);
672c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        IdentifierExpr c = lb.addVariable("c", boolean.class.getCanonicalName(), null);
673c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        IdentifierExpr d = lb.addVariable("d", boolean.class.getCanonicalName(), null);
674c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        IdentifierExpr e = lb.addVariable("e", boolean.class.getCanonicalName(), null);
6757b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar        final TernaryExpr cTernary = parse(lb, "c ? (a ? d : false) : false", TernaryExpr.class);
6767b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar        final TernaryExpr baTernary = parse(lb, "b ? a : false", TernaryExpr.class);
6777b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar        final TernaryExpr eaTernary = parse(lb, "e ? a : false", TernaryExpr.class);
6787b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar        mExprModel.seal();
6792611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        List<Expr> shouldRead = getShouldRead();
6807b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar        assertExactMatch(shouldRead, b, c, e);
6817b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar        assertTrue(mExprModel.markBitsRead());
6827b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar        shouldRead = getShouldRead();
6837b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar        assertExactMatch(shouldRead, a, baTernary, eaTernary);
6847b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar        assertTrue(mExprModel.markBitsRead());
6857b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar        shouldRead = getShouldRead();
6867b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar        assertExactMatch(shouldRead, d, cTernary.getIfTrue(), cTernary);
6877b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar        assertFalse(mExprModel.markBitsRead());
6887b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar    }
6897b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar
6907b07818f07c28c6dec34ca2a9ab5f61e86afb493Yigit Boyar    @Test
691dc69f49d687ec036947f26a9bf9025a305de0721Yigit Boyar    public void testNoFlagsForNonBindingStatic() {
692eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        MockLayoutBinder lb = new MockLayoutBinder();
693dc69f49d687ec036947f26a9bf9025a305de0721Yigit Boyar        mExprModel = lb.getModel();
694c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        lb.addVariable("a", int.class.getCanonicalName(), null);
695dc69f49d687ec036947f26a9bf9025a305de0721Yigit Boyar        final MathExpr parsed = parse(lb, "a * (3 + 2)", MathExpr.class);
696dc69f49d687ec036947f26a9bf9025a305de0721Yigit Boyar        mExprModel.seal();
697019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        // +1 for invalidate all flag
698019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        assertEquals(1, parsed.getRight().getInvalidFlags().cardinality());
699019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        // +1 for invalidate all flag
700019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        assertEquals(2, parsed.getLeft().getInvalidFlags().cardinality());
701019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        // +1 for invalidate all flag
702019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        assertEquals(2, mExprModel.getInvalidateableFieldLimit());
703dc69f49d687ec036947f26a9bf9025a305de0721Yigit Boyar    }
704dc69f49d687ec036947f26a9bf9025a305de0721Yigit Boyar
705dc69f49d687ec036947f26a9bf9025a305de0721Yigit Boyar    @Test
706dc69f49d687ec036947f26a9bf9025a305de0721Yigit Boyar    public void testFlagsForBindingStatic() {
707eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        MockLayoutBinder lb = new MockLayoutBinder();
708dc69f49d687ec036947f26a9bf9025a305de0721Yigit Boyar        mExprModel = lb.getModel();
709c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        lb.addVariable("a", int.class.getCanonicalName(), null);
710dc69f49d687ec036947f26a9bf9025a305de0721Yigit Boyar        final Expr staticParsed = parse(lb, "3 + 2", MathExpr.class);
711dc69f49d687ec036947f26a9bf9025a305de0721Yigit Boyar        final MathExpr parsed = parse(lb, "a * (3 + 2)", MathExpr.class);
712dc69f49d687ec036947f26a9bf9025a305de0721Yigit Boyar        mExprModel.seal();
713dc69f49d687ec036947f26a9bf9025a305de0721Yigit Boyar        assertTrue(staticParsed.isBindingExpression());
714019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        // +1 for invalidate all flag
7158533f27db6c31b0c295ae62d314dbf07ea640571Yigit Boyar        assertEquals(1, staticParsed.getInvalidFlags().cardinality());
716dc69f49d687ec036947f26a9bf9025a305de0721Yigit Boyar        assertEquals(parsed.getRight().getInvalidFlags(), staticParsed.getInvalidFlags());
717019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        // +1 for invalidate all flag
718019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        assertEquals(2, parsed.getLeft().getInvalidFlags().cardinality());
719019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        // +1 for invalidate all flag
7208533f27db6c31b0c295ae62d314dbf07ea640571Yigit Boyar        assertEquals(2, mExprModel.getInvalidateableFieldLimit());
721019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar    }
722019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar
723019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar    @Test
724019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar    public void testFinalFieldOfAVariable() {
725eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        MockLayoutBinder lb = new MockLayoutBinder();
726019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        mExprModel = lb.getModel();
727c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        IdentifierExpr user = lb.addVariable("user", User.class.getCanonicalName(),
728c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar                null);
729019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        Expr fieldGet = parse(lb, "user.finalField", FieldAccessExpr.class);
730019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        mExprModel.seal();
731019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        assertTrue(fieldGet.isDynamic());
732019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        // read user
733c96847768305d83c6bc4919432af9bd9bfe4c08eGeorge Mount        assertExactMatch(getShouldRead(), user, fieldGet);
734019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        mExprModel.markBitsRead();
735019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        // no need to read user.finalField
7362611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        assertEquals(0, getShouldRead().size());
737019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar    }
738019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar
739019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar    @Test
740019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar    public void testFinalFieldOfAField() {
741eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        MockLayoutBinder lb = new MockLayoutBinder();
742019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        mExprModel = lb.getModel();
743c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        lb.addVariable("user", User.class.getCanonicalName(), null);
744019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        Expr finalFieldGet = parse(lb, "user.subObj.finalField", FieldAccessExpr.class);
745019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        mExprModel.seal();
746019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        assertTrue(finalFieldGet.isDynamic());
747019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        Expr userSubObjGet = finalFieldGet.getChildren().get(0);
748019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        // read user
7492611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        List<Expr> shouldRead = getShouldRead();
7502611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        assertEquals(3, shouldRead.size());
751019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        assertExactMatch(shouldRead, userSubObjGet.getChildren().get(0), userSubObjGet,
752019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar                finalFieldGet);
753019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        mExprModel.markBitsRead();
754019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        // no need to read user.subObj.finalField because it is final
7552611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        assertEquals(0, getShouldRead().size());
756019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar    }
757019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar
758019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar    @Test
759019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar    public void testFinalFieldOfAMethod() {
760eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        MockLayoutBinder lb = new MockLayoutBinder();
761019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        mExprModel = lb.getModel();
762c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        lb.addVariable("user", User.class.getCanonicalName(), null);
763019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        Expr finalFieldGet = parse(lb, "user.anotherSubObj.finalField", FieldAccessExpr.class);
764019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        mExprModel.seal();
765019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        assertTrue(finalFieldGet.isDynamic());
766019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        Expr userSubObjGet = finalFieldGet.getChildren().get(0);
767019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        // read user
7682611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        List<Expr> shouldRead = getShouldRead();
7692611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        assertEquals(3, shouldRead.size());
770019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        assertExactMatch(shouldRead, userSubObjGet.getChildren().get(0), userSubObjGet,
771019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar                finalFieldGet);
772019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        mExprModel.markBitsRead();
773019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        // no need to read user.subObj.finalField because it is final
7742611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        assertEquals(0, getShouldRead().size());
775dc69f49d687ec036947f26a9bf9025a305de0721Yigit Boyar    }
776dc69f49d687ec036947f26a9bf9025a305de0721Yigit Boyar
777019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar    @Test
778019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar    public void testFinalOfAClass() {
779eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        MockLayoutBinder lb = new MockLayoutBinder();
780019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        mExprModel = lb.getModel();
781c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        mExprModel.addImport("View", "android.view.View", null);
782019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        FieldAccessExpr fieldAccess = parse(lb, "View.VISIBLE", FieldAccessExpr.class);
783019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        assertFalse(fieldAccess.isDynamic());
784019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        mExprModel.seal();
7852611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        assertEquals(0, getShouldRead().size());
786019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar    }
787019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar
788019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar    @Test
789ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar    public void testStaticFieldOfInstance() {
790eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        MockLayoutBinder lb = new MockLayoutBinder();
791ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar        mExprModel = lb.getModel();
792c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        lb.addVariable("myView", "android.view.View", null);
793ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar        FieldAccessExpr fieldAccess = parse(lb, "myView.VISIBLE", FieldAccessExpr.class);
794ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar        assertFalse(fieldAccess.isDynamic());
795ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar        mExprModel.seal();
7962611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        assertEquals(0, getShouldRead().size());
797ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar        final Expr child = fieldAccess.getChild();
798ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar        assertTrue(child instanceof StaticIdentifierExpr);
799ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar        StaticIdentifierExpr id = (StaticIdentifierExpr) child;
800ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar        assertEquals(id.getResolvedType().getCanonicalName(), "android.view.View");
801ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar        // on demand import
802ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar        assertEquals("android.view.View", mExprModel.getImports().get("View"));
803ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar    }
804ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar
805ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar    @Test
806ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar    public void testOnDemandImportConflict() {
807eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        MockLayoutBinder lb = new MockLayoutBinder();
808ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar        mExprModel = lb.getModel();
809c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        final IdentifierExpr myView = lb.addVariable("u", "android.view.View",
810c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar                null);
811c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        mExprModel.addImport("View", User.class.getCanonicalName(), null);
812ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar        final StaticIdentifierExpr id = mExprModel.staticIdentifierFor(myView.getResolvedType());
813ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar        mExprModel.seal();
814ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar        // on demand import with conflict
815ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar        assertEquals("android.view.View", mExprModel.getImports().get("View1"));
816ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar        assertEquals("View1", id.getName());
817ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar        assertEquals("android.view.View", id.getUserDefinedType());
818ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar    }
819ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar
820ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar    @Test
821ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar    public void testOnDemandImportAlreadyImported() {
822eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        MockLayoutBinder lb = new MockLayoutBinder();
823ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar        mExprModel = lb.getModel();
824c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        final StaticIdentifierExpr ux = mExprModel.addImport("UX", User.class.getCanonicalName(),
825c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar                null);
826c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        final IdentifierExpr u = lb.addVariable("u", User.class.getCanonicalName(),
827c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar                null);
828ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar        final StaticIdentifierExpr id = mExprModel.staticIdentifierFor(u.getResolvedType());
829ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar        mExprModel.seal();
830ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar        // on demand import with conflict
831ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar        assertSame(ux, id);
832ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar    }
833ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar
834ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar    @Test
835ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar    public void testStaticMethodOfInstance() {
836eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        MockLayoutBinder lb = new MockLayoutBinder();
837ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar        mExprModel = lb.getModel();
838c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        lb.addVariable("user", User.class.getCanonicalName(), null);
839ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar        MethodCallExpr methodCall = parse(lb, "user.ourStaticMethod()", MethodCallExpr.class);
840ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar        assertTrue(methodCall.isDynamic());
841ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar        mExprModel.seal();
842ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar        final Expr child = methodCall.getTarget();
843ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar        assertTrue(child instanceof StaticIdentifierExpr);
844ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar        StaticIdentifierExpr id = (StaticIdentifierExpr) child;
845ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar        assertEquals(id.getResolvedType().getCanonicalName(), User.class.getCanonicalName());
846ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar    }
847ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar
848ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar    @Test
849019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar    public void testFinalOfStaticField() {
850eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        MockLayoutBinder lb = new MockLayoutBinder();
851019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        mExprModel = lb.getModel();
852c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        mExprModel.addImport("UX", User.class.getCanonicalName(), null);
853c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        FieldAccessExpr fieldAccess = parse(lb, "UX.innerStaticInstance.finalStaticField",
854c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar                FieldAccessExpr.class);
855019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        assertFalse(fieldAccess.isDynamic());
856019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        mExprModel.seal();
857ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar        // nothing to read since it is all final and static
8582611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        assertEquals(0, getShouldRead().size());
859019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar    }
860019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar
861019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar    @Test
862019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar    public void testFinalOfFinalStaticField() {
863eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        MockLayoutBinder lb = new MockLayoutBinder();
864019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        mExprModel = lb.getModel();
865c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        mExprModel.addImport("User", User.class.getCanonicalName(), null);
866c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        FieldAccessExpr fieldAccess = parse(lb, "User.innerFinalStaticInstance.finalStaticField",
867c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar                FieldAccessExpr.class);
868019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        assertFalse(fieldAccess.isDynamic());
869019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        mExprModel.seal();
8702611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        assertEquals(0, getShouldRead().size());
871019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar    }
872019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar
873c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar    @Test
874c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar    public void testLocationTracking() {
875eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        MockLayoutBinder lb = new MockLayoutBinder();
876c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        mExprModel = lb.getModel();
877c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        final String input = "a > 3 ? b : c";
878c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        TernaryExpr ternaryExpr = parse(lb, input, TernaryExpr.class);
879c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        final Location location = ternaryExpr.getLocations().get(0);
880c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        assertNotNull(location);
881c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        assertEquals(0, location.startLine);
882c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        assertEquals(0, location.startOffset);
883c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        assertEquals(0, location.endLine);
884c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        assertEquals(input.length() - 1, location.endOffset);
885c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar
886c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        final ComparisonExpr comparison = (ComparisonExpr) ternaryExpr.getPred();
887c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        final Location predLoc = comparison.getLocations().get(0);
888c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        assertNotNull(predLoc);
889c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        assertEquals(0, predLoc.startLine);
890c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        assertEquals(0, predLoc.startOffset);
891c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        assertEquals(0, predLoc.endLine);
892c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        assertEquals(4, predLoc.endOffset);
893c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar
894c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        final Location aLoc = comparison.getLeft().getLocations().get(0);
895c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        assertNotNull(aLoc);
896c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        assertEquals(0, aLoc.startLine);
897c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        assertEquals(0, aLoc.startOffset);
898c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        assertEquals(0, aLoc.endLine);
899c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        assertEquals(0, aLoc.endOffset);
900c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar
901c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        final Location tLoc = comparison.getRight().getLocations().get(0);
902c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        assertNotNull(tLoc);
903c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        assertEquals(0, tLoc.startLine);
904c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        assertEquals(4, tLoc.startOffset);
905c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        assertEquals(0, tLoc.endLine);
906c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        assertEquals(4, tLoc.endOffset);
907c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar
908c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        final Location bLoc = ternaryExpr.getIfTrue().getLocations().get(0);
909c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        assertNotNull(bLoc);
910c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        assertEquals(0, bLoc.startLine);
911c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        assertEquals(8, bLoc.startOffset);
912c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        assertEquals(0, bLoc.endLine);
913c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        assertEquals(8, bLoc.endOffset);
914c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar
915c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        final Location cLoc = ternaryExpr.getIfFalse().getLocations().get(0);
916c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        assertNotNull(cLoc);
917c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        assertEquals(0, cLoc.startLine);
918c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        assertEquals(12, cLoc.startOffset);
919c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        assertEquals(0, cLoc.endLine);
920c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar        assertEquals(12, cLoc.endOffset);
921c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar    }
922c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar
923019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar//    TODO uncomment when we have inner static access
924019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar//    @Test
925019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar//    public void testFinalOfInnerStaticClass() {
926eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar//        MockLayoutBinder lb = new MockLayoutBinder();
927019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar//        mExprModel = lb.getModel();
928019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar//        mExprModel.addImport("User", User.class.getCanonicalName());
929019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar//        FieldAccessExpr fieldAccess = parse(lb, "User.InnerStaticClass.finalStaticField", FieldAccessExpr.class);
930019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar//        assertFalse(fieldAccess.isDynamic());
931019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar//        mExprModel.seal();
9322611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar//        assertEquals(0, getShouldRead().size());
933019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar//    }
934019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar
935d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    private void assertFlags(Expr a, int... flags) {
936d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        BitSet bitset = new BitSet();
937d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        for (int flag : flags) {
938d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            bitset.set(flag);
939d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
940d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        assertEquals("flag test for " + a.getUniqueKey(), bitset, a.getShouldReadFlags());
941d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
942d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
943d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    private void assertFlags(Expr a, Expr... exprs) {
944d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        BitSet bitSet = a.getShouldReadFlags();
945d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        for (Expr expr : exprs) {
946d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            BitSet clone = (BitSet) bitSet.clone();
947d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            clone.and(expr.getInvalidFlags());
948d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            assertEquals("should read flags of " + a.getUniqueKey() + " should include " + expr
949d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar                    .getUniqueKey(), expr.getInvalidFlags(), clone);
950d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
951d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
952d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        BitSet composite = new BitSet();
953d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        for (Expr expr : exprs) {
954d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            composite.or(expr.getInvalidFlags());
955d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
956d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        assertEquals("composite flags should match", composite, bitSet);
957d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
958d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
9592611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar    private void assertExactMatch(List<Expr> iterable, Expr... exprs) {
960d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        int i = 0;
961eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        String listLog = Arrays.toString(iterable.toArray());
962eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        String itemsLog = Arrays.toString(exprs);
963eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar        String log = "list: " + listLog + "\nitems: " + itemsLog;
964d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        log("list", iterable);
965d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        for (Expr expr : exprs) {
966ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar            assertTrue((i++) + ":must contain " + expr.getUniqueKey() + "\n" + log,
9672611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar                    iterable.contains(expr));
968d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
969d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        i = 0;
970d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        for (Expr expr : iterable) {
971eebcbdd5d35e56a2c8ef37feeb65df46130d001dYigit Boyar            assertTrue((i++) + ":must be expected " + expr.getUniqueKey() + "\n" + log,
9724ba16229a40e9758db86d4fb1df5119fdcb8aa2aDeepanshu Gupta                    Arrays.asList(exprs).contains(expr));
973d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
974d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
975d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
976d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    private <T extends Expr> T parse(LayoutBinder binder, String input, Class<T> klass) {
977d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        final Expr parsed = binder.parse(input, false, null);
978d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        assertTrue(klass.isAssignableFrom(parsed.getClass()));
979d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        return (T) parsed;
980d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
981d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
9822611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar    private void log(String s, List<Expr> iterable) {
983d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        L.d(s);
984d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        for (Expr e : iterable) {
98574f72d77b1db2b78ee6422da2ec94de12edcb6dcYigit Boyar            L.d(": %s : %s allFlags: %s readSoFar: %s", e.getUniqueKey(), e.getShouldReadFlags(),
98674f72d77b1db2b78ee6422da2ec94de12edcb6dcYigit Boyar                    e.getShouldReadFlagsWithConditionals(), e.getReadSoFar());
987d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
988d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        L.d("end of %s", s);
989d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
990d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
9912611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar    private List<Expr> getReadFirst(List<Expr> shouldRead) {
9920fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar        return getReadFirst(shouldRead, null);
9930fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar    }
99474f72d77b1db2b78ee6422da2ec94de12edcb6dcYigit Boyar
9952611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar    private List<Expr> getReadFirst(List<Expr> shouldRead, final List<Expr> justRead) {
9962611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        List<Expr> result = new ArrayList<Expr>();
9972611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        for (Expr expr : shouldRead) {
9982611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar            if (expr.shouldReadNow(justRead)) {
9992611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar                result.add(expr);
10000fa158e8aa91297cc246e3bb9e5d1388dc2355ccYigit Boyar            }
10012611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        }
10022611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar        return result;
1003d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
1004d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
10052611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar    private List<Expr> getShouldRead() {
1006af146d6a8c0efcf5682d14047c06866a5548f78fYigit Boyar        return ExprModel.filterShouldRead(mExprModel.getPendingExpressions());
1007d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
1008d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
1009e61d1cc710803cdf0ab4f2aca3d18c46949758a9Yigit Boyar    public static class User implements Observable {
101074f72d77b1db2b78ee6422da2ec94de12edcb6dcYigit Boyar
1011d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        String name;
101274f72d77b1db2b78ee6422da2ec94de12edcb6dcYigit Boyar
1013d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        String lastName;
1014d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
1015019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        public final int finalField = 5;
1016c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar
1017019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        public static InnerStaticClass innerStaticInstance = new InnerStaticClass();
1018c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar
1019019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        public static final InnerStaticClass innerFinalStaticInstance = new InnerStaticClass();
1020c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar
1021019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        public SubObj subObj = new SubObj();
1022019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar
1023d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        public String getName() {
1024d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            return name;
1025d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
1026d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
1027d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        public String getLastName() {
1028d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            return lastName;
1029d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
1030d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar
1031d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        public boolean getCond(int i) {
1032d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar            return true;
1033d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar        }
1034019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar
1035019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        public SubObj getAnotherSubObj() {
1036019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar            return new SubObj();
1037019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        }
1038019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar
1039ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar        public static boolean ourStaticMethod() {
1040ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar            return true;
1041ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar        }
1042ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar
1043d615f15f0f0cc4c4de7570119d181e13d44e708aGeorge Mount        public String comment;
1044d615f15f0f0cc4c4de7570119d181e13d44e708aGeorge Mount
1045d615f15f0f0cc4c4de7570119d181e13d44e708aGeorge Mount        @Bindable
1046876ba3272f17ed891ea455e7dd526d44e468757cYigit Boyar        public boolean getUseComment() {
1047d615f15f0f0cc4c4de7570119d181e13d44e708aGeorge Mount            return true;
1048d615f15f0f0cc4c4de7570119d181e13d44e708aGeorge Mount        }
1049d615f15f0f0cc4c4de7570119d181e13d44e708aGeorge Mount
1050e61d1cc710803cdf0ab4f2aca3d18c46949758a9Yigit Boyar        @Override
1051e61d1cc710803cdf0ab4f2aca3d18c46949758a9Yigit Boyar        public void addOnPropertyChangedCallback(OnPropertyChangedCallback callback) {
1052e61d1cc710803cdf0ab4f2aca3d18c46949758a9Yigit Boyar
1053e61d1cc710803cdf0ab4f2aca3d18c46949758a9Yigit Boyar        }
1054e61d1cc710803cdf0ab4f2aca3d18c46949758a9Yigit Boyar
1055e61d1cc710803cdf0ab4f2aca3d18c46949758a9Yigit Boyar        @Override
1056e61d1cc710803cdf0ab4f2aca3d18c46949758a9Yigit Boyar        public void removeOnPropertyChangedCallback(OnPropertyChangedCallback callback) {
1057e61d1cc710803cdf0ab4f2aca3d18c46949758a9Yigit Boyar
1058e61d1cc710803cdf0ab4f2aca3d18c46949758a9Yigit Boyar        }
1059e61d1cc710803cdf0ab4f2aca3d18c46949758a9Yigit Boyar
1060019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        public static class InnerStaticClass {
1061c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar
1062019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar            public static final int finalField = 3;
1063c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar
1064019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar            public static final int finalStaticField = 3;
1065019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        }
1066d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar    }
1067019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar
1068019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar    public static class SubObj {
1069c1560e6b00b398867da12fbdc5a1fcd1d50b801cYigit Boyar
1070019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar        public final int finalField = 5;
1071019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar    }
1072019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar
1073d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar}
1074