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