1#!/usr/bin/env python 2# Copyright 2015 The Chromium Authors. All rights reserved. 3# Use of this source code is governed by a BSD-style license that can be 4# found in the LICENSE file. 5 6""" 7Unit tests for the contents of shared_prefs.py (mostly SharedPrefs). 8""" 9 10import logging 11import unittest 12 13from devil import devil_env 14from devil.android import device_utils 15from devil.android.sdk import shared_prefs 16 17with devil_env.SysPath(devil_env.PYMOCK_PATH): 18 import mock # pylint: disable=import-error 19 20 21def MockDeviceWithFiles(files=None): 22 if files is None: 23 files = {} 24 25 def file_exists(path): 26 return path in files 27 28 def write_file(path, contents, **_kwargs): 29 files[path] = contents 30 31 def read_file(path, **_kwargs): 32 return files[path] 33 34 device = mock.MagicMock(spec=device_utils.DeviceUtils) 35 device.FileExists = mock.Mock(side_effect=file_exists) 36 device.WriteFile = mock.Mock(side_effect=write_file) 37 device.ReadFile = mock.Mock(side_effect=read_file) 38 return device 39 40 41class SharedPrefsTest(unittest.TestCase): 42 43 def setUp(self): 44 self.device = MockDeviceWithFiles({ 45 '/data/data/com.some.package/shared_prefs/prefs.xml': 46 "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n" 47 '<map>\n' 48 ' <int name="databaseVersion" value="107" />\n' 49 ' <boolean name="featureEnabled" value="false" />\n' 50 ' <string name="someHashValue">249b3e5af13d4db2</string>\n' 51 '</map>'}) 52 self.expected_data = {'databaseVersion': 107, 53 'featureEnabled': False, 54 'someHashValue': '249b3e5af13d4db2'} 55 56 def testPropertyLifetime(self): 57 prefs = shared_prefs.SharedPrefs( 58 self.device, 'com.some.package', 'prefs.xml') 59 self.assertEquals(len(prefs), 0) # collection is empty before loading 60 prefs.SetInt('myValue', 444) 61 self.assertEquals(len(prefs), 1) 62 self.assertEquals(prefs.GetInt('myValue'), 444) 63 self.assertTrue(prefs.HasProperty('myValue')) 64 prefs.Remove('myValue') 65 self.assertEquals(len(prefs), 0) 66 self.assertFalse(prefs.HasProperty('myValue')) 67 with self.assertRaises(KeyError): 68 prefs.GetInt('myValue') 69 70 def testPropertyType(self): 71 prefs = shared_prefs.SharedPrefs( 72 self.device, 'com.some.package', 'prefs.xml') 73 prefs.SetInt('myValue', 444) 74 self.assertEquals(prefs.PropertyType('myValue'), 'int') 75 with self.assertRaises(TypeError): 76 prefs.GetString('myValue') 77 with self.assertRaises(TypeError): 78 prefs.SetString('myValue', 'hello') 79 80 def testLoad(self): 81 prefs = shared_prefs.SharedPrefs( 82 self.device, 'com.some.package', 'prefs.xml') 83 self.assertEquals(len(prefs), 0) # collection is empty before loading 84 prefs.Load() 85 self.assertEquals(len(prefs), len(self.expected_data)) 86 self.assertEquals(prefs.AsDict(), self.expected_data) 87 self.assertFalse(prefs.changed) 88 89 def testClear(self): 90 prefs = shared_prefs.SharedPrefs( 91 self.device, 'com.some.package', 'prefs.xml') 92 prefs.Load() 93 self.assertEquals(prefs.AsDict(), self.expected_data) 94 self.assertFalse(prefs.changed) 95 prefs.Clear() 96 self.assertEquals(len(prefs), 0) # collection is empty now 97 self.assertTrue(prefs.changed) 98 99 def testCommit(self): 100 prefs = shared_prefs.SharedPrefs( 101 self.device, 'com.some.package', 'other_prefs.xml') 102 self.assertFalse(self.device.FileExists(prefs.path)) # file does not exist 103 prefs.Load() 104 self.assertEquals(len(prefs), 0) # file did not exist, collection is empty 105 prefs.SetInt('magicNumber', 42) 106 prefs.SetFloat('myMetric', 3.14) 107 prefs.SetLong('bigNumner', 6000000000) 108 prefs.SetStringSet('apps', ['gmail', 'chrome', 'music']) 109 self.assertFalse(self.device.FileExists(prefs.path)) # still does not exist 110 self.assertTrue(prefs.changed) 111 prefs.Commit() 112 self.assertTrue(self.device.FileExists(prefs.path)) # should exist now 113 self.device.KillAll.assert_called_once_with(prefs.package, exact=True, 114 as_root=True, quiet=True) 115 self.assertFalse(prefs.changed) 116 117 prefs = shared_prefs.SharedPrefs( 118 self.device, 'com.some.package', 'other_prefs.xml') 119 self.assertEquals(len(prefs), 0) # collection is empty before loading 120 prefs.Load() 121 self.assertEquals(prefs.AsDict(), { 122 'magicNumber': 42, 123 'myMetric': 3.14, 124 'bigNumner': 6000000000, 125 'apps': ['gmail', 'chrome', 'music']}) # data survived roundtrip 126 127 def testAsContextManager_onlyReads(self): 128 with shared_prefs.SharedPrefs( 129 self.device, 'com.some.package', 'prefs.xml') as prefs: 130 self.assertEquals(prefs.AsDict(), self.expected_data) # loaded and ready 131 self.assertEquals(self.device.WriteFile.call_args_list, []) # did not write 132 133 def testAsContextManager_readAndWrite(self): 134 with shared_prefs.SharedPrefs( 135 self.device, 'com.some.package', 'prefs.xml') as prefs: 136 prefs.SetBoolean('featureEnabled', True) 137 prefs.Remove('someHashValue') 138 prefs.SetString('newString', 'hello') 139 140 self.assertTrue(self.device.WriteFile.called) # did write 141 with shared_prefs.SharedPrefs( 142 self.device, 'com.some.package', 'prefs.xml') as prefs: 143 # changes persisted 144 self.assertTrue(prefs.GetBoolean('featureEnabled')) 145 self.assertFalse(prefs.HasProperty('someHashValue')) 146 self.assertEquals(prefs.GetString('newString'), 'hello') 147 self.assertTrue(prefs.HasProperty('databaseVersion')) # still there 148 149 def testAsContextManager_commitAborted(self): 150 with self.assertRaises(TypeError): 151 with shared_prefs.SharedPrefs( 152 self.device, 'com.some.package', 'prefs.xml') as prefs: 153 prefs.SetBoolean('featureEnabled', True) 154 prefs.Remove('someHashValue') 155 prefs.SetString('newString', 'hello') 156 prefs.SetInt('newString', 123) # oops! 157 158 self.assertEquals(self.device.WriteFile.call_args_list, []) # did not write 159 with shared_prefs.SharedPrefs( 160 self.device, 'com.some.package', 'prefs.xml') as prefs: 161 # contents were not modified 162 self.assertEquals(prefs.AsDict(), self.expected_data) 163 164if __name__ == '__main__': 165 logging.getLogger().setLevel(logging.DEBUG) 166 unittest.main(verbosity=2) 167