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() {
60            return new KCode();
61        }
62
63        @Override
64        public Expr cloneToModel(ExprModel model) {
65            return this;
66        }
67
68        @Override
69        protected String getInvertibleError() {
70            return null;
71        }
72
73        @Override
74        public boolean isDynamic() {
75            return true;
76        }
77    }
78
79    @Before
80    public void setUp() throws Exception {
81        JavaAnalyzer.initForTests();
82    }
83
84    @Test(expected=Throwable.class)
85    public void testBadExpr() {
86        Expr expr = new Expr() {
87            @Override
88            protected ModelClass resolveType(ModelAnalyzer modelAnalyzer) {
89                return modelAnalyzer.findClass(Integer.class);
90            }
91
92            @Override
93            protected List<Dependency> constructDependencies() {
94                return constructDynamicChildrenDependencies();
95            }
96
97            @Override
98            protected KCode generateCode() {
99                return new KCode();
100            }
101
102            @Override
103            public Expr cloneToModel(ExprModel model) {
104                return this;
105            }
106
107            @Override
108            protected String getInvertibleError() {
109                return null;
110            }
111        };
112        expr.getUniqueKey();
113    }
114
115    @Test
116    public void testBasicInvalidationFlag() {
117        LayoutBinder lb = new MockLayoutBinder();
118        ExprModel model = lb.getModel();
119        model.seal();
120        DummyExpr d = new DummyExpr("a");
121        d.setModel(model);
122        d.setId(3);
123        d.enableDirectInvalidation();
124        assertTrue(d.getInvalidFlags().get(3));
125        BitSet clone = (BitSet) model.getInvalidateAnyBitSet().clone();
126        clone.and(d.getInvalidFlags());
127        assertEquals(1, clone.cardinality());
128    }
129
130    @Test
131    public void testCannotBeInvalidated() {
132        LayoutBinder lb = new MockLayoutBinder();
133        ExprModel model = lb.getModel();
134        model.seal();
135        DummyExpr d = new DummyExpr("a");
136        d.setModel(model);
137        d.setId(3);
138        // +1 for invalidate all flag
139        assertEquals(1, d.getInvalidFlags().cardinality());
140        assertEquals(model.getInvalidateAnyBitSet(), d.getInvalidFlags());
141    }
142
143    @Test
144    public void testInvalidationInheritance() {
145        ExprModel model = new ExprModel();
146        DummyExpr a = model.register(new DummyExpr("a"));
147        DummyExpr b = model.register(new DummyExpr("b"));
148        DummyExpr c = model.register(new DummyExpr("c", a, b));
149        a.enableDirectInvalidation();
150        b.enableDirectInvalidation();
151        c.setBindingExpression(true);
152        model.seal();
153        assertFlags(c, a, b);
154    }
155
156    @Test
157    public void testInvalidationInheritance2() {
158        ExprModel model = new ExprModel();
159        DummyExpr a = model.register(new DummyExpr("a"));
160        DummyExpr b = model.register(new DummyExpr("b", a));
161        DummyExpr c = model.register(new DummyExpr("c", b));
162        a.enableDirectInvalidation();
163        b.enableDirectInvalidation();
164        c.setBindingExpression(true);
165        model.seal();
166        assertFlags(c, a, b);
167    }
168
169    @Test
170    public void testShouldReadFlags() {
171        ExprModel model = new ExprModel();
172        DummyExpr a = model.register(new DummyExpr("a"));
173        a.enableDirectInvalidation();
174        a.setBindingExpression(true);
175        model.seal();
176        assertFlags(a, a);
177    }
178
179    @Test
180    public void testShouldReadDependencyFlags() {
181        ExprModel model = new ExprModel();
182        DummyExpr a = model.register(new DummyExpr("a"));
183        DummyExpr b = model.register(new DummyExpr("b", a));
184        DummyExpr c = model.register(new DummyExpr("c", b));
185        a.enableDirectInvalidation();
186        b.enableDirectInvalidation();
187        b.setBindingExpression(true);
188        c.setBindingExpression(true);
189        model.seal();
190        assertFlags(b, a, b);
191        assertFlags(c, a, b);
192    }
193
194    private void assertFlags(Expr a, Expr... exprs) {
195        BitSet bitSet = a.getShouldReadFlags();
196        for (Expr expr : exprs) {
197            BitSet clone = (BitSet) bitSet.clone();
198            clone.and(expr.getInvalidFlags());
199            assertEquals("should read flags of " + a.getUniqueKey() + " should include " + expr
200                    .getUniqueKey(), expr.getInvalidFlags(), clone);
201        }
202
203        BitSet composite = new BitSet();
204        for (Expr expr : exprs) {
205            composite.or(expr.getInvalidFlags());
206        }
207        assertEquals("composite flags should match", composite, bitSet);
208    }
209}
210