1/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.databinding.tool.expr;
18
19import android.databinding.tool.LayoutBinder;
20import android.databinding.tool.MockLayoutBinder;
21import android.databinding.tool.reflection.ModelAnalyzer;
22import android.databinding.tool.reflection.ModelClass;
23import android.databinding.tool.reflection.java.JavaAnalyzer;
24import android.databinding.tool.writer.KCode;
25
26import org.junit.Before;
27import org.junit.Test;
28
29import java.util.BitSet;
30import java.util.List;
31
32import static org.junit.Assert.assertEquals;
33import static org.junit.Assert.assertTrue;
34
35public class ExprTest{
36    private static class DummyExpr extends Expr {
37        String mKey;
38        public DummyExpr(String key, DummyExpr... children) {
39            super(children);
40            mKey = key;
41        }
42
43        @Override
44        protected ModelClass resolveType(ModelAnalyzer modelAnalyzer) {
45            return modelAnalyzer.findClass(Integer.class);
46        }
47
48        @Override
49        protected List<Dependency> constructDependencies() {
50            return constructDynamicChildrenDependencies();
51        }
52
53        @Override
54        protected String computeUniqueKey() {
55            return mKey + super.computeUniqueKey();
56        }
57
58        @Override
59        protected KCode generateCode(boolean full) {
60            return new KCode();
61        }
62
63        @Override
64        protected String getInvertibleError() {
65            return null;
66        }
67
68        @Override
69        public boolean isDynamic() {
70            return true;
71        }
72    }
73
74    @Before
75    public void setUp() throws Exception {
76        JavaAnalyzer.initForTests();
77    }
78
79    @Test(expected=Throwable.class)
80    public void testBadExpr() {
81        Expr expr = new Expr() {
82            @Override
83            protected ModelClass resolveType(ModelAnalyzer modelAnalyzer) {
84                return modelAnalyzer.findClass(Integer.class);
85            }
86
87            @Override
88            protected List<Dependency> constructDependencies() {
89                return constructDynamicChildrenDependencies();
90            }
91
92            @Override
93            protected KCode generateCode(boolean full) {
94                return new KCode();
95            }
96
97            @Override
98            protected String getInvertibleError() {
99                return null;
100            }
101        };
102        expr.getUniqueKey();
103    }
104
105    @Test
106    public void testBasicInvalidationFlag() {
107        LayoutBinder lb = new MockLayoutBinder();
108        ExprModel model = lb.getModel();
109        model.seal();
110        DummyExpr d = new DummyExpr("a");
111        d.setModel(model);
112        d.setId(3);
113        d.enableDirectInvalidation();
114        assertTrue(d.getInvalidFlags().get(3));
115        BitSet clone = (BitSet) model.getInvalidateAnyBitSet().clone();
116        clone.and(d.getInvalidFlags());
117        assertEquals(1, clone.cardinality());
118    }
119
120    @Test
121    public void testCannotBeInvalidated() {
122        LayoutBinder lb = new MockLayoutBinder();
123        ExprModel model = lb.getModel();
124        model.seal();
125        DummyExpr d = new DummyExpr("a");
126        d.setModel(model);
127        d.setId(3);
128        // +1 for invalidate all flag
129        assertEquals(1, d.getInvalidFlags().cardinality());
130        assertEquals(model.getInvalidateAnyBitSet(), d.getInvalidFlags());
131    }
132
133    @Test
134    public void testInvalidationInheritance() {
135        ExprModel model = new ExprModel();
136        DummyExpr a = model.register(new DummyExpr("a"));
137        DummyExpr b = model.register(new DummyExpr("b"));
138        DummyExpr c = model.register(new DummyExpr("c", a, b));
139        a.enableDirectInvalidation();
140        b.enableDirectInvalidation();
141        c.setBindingExpression(true);
142        model.seal();
143        assertFlags(c, a, b);
144    }
145
146    @Test
147    public void testInvalidationInheritance2() {
148        ExprModel model = new ExprModel();
149        DummyExpr a = model.register(new DummyExpr("a"));
150        DummyExpr b = model.register(new DummyExpr("b", a));
151        DummyExpr c = model.register(new DummyExpr("c", b));
152        a.enableDirectInvalidation();
153        b.enableDirectInvalidation();
154        c.setBindingExpression(true);
155        model.seal();
156        assertFlags(c, a, b);
157    }
158
159    @Test
160    public void testShouldReadFlags() {
161        ExprModel model = new ExprModel();
162        DummyExpr a = model.register(new DummyExpr("a"));
163        a.enableDirectInvalidation();
164        a.setBindingExpression(true);
165        model.seal();
166        assertFlags(a, a);
167    }
168
169    @Test
170    public void testShouldReadDependencyFlags() {
171        ExprModel model = new ExprModel();
172        DummyExpr a = model.register(new DummyExpr("a"));
173        DummyExpr b = model.register(new DummyExpr("b", a));
174        DummyExpr c = model.register(new DummyExpr("c", b));
175        a.enableDirectInvalidation();
176        b.enableDirectInvalidation();
177        b.setBindingExpression(true);
178        c.setBindingExpression(true);
179        model.seal();
180        assertFlags(b, a, b);
181        assertFlags(c, a, b);
182    }
183
184    private void assertFlags(Expr a, Expr... exprs) {
185        BitSet bitSet = a.getShouldReadFlags();
186        for (Expr expr : exprs) {
187            BitSet clone = (BitSet) bitSet.clone();
188            clone.and(expr.getInvalidFlags());
189            assertEquals("should read flags of " + a.getUniqueKey() + " should include " + expr
190                    .getUniqueKey(), expr.getInvalidFlags(), clone);
191        }
192
193        BitSet composite = new BitSet();
194        for (Expr expr : exprs) {
195            composite.or(expr.getInvalidFlags());
196        }
197        assertEquals("composite flags should match", composite, bitSet);
198    }
199}
200