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 package com.android.providers.settings; 17 18 import android.test.AndroidTestCase; 19 import android.util.Xml; 20 21 import org.xmlpull.v1.XmlSerializer; 22 23 import java.io.ByteArrayOutputStream; 24 import java.io.File; 25 import java.io.FileOutputStream; 26 import java.io.PrintStream; 27 import java.nio.charset.StandardCharsets; 28 29 public class SettingsStateTest extends AndroidTestCase { 30 public static final String CRAZY_STRING = 31 "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\u0008\u0009\n\u000b\u000c\r" + 32 "\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a" + 33 "\u001b\u001c\u001d\u001e\u001f\u0020" + 34 "fake_setting_value_1" + 35 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + 36 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + 37 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + 38 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + 39 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + 40 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + 41 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + 42 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + 43 "\u1000 \u2000 \u5000 \u8000 \uc000 \ue000" + 44 "\ud800\udc00\udbff\udfff" + // surrogate pairs 45 "\uD800ab\uDC00 " + // broken surrogate pairs 46 ""; 47 48 49 public void testIsBinary() { 50 assertFalse(SettingsState.isBinary(" abc ")); 51 52 for (char ch = 0x20; ch < 0xd800; ch++) { 53 assertFalse("ch=" + Integer.toString(ch, 16), 54 SettingsState.isBinary(String.valueOf(ch))); 55 } 56 for (char ch = 0xe000; ch < 0xfffe; ch++) { 57 assertFalse("ch=" + Integer.toString(ch, 16), 58 SettingsState.isBinary(String.valueOf(ch))); 59 } 60 61 for (char ch = 0x0000; ch < 0x20; ch++) { 62 assertTrue("ch=" + Integer.toString(ch, 16), 63 SettingsState.isBinary(String.valueOf(ch))); 64 } 65 for (char ch = 0xd800; ch < 0xe000; ch++) { 66 assertTrue("ch=" + Integer.toString(ch, 16), 67 SettingsState.isBinary(String.valueOf(ch))); 68 } 69 assertTrue(SettingsState.isBinary("\ufffe")); 70 assertTrue(SettingsState.isBinary("\uffff")); 71 try { 72 assertFalse(SettingsState.isBinary(null)); 73 fail("NullPointerException expected"); 74 } catch (NullPointerException expected) { 75 } 76 } 77 78 /** Make sure we won't pass invalid characters to XML serializer. */ 79 public void testWriteReadNoCrash() throws Exception { 80 ByteArrayOutputStream os = new ByteArrayOutputStream(); 81 82 XmlSerializer serializer = Xml.newSerializer(); 83 serializer.setOutput(os, StandardCharsets.UTF_8.name()); 84 serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true); 85 serializer.startDocument(null, true); 86 87 for (int ch = 0; ch < 0x10000; ch++) { 88 checkWriteSingleSetting("char=0x" + Integer.toString(ch, 16), serializer, 89 "key", String.valueOf((char) ch)); 90 } 91 checkWriteSingleSetting(serializer, "k", ""); 92 checkWriteSingleSetting(serializer, "x", "abc"); 93 checkWriteSingleSetting(serializer, "abc", CRAZY_STRING); 94 checkWriteSingleSetting(serializer, "def", null); 95 96 // Invlid input, but shouoldn't crash. 97 checkWriteSingleSetting(serializer, null, null); 98 checkWriteSingleSetting(serializer, CRAZY_STRING, null); 99 SettingsState.writeSingleSetting( 100 SettingsState.SETTINGS_VERSOIN_NEW_ENCODING, 101 serializer, null, "k", "v", "package"); 102 SettingsState.writeSingleSetting( 103 SettingsState.SETTINGS_VERSOIN_NEW_ENCODING, 104 serializer, "1", "k", "v", null); 105 } 106 107 private void checkWriteSingleSetting(XmlSerializer serializer, String key, String value) 108 throws Exception { 109 checkWriteSingleSetting(key + "/" + value, serializer, key, value); 110 } 111 112 private void checkWriteSingleSetting(String msg, XmlSerializer serializer, 113 String key, String value) throws Exception { 114 // Make sure the XML serializer won't crash. 115 SettingsState.writeSingleSetting( 116 SettingsState.SETTINGS_VERSOIN_NEW_ENCODING, 117 serializer, "1", key, value, "package"); 118 } 119 120 /** 121 * Make sure settings can be written to a file and also can be read. 122 */ 123 public void testReadWrite() { 124 final File file = new File(getContext().getCacheDir(), "setting.xml"); 125 file.delete(); 126 final Object lock = new Object(); 127 128 final SettingsState ssWriter = new SettingsState(lock, file, 1, 129 SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED); 130 ssWriter.setVersionLocked(SettingsState.SETTINGS_VERSOIN_NEW_ENCODING); 131 132 ssWriter.insertSettingLocked("k1", "\u0000", "package"); 133 ssWriter.insertSettingLocked("k2", "abc", "p2"); 134 ssWriter.insertSettingLocked("k3", null, "p2"); 135 ssWriter.insertSettingLocked("k4", CRAZY_STRING, "p3"); 136 synchronized (lock) { 137 ssWriter.persistSyncLocked(); 138 } 139 140 final SettingsState ssReader = new SettingsState(lock, file, 1, 141 SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED); 142 synchronized (lock) { 143 assertEquals("\u0000", ssReader.getSettingLocked("k1").getValue()); 144 assertEquals("abc", ssReader.getSettingLocked("k2").getValue()); 145 assertEquals(null, ssReader.getSettingLocked("k3").getValue()); 146 assertEquals(CRAZY_STRING, ssReader.getSettingLocked("k4").getValue()); 147 } 148 } 149 150 /** 151 * In version 120, value "null" meant {code NULL}. 152 */ 153 public void testUpgrade() throws Exception { 154 final File file = new File(getContext().getCacheDir(), "setting.xml"); 155 file.delete(); 156 final Object lock = new Object(); 157 final PrintStream os = new PrintStream(new FileOutputStream(file)); 158 os.print( 159 "<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>" + 160 "<settings version=\"120\">" + 161 " <setting id=\"0\" name=\"k0\" value=\"null\" package=\"null\" />" + 162 " <setting id=\"1\" name=\"k1\" value=\"\" package=\"\" />" + 163 " <setting id=\"2\" name=\"k2\" value=\"v2\" package=\"p2\" />" + 164 "</settings>"); 165 os.close(); 166 167 final SettingsState ss = new SettingsState(lock, file, 1, 168 SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED); 169 synchronized (lock) { 170 SettingsState.Setting s; 171 s = ss.getSettingLocked("k0"); 172 assertEquals(null, s.getValue()); 173 assertEquals("null", s.getPackageName()); 174 175 s = ss.getSettingLocked("k1"); 176 assertEquals("", s.getValue()); 177 assertEquals("", s.getPackageName()); 178 179 s = ss.getSettingLocked("k2"); 180 assertEquals("v2", s.getValue()); 181 assertEquals("p2", s.getPackageName()); 182 } 183 } 184 } 185