[tor-commits] [nyx/master] Test for drawing a blank subgraph

atagar at torproject.org atagar at torproject.org
Sun Jun 26 00:48:01 UTC 2016


commit 7719621a1e184e5e94fec94a06a70ded0d2171e0
Author: Damian Johnson <atagar at torproject.org>
Date:   Sat Jun 25 12:34:24 2016 -0700

    Test for drawing a blank subgraph
    
    Not an overly useful test but first step in breaking these into functions and
    adding test coverage.
---
 nyx/panel/graph.py  | 216 ++++++++++++++++++++++++++--------------------------
 test/panel/graph.py |  30 ++++++++
 2 files changed, 140 insertions(+), 106 deletions(-)

diff --git a/nyx/panel/graph.py b/nyx/panel/graph.py
index d3ed768..68c136a 100644
--- a/nyx/panel/graph.py
+++ b/nyx/panel/graph.py
@@ -556,152 +556,156 @@ class GraphPanel(nyx.panel.Panel):
 
     subwindow.addstr(0, 0, attr.stat.title(subwindow.width), HIGHLIGHT)
 
-    self._draw_subgraph(subwindow, attr, attr.stat.primary, 0, PRIMARY_COLOR)
-    self._draw_subgraph(subwindow, attr, attr.stat.secondary, attr.subgraph_width, SECONDARY_COLOR)
+    _draw_subgraph(subwindow, attr, attr.stat.primary, 0, PRIMARY_COLOR)
+    _draw_subgraph(subwindow, attr, attr.stat.secondary, attr.subgraph_width, SECONDARY_COLOR)
 
     if attr.stat.stat_type() == GraphStat.BANDWIDTH and accounting_stats:
       _draw_accounting_stats(subwindow, DEFAULT_CONTENT_HEIGHT + attr.subgraph_height - 2, accounting_stats)
 
-  def _draw_subgraph(self, subwindow, attr, data, x, color):
-    # Concering our subgraph colums, the y-axis label can be at most six
-    # characters, with two spaces of padding on either side of the graph.
-    # Starting with the smallest size, then possibly raise it after determing
-    # the y_axis_labels.
+  def _update_accounting(self, event):
+    if not CONFIG['features.graph.bw.accounting.show']:
+      self._accounting_stats = None
+    elif not self._accounting_stats or time.time() - self._accounting_stats.retrieved >= ACCOUNTING_RATE:
+      old_accounting_stats = self._accounting_stats
+      self._accounting_stats = tor_controller().get_accounting_stats(None)
 
-    subgraph_columns = attr.subgraph_width - 8
-    min_bound, max_bound = self._get_graph_bounds(attr, data, subgraph_columns)
+      if not self.is_paused():
+        # if we either added or removed accounting info then redraw the whole
+        # screen to account for resizing
 
-    x_axis_labels = self._get_x_axis_labels(attr, subgraph_columns)
-    y_axis_labels = self._get_y_axis_labels(attr, data, min_bound, max_bound)
-    subgraph_columns = max(subgraph_columns, attr.subgraph_width - max([len(label) for label in y_axis_labels.values()]) - 2)
-    axis_offset = max([len(label) for label in y_axis_labels.values()])
+        if bool(old_accounting_stats) != bool(self._accounting_stats):
+          nyx.controller.get_controller().redraw()
 
-    subwindow.addstr(x, 1, data.header(attr.subgraph_width), color, BOLD)
+  def _update_stats(self, event):
+    for stat in self._stats.values():
+      stat.bandwidth_event(event)
 
-    for x_offset, label in x_axis_labels.items():
-      if attr.right_to_left:
-        subwindow.addstr(x + attr.subgraph_width - x_offset, attr.subgraph_height, label, color)
-      else:
-        subwindow.addstr(x + x_offset + axis_offset, attr.subgraph_height, label, color)
+    if self.displayed_stat:
+      param = self._stats[self.displayed_stat]
+      update_rate = INTERVAL_SECONDS[self.update_interval]
 
-    for y, label in y_axis_labels.items():
-      subwindow.addstr(x, y, label, color)
+      if param.primary.tick % update_rate == 0:
+        self.redraw(True)
 
-    for col in range(subgraph_columns):
-      column_count = int(data.values[attr.interval][col]) - min_bound
-      column_height = int(min(attr.subgraph_height - 2, (attr.subgraph_height - 2) * column_count / (max(1, max_bound) - min_bound)))
 
-      for row in range(column_height):
-        if attr.right_to_left:
-          subwindow.addstr(x + attr.subgraph_width - col - 1, attr.subgraph_height - 1 - row, ' ', color, HIGHLIGHT)
-        else:
-          subwindow.addstr(x + col + axis_offset + 1, attr.subgraph_height - 1 - row, ' ', color, HIGHLIGHT)
+def _draw_subgraph(subwindow, attr, data, x, color):
+  # Concering our subgraph colums, the y-axis label can be at most six
+  # characters, with two spaces of padding on either side of the graph.
+  # Starting with the smallest size, then possibly raise it after determing
+  # the y_axis_labels.
 
-  def _get_graph_bounds(self, attr, data, subgraph_columns):
-    """
-    Provides the range the graph shows (ie, its minimum and maximum value).
-    """
+  subgraph_columns = attr.subgraph_width - 8
+  min_bound, max_bound = _get_graph_bounds(attr, data, subgraph_columns)
 
-    min_bound, max_bound = 0, 0
-    values = data.values[attr.interval][:subgraph_columns]
+  x_axis_labels = _x_axis_labels(attr.interval, subgraph_columns)
+  y_axis_labels = _y_axis_labels(attr.subgraph_height, data, min_bound, max_bound)
+  subgraph_columns = max(subgraph_columns, attr.subgraph_width - max([len(label) for label in y_axis_labels.values()]) - 2)
+  axis_offset = max([len(label) for label in y_axis_labels.values()])
 
-    if attr.bounds_type == Bounds.GLOBAL_MAX:
-      max_bound = data.max_value[attr.interval]
-    elif subgraph_columns > 0:
-      max_bound = max(values)  # local maxima
+  subwindow.addstr(x, 1, data.header(attr.subgraph_width), color, BOLD)
 
-    if attr.bounds_type == Bounds.TIGHT and subgraph_columns > 0:
-      min_bound = min(values)
+  for x_offset, label in x_axis_labels.items():
+    if attr.right_to_left:
+      subwindow.addstr(x + attr.subgraph_width - x_offset, attr.subgraph_height, label, color)
+    else:
+      subwindow.addstr(x + x_offset + axis_offset, attr.subgraph_height, label, color)
 
-      # if the max = min pick zero so we still display something
+  for y, label in y_axis_labels.items():
+    subwindow.addstr(x, y, label, color)
 
-      if min_bound == max_bound:
-        min_bound = 0
+  for col in range(subgraph_columns):
+    column_count = int(data.values[attr.interval][col]) - min_bound
+    column_height = int(min(attr.subgraph_height - 2, (attr.subgraph_height - 2) * column_count / (max(1, max_bound) - min_bound)))
 
-    return min_bound, max_bound
+    for row in range(column_height):
+      if attr.right_to_left:
+        subwindow.addstr(x + attr.subgraph_width - col - 1, attr.subgraph_height - 1 - row, ' ', color, HIGHLIGHT)
+      else:
+        subwindow.addstr(x + col + axis_offset + 1, attr.subgraph_height - 1 - row, ' ', color, HIGHLIGHT)
 
-  def _get_y_axis_labels(self, attr, data, min_bound, max_bound):
-    """
-    Provides the labels for the y-axis. This is a mapping of the position it
-    should be drawn at to its text.
-    """
 
-    y_axis_labels = {
-      2: data.y_axis_label(max_bound),
-      attr.subgraph_height - 1: data.y_axis_label(min_bound),
-    }
+def _get_graph_bounds(attr, data, subgraph_columns):
+  """
+  Provides the range the graph shows (ie, its minimum and maximum value).
+  """
 
-    ticks = (attr.subgraph_height - 5) / 2
+  min_bound, max_bound = 0, 0
+  values = data.values[attr.interval][:subgraph_columns]
 
-    for i in range(ticks):
-      row = attr.subgraph_height - (2 * i) - 5
+  if attr.bounds_type == Bounds.GLOBAL_MAX:
+    max_bound = data.max_value[attr.interval]
+  elif subgraph_columns > 0:
+    max_bound = max(values)  # local maxima
 
-      if attr.subgraph_height % 2 == 0 and i >= (ticks / 2):
-        row -= 1  # make extra gap be in the middle when we're an even size
+  if attr.bounds_type == Bounds.TIGHT and subgraph_columns > 0:
+    min_bound = min(values)
 
-      val = (max_bound - min_bound) * (attr.subgraph_height - row - 3) / (attr.subgraph_height - 3)
+    # if the max = min pick zero so we still display something
 
-      if val not in (min_bound, max_bound):
-        y_axis_labels[row + 2] = data.y_axis_label(val)
+    if min_bound == max_bound:
+      min_bound = 0
 
-    return y_axis_labels
+  return min_bound, max_bound
 
-  def _get_x_axis_labels(self, attr, subgraph_columns):
-    """
-    Provides the labels for the x-axis. We include the units for only its first
-    value, then bump the precision for subsequent units. For example...
 
-      10s, 20, 30, 40, 50, 1m, 1.1, 1.3, 1.5
-    """
+def _x_axis_labels(interval, subgraph_columns):
+  """
+  Provides the labels for the x-axis. We include the units for only its first
+  value, then bump the precision for subsequent units. For example...
 
-    x_axis_labels = {}
+    10s, 20, 30, 40, 50, 1m, 1.1, 1.3, 1.5
+  """
 
-    interval_sec = INTERVAL_SECONDS[attr.interval]
-    interval_spacing = 10 if subgraph_columns >= WIDE_LABELING_GRAPH_COL else 5
-    units_label, decimal_precision = None, 0
+  x_axis_labels = {}
 
-    for i in range((subgraph_columns - 4) / interval_spacing):
-      x = (i + 1) * interval_spacing
-      time_label = str_tools.time_label(x * interval_sec, decimal_precision)
+  interval_sec = INTERVAL_SECONDS[interval]
+  interval_spacing = 10 if subgraph_columns >= WIDE_LABELING_GRAPH_COL else 5
+  units_label, decimal_precision = None, 0
 
-      if not units_label:
-        units_label = time_label[-1]
-      elif units_label != time_label[-1]:
-        # upped scale so also up precision of future measurements
-        units_label = time_label[-1]
-        decimal_precision += 1
-      else:
-        # if constrained on space then strips labeling since already provided
-        time_label = time_label[:-1]
+  for i in range((subgraph_columns - 4) / interval_spacing):
+    x = (i + 1) * interval_spacing
+    time_label = str_tools.time_label(x * interval_sec, decimal_precision)
 
-      x_axis_labels[x] = time_label
+    if not units_label:
+      units_label = time_label[-1]
+    elif units_label != time_label[-1]:
+      # upped scale so also up precision of future measurements
+      units_label = time_label[-1]
+      decimal_precision += 1
+    else:
+      # if constrained on space then strips labeling since already provided
+      time_label = time_label[:-1]
 
-    return x_axis_labels
+    x_axis_labels[x] = time_label
 
-  def _update_accounting(self, event):
-    if not CONFIG['features.graph.bw.accounting.show']:
-      self._accounting_stats = None
-    elif not self._accounting_stats or time.time() - self._accounting_stats.retrieved >= ACCOUNTING_RATE:
-      old_accounting_stats = self._accounting_stats
-      self._accounting_stats = tor_controller().get_accounting_stats(None)
+  return x_axis_labels
 
-      if not self.is_paused():
-        # if we either added or removed accounting info then redraw the whole
-        # screen to account for resizing
 
-        if bool(old_accounting_stats) != bool(self._accounting_stats):
-          nyx.controller.get_controller().redraw()
+def _y_axis_labels(subgraph_height, data, min_bound, max_bound):
+  """
+  Provides the labels for the y-axis. This is a mapping of the position it
+  should be drawn at to its text.
+  """
 
-  def _update_stats(self, event):
-    for stat in self._stats.values():
-      stat.bandwidth_event(event)
+  y_axis_labels = {
+    2: data.y_axis_label(max_bound),
+    subgraph_height - 1: data.y_axis_label(min_bound),
+  }
 
-    if self.displayed_stat:
-      param = self._stats[self.displayed_stat]
-      update_rate = INTERVAL_SECONDS[self.update_interval]
+  ticks = (subgraph_height - 5) / 2
 
-      if param.primary.tick % update_rate == 0:
-        self.redraw(True)
+  for i in range(ticks):
+    row = subgraph_height - (2 * i) - 5
+
+    if subgraph_height % 2 == 0 and i >= (ticks / 2):
+      row -= 1  # make extra gap be in the middle when we're an even size
+
+    val = (max_bound - min_bound) * (subgraph_height - row - 3) / (subgraph_height - 3)
+
+    if val not in (min_bound, max_bound):
+      y_axis_labels[row + 2] = data.y_axis_label(val)
+
+  return y_axis_labels
 
 
 def _draw_accounting_stats(subwindow, y, accounting):
diff --git a/test/panel/graph.py b/test/panel/graph.py
index f2eca4b..26fd7da 100644
--- a/test/panel/graph.py
+++ b/test/panel/graph.py
@@ -7,12 +7,23 @@ import unittest
 
 import stem.control
 
+import nyx.curses
 import nyx.panel.graph
 import test
 
 from test import require_curses
 from mock import patch
 
+EXPECTED_BLANK_GRAPH = """
+Download:
+0 b
+
+
+
+0 b
+        5s   10   15
+""".rstrip()
+
 EXPECTED_ACCOUNTING = """
 Accounting (awake)                 Time to reset: 01:02
   37.7 Kb / 842.0 Kb                 16.0 Kb / 74.1 Kb
@@ -22,6 +33,25 @@ Accounting (awake)                 Time to reset: 01:02
 class TestGraph(unittest.TestCase):
   @require_curses
   @patch('nyx.panel.graph.tor_controller')
+  def test_draw_subgraph_blank(self, tor_controller_mock):
+    tor_controller_mock().get_info.return_value = None
+
+    attr = nyx.panel.graph.DrawAttributes(
+      stat = None,
+      subgraph_height = 7,
+      subgraph_width = 30,
+      interval = nyx.panel.graph.Interval.EACH_SECOND,
+      bounds_type = nyx.panel.graph.Bounds.LOCAL_MAX,
+      right_to_left = False,
+    )
+
+    data = nyx.panel.graph.BandwidthStats()
+
+    rendered = test.render(nyx.panel.graph._draw_subgraph, attr, data.primary, 0, nyx.curses.Color.CYAN)
+    self.assertEqual(EXPECTED_BLANK_GRAPH, rendered.content)
+
+  @require_curses
+  @patch('nyx.panel.graph.tor_controller')
   def test_draw_accounting_stats(self, tor_controller_mock):
     tor_controller_mock().is_alive.return_value = True
 





More information about the tor-commits mailing list