# A trace records the evolution of a computation. # Traces are useful for: # error-handling # testing # auditing # debugging # learning # # An integral part of the Mu computer is facilities for browsing traces. type trace { max-depth: int curr-depth: int # depth that will be assigned to next line appended data: (handle array trace-line) first-free: int first-full: int # used only by check-trace-scan # steady-state life cycle of a trace: # reload loop: # there are already some visible lines # append a bunch of new trace lines to the trace # recreate trace caches # render loop: # rendering displays trace lines that match visible lines # (caching in each line) # (caching top-line) # rendering computes cursor-line based on the cursor-y coordinate # edit-trace updates cursor-y coordinate # edit-trace might add/remove lines to visible # edit-trace might update top-line visible: (handle array trace-line) recreate-caches?: boolean cursor-line-index: int # index into data cursor-y: int # row index on screen unclip-cursor-line?: boolean # extremely short-lived; reset any time cursor moves top-line-index: int # start rendering trace past this index into data (updated on re-evaluation) top-line-y: int # trace starts rendering at this row index on screen (updated on re-evaluation) screen-height: int # initialized during render-trace } type trace-line { depth: int label: (handle array byte) data: (handle array byte) visible?: boolean } # when we recreate the trace this data structure will help stabilize our view into it # we can shallowly copy handles because lines are not reused across reruns type trace-index-stash { cursor-line-depth: int cursor-line-label: (handle array byte) cursor-line-data: (handle array byte) top-line-depth: int top-line-label: (handle array byte) top-line-data: (handle array byte) } ## generating traces fn initialize-trace _self: (addr trace), max-depth: int, capacity: int, visible-capacity: int { var self/esi: (addr trace) <- copy _self compare self, 0 { break-if-!= abort "null trace" } var src/ecx: int <- copy max-depth var dest/eax: (addr int) <- get self, max-depth copy-to *dest, src dest <- get self, curr-depth copy-to *dest, 1 # 0 is the error depth var trace-ah/eax: (addr handle array trace-line) <- get self, data populate trace-ah, capacity var visible-ah/eax: (addr handle array trace-line) <- get self, visible populate visible-ah, visible-capacity mark-lines-dirty self } fn clear-trace _self: (addr trace) { var self/eax: (addr trace) <- copy _self compare self, 0 { break-if-!= abort "null trace" } var curr-depth-addr/ecx: (addr int) <- get self, curr-depth copy-to *curr-depth-addr, 1 var len/edx: (addr int) <- get self, first-free copy-to *len, 0 # leak: nested handles within trace-lines } fn has-errors? _self: (addr trace) -> _/eax: boolean { var self/eax: (addr trace) <- copy _self compare self, 0 { break-if-!= abort "null trace" } var max/edx: (addr int) <- get self, first-free var trace-ah/eax: (addr handle array trace-line) <- get self, data var _trace/eax: (addr array trace-line) <- lookup *trace-ah var trace/esi: (addr array trace-line) <- copy _trace var i/ecx: int <- copy 0 { compare i, *max break-if->= var offset/eax: (offset trace-line) <- compute-offset trace, i var curr/eax: (addr trace-line) <- index trace, offset var curr-depth-a/eax: (addr int) <- get curr, depth compare *curr-depth-a, 0/error { break-if-!= return 1/true } i <- increment loop } return 0/false } fn should-trace? _self: (addr trace) -> _/eax: boolean { var self/esi: (addr trace) <- copy _self compare self, 0 { break-if-!= abort "null trace" } var depth-a/ecx: (addr int) <- get self, curr-depth var depth/ecx: int <- copy *depth-a var max-depth-a/eax: (addr int) <- get self, max-depth compare depth, *max-depth-a { break-if->= return 1/true } return 0/false } fn trace _self: (addr trace), label: (addr array byte), message: (addr stream byte) { var self/esi: (addr trace) <- copy _self compare self, 0 { break-if-!= abort "null trace" } var should-trace?/eax: boolean <- should-trace? self compare should-trace?, 0/false { break-if-!= return } var data-ah/eax: (addr handle array trace-line) <- get self, data var data/eax: (addr array trace-line) <- lookup *data-ah var index-addr/edi: (addr int) <- get self, first-free { compare *index-addr, 0x8000/lines break-if-< return } var index/ecx: int <- copy *index-addr var offset/ecx: (offset trace-line) <- compute-offset data,
# Copyright (C) 2009, 2010 Roman Zimbelmann <romanz@lavabit.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
if __name__ == '__main__': from __init__ import init; init()
from ranger.container import History
from unittest import TestCase, main
import unittest
class Test(TestCase):
def test_history(self):
hist = History(3)
for i in range(6):
hist.add(i)
self.assertEqual([3,4,5], list(hist))
hist.back()
self.assertEqual(4, hist.current())
self.assertEqual([3,4], list(hist))
self.assertEqual(5, hist.top())
hist.back()
self.assertEqual(3, hist.current())
self.assertEqual([3], list(hist))
# no change if current == bottom
self.assertEqual(hist.current(), hist.bottom())
last = hist.current()
hist.back()
self.assertEqual(hist.current(), last)
self.assertEqual(5, hist.top())
hist.forward()
hist.forward()
self.assertEqual(5, hist.current())
self.assertEqual([3,4,5], list(hist))
self.assertEqual(3, hist.bottom())
hist.add(6)
self.assertEqual(4, hist.bottom())
self.assertEqual([4,5,6], list(hist))
if __name__ == '__main__': main()