5 ms·
Short version: I'm close to figuring out how to encourage more prototyping of software by making tests super easy to write during the prototyping process, and s
by akkartik 5y ago
Short version: I'm close to figuring out how to encourage more prototyping of software by making tests super easy to write during the prototyping process, and so de-risking rewrites. But one problem I've been stymied by is how to represent expectations of screens when they contain graphics.
Long version: My Mu project (https://github.com/akkartik/mu https://github.com/akkartik/mu) is building a computing stack up from machine code. The goal is partly to figure out why people don't do real prototyping more often. We all know we should throw the first one away (https://wiki.c2.com/?PlanToThrowOneAway https://wiki.c2.com/?PlanToThrowOneAway), but we rarely do so. The hypothesis is that we'd be better about throwing the first one away if rewriting was less risky. By the time the prototyping phase ends, a prototype often tacitly encodes lots of information that is risky to rewrite.
To falsify this hypothesis, I want to make it super easy to turn any manual run into a reproducible automated test. If all the tacit knowledge had tests (stuff you naturally did as you built features), rewriting would become a non-risky activity, even if it still requires some effort.Turning manual tests into automated ones requires carefully tracking dependencies and outlawing side-effects. For example, in Mu functions that modify the screen always take a screen object. That way I can start out with a manual test on the real screen, and easily swap in a fake screen to automate the test. Hence my problem:
How do you represent screens in a test?
Currently I represent screens as 2D arrays of characters. That is doable a lot of the time, but complicates many scenarios:
* Text mode character attributes. If I want to check the foreground or background color, I currently use primitives like `check-screen-in-bg` which ignores spaces in a 2D array, but checks that non-spaces match the given background attribute. In practice this leads frequently to tests that first check the character content on a screen and then perform more passes to check colors and other attributes.
* Non-text. Checking pixels scales poorly, either line at a time or pixel at a time. A good test should seem self-evident based on the name, but drawing ASCII art where each character is a pixel results in really long lines or stanzas. So far I maintain separate buffers for text vs pixels, so that at least text continues to test easily.
* Proportional fonts. Treating the screen as a grid of characters works only when each character is the same width. If widths differ I end up having to go back to treating characters as collections of pixels. So Mu currently doesn't support arbitrary proportional fonts.
* Unicode. Mu currently uses a single font, GNU Unifont (http://unifoundry.com/unifont/index.html http://unifoundry.com/unifont/index.html). Unifont is mostly fixed-width, but lots of graphemes (e.g. Chinese, Japanese, Korean, Indian) require double-width to render. That takes us back to the problems of proportional fonts. Currently I permit just variable width in multiples of some underlying grid resolution, but it feels hacky.
Can people think of solutions to any of these bullets in a text-based language? Or a more powerful non-text representation?
- minhmeoke 5y agoYour project is quite impressive. And welcome to the world of computer graphics! I'd consider taking inspiration from the following sources: 1. GUI toolkits like QT QML [1] or Android [2]. These typically build a hierarchical tree of different components (eg: start with a root window, which contains panes, which in turn contain text and buttons). Each component may contain different properties (eg: font, color), and properties may be inherited from the parent component. Advantages: + preserves semantics of component properties and how they are linked to each other (eg: the caption is below the image) Disadvantages: - complexity: building a layout/constraint engine can be difficult, or alternatively you can use absolute positioning with relative offsets which can be tedious to use (in this case the layer-based approach below might make more sense). [1] https://en.wikipedia.org/wiki/QML https://en.wikipedia.org/wiki/QML [2] https://developer.android.com/guide/topics/ui/declaring-layout https://developer.android.com/guide/topics/ui/declaring-layo... 2. Graphical editor programs like Gimp or Photoshop, or Adobe Flash. These build up a screen as a collection of vertically stacked layers or assets (eg: graphics, text, etc) with attached properties and optionally bounding boxes. Higher layers/assets occlude the content of the layers below them, so you would need to implement some kind of visibility logic. Advantages: + simplicity + you can use identifiers for assets, and therefore don't need to perform pixel-by-pixel comparisons. Disadvantages: - may lose some information about how different components are related to each other Also, rather than a raster pixel-based representation, it might make sense to use a vector representation internally [3]. The most popular vector representation is SVG. The full spec is very verbose, so you probably only want to implement a small subset of it. This would permit you to specify properties like line thickness, color, striped/dotted patterns. At render time, you could convert the (proportional) fonts to vectors as well for consistency, and then rasterize the entire scene when rendering to a display surface. But for testing, it would be better to use the scene graph / vector format which is easier for users to reason about. [3] https://en.wikipedia.org/wiki/Vector_graphics https://en.wikipedia.org/wiki/Vector_graphics [4] http://blog.leahhanson.us/post/recursecenter2016/haiku_icons.html http://blog.leahhanson.us/post/recursecenter2016/haiku_icons... But perhaps this is over-complicating things.
- akkartik 5y agoThank you for those suggestions! Do you know if any of those tools following either approach has any automated tests? My immediate problem is how to manage the complexity of implementing a layout engine or editor. Somewhere I need something checking that a given asset identifier results in specific pixels. And I'd like the tests for _that_ to be nice to read. It's a bit of a chicken-and-egg problem..