Saturday, August 8, 2009

Epiphany

For the past few days, I've switched from Firefox to Epiphany as my main web browser.

Epiphany is a Gecko-based* browser with an interface designed according to the GNOME Human Interface Guidelines. It has the basic features you expect from a web browser: bookmarks, tabbed browsing, search via the location bar. Essentially, Epiphany is a stripped-down version of Firefox. It supports the Netscape plugin architecture, so any plugins you installed via Firefox will just work. And since it's Gecko under the hood, websites should look identical to those in Firefox.

Out of the box, there is some strangeness with Epiphany. For example, the default screen layout has two toolbars, one of which has only the location bar, the other featuring the back/forward/stop/bookmark buttons. But you can right click on any active toolbar button and choose "Customize toolbars", then start dragging the buttons into a more auspicious arrangement.

Also, GNOME uses Ctrl+PageUp and Ctrl+PageDown by default to navigate tabbed interfaces. This is inherently evil because it requires use of the right hand, which, when using a browser, should normally be positioned on the mouse. Normally I'd remap the key bindings (in GNOME, you can go to System -> Preferences -> Appearance and check the "editable menu shortcut keys" entry under the Interface tab), but GNOME won't let you rebind anything to Ctrl+Tab, since that's used to tab out of a multiline textbox. Fortunately, there is a plugin that ships with Epiphany that allows you to use Ctrl+Tab to navigate between tabs.

Javascript alerts are problematic -- they are window-specific rather than tab-specific, and you can't even close the window when one is active. This is an issue that Opera solved, and Chrome uses that solution; solving it in a way that fits in with GNOME will require some thought.

Favicons are another issue. By default, Epiphany only loads favicons for websites that use the <link rel="icon"> syntax, but most websites simply include a /favicon.ico file in the root directory. (GNOME's one of the few sites that use the former method.) There's a plugin to fix this, but the version included in Ubuntu does not work.

The final issue is unsolved via plugins, as far as I can tell. Your browsing session is not restored when you close the application normally. If the application closes due to a SIGKILL or SIGTERM or a crash, it will offer to reload your tabs the next time. Otherwise, it'll start a new session every time.

What are the benefits, if I'm willing to deal with the awkwardness?


  • Desktop integration. You specify your preferred applications in GNOME, and Epiphany will open downloaded documents with those.

  • Desktop integration. Epiphany looks exactly like I expect an application to look. Proper font sizes, for example (Firefox menu fonts are about 60% too large). And using GNOME's standard alert balloons rather than a hacked-up, application-specific toast alert that renders choppily.

  • Desktop integration. Epiphany doesn't have its own "view page source" function; it dumps a copy of the page in /tmp and opens your preferred graphical text editor on it.

  • The awesome bar looks nicer. This is probably the result of using proper font sizes.

  • Speed. Firefox is slow at starting. Epiphany is much faster.

  • Smarter behavior when closing tabs. Firefox is inconsistent with this; sometimes it'll return me to the last viewed tab, whereas others, it will choose to select the next adjacent tab. Epiphany always returns me to the last viewed tab.



All considered, Epiphany shows a lot of promise. If you normally use GNOME, you should try it out.

* With GNOME 2.28, Epiphany will use Webkit, but as of this writing, the latest released version, 2.26, uses Gecko.

Friday, July 24, 2009

Build Your Own CAB: Introduction

Jeremy Miller was working on a "Build Your Own CAB" series a while back. However, he does not have an intimate familiarity with CAB. I have spent 2.5 years working on a CAB-based application, with some side projects that use Castle Windsor.

Currently, I'm starting on a GUI project using Mono on Linux. It's against the CAB license agreement to use it on Linux, so I won't be using it. Instead, I'll be taking a look at the components of CAB, how to reimplement them or what replacements are readily available, the merits and deficiencies of CAB's implementation, and ways to avoid potential problems.

CAB Components


CAB consists of several components which could in theory be used separately. In practice, CAB's internal design is too scary to contemplate swapping out components, so the best you could hope for is to rip out part to use elsewhere.

Service locator


Technically, it's dependency injection, but I generally expect a dependency injection system to figure out the correct order in which to build things.

CAB's dependency injection system encourages you to have god classes that add a few hundred services to the workitem. (A WorkItem is like a Windsor container; it holds a collection of services and objects built, and handles events.) This is very procedural and does not involve actual inversion of control, as such; but it looks enough like using a full-fledged IoC container that it's reasonable to switch.

Events


CAB events are wonderful. Somewhat. They closely match Ayende's EventBroker, except for being based around EventHandler rather than Action (that is, Ayende decided his events shouldn't ever have parameters, whereas CAB decided on [object, EventArgs]).

There are some advantages to the CAB system, but there are a couple of maintenance issues as well, and a few handy features that it entirely lacks support for. On the whole, CAB events are great.

Commands


Commands are events that can be turned on or off. Not much to say about them other than that.

Items


Items are, well, any state you want to keep around. It's a place to build transient objects or store items temporarily.

I suggest only using it for building transient objects. You don't want arbitrary classes pulling stuff directly out of the workitem, since that's unnecessary coupling, so you may as well use a service with local variables instead.

Modules


A Module is just a DLL with some bootstrapping code. A CAB application will contain an XML catalog of modules that will be loaded and run on startup.

CAB Organization


In CAB, everything is part of a WorkItem. The intent is that you have a root WorkItem that represents the essential, system-wide state of your application, and you create child WorkItems on a per-task basis.

In essence, CAB uses WorkItems as a lifecycle mechanism for components. In CAB, configuration is tied to initialization. This means that creating a child WorkItem requires you to call the necessary configuration code when creating the WorkItem. This code can be relatively verbose, and this leads to the impression that CAB is slow. (Additionally, since CAB uses reflection extensively and, due to the marriage of configuration and initialization, unable to cache anything, CAB is slow. However, your IoC container will almost never be a significant bottleneck.)

In practice, child WorkItems will be used rarely. Only if you know you'll have a whole slew of items that you need to create now and destroy later -- for instance, creating a new and complex window that shares little functionality with the rest of your application-- will you resort to child workitems.

Conclusion


I've talked a bit about what CAB is. Next time, I'll discuss how a CAB application is structured, with special reference to the common pain points.

Monday, July 13, 2009

On window managers and Windows 7

I hate Windows.

There are two major reasons for this. First is the lack of a reasonable text shell like bash. Second is the window manager.

The State of the Art


There are a lot of great features that every window manager on Linux has: edge detection (provide resistance to positioning windows partially off-screen or overlapping other windows), virtual desktops (swap out all your windows for another set of windows), vertical maximize/horizontal maximize, alt-drag, always on top...

Windows XP was early enough that these features were not necessarily compulsory. Windows doesn't need to be a technology leader. Vista should have included them. Windows 7 still doesn't.

Vista/W7 tried to include a couple new features for the window manager. Edge detection? No. Virtual desktops? No. Always on top? No. Alt drag? No.

There's vertical maximize...sort of. If you drag a window to the left or right side of the screen, it's resized to take up that half of the screen.

There are two other notable features in W7's window manager.

Mouse Gestures


Make that mouse gesture. There's only one. If you "shake" a window, all other windows are minimized.

Why? When would you want this? If you only want the one window, why not maximize it? If you had virtual desktops, you could send the window to an empty desktop, or even make a new desktop and send it to that.

Perhaps someone heard about virtual desktops and misunderstood the feature entirely. They ended up with something absolutely useless.

Alt-Tab Outlining


When you're waiting in the alt-tab menu, the window you're currently waiting on will be outlined. For example, if you have Firefox maximized, and a terminal in the background in the upper left and another in the lower right, you can cycle through the alt-tab menu, and it'll show the outline of the upper left terminal when you've selected it, and the same with the lower right.

Windows 7 takes this to the logical extreme. When alt-tabbing, all windows are rendered as outlines. (Well, shadows, actually. Which is effectively the same, just harder to see.) If you have ten windows open, you have no hope of distinguishing between them, except the 1/16 scale pictures of the window that the menu provides.

It's The Team, Stupid


If anyone working on these features had sat back and thought about them even briefly, they would have realized that their implementations were worse than useless. This is a case of keeping up with the Joneses without knowing what the Joneses are doing.

Microsoft stole these features, but when you're stealing a feature, you can at least get it vaguely right. With Microsoft's resources, they should be able to surpass the features they stole. This can only be a result of gross incompetence.

Wednesday, May 20, 2009

Monoculture == good?

Being a performance-minded person, I wanted to compare the speed of my dependency injection / inversion of control container, dconstructor, to the speed of other popular IoC containers. Since I am most familiar with C#, my first thought was to try Castle Windsor.

My day job involves programming in C# on Windows, but at home, I use Linux exclusively. So this means using Mono. Perhaps unsurprisingly, Castle Windsor does not work on Mono. It has dependencies on C#3.5 libraries that are only partially implemented in Mono.

I began to consider, at this point, the relative situation between Mono and D. In the past, I have gotten internal compiler errors in both, and much more frequently than I would expect with a production-quality compiler. In Mono, these usually related to libraries -- perhaps with Castle, sometimes; never with any library I thought might typically be developed with Mono. In D, it was usually my code, though I'll grant that my D code involves fewer libraries in many cases.

The primary issue is that C# libraries can target two platforms, one of which is significantly more stable and has a more extensive standard library and much larger installation base. There was a time, I am told, when C# libraries would contain workarounds for differences and errors present in Mono and not in .NET, but this attitude is no longer prevalent.

In D, there is only DMDFE. All libraries target it.

Another helpful element is that the primary way to distribute a library with D is by source. It's quite doable to fix up problems in a library that come about as a result of compiler and stdlib differences. There's not much you can do with an opaque DLL. This makes problems seem more insurmountable than they might be.

All told, though, I think that D's relative monoculture is a good thing. There are two or three teams independently working on the same open source codebase, so there's less worry about D suddenly going away if Walter ceases to distribute it. But I can assume that any maintained library in D will continue to work with up-to-date compilers.

That might change when Dil comes around, but I still look forward to Dil. I've seen DMDFE, after all.

Tuesday, May 19, 2009

Lifecycle support in dconstructor

Dconstructor now has lifecycle support.

What does this mean? It means your objects will die a fiery death.

Previously, dconstructor supported two lifecycles: Instance and Singleton. Instance indicated that an object was entirely transient and had to be rebuilt each time it was required. Singleton indicated that an object was permanent and could be safely reused from the time it was first created onward to the end of time.

This has been generalized. Each object builder is now associated with a lifecycle. When it builds, it gets a lifecycle ID from the lifecycle. The next time it builds, it asks the lifecycle if its ID is still valid. If the ID is valid, then the builder returns the same instance; otherwise, it creates a new instance.

When registering a type, you can specify a lifecycle. You can also set a default lifecycle, and create LifecycleProviders to determine policy for particular types.

This is a part of dconstructor.build2, of course.

Dconstructor updates

Just a quick note about dconstructor: I've added dconstructor.build2, which is nearly a drop-in replacement for dconstructor.build. (Interceptors require modification.)

This reduces the executable bloat significantly -- in one mid-size example, dconstructor previously was responsible for a 75% increase in executable size (4.8MB to 8.3MB) and is now only responsible for about 100KB. The new version is less than 5% slower.

This also greatly decreases compilation times. examples/speed.d compiles in 3.4s rather than 14s.

The update is highly recommended, unless you need templated interceptors. Additionally, default_builder will soon be changed to use build2, since default_builder does not allow you to inject interceptors.

Thursday, May 14, 2009

The Visitor Pattern and Extensibility

I've been dealing with Dil lately. It's a compiler project for the D programming language, written in D. It makes use of the visitor pattern to provide semantic analysis. (The visitor pattern is a way of achieving dynamic dispatch via strongly typed overloads. It was a clever hack when it was first created.)

One issue with the visitor pattern is that it requires a lot of boilerplate code. If you want to have multiple semantic passes, you need to use an interface, and that interface requires a method for each type. If your visitor only cares about ten types and the interface supports fifty, you have a problem.

This doesn't much matter for dil -- very few types will not matter for any given visitor.

But let's look at a different problem. Let's say we want to log all visitor actions. Where do we do this? There are two choices: every single visitor method, or every single visited class. Similarly if we want to filter visited items, or set a breakpoint, or anything interesting like that.

I'm working on semantic analysis in Dil right now. For cleanness, I would like to split semantic analysis into possibly many phases. However, I would also like to combine semantic passes when possible for efficiency. To do this, I need to create a visitor that will coordinate between several visitors. This is an unreasonably large task with the current Visitor pattern implementation.

What else could I use, though?

In the past, I've used this concept:


void delegate(Node)[ClassInfo] handlers;
void visit(Node node)
{
if (auto ptr = node.classinfo in handlers)
{
auto dg = *ptr;
dg(node);
}
}


This design is sufficiently minimal that it's easy to do a fair bit with it:

  • Log each visited node

  • Use multiple handlers per node type

  • Use the same handler for multiple node types

  • Filter or preprocess nodes based on some criterion available in the base class

  • Ignore various node types by not writing any code for them



There is one problem with it, though: you have to do a lot of casting. In C#, you can use reflection to invoke the methods without caring about their types. In D, you can write a little wrapper:


class Invoker(T : Node)
{
void delegate(T) dg;
void invoke(Node node)
{
debug
{
// safety: cast and check
auto theNode = cast(T)node;
assert (theNode !is null, "expected: " ~ T.stringof ~
"but was " ~ node.classinfo.name);
}
else
{
// efficiency: force cast and assume
auto theNode = *cast(T*)&node;
}
return dg(theNode);
}
}
handlers[type] = &(new Invoker(dg)).invoke;


A slightly simpler version is possible with D2's closures.

There is one problem with our solution: it uses associative arrays, which could be slow.

If you know what types you support in advance, you can map each to an index to get a very fast lookup. This requires a fast means of getting this index, however. I'm generally inclined to just use the associative array; it's going to be small in any case, so it will not incur a significant penalty in most cases.

Wednesday, May 13, 2009

Metacity hacks

I've been using Enlightenment 17 as a window manager, but decided to go back to GNOME/Metacity since they're more polished. Overall a good move.

There are three issues I have with GNOME/Metacity. The first, and least solvable, is resources: GNOME is not lightweight. But I have sufficient RAM to ignore that issue for the most part.

The second problem is switching workspaces. In Enlightenment, going left from the leftmost workspace yields the rightmost workspace. Similarly for the rest of the directions. This is not the case for Metacity; you cannot go left from the leftmost workspace, or right from the rightmost.

Lastly, window placement. ANYTHING would be better than Metacity's policy, which is tiling all new windows from the top left. Open up four terminals on an empty workspace, you get what looks like one terminal with four titlebars, plus a lot of empty screen.

workspace_switch.py has sane workspace switching behavior. You can map Ctrl+Alt+Right and Ctr+Alt+Left to custom commands using gconf-editor (/apps/metacity/global_keybindings and /apps/metacity/keybinding_commands). Check workspace_switch.py --help for details.

I had to modify metacity to get reasonable behavior for its window locations -- metacity is renouned for its lack of configuration options.

In the metacity sources, go to src/core/place.c. Nuke all existing functions and add the following:


void
meta_window_place (MetaWindow *window,
MetaFrameGeometry *fgeom,
int x,
int y,
int *new_x,
int *new_y)
{
MetaRectangle work_area;
const MetaXineramaScreenInfo* xinerama =
meta_screen_get_current_xinerama (
window->screen);
meta_window_get_work_area_for_xinerama (window,
xinerama->number, &work_area);
int xrange = work_area.width - x;
int yrange = work_area.height - y;
*new_x = (rand() % xrange);
*new_y = (rand() % yrange);
}
As you can see, this positions the new window at some random location, ensuring that no portion of the window is off the screen (unless perhaps the window is larger than the screen).

Perhaps I'll work on this -- certain things that would ideally be centered or center-parent are positioned randomly, such as the GNOME run dialog or modal dialogs. But for now, it's a huge improvement.

Monday, March 17, 2008

Recursive it is.

Well, for the gtk# presenter injection issue, I determined that I could do the recursive method for in about fifteen lines of code, so I implemented that. I was stumped for quite some time because the recursion wasn't descending at all -- it turns out I was casting widgets to Gtk.Bin when I should have been casting to Gtk.Container.

The code:

public class ViewAttribute : Attribute {}

public class InjectAttribute : Attribute {}

[CastleComponent("bootstrapViews", typeof(BootstrapViews))]
public class BootstrapViews
{
private IWindsorContainer _container;

public BootstrapViews(IWindsorContainer container)
{
_container = container;
}

public void Bootstrap(Widget widget)
{
Container bin = widget as Container;
if (bin == null)
{
return;
}
foreach (Widget child in bin.Children)
{
Bootstrap(child);
}

object[] attrs = bin.GetType().GetCustomAttributes(typeof(ViewAttribute), false);
if (attrs.Length > 0)
{
foreach (FieldInfo field in bin.GetType().GetFields())
{
if (field.GetCustomAttributes(typeof(InjectAttribute), false).Length > 0)
{
field.SetValue(bin, _container.Resolve(field.FieldType));
}
}
}
}
}

Sunday, March 16, 2008

gtksharp and MVP

Switching gears to C#, since, though I love D, I need a working mocks library to write any significant code in it, and dmd bugs prevent dmocks from working correctly.

I'm using gtk#/stetic to create a GUI of moderate complexity, and of course I'm using the Model-View-Presenter pattern. Reminiscent of ASP.NET MVP issues, the main problem is getting a reference to a presenter into a view -- gtk# doesn't use a central object builder that I can hook into; everything happens in a Build method.

So I have three options that I can pursue in achieving a reasonable MVP model:
  1. Each custom widget gets a reference to the Castle container and resolves its presenter that way.
  2. I build my GUI, then do a depth-first traversal of all the components, looking for an attribute set: [View(Type register)] on the class, [Inject] on the presenter(s). Any such classes, I register with the container, then fill in their dependencies. This works for everything that inherits from Gtk.Bin, but I have to copy it for any other gtk classes that my widgets derive from.
  3. Possibly using inheritance, my widgets subclass a SmartPart class and register themselves with a singleton (using the typical singleton pattern) that will register them with the container and fill in dependencies. This means I spend less time at runtime looking at widgets.
Option #1 is not happening.
Option #3, using generics, is reasonably simple, and it works unless I have one view with multiple presenters.
Option #2 is the fully general solution, which I probably won't be implementing. It'd be great, except for the speed, but it's rather yagni.

Of course, the problem with #2 is that my constructors will have to be modified, or the presenters might do something foolish:

public MyWidget()
{
this.Build();
base(whatever);
}
// was:
// public MyWidget() : base(whatever)
// {
// this.Build();
// }

As an aside, has anyone had luck getting CruiseControl.net running on debian?

Wednesday, March 12, 2008

DUnit

I whipped together a quick unittest library, DUnit. Took less than an hour; apparently, SUnit took about two hours to write, so I'm in decent company.

This doesn't offer very much; in particular, there's no measure of progress. That's a deviation from the xUnit standard. And there's no way to control which tests get run. But I'm working on a better version already that offers those features.

On an unrelated note, dmd2 is too unstable to be usable, so dmocks is dead. I'll be updating it to dmd2.011, but probably no further, at least until dmd2 is in late beta or beyond.

Tuesday, February 26, 2008

Horrible...

Everything I said about templates? Double for mixins.

A short mixin can be a wonderful thing. Like for unittests:

string test(string name)()
{
return `
Stdout("` ~ name ~ `");
scope (failure) Stdout("failed").newline;
scope (success) Stdout("passed").newline;`
}
unittest
{
mixin(test!("test naming test"));
}


But mixins should be passive, delegating to concrete methods and classes whenever possible. Line numbers are that important.

Monday, February 18, 2008

New project woes

Got a university project that's decidedly not Agile. And I don't have any time to do requirements analysis in this weakly waterfall style. If it were Agile, I'd only have time for about four or five iterations....

It's tempting to ignore the customers at this point and just code up an initial project that fulfills some need. Then I'd have something to talk about. The one source I have wants the system to have insane amounts of detail -- if I asked him to fill it out, he'd refuse, I think. And there's only one person in the department who would benefit from the information.

Sunday, February 17, 2008

CTFE and testability

A lot of my code makes heavy use of CTFE. Really heavy. As in, more lines of code get executed at compile time than at runtime. How do I start to write unittests for it?

Answer: I don't.

That's rather harsh. Let's look at one case, or actually an abbreviated form of it. This is taken from DMocks:


string Methods (T, string name) () {
string methodBodies = "";
foreach (method; __traits(getVirtualFunctions, T, name)) {
alias typeof(method) func;
static if (is(ReturnType!(func) == void)) {
methodBodies ~= VoidMethod!(T.stringof, name, ParameterTypeTuple!(func));
} else {
methodBodies ~= ReturningMethod!(
T.stringof,
name,
ReturnType!(func),
ParameterTypeTuple!(func));
}
}
return methodBodies;
}

string ReturningMethod (string type, string name, T, U...)() {
string qualified = type ~ `.` ~ name;
string args = String!(U)();
string argArgs = Arguments!(U);
string nameArgs = `"` ~ qualified ~ (U.length == 0 ? `"` : `", ` ~ Arguments!(U)());
string retArgs = T.stringof ~ (U.length == 0 ? `` : `, ` ~ args);
return `some very long string that uses those strings I just assigned above`;
}
// VoidMethod looks pretty much like ReturningMethod.


That is terribly ugly, of course. If I could do it at runtime, I could introduce about two classes for the first template, then use tango.text.convert.Layout and public static format strings to deal with ReturningMethod. I'd do it with a format string looking like this:


public const string methodOutline = `{0} {1} ({2}) {{{
{{0}}
}}}`;
public const string methodBodyPart1 = `{0} {1} ...`;
public const string methodBodyPart2 = `{0} {1} ...`; // and so on


Of course, Layout won't work at compile time. Even if it did, I'd be left with a glob of functions to go through for my "unit" tests. But at that rate, I might as well complete the integration test by running the code that mixes in this giant string.

So I've been thinking of how to do it. The answer lies in two parts:

  1. Write a compile-time string formatting function.

  2. Implement any method I want to test as a string that I mix in.



The former makes it much easier to make sure the result string has the right arguments in the right place. The latter means I can test each in isolation by providing default implementations of templates that I'm not testing.

But for now, I've got some ugly, unmaintainable blobs of code to rewrite. The joy.

Continuous Integration for D

You don't need to use Agile to benefit from a Continuous Integration server. The basic idea is, you've got a server that checks out your code whenever there are updates, builds it according to a build script, and (almost always) runs some scripted tests on it.

I'm pondering how to set one up for D, using a daemon of some sort. The approach looks something like this:


  • A config file with the repository information and where to check it out to.

  • A DSSS file in the root of the repository.

  • A list of directories that contain tests. These should only contain tests; perhaps an exclude option for files and directories that contain helper methods.



The build process isn't that exciting:

  • Check for updates; if none, sleep.

  • Run dsss build.

  • Recursively go through the test directories, running rebuild on each .d file and executing the resulting executable.

  • Publish the results.



This requires that each test file contain a main() method. However, it has the benefit that the main executable does not contain unit tests, enforcing or at least encouraging separation of concerns and design practices that do require tests to have private access to the tested modules.

Ugh.

Stack traces are beautiful. If you are ever in control of a standard library, make sure your exceptions have stack traces.

I'm trying to do TDD without them, and that means inserting a lot of tracing code, which is a bad sign.

Saturday, February 16, 2008

Did it...

Got the assertions stuff done, at least the basic stuff. The list stuff is annoying -- and not fully tested -- but should work with with builtin arrays (which, in D, are actually resizeable, sliceable, and everything you'd expect from a thorough library implementation) as well as just about any collection class that Tango contains.

The annoying part is formatting everything without taking mounds of code for it. I've got that working, aside from negation.

Now I'm working on test cases for everything else I've written. It's much easier to build stuff with Descent for an IDE and Rebuild, but still difficult enough that it's difficult to support a proper TDD model.

Hi!

The intent of this blog is to encourage me to code. As such, I may update infrequently or say stuff that seems quite inane. Also, most of my posts will relate strongly to my code and be irrelevant for most other people.

My code, since I've mentioned it, is mostly in the D programming language. I've got a collection of libraries called Felt in various stages of development, aiming at being a Castle clone. Or maybe I'm trying to catch up with Ayende @ Rahien. The code's all at the Felt dsource page.

Anyway, I'll catch up with you later.

felt assertions

I'm working on an assertions library right now. Library? Well, just a couple files, two structs, an exception class, and a half dozen functions.

It's in the D programming language. It depends on Tango Variant, which can actually handle structs of nontrivial sizes. Phobos Variant can't. And it should work with D1 and D2.

I need to get my hands on Tango for D2. Even if Phobos were decent, I can't afford to write so many version statements. It just isn't worth my time. But the reflection capabilities introduced in D2 are great.

The final product will look something like this:
expect(4).equals(4);
expect([1, 2, 3, 4]).has(2).where((int x) { return x % 2 == 0; });

// should be 2 where the constraint is false
expect([1, 2, 3, 4]).has(2).not.where((int x) { return x % 2 == 0; });

// should be other than two where the constraint is false
expect([1, 2, 3, 4]).not.has(2).where((int x) { return x % 3 == 0; });
expect([1, 2, 3, 4]).hasOne.sameAs(2);
expect(true);
expect(null).isNull;
o = new Object;
auto p = o;
expect(o).sameAs(p);
p = new Object;
expect(p).not.sameAs(o);

It'll be ready some time today. And then I should stop slacking and get Felt.Sleeper working. Or fix interfaces with dmocks.