/* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.tools.lint.checks; import com.android.tools.lint.detector.api.Detector; @SuppressWarnings("javadoc") public class ResourceCycleDetectorTest extends AbstractCheckTest { @Override protected Detector getDetector() { return new ResourceCycleDetector(); } public void testStyles() throws Exception { assertEquals("" + "res/values/styles.xml:9: Error: Style DetailsPage_EditorialBuyButton should not extend itself [ResourceCycle]\n" + "<style name=\"DetailsPage_EditorialBuyButton\" parent=\"@style/DetailsPage_EditorialBuyButton\" />\n" + " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" + "1 errors, 0 warnings\n", lintProject("res/values/styles.xml")); } public void testStyleImpliedParent() throws Exception { assertEquals("" + "res/values/stylecycle.xml:3: Error: Potential cycle: PropertyToggle is the implied parent of PropertyToggle.Base and this defines the opposite [ResourceCycle]\n" + " <style name=\"PropertyToggle\" parent=\"@style/PropertyToggle.Base\"></style>\n" + " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" + "1 errors, 0 warnings\n", lintProject("res/values/stylecycle.xml")); } public void testLayouts() throws Exception { assertEquals("" + "res/layout/layoutcycle1.xml:10: Error: Layout layoutcycle1 should not include itself [ResourceCycle]\n" + " layout=\"@layout/layoutcycle1\" />\n" + " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" + "1 errors, 0 warnings\n", lintProject("res/layout/layoutcycle1.xml")); } public void testColors() throws Exception { assertEquals("" + "res/values/colorcycle1.xml:2: Error: Color test should not reference itself [ResourceCycle]\n" + " <color name=\"test\">@color/test</color>\n" + " ^\n" + "1 errors, 0 warnings\n", lintProject("res/values/colorcycle1.xml")); } public void testAaptCrash() throws Exception { assertEquals("" + "res/values/aaptcrash.xml:5: Error: This construct can potentially crash aapt during a build. Change @+id/titlebar to @id/titlebar and define the id explicitly using <item type=\"id\" name=\"titlebar\"/> instead. [AaptCrash]\n" + " <item name=\"android:id\">@+id/titlebar</item>\n" + " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" + "1 errors, 0 warnings\n", lintProject("res/values/aaptcrash.xml")); } public void testDeepColorCycle1() throws Exception { assertEquals("" + "res/values/colorcycle2.xml:2: Error: Color Resource definition cycle: test1 => test2 => test3 => test1 [ResourceCycle]\n" + " <color name=\"test1\">@color/test2</color>\n" + " ^\n" + " res/values/colorcycle4.xml:2: Reference from @color/test3 to color/test1 here\n" + " res/values/colorcycle3.xml:2: Reference from @color/test2 to color/test3 here\n" + "1 errors, 0 warnings\n", lintProject( "res/values/colorcycle2.xml", "res/values/colorcycle3.xml", "res/values/colorcycle4.xml" )); } public void testDeepColorCycle2() throws Exception { assertEquals("" + "res/values/colorcycle5.xml:2: Error: Color Resource definition cycle: test1 => test2 => test1 [ResourceCycle]\n" + " <color name=\"test1\">@color/test2</color>\n" + " ^\n" + " res/values/colorcycle5.xml:3: Reference from @color/test2 to color/test1 here\n" + "1 errors, 0 warnings\n", lintProject( "res/values/colorcycle5.xml" )); } public void testDeepStyleCycle1() throws Exception { assertEquals("" + "res/values/stylecycle1.xml:6: Error: Style Resource definition cycle: ButtonStyle => ButtonStyle.Base => ButtonStyle [ResourceCycle]\n" + " <style name=\"ButtonStyle\" parent=\"ButtonStyle.Base\">\n" + " ~~~~~~~~~~~~~~~~~~~~~~~~~\n" + " res/values/stylecycle1.xml:3: Reference from @style/ButtonStyle.Base to style/ButtonStyle here\n" + "1 errors, 0 warnings\n", lintProject( "res/values/stylecycle1.xml" )); } public void testDeepStyleCycle2() throws Exception { assertEquals("" + "res/values/stylecycle2.xml:3: Error: Style Resource definition cycle: mystyle1 => mystyle2 => mystyle3 => mystyle1 [ResourceCycle]\n" + " <style name=\"mystyle1\" parent=\"@style/mystyle2\">\n" + " ~~~~~~~~~~~~~~~~~~~~~~~~\n" + " res/values/stylecycle2.xml:9: Reference from @style/mystyle3 to style/mystyle1 here\n" + " res/values/stylecycle2.xml:6: Reference from @style/mystyle2 to style/mystyle3 here\n" + "1 errors, 0 warnings\n", lintProject( "res/values/stylecycle2.xml" )); } public void testDeepIncludeOk() throws Exception { assertEquals("" + "No warnings.", lintProject( "res/layout/layout1.xml", "res/layout/layout2.xml", "res/layout/layout3.xml", "res/layout/layout4.xml" )); } public void testDeepIncludeCycle() throws Exception { assertEquals("" + "res/layout/layout1.xml:10: Error: Layout Resource definition cycle: layout1 => layout2 => layout4 => layout1 [ResourceCycle]\n" + " layout=\"@layout/layout2\" />\n" + " ~~~~~~~~~~~~~~~~~~~~~~~~\n" + " res/layout/layout4.xml:16: Reference from @layout/layout4 to layout/layout1 here\n" + " res/layout/layout2.xml:16: Reference from @layout/layout2 to layout/layout4 here\n" + "1 errors, 0 warnings\n", lintProject( "res/layout/layout1.xml", "res/layout/layout2.xml", "res/layout/layout3.xml", "res/layout/layout4cycle.xml=>res/layout/layout4.xml" )); } public void testDeepAliasCycle() throws Exception { assertEquals("" + "res/values/aliases.xml:2: Error: Layout Resource definition cycle: layout10 => layout20 => layout30 => layout10 [ResourceCycle]\n" + " <item name=\"layout10\" type=\"layout\">@layout/layout20</item>\n" + " ^\n" + " res/values/aliases.xml:4: Reference from @layout/layout30 to layout/layout10 here\n" + " res/values/aliases.xml:3: Reference from @layout/layout20 to layout/layout30 here\n" + "res/values/colorcycle2.xml:2: Error: Color Resource definition cycle: test1 => test2 => test1 [ResourceCycle]\n" + " <color name=\"test1\">@color/test2</color>\n" + " ^\n" + " res/values/aliases.xml:5: Reference from @color/test2 to color/test1 here\n" + "res/layout/layout1.xml:10: Error: Layout Resource definition cycle: layout1 => layout2 => layout4 => layout1 [ResourceCycle]\n" + " layout=\"@layout/layout2\" />\n" + " ~~~~~~~~~~~~~~~~~~~~~~~~\n" + " res/values/aliases.xml:6: Reference from @layout/layout4 to layout/layout1 here\n" + " res/layout/layout2.xml:16: Reference from @layout/layout2 to layout/layout4 here\n" + "3 errors, 0 warnings\n", lintProject( "res/values/aliases.xml", "res/layout/layout1.xml", "res/layout/layout2.xml", "res/layout/layout3.xml", "res/values/colorcycle2.xml" )); } public void testColorStateListCycle() throws Exception { assertEquals("" + "res/values/aliases2.xml:2: Error: Color Resource definition cycle: bright_foreground_dark => color1 => bright_foreground_dark [ResourceCycle]\n" + " <item name=\"bright_foreground_dark\" type=\"color\">@color/color1</item>\n" + " ^\n" + " res/color/color1.xml:3: Reference from @color/color1 to color/bright_foreground_dark here\n" + "1 errors, 0 warnings\n", lintProject( "res/color/color1.xml", "res/values/aliases2.xml" )); } public void testDrawableStateListCycle() throws Exception { assertEquals("" + "res/drawable/drawable1.xml:4: Error: Drawable Resource definition cycle: drawable1 => textfield_search_pressed => drawable2 => drawable1 [ResourceCycle]\n" + " <item android:state_window_focused=\"false\" android:state_enabled=\"true\"\n" + " ^\n" + " res/values/aliases2.xml:4: Reference from @drawable/drawable2 to drawable/drawable1 here\n" + " res/values/aliases2.xml:3: Reference from @drawable/textfield_search_pressed to drawable/drawable2 here\n" + "1 errors, 0 warnings\n", lintProject( "res/drawable/drawable1.xml", "res/values/aliases2.xml" )); } }