Added tests for the serialization of the widget state
This commit is contained in:
Родитель
ab46da1f5d
Коммит
efda8e4bd9
|
@ -0,0 +1,414 @@
|
|||
import pytest
|
||||
|
||||
from ..core import BaseWWTWidget
|
||||
from ..layers import SIZE_COLUMN_NAME, CMAP_COLUMN_NAME
|
||||
|
||||
import numpy as np
|
||||
|
||||
from astropy.wcs import WCS
|
||||
from astropy.table import Table
|
||||
from astropy import units as u
|
||||
from astropy.coordinates import SkyCoord
|
||||
|
||||
DEGREES_TO_HOURS = 1. / 15.
|
||||
STARDARD_WWT_SETTINGS = ['actualPlanetScale', 'showAltAzGrid', 'showConstellationBoundries', 'constellationBoundryColor',
|
||||
'constellationFigureColor', 'showConstellationFigures', 'showConstellationSelection',
|
||||
'constellationSelectionColor', 'showCrosshairs', 'crosshairsColor', 'showEcliptic',
|
||||
'showEclipticGrid', 'showGalacticGrid', 'galacticMode', 'showGrid', 'localHorizonMode',
|
||||
'locationAltitude', 'locationLat', 'locationLng']
|
||||
|
||||
|
||||
# Mock class so that we test serialization without instantiating an actual widget
|
||||
class MockWWTWidget(BaseWWTWidget):
|
||||
def quick_serialize(self):
|
||||
return self._serialize_state(None, None, None)
|
||||
|
||||
def _get_view_data(self, field):
|
||||
mock_vals = {'ra': 5. * DEGREES_TO_HOURS, 'dec': 10., 'fov': 15.}
|
||||
return mock_vals[field]
|
||||
|
||||
def _serve_file(self, filename, extension=''):
|
||||
return filename
|
||||
|
||||
|
||||
def check_settings_list(setting_list, expected_values):
|
||||
seen_settings = set()
|
||||
|
||||
# Make sure that we see each setting has the correct format and value and does not have duplicate entries
|
||||
for setting in setting_list:
|
||||
assert 'name' in setting
|
||||
assert 'value' in setting
|
||||
name = setting['name']
|
||||
assert setting['value'] == expected_values[name], 'Value mismatch for setting: {0}'.format(name)
|
||||
assert setting['name'] not in seen_settings, 'Duplicate found for setting: {0}'.format(name)
|
||||
seen_settings.add(name)
|
||||
|
||||
# Make sure that we have all the settings we expect to see
|
||||
for name in expected_values.keys():
|
||||
assert name in seen_settings, "Unexpected setting found: {0}".format(name)
|
||||
|
||||
def test_basic_serialization():
|
||||
widget = MockWWTWidget()
|
||||
test_state = widget._serialize_state('Title', 100, 200)
|
||||
assert test_state
|
||||
|
||||
assert 'wwt_settings' in test_state
|
||||
|
||||
assert 'html_settings' in test_state
|
||||
page_settings = test_state['html_settings']
|
||||
assert page_settings['title'] == 'Title'
|
||||
assert page_settings['max_width'] == 100
|
||||
assert page_settings['max_height'] == 200
|
||||
|
||||
assert 'view_settings' in test_state
|
||||
view_settings = test_state['view_settings']
|
||||
assert view_settings['mode'] == 'sky'
|
||||
assert view_settings['ra'] == pytest.approx(5.) # Behind the scenes unit conversion
|
||||
assert view_settings['dec'] == 10.
|
||||
assert view_settings['fov'] == 15.
|
||||
|
||||
assert 'foreground_settings' in test_state
|
||||
foreground_settings = test_state['foreground_settings']
|
||||
assert 'foreground' in foreground_settings
|
||||
assert 'background' in foreground_settings
|
||||
assert 'foreground_alpha' in foreground_settings
|
||||
|
||||
assert 'layers' in test_state
|
||||
assert test_state['layers'] == []
|
||||
|
||||
assert 'annotations' in test_state
|
||||
assert test_state['annotations'] == []
|
||||
|
||||
def test_widget_settings_serialization():
|
||||
widget = MockWWTWidget()
|
||||
widget.actual_planet_scale = True
|
||||
widget.alt_az_grid = False
|
||||
widget.constellation_boundaries = True
|
||||
widget.constellation_boundary_color = 'red'
|
||||
widget.constellation_figure_color = '#24680b'
|
||||
widget.constellation_figures = False
|
||||
widget.constellation_selection = True
|
||||
widget.constellation_selection_color = 'c' #cyan
|
||||
widget.crosshairs = True
|
||||
widget.crosshairs_color = (128./255.,64./255.,16./255.)
|
||||
widget.ecliptic = False
|
||||
widget.ecliptic_grid = True
|
||||
widget.galactic_grid = False
|
||||
widget.galactic_mode = True
|
||||
widget.grid = False
|
||||
widget.local_horizon_mode = True
|
||||
widget.location_altitude = 7*u.m
|
||||
widget.location_latitude = 12*u.deg
|
||||
widget.location_longitude = -18*u.deg
|
||||
expected_settings = {'actualPlanetScale': True, 'showAltAzGrid': False, 'showConstellationBoundries': True,
|
||||
'constellationBoundryColor': '#ff0000', 'constellationFigureColor': '#24680b',
|
||||
'showConstellationFigures': False, 'showConstellationSelection': True,
|
||||
'constellationSelectionColor': '#00bfbf', 'showCrosshairs': True, 'crosshairsColor': '#804010',
|
||||
'showEcliptic': False, 'showEclipticGrid': True, 'showGalacticGrid': False,
|
||||
'galacticMode': True, 'showGrid': False, 'localHorizonMode': True, 'locationAltitude': 7,
|
||||
'locationLat': 12., 'locationLng': -18.}
|
||||
state = widget.quick_serialize()
|
||||
check_settings_list(state['wwt_settings'], expected_settings)
|
||||
|
||||
|
||||
def test_mode_serialization():
|
||||
view_mode_map = {'sky': 'sky', 'Sun': 'sun', 'Mercury': 'mercury', 'venus': 'venus', 'Earth': 'Bing Maps Aerial',
|
||||
'moon': 'moon', 'mars': 'Visible Imagery', 'jupiter': 'jupiter', 'callisto': 'callisto',
|
||||
'europa': 'europa', 'ganymede': 'ganymede', 'Io': 'io', 'saturn': 'saturn', 'Uranus': 'uranus',
|
||||
'neptune': 'neptune', 'Pluto': 'pluto', 'panorama': 'panorama',
|
||||
'Solar System': '3D Solar System View', 'milky way': '3D Solar System View',
|
||||
'universe': '3D Solar System View'}
|
||||
|
||||
widget = MockWWTWidget()
|
||||
for in_mode, out_mode in view_mode_map.items():
|
||||
widget.set_view(in_mode)
|
||||
assert widget.quick_serialize()['view_settings']['mode'] == out_mode, 'Mismatch for requested mode: {0}'.format(in_mode)
|
||||
|
||||
|
||||
def test_3d_serialization():
|
||||
widget = MockWWTWidget()
|
||||
widget.set_view('milky way')
|
||||
widget.solar_system.cosmos=True
|
||||
widget.solar_system.lighting=False
|
||||
widget.solar_system.milky_way = True
|
||||
widget.solar_system.minor_orbits = False
|
||||
widget.solar_system.orbits = True
|
||||
widget.solar_system.objects = False
|
||||
widget.solar_system.scale = 8
|
||||
widget.solar_system.stars = True
|
||||
|
||||
expected_3d_settings = {'solarSystemCosmos':True, 'solarSystemLighting':False, 'solarSystemMilkyWay':True,
|
||||
'solarSystemMinorOrbits':False, 'solarSystemOrbits':True, 'solarSystemPlanets':False,
|
||||
'solarSystemScale': '8', # The validation method casts the int to a string
|
||||
'solarSystemStars':True}
|
||||
|
||||
init_state = widget.quick_serialize()
|
||||
assert len(init_state['wwt_settings']) == len(STARDARD_WWT_SETTINGS) + len(expected_3d_settings)
|
||||
for setting in init_state['wwt_settings']:
|
||||
assert 'name' in setting
|
||||
assert 'value' in setting
|
||||
assert setting['name'] in expected_3d_settings or setting['name'] in STARDARD_WWT_SETTINGS
|
||||
if setting['name'] in expected_3d_settings:
|
||||
assert setting['value'] == expected_3d_settings[setting['name']], 'Mismatch for setting {0}'.format(setting['name'])
|
||||
|
||||
assert 'tracked_object_id' in init_state['view_settings']
|
||||
assert init_state['view_settings']['tracked_object_id'] == 0
|
||||
|
||||
track_id_map = {'sun': 0, 'mercury': 1, 'venus': 2, 'mars': 3, 'jupiter': 4, 'saturn': 5, 'uranus': 6, 'neptune': 7,
|
||||
'pluto': 8, 'moon': 9, 'io': 10, 'europa': 11, 'ganymede': 12, 'callisto': 13, 'ioshadow': 14,
|
||||
'europashadow': 15, 'ganymedeshadow': 16, 'callistoshadow': 17, 'suneclipsed': 18, 'earth': 19}
|
||||
|
||||
for obj_name, obj_id in track_id_map.items():
|
||||
widget.solar_system.track_object(obj_name)
|
||||
assert widget.quick_serialize()['view_settings']['tracked_object_id'] == obj_id, "ID mismatch for {0}".format(obj_name)
|
||||
|
||||
|
||||
def test_add_remove_annotation_serialization():
|
||||
widget = MockWWTWidget()
|
||||
circ = widget.add_circle()
|
||||
poly = widget.add_polygon()
|
||||
line = widget.add_line()
|
||||
state = widget.quick_serialize()
|
||||
assert len(state['annotations']) == 3
|
||||
for annotation in state['annotations']:
|
||||
assert annotation['id'] in [circ.id, poly.id, line.id]
|
||||
|
||||
circ.remove()
|
||||
state = widget.quick_serialize()
|
||||
assert len(state['annotations']) == 2
|
||||
for annotation in state['annotations']:
|
||||
assert annotation['id'] in [poly.id, line.id]
|
||||
|
||||
widget.clear_annotations()
|
||||
state = widget.quick_serialize()
|
||||
assert len(state['annotations']) == 0
|
||||
|
||||
|
||||
def test_circle_annotation_serialization():
|
||||
widget = MockWWTWidget()
|
||||
circ = widget.add_circle(fill_color='#012345', radius=0.3*u.deg)
|
||||
circ.set_center(SkyCoord(0.1*u.deg,0.2*u.deg))
|
||||
circ.fill = True
|
||||
circ.tag = 'Test Circ Tag'
|
||||
circ.line_color = 'orange'
|
||||
circ.line_width = 5*u.pix
|
||||
circ.opacity = 0.7
|
||||
circ.label = 'Test Circ Label'
|
||||
circ.hover_label = True
|
||||
expected_settings = {'radius': 0.3, 'fill': True, 'tag': 'Test Circ Tag', 'fillColor': '#012345', 'lineColor': '#ffa500',
|
||||
'lineWidth': 5, 'opacity': 0.7, 'label': 'Test Circ Label', 'showHoverLabel': True, 'skyRelative': True}
|
||||
|
||||
annot_state = widget.quick_serialize()['annotations'][0]
|
||||
|
||||
assert annot_state['id'] == circ.id
|
||||
assert annot_state['shape'] == 'circle'
|
||||
|
||||
assert 'center' in annot_state
|
||||
assert annot_state['center']['ra'] == pytest.approx(0.1)
|
||||
assert annot_state['center']['dec'] == pytest.approx(0.2)
|
||||
|
||||
assert 'settings' in annot_state
|
||||
check_settings_list(annot_state['settings'], expected_settings)
|
||||
|
||||
circ.radius = 7*u.pix
|
||||
circ.fill_color = 'g'
|
||||
expected_settings['radius'] = 7
|
||||
expected_settings['skyRelative'] = False
|
||||
expected_settings['fillColor'] = '#008000'
|
||||
annot_state = widget.quick_serialize()['annotations'][0]
|
||||
check_settings_list(annot_state['settings'], expected_settings)
|
||||
|
||||
#Check circle annotation with no specified center
|
||||
circ.remove()
|
||||
circ2 = widget.add_circle()
|
||||
center = widget.quick_serialize()['annotations'][0]['center']
|
||||
assert center['ra'] == pytest.approx(5.)
|
||||
assert center['dec'] == 10.
|
||||
|
||||
#Circle annotation with center in constructor
|
||||
circ2.remove()
|
||||
widget.add_circle(center = SkyCoord(15*u.deg,16*u.deg))
|
||||
center = widget.quick_serialize()['annotations'][0]['center']
|
||||
assert center['ra'] == 15
|
||||
assert center['dec'] == 16
|
||||
|
||||
|
||||
def test_poly_annotation_setting():
|
||||
widget = MockWWTWidget()
|
||||
poly = widget.add_polygon(fill = True, tag='Test Poly Tag')
|
||||
poly.fill_color = '#123456'
|
||||
poly.line_color = 'antiquewhite'
|
||||
poly.line_width = 9*u.pix
|
||||
poly.opacity = 0.9
|
||||
poly.label = 'Test Poly Label'
|
||||
poly.hover_label = False
|
||||
poly.add_point(SkyCoord([1,2,3]*u.deg,[5,6,7]*u.deg))
|
||||
poly.add_point(SkyCoord(4*u.deg,8*u.deg))
|
||||
expected_settings = {'fill': True, 'tag': 'Test Poly Tag', 'fillColor': '#123456', 'lineColor': '#faebd7',
|
||||
'lineWidth': 9, 'opacity': 0.9, 'label': 'Test Poly Label', 'showHoverLabel': False}
|
||||
|
||||
annot_state = widget.quick_serialize()['annotations'][0]
|
||||
|
||||
assert annot_state['id'] == poly.id
|
||||
assert annot_state['shape'] == 'polygon'
|
||||
|
||||
expected_ras = [1,2,3,4]
|
||||
expected_decs = [5,6,7,8]
|
||||
assert 'points' in annot_state
|
||||
pts = annot_state['points']
|
||||
assert len(pts) == 4
|
||||
for i in range(len(pts)):
|
||||
assert pts[i]['ra'] == expected_ras[i], 'RA mismatch for point {0}'.format(i)
|
||||
assert pts[i]['dec'] == expected_decs[i], 'Dec mismatch for point {0}'.format(i)
|
||||
|
||||
assert 'settings' in annot_state
|
||||
check_settings_list(annot_state['settings'], expected_settings)
|
||||
|
||||
def test_line_annotation_setting():
|
||||
widget = MockWWTWidget()
|
||||
line = widget.add_line(color = '#abcde0')
|
||||
line.tag = 'Test Line Tag'
|
||||
line.width = 11*u.pix
|
||||
line.opacity = 0.2
|
||||
line.label = 'Test Line Label'
|
||||
line.hover_label = True
|
||||
line.add_point(SkyCoord([2,4,6]*u.deg,[10,12,14]*u.deg))
|
||||
line.add_point(SkyCoord(8*u.deg,16*u.deg))
|
||||
expected_settings = {'tag': 'Test Line Tag', 'lineColor': '#abcde0', 'lineWidth': 11, 'opacity': 0.2,
|
||||
'label': 'Test Line Label', 'showHoverLabel': True}
|
||||
|
||||
annot_state = widget.quick_serialize()['annotations'][0]
|
||||
|
||||
assert annot_state['id'] == line.id
|
||||
assert annot_state['shape'] == 'line'
|
||||
|
||||
expected_ras = [2,4,6,8]
|
||||
expected_decs = [10,12,14,16]
|
||||
assert 'points' in annot_state
|
||||
pts = annot_state['points']
|
||||
assert len(pts) == 4
|
||||
for i in range(len(pts)):
|
||||
assert pts[i]['ra'] == expected_ras[i], 'RA mismatch for point {0}'.format(i)
|
||||
assert pts[i]['dec'] == expected_decs[i], 'Dec mismatch for point {0}'.format(i)
|
||||
|
||||
assert 'settings' in annot_state
|
||||
check_settings_list(annot_state['settings'], expected_settings)
|
||||
|
||||
|
||||
def test_add_remove_layer_serialization():
|
||||
widget = MockWWTWidget()
|
||||
|
||||
table = Table()
|
||||
table['flux'] = [2, 3, 4, 5, 6]
|
||||
table['dec'] = [84, 85, 86, 87, 88]
|
||||
table['ra'] = [250, 260, 270, 280, 290] * u.deg
|
||||
|
||||
table1 = widget.layers.add_table_layer(table=table)
|
||||
table2 = widget.layers.add_table_layer(table, color='#ff00ff')
|
||||
|
||||
array = np.arange(100).reshape((10, 10))
|
||||
wcs = WCS()
|
||||
wcs.wcs.ctype = 'GLON-CAR', 'GLAT-CAR'
|
||||
wcs.wcs.crpix = 50.5, 50.5
|
||||
wcs.wcs.cdelt = -0.03, 0.03
|
||||
wcs.wcs.crval = 33, 43
|
||||
img1 = widget.layers.add_image_layer(image=(array, wcs))
|
||||
wcs.wcs.crval = 33, 45
|
||||
img2 = widget.layers.add_image_layer((array, wcs))
|
||||
|
||||
state = widget.quick_serialize()
|
||||
|
||||
assert len(state['layers']) == 4
|
||||
layer_ids = [table1.id, table2.id, img1.id, img2.id]
|
||||
for layer in state['layers']:
|
||||
assert layer['id'] in layer_ids
|
||||
layer_ids.remove(layer['id'])
|
||||
|
||||
table2.remove()
|
||||
widget.layers.remove_layer(img2)
|
||||
state = widget.quick_serialize()
|
||||
|
||||
layer_ids = [table1.id,img1.id]
|
||||
assert len(state['layers']) == 2
|
||||
for layer in state['layers']:
|
||||
assert layer['id'] in layer_ids
|
||||
layer_ids.remove(layer['id'])
|
||||
|
||||
widget.reset()
|
||||
state = widget.quick_serialize()
|
||||
assert len(state['layers']) == 0
|
||||
|
||||
def test_table_setting_serialization():
|
||||
widget = MockWWTWidget()
|
||||
|
||||
table = Table()
|
||||
table['flux'] = [2, 3, 4, 5, 6]
|
||||
table['dec'] = [84, 85, 86, 87, 88]
|
||||
table['ra'] = [250, 260, 270, 280, 290]*u.deg
|
||||
|
||||
layer = widget.layers.add_table_layer(table, frame='earth', alt_att='flux', far_side_visible=True)
|
||||
layer.alt_type = 'distance'
|
||||
layer.color = '#aacc00'
|
||||
layer.size_scale = 14
|
||||
layer.opacity = 0.75
|
||||
layer.marker_type = 'square'
|
||||
layer.marker_scale = 'world'
|
||||
|
||||
layer_state = widget.quick_serialize()['layers'][0]
|
||||
assert layer_state['id'] == layer.id
|
||||
assert layer_state['layer_type'] == 'table'
|
||||
assert layer_state['frame'] == 'Earth'
|
||||
|
||||
assert 'settings' in layer_state
|
||||
expected_settings = {'lngColumn':'ra', 'raUnits': 'degrees', 'latColumn': 'dec', 'altColumn': 'flux',
|
||||
'altUnit': None, 'altType': 'distance', 'color': '#aacc00', 'scaleFactor': 14,
|
||||
'opacity': 0.75, 'plotType': 'square', 'markerScale': 'world', 'showFarSide': True,
|
||||
'sizeColumn': -1, '_colorMap': 0, 'colorMapColumn': -1}
|
||||
check_settings_list(layer_state['settings'], expected_settings)
|
||||
|
||||
#Check when we have colormap and scaling
|
||||
layer.cmap_att = 'flux'
|
||||
layer.size_att = 'dec'
|
||||
layer.alt_unit = u.Mpc
|
||||
|
||||
expected_settings['sizeColumn'] = SIZE_COLUMN_NAME
|
||||
expected_settings['pointScaleType'] = 0
|
||||
expected_settings['colorMapColumn'] = CMAP_COLUMN_NAME
|
||||
expected_settings['_colorMap'] = 3
|
||||
expected_settings['altUnit'] = 'megaParsecs'
|
||||
|
||||
check_settings_list(widget.quick_serialize()['layers'][0]['settings'], expected_settings)
|
||||
|
||||
def test_image_setting_serialization():
|
||||
widget = MockWWTWidget()
|
||||
|
||||
array = np.arange(100).reshape((10, 10))
|
||||
wcs = WCS()
|
||||
wcs.wcs.ctype = 'GLON-CAR', 'GLAT-CAR'
|
||||
wcs.wcs.crpix = 50.5, 50.5
|
||||
wcs.wcs.cdelt = -0.03, 0.03
|
||||
wcs.wcs.crval = 33, 43
|
||||
layer = widget.layers.add_image_layer(image=(array, wcs))
|
||||
|
||||
layer.opacity = 0.3
|
||||
layer.vmin = -1
|
||||
layer.vmax = 1
|
||||
layer_state = widget.quick_serialize()['layers'][0]
|
||||
|
||||
assert layer_state['id'] == layer.id
|
||||
assert layer_state['layer_type'] == 'image'
|
||||
assert 'stretch_info' in layer_state
|
||||
assert layer_state['stretch_info']['vmin'] == -1
|
||||
assert layer_state['stretch_info']['vmax'] == 1
|
||||
assert layer_state['stretch_info']['stretch'] == 0
|
||||
|
||||
assert 'settings' in layer_state
|
||||
settings = layer_state['settings']
|
||||
assert len(settings) == 1
|
||||
assert settings[0]['name'] == 'opacity'
|
||||
assert settings[0]['value'] == 0.3
|
||||
|
||||
stretches = {'linear': 0, 'log': 1, 'power': 2, 'sqrt': 3, 'histeq': 4}
|
||||
for stretch_name, stretch_id in stretches.items():
|
||||
layer.stretch = stretch_name
|
||||
assert widget.quick_serialize()['layers'][0]['stretch_info']['stretch'] == stretch_id, "Stretch id mismatch for: {0}".format(stretch_name)
|
Загрузка…
Ссылка в новой задаче