Make mock behaviors be ordered.
See https://code.google.com/p/dart/issues/detail?id=8950

R=sigmund@google.com

Review URL: https://codereview.chromium.org//13851022

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@22191 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/pkg/unittest/lib/mock.dart b/pkg/unittest/lib/mock.dart
index cacaec7..b6e48a4 100644
--- a/pkg/unittest/lib/mock.dart
+++ b/pkg/unittest/lib/mock.dart
@@ -108,6 +108,7 @@
 library mock;
 
 import 'dart:mirrors' show MirrorSystem;
+import 'dart:collection' show LinkedHashMap;
 
 import 'matcher.dart';
 
@@ -1237,7 +1238,7 @@
   final String name;
 
   /** The set of [Behavior]s supported. */
-  Map<String,Behavior> _behaviors;
+  LinkedHashMap<String,Behavior> _behaviors;
 
   /** The [log] of calls made. Only used if [name] is null. */
   LogEntryList log;
@@ -1262,7 +1263,7 @@
    */
   Mock() : _throwIfNoBehavior = false, log = null, name = null {
     logging = true;
-    _behaviors = new Map<String,Behavior>();
+    _behaviors = new LinkedHashMap<String,Behavior>();
   }
 
   /**
@@ -1281,7 +1282,7 @@
       throw new Exception("Mocks with shared logs must have a name.");
     }
     logging = enableLogging;
-    _behaviors = new Map<String,Behavior>();
+    _behaviors = new LinkedHashMap<String,Behavior>();
   }
 
   /**
diff --git a/pkg/unittest/test/mock_test.dart b/pkg/unittest/test/mock_test.dart
index 1788e82..5669f3f 100644
--- a/pkg/unittest/test/mock_test.dart
+++ b/pkg/unittest/test/mock_test.dart
@@ -661,4 +661,62 @@
     expect(m.foo(alice), true);
     expect(m.foo(bob), false);
   });
+
+  test("Behavior ordering", () {
+    // This is distinct from value ordering, i.e.
+    //
+    // m.when(...).thenReturn(1).thenReturn(2)
+    // 
+    // Here we want to test using distinct matchers being
+    // applied in order, so we have a single call that
+    // matches 3 different behaviors, and test that 
+    // the behaviors are applied in the order they are
+    // defined.
+    var m = new Mock();
+    m.when(callsTo("foo")).thenReturn("A");
+    m.when(callsTo("foo", "bar")).thenReturn("B");
+    m.when(callsTo("foo", "bar", "mock")).alwaysReturn("C");
+    expect(m.foo("bar", "mock"), "A");
+    expect(m.foo("bar", "mock"), "B");
+    expect(m.foo("bar", "mock"), "C");
+    expect(m.foo("bar", "mock"), "C");
+    m.resetBehavior();
+
+    m.when(callsTo("foo")).thenReturn("A");
+    m.when(callsTo("foo", "bar", "mock")).alwaysReturn("C");
+    m.when(callsTo("foo", "bar")).thenReturn("B");
+    expect(m.foo("bar", "mock"), "A");
+    expect(m.foo("bar", "mock"), "C");
+    expect(m.foo("bar", "mock"), "C");
+    expect(m.foo("bar", "mock"), "C");
+    m.resetBehavior();
+
+    m.when(callsTo("foo", "bar")).thenReturn("B");
+    m.when(callsTo("foo")).thenReturn("A");
+    m.when(callsTo("foo", "bar", "mock")).alwaysReturn("C");
+    expect(m.foo("bar", "mock"), "B");
+    expect(m.foo("bar", "mock"), "A");
+    expect(m.foo("bar", "mock"), "C");
+    expect(m.foo("bar", "mock"), "C");
+    m.resetBehavior();
+
+    m.when(callsTo("foo", "bar")).thenReturn("B");
+    m.when(callsTo("foo", "bar", "mock")).alwaysReturn("C");
+    m.when(callsTo("foo")).thenReturn("A");
+    expect(m.foo("bar", "mock"), "B");
+    expect(m.foo("bar", "mock"), "C");
+    expect(m.foo("bar", "mock"), "C");
+    expect(m.foo("bar", "mock"), "C");
+    m.resetBehavior();
+
+    m.when(callsTo("foo", "bar", "mock")).alwaysReturn("C");
+    m.when(callsTo("foo")).thenReturn("A");
+    m.when(callsTo("foo", "bar")).thenReturn("B");
+    expect(m.foo("bar", "mock"), "C");
+    expect(m.foo("bar", "mock"), "C");
+    expect(m.foo("bar", "mock"), "C");
+    expect(m.foo("bar", "mock"), "C");
+    m.resetBehavior();
+  });
 }
+