Example #1
0
    def test__call(self):
        # Check that the function creates an FF2PP and returns the result
        # of iterating over it.

        # Make a real (test) iterator object, as otherwise iter() complains...
        mock_iterator = (1 for x in ())
        # Make a mock for the iter() call of an FF2PP object.
        mock_iter_call = mock.MagicMock(return_value=mock_iterator)
        # Make a mock FF2PP object instance.
        mock_ff2pp_instance = mock.MagicMock(__iter__=mock_iter_call)
        # Make the mock FF2PP class.
        mock_ff2pp_class = mock.MagicMock(return_value=mock_ff2pp_instance)

        # Call um_to_pp while patching the um._ff_replacement.FF2PP class.
        test_path = '/any/old/file.name'
        with mock.patch('iris.fileformats.um._ff_replacement.FF2PP',
                        mock_ff2pp_class):
            result = um_to_pp(test_path)

        # Check that it called FF2PP in the expected way.
        self.assertEqual(mock_ff2pp_class.call_args_list,
                         [mock.call('/any/old/file.name', read_data=False)])
        self.assertEqual(mock_ff2pp_instance.__iter__.call_args_list,
                         [mock.call()])

        # Check that it returned the expected result.
        self.assertIs(result, mock_iterator)
Example #2
0
 def test_two_plots_with_independent_axes(self):
     c1 = Contour(self.cube, self.axes)
     levels = 5
     other = _add_levels(self.cube, levels)[:, 0]
     c2 = Contour(other, self.axes)
     with mock.patch('cube_browser.Contour.__call__') as func:
         browser = Browser([c1, c2])
         browser.display()
         # Check the initial render.
         self.assertEqual(func.call_count, 2)
         expected = [
             mock.call(time=self.value),
             mock.call(model_level_number=self.value)
         ]
         func.assert_has_calls(expected)
         # Now simulate a 'time' slider change.
         slider = browser._slider_by_name['time']
         change = dict(owner=slider)
         browser.on_change(change)
         self.assertEqual(func.call_count, 3)
         expected.append(mock.call(time=self.value))
         func.assert_has_calls(expected)
         # Now simulate a 'model_level_number' slider change.
         slider = browser._slider_by_name['model_level_number']
         change = dict(owner=slider)
         browser.on_change(change)
         self.assertEqual(func.call_count, 4)
         expected.append(mock.call(model_level_number=self.value))
         func.assert_has_calls(expected)
Example #3
0
 def test_two_plots_with_independent_axes(self):
     c1 = Contour(self.cube, self.axes)
     levels = 5
     other = _add_levels(self.cube, levels)[:, 0]
     c2 = Contour(other, self.axes)
     with mock.patch('cube_browser.Contour.__call__') as func:
         browser = Browser([c1, c2])
         browser.display()
         # Check the initial render.
         self.assertEqual(func.call_count, 2)
         expected = [mock.call(time=self.value),
                     mock.call(model_level_number=self.value)]
         func.assert_has_calls(expected)
         # Now simulate a 'time' slider change.
         slider = browser._slider_by_name['time']
         change = dict(owner=slider)
         browser.on_change(change)
         self.assertEqual(func.call_count, 3)
         expected.append(mock.call(time=self.value))
         func.assert_has_calls(expected)
         # Now simulate a 'model_level_number' slider change.
         slider = browser._slider_by_name['model_level_number']
         change = dict(owner=slider)
         browser.on_change(change)
         self.assertEqual(func.call_count, 4)
         expected.append(mock.call(model_level_number=self.value))
         func.assert_has_calls(expected)
 def test_save_append(self):
     if six.PY3:
         open_func = 'builtins.open'
     else:
         open_func = '__builtin__.open'
     m = mock.mock_open()
     with mock.patch(open_func, m, create=True):
         pp.save_fields([self.pp_field], 'foo.pp', append=True)
     self.assertTrue(mock.call('foo.pp', 'ab') in m.mock_calls)
     self.assertTrue(mock.call().write('saved') in m.mock_calls)
Example #5
0
 def test_two_plots_with_no_axis(self):
     cube = self.cube[0]
     c1 = Contour(cube, self.axes)
     c2 = Contour(cube, self.axes)
     with mock.patch('cube_browser.Contour.__call__') as func:
         browser = Browser([c1, c2])
         browser.display()
         # Check the initial render - forced!
         self.assertEqual(func.call_count, 2)
         expected = [mock.call(), mock.call()]
         func.assert_has_calls(expected)
Example #6
0
 def test_two_plots_with_no_axis(self):
     cube = self.cube[0]
     c1 = Contour(cube, self.axes)
     c2 = Contour(cube, self.axes)
     with mock.patch('cube_browser.Contour.__call__') as func:
         browser = Browser([c1, c2])
         browser.display()
         # Check the initial render - forced!
         self.assertEqual(func.call_count, 2)
         expected = [mock.call(), mock.call()]
         func.assert_has_calls(expected)
Example #7
0
 def test_single_plot_with_axis(self):
     plot = Contour(self.cube, self.axes)
     with mock.patch('cube_browser.Contour.__call__') as func:
         browser = Browser(plot)
         browser.display()
         # Check the initial render.
         func.assert_called_once_with(time=self.value)
         # Now simulate a slider change.
         slider = browser._slider_by_name['time']
         change = dict(owner=slider)
         browser.on_change(change)
         self.assertEqual(func.call_count, 2)
         expected = [mock.call(time=self.value), mock.call(time=self.value)]
         func.assert_has_calls(expected)
Example #8
0
 def test_single_plot_with_axis(self):
     plot = Contour(self.cube, self.axes)
     with mock.patch('cube_browser.Contour.__call__') as func:
         browser = Browser(plot)
         browser.display()
         # Check the initial render.
         func.assert_called_once_with(time=self.value)
         # Now simulate a slider change.
         slider = browser._slider_by_name['time']
         change = dict(owner=slider)
         browser.on_change(change)
         self.assertEqual(func.call_count, 2)
         expected = [mock.call(time=self.value),
                     mock.call(time=self.value)]
         func.assert_has_calls(expected)
Example #9
0
 def test_default_chunks_limiting(self):
     # Check that chunking is limited when no specific 'chunks' given.
     limitcall_patch = self.patch('iris._lazy_data._limited_shape')
     test_shape = (3, 2, 4)
     data = self._dummydata(test_shape)
     as_lazy_data(data)
     self.assertEqual(limitcall_patch.call_args_list,
                      [mock.call(test_shape)])
Example #10
0
 def test_time_as_object(self):
     # Ensure Coord.cell() converts the point/bound values to
     # "datetime" objects.
     coord = self._mock_coord()
     coord.units.num2date = mock.Mock(
         side_effect=[mock.sentinel.datetime,
                      (mock.sentinel.datetime_lower,
                       mock.sentinel.datetime_upper)])
     cell = Coord.cell(coord, 0)
     self.assertIs(cell.point, mock.sentinel.datetime)
     self.assertEqual(cell.bound,
                      (mock.sentinel.datetime_lower,
                       mock.sentinel.datetime_upper))
     self.assertEqual(coord.units.num2date.call_args_list,
                      [mock.call((mock.sentinel.time,)),
                       mock.call((mock.sentinel.lower,
                                  mock.sentinel.upper))])
Example #11
0
 def test_read_headers_call(self):
     # Checks that the two calls to np.fromfile are called in the
     # expected way.
     pp_field = mock.Mock(lblrec=1,
                          lbext=0,
                          lbuser=[0])
     with self.mock_for_field_gen([pp_field]):
         open_fh = mock.MagicMock(spec=io.RawIOBase)
         open.return_value = open_fh
         next(pp._field_gen('mocked', read_data_bytes=False))
         with open_fh as open_fh_ctx:
             calls = [mock.call(open_fh_ctx, count=45, dtype='>i4'),
                      mock.call(open_fh_ctx, count=19, dtype='>f4')]
         np.fromfile.assert_has_calls(calls)
     with open_fh as open_fh_ctx:
         expected_deferred_bytes = ('mocked', open_fh_ctx.tell(),
                                    4, np.dtype('>f4'))
     self.assertEqual(pp_field._data, expected_deferred_bytes)
Example #12
0
 def test_time_as_object(self):
     # When iris.FUTURE.cell_datetime_objects is True, ensure
     # Coord.cell() converts the point/bound values to "datetime"
     # objects.
     coord = self._mock_coord()
     coord.units.num2date = mock.Mock(
         side_effect=[mock.sentinel.datetime,
                      (mock.sentinel.datetime_lower,
                       mock.sentinel.datetime_upper)])
     with mock.patch('iris.FUTURE', cell_datetime_objects=True):
         cell = Coord.cell(coord, 0)
     self.assertIs(cell.point, mock.sentinel.datetime)
     self.assertEqual(cell.bound,
                      (mock.sentinel.datetime_lower,
                       mock.sentinel.datetime_upper))
     self.assertEqual(coord.units.num2date.call_args_list,
                      [mock.call((mock.sentinel.time,)),
                       mock.call((mock.sentinel.lower,
                                  mock.sentinel.upper))])
Example #13
0
 def test_default_chunks_limiting(self):
     # Check that chunking is still controlled when no specific 'chunks'
     # is passed.
     limitcall_patch = self.patch('iris._lazy_data._optimum_chunksize')
     test_shape = (3, 2, 4)
     data = self._dummydata(test_shape)
     as_lazy_data(data)
     self.assertEqual(limitcall_patch.call_args_list, [
         mock.call(list(test_shape), shape=test_shape, dtype=np.dtype('f4'))
     ])
Example #14
0
 def test_time_as_object(self):
     # When iris.FUTURE.cell_datetime_objects is True, ensure
     # Coord.cell() converts the point/bound values to "datetime"
     # objects.
     coord = self._mock_coord()
     coord.units.num2date = mock.Mock(
         side_effect=[mock.sentinel.datetime,
                      (mock.sentinel.datetime_lower,
                       mock.sentinel.datetime_upper)])
     with mock.patch('iris.FUTURE', cell_datetime_objects=True):
         cell = Coord.cell(coord, 0)
     self.assertIs(cell.point, mock.sentinel.datetime)
     self.assertEqual(cell.bound,
                      (mock.sentinel.datetime_lower,
                       mock.sentinel.datetime_upper))
     self.assertEqual(coord.units.num2date.call_args_list,
                      [mock.call((mock.sentinel.time,)),
                       mock.call((mock.sentinel.lower,
                                  mock.sentinel.upper))])
Example #15
0
    def _check_bounds_setting(self, climatological=False):
        # Generic test that can run with or without a climatological coord.
        cube = stock.climatology_3d()
        coord = cube.coord('time').copy()
        # Over-write original value from stock.climatology_3d with test value.
        coord.climatological = \
            climatological

        # Set up expected strings.
        if climatological:
            property_name = 'climatology'
            varname_extra = 'climatology'
        else:
            property_name = 'bounds'
            varname_extra = 'bnds'
        boundsvar_name = 'time_' + varname_extra

        # Set up arguments for testing _create_cf_bounds.
        saver = mock.MagicMock(spec=Saver)
        # NOTE: 'saver' must have spec=Saver to fake isinstance(save, Saver),
        # so it can pass as 'self' in the call to _create_cf_cbounds.
        # Mock a '_dataset' property; not automatic because 'spec=Saver'.
        saver._dataset = mock.MagicMock()
        # Mock the '_ensure_valid_dtype' method to return an object with a
        # suitable 'shape' and 'dtype'.
        saver._ensure_valid_dtype.return_value = mock.Mock(
            shape=coord.bounds.shape, dtype=coord.bounds.dtype)
        var = mock.MagicMock(spec=nc.Variable)

        # Make the main call.
        Saver._create_cf_bounds(saver, coord, var, 'time')

        # Test the call of _setncattr in _create_cf_bounds.
        setncattr_call = mock.call(property_name,
                                   boundsvar_name.encode(encoding='ascii'))
        self.assertEqual(setncattr_call, var.setncattr.call_args)

        # Test the call of createVariable in _create_cf_bounds.
        dataset = saver._dataset
        expected_dimensions = var.dimensions + ('bnds', )
        create_var_call = mock.call(boundsvar_name, coord.bounds.dtype,
                                    expected_dimensions)
        self.assertEqual(create_var_call, dataset.createVariable.call_args)
Example #16
0
 def test_realise_data(self):
     # Simply check that calling CubeList.realise_data is calling
     # _lazy_data.co_realise_cubes.
     mock_cubes_list = [mock.Mock(ident=count) for count in range(3)]
     test_cubelist = CubeList(mock_cubes_list)
     call_patch = self.patch('iris._lazy_data.co_realise_cubes')
     test_cubelist.realise_data()
     # Check it was called once, passing cubes as *args.
     self.assertEqual(call_patch.call_args_list,
                      [mock.call(*mock_cubes_list)])
    def _call_target(self, fill_value, keys, vals):
        inner_target = mock.MagicMock()
        target = _FillValueMaskCheckAndStoreTarget(inner_target,
                                                   fill_value=fill_value)

        for key, val in zip(keys, vals):
            target[key] = val

        calls = [mock.call(key, val) for key, val in zip(keys, vals)]
        inner_target.__setitem__.assert_has_calls(calls)

        return target
Example #18
0
 def test_basic(self):
     result = product_definition_template_9(
         self.section, self.metadata, self.frt_coord)
     # Check expected function was called.
     self.assertEqual(
         self.patch_pdt8_call.call_args_list,
         [mock.call(self.section, self.metadata, self.frt_coord)])
     # Check metadata content (N.B. cell_method has been removed!).
     self.assertEqual(self.metadata, {'cell_methods': [],
                                      'aux_coords_and_dims': []})
     # Check result.
     self.assertEqual(result, Probability('above_threshold', 5.3))
Example #19
0
 def test_caching(self):
     # Check that it calculates regrid info just once, and re-uses it in
     # subsequent calls.
     src_grid = self.src_grid
     target_grid = self.tgt_grid
     regridder = Regridder(src_grid, target_grid, self.weights)
     different_src_cube = self.src_grid.copy()
     different_src_cube.rename('Different_source')
     with mock.patch(self.func_setup,
                     return_value=mock.sentinel.regrid_info) as patch_setup:
         with mock.patch(
                 self.func_operate,
                 return_value=self.dummy_slice_result) as patch_operate:
             result1 = regridder(src_grid)
             result2 = regridder(different_src_cube)
     patch_setup.assert_called_once_with(src_grid, self.weights,
                                         target_grid)
     self.assertEqual(len(patch_operate.call_args_list), 2)
     self.assertEqual(patch_operate.call_args_list, [
         mock.call(src_grid, mock.sentinel.regrid_info),
         mock.call(different_src_cube, mock.sentinel.regrid_info)
     ])
Example #20
0
 def test_save(self):
     if six.PY3:
         open_func = 'builtins.open'
     else:
         open_func = '__builtin__.open'
     m = mock.mock_open()
     with mock.patch(open_func, m, create=True):
         # sending a MagicMock object to gribapi raises an AssertionError
         # as the gribapi code does a type check
         # this is deemed acceptable within the scope of this unit test
         with self.assertRaises(AssertionError):
             grib.save_messages([self.grib_message], 'foo.grib2')
     self.assertTrue(mock.call('foo.grib2', 'wb') in m.mock_calls)
 def test_caching(self):
     # Check that it calculates regrid info just once, and re-uses it in
     # subsequent calls.
     src_grid = self.src_grid
     target_grid = self.tgt_grid
     regridder = Regridder(src_grid, target_grid, self.weights)
     different_src_cube = self.src_grid.copy()
     different_src_cube.rename('Different_source')
     with mock.patch(self.func_setup,
                     return_value=mock.sentinel.regrid_info) as patch_setup:
         with mock.patch(
                 self.func_operate,
                 return_value=self.dummy_slice_result) as patch_operate:
             result1 = regridder(src_grid)
             result2 = regridder(different_src_cube)
     patch_setup.assert_called_once_with(
         src_grid, self.weights, target_grid)
     self.assertEqual(len(patch_operate.call_args_list), 2)
     self.assertEqual(
         patch_operate.call_args_list,
         [mock.call(src_grid, mock.sentinel.regrid_info),
          mock.call(different_src_cube, mock.sentinel.regrid_info)])
Example #22
0
 def test_save(self):
     if six.PY3:
         open_func = 'builtins.open'
     else:
         open_func = '__builtin__.open'
     m = mock.mock_open()
     with mock.patch(open_func, m, create=True):
         # sending a MagicMock object to gribapi raises an AssertionError
         # as the gribapi code does a type check
         # this is deemed acceptable within the scope of this unit test
         with self.assertRaises(AssertionError):
             grib.save_messages([self.grib_message], 'foo.grib2')
     self.assertTrue(mock.call('foo.grib2', 'wb') in m.mock_calls)
Example #23
0
 def test_save_append(self):
     if six.PY3:
         open_func = "builtins.open"
     else:
         open_func = "__builtin__.open"
     m = mock.mock_open()
     with mock.patch(open_func, m, create=True):
         # sending a MagicMock object to gribapi raises an AssertionError
         # as the gribapi code does a type check
         # this is deemed acceptable within the scope of this unit test
         with self.assertRaises((AssertionError, TypeError)):
             grib.save_messages([self.grib_message], "foo.grib2", append=True)
     self.assertTrue(mock.call("foo.grib2", "ab") in m.mock_calls)
Example #24
0
 def test_two_plots_with_shared_axis(self):
     coords = ('time', 'grid_latitude')
     c1 = Contour(self.cube, self.axes, coords=coords)
     c2 = Contour(self.cube, self.axes, coords=coords)
     with mock.patch('cube_browser.Contour.__call__') as func:
         browser = Browser([c1, c2])
         browser.display()
         # Check the initial render.
         expected = [mock.call(grid_longitude=self.value)]
         self.assertEqual(func.call_args_list, expected * 2)
         # Now simulate a slider change.
         slider = browser._slider_by_name['grid_longitude']
         change = dict(owner=slider)
         browser.on_change(change)
         self.assertEqual(func.call_args_list, expected * 4)
Example #25
0
 def test_two_plots_with_shared_axis(self):
     coords = ('time', 'grid_latitude')
     c1 = Contour(self.cube, self.axes, coords=coords)
     c2 = Contour(self.cube, self.axes, coords=coords)
     with mock.patch('cube_browser.Contour.__call__') as func:
         browser = Browser([c1, c2])
         browser.display()
         # Check the initial render.
         expected = [mock.call(grid_longitude=self.value)]
         self.assertEqual(func.call_args_list, expected * 2)
         # Now simulate a slider change.
         slider = browser._slider_by_name['grid_longitude']
         change = dict(owner=slider)
         browser.on_change(change)
         self.assertEqual(func.call_args_list, expected * 4)
Example #26
0
 def test_zlib(self):
     cube = self._simple_cube('>f4')
     api = self.patch('iris.fileformats.netcdf.netCDF4')
     with Saver('/dummy/path', 'NETCDF4') as saver:
         saver.write(cube, zlib=True)
     dataset = api.Dataset.return_value
     create_var_call = mock.call('air_pressure_anomaly',
                                 np.dtype('float32'), ['dim0', 'dim1'],
                                 fill_value=None,
                                 shuffle=True,
                                 least_significant_digit=None,
                                 contiguous=False,
                                 zlib=True,
                                 fletcher32=False,
                                 endian='native',
                                 complevel=4,
                                 chunksizes=None)
     self.assertIn(create_var_call, dataset.createVariable.call_args_list)
Example #27
0
 def test_contig_tol(self):
     # Patch the inner call to ensure contiguity_tolerance is passed.
     cube_argument = mock.sentinel.passed_arg
     expected_result = mock.sentinel.returned_value
     blockplot_patch = self.patch(
         'iris.plot._draw_2d_from_bounds',
         mock.Mock(return_value=expected_result))
     # Make the call
     draw_func = self.blockplot_func()
     other_kwargs = self.additional_kwargs
     result = draw_func(cube_argument, contiguity_tolerance=0.0123)
     drawfunc_name = draw_func.__name__
     # Check details of the call that was made.
     self.assertEqual(
         blockplot_patch.call_args_list,
         [mock.call(drawfunc_name, cube_argument,
                    contiguity_tolerance=0.0123, **other_kwargs)])
     self.assertEqual(result, expected_result)
Example #28
0
 def test_contig_tol(self):
     # Patch the inner call to ensure contiguity_tolerance is passed.
     cube_argument = mock.sentinel.passed_arg
     expected_result = mock.sentinel.returned_value
     blockplot_patch = self.patch('iris.plot._draw_2d_from_bounds',
                                  mock.Mock(return_value=expected_result))
     # Make the call
     draw_func = self.blockplot_func()
     other_kwargs = self.additional_kwargs
     result = draw_func(cube_argument, contiguity_tolerance=0.0123)
     drawfunc_name = draw_func.__name__
     # Check details of the call that was made.
     self.assertEqual(blockplot_patch.call_args_list, [
         mock.call(drawfunc_name,
                   cube_argument,
                   contiguity_tolerance=0.0123,
                   **other_kwargs)
     ])
     self.assertEqual(result, expected_result)
Example #29
0
 def _check_cs(self, bplat, bplon, rotated):
     field = TestPPField()
     field.bplat = bplat
     field.bplon = bplon
     with mock.patch('iris.fileformats.pp.iris.coord_systems') \
             as mock_cs_mod:
         result = field.coord_system()
     if not rotated:
         # It should return a standard unrotated CS.
         self.assertTrue(mock_cs_mod.GeogCS.call_count == 1)
         self.assertEqual(result, mock_cs_mod.GeogCS())
     else:
         # It should return a rotated CS with the correct makeup.
         self.assertTrue(mock_cs_mod.GeogCS.call_count == 1)
         self.assertTrue(mock_cs_mod.RotatedGeogCS.call_count == 1)
         self.assertEqual(result, mock_cs_mod.RotatedGeogCS())
         self.assertEqual(
             mock_cs_mod.RotatedGeogCS.call_args_list[0],
             mock.call(bplat, bplon, ellipsoid=mock_cs_mod.GeogCS()))
Example #30
0
 def _check_cs(self, bplat, bplon, rotated):
     field = TestPPField()
     field.bplat = bplat
     field.bplon = bplon
     with mock.patch('iris.fileformats.pp.iris.coord_systems') \
             as mock_cs_mod:
         result = field.coord_system()
     if not rotated:
         # It should return a standard unrotated CS.
         self.assertTrue(mock_cs_mod.GeogCS.call_count == 1)
         self.assertEqual(result, mock_cs_mod.GeogCS())
     else:
         # It should return a rotated CS with the correct makeup.
         self.assertTrue(mock_cs_mod.GeogCS.call_count == 1)
         self.assertTrue(mock_cs_mod.RotatedGeogCS.call_count == 1)
         self.assertEqual(result, mock_cs_mod.RotatedGeogCS())
         self.assertEqual(mock_cs_mod.RotatedGeogCS.call_args_list[0],
                          mock.call(bplat, bplon,
                                    ellipsoid=mock_cs_mod.GeogCS()))
Example #31
0
    def test_cmip6_volcello_load_issue_3367(self):
        # Ensure that reading a file which references itself in
        # `cell_measures` can be read. At the same time, ensure that we
        # still receive a warning about other variables mentioned in
        # `cell_measures` i.e. a warning should be raised about missing
        # areacello.
        areacello_str = "areacello" if six.PY3 else u"areacello"
        volcello_str = "volcello" if six.PY3 else u"volcello"
        expected_msg = "Missing CF-netCDF measure variable %r, " \
                       "referenced by netCDF variable %r" \
                       % (areacello_str, volcello_str)

        with mock.patch('warnings.warn') as warn:
            # ensure file loads without failure
            cube = iris.load_cube(self.fname)
            warn.assert_has_calls([mock.call(expected_msg)])

        # extra check to ensure correct variable was found
        assert cube.standard_name == 'ocean_volume'
Example #32
0
 def test_two_plots_with_shared_alias_axis(self):
     coords = ('time', 'grid_longitude')
     c1 = Contour(self.cube, self.axes, coords=coords)
     c1.alias(wibble=1)
     c2 = Contour(self.cube, self.axes, coords=coords)
     c2.alias(wibble=1)
     with mock.patch('cube_browser.Contour.__call__') as func:
         browser = Browser([c1, c2])
         browser.display()
         # Check the initial render.
         self.assertEqual(func.call_count, 2)
         expected = [mock.call(wibble=self.value)] * 2
         func.assert_has_calls(expected)
         # Now simulate a slider change.
         slider = browser._slider_by_name['wibble']
         change = dict(owner=slider)
         browser.on_change(change)
         self.assertEqual(func.call_count, 4)
         expected *= 2
         func.assert_has_calls(expected)
Example #33
0
 def test_two_plots_with_shared_alias_axis(self):
     coords = ('time', 'grid_longitude')
     c1 = Contour(self.cube, self.axes, coords=coords)
     c1.alias(wibble=1)
     c2 = Contour(self.cube, self.axes, coords=coords)
     c2.alias(wibble=1)
     with mock.patch('cube_browser.Contour.__call__') as func:
         browser = Browser([c1, c2])
         browser.display()
         # Check the initial render.
         self.assertEqual(func.call_count, 2)
         expected = [mock.call(wibble=self.value)] * 2
         func.assert_has_calls(expected)
         # Now simulate a slider change.
         slider = browser._slider_by_name['wibble']
         change = dict(owner=slider)
         browser.on_change(change)
         self.assertEqual(func.call_count, 4)
         expected *= 2
         func.assert_has_calls(expected)