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