// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. library MintMakerTest; import 'dart:async'; import 'dart:isolate'; import 'package:unittest/unittest.dart'; import "remote_unittest_helper.dart"; class Mint { Map _registry; SendPort port; Mint() : _registry = new Map() { ReceivePort mintPort = new ReceivePort(); port = mintPort.sendPort; serveMint(mintPort); } void serveMint(ReceivePort port) { port.listen((message) { int balance = message[0]; Purse purse = createPurse(balance); message[1].send(purse.port); }); } Purse createPurse(int balance) { Purse purse = new Purse(this, balance); _registry[purse.port] = purse; return purse; } Purse lookupPurse(SendPort port) { return _registry[port]; } } class MintWrapper { SendPort _mint; MintWrapper(SendPort this._mint) {} void createPurse(int balance, handlePurse(PurseWrapper purse)) { ReceivePort reply = new ReceivePort(); reply.first.then((SendPort purse) { handlePurse(new PurseWrapper(purse)); }); _mint.send([balance, reply.sendPort]); } } class Purse { Mint mint; int balance; SendPort port; Purse(this.mint, this.balance) { ReceivePort recipient = new ReceivePort(); port = recipient.sendPort; servePurse(recipient); } void servePurse(ReceivePort recipient) { recipient.listen((message) { String command = message[0]; if (command == "balance") { SendPort replyTo = message.last; replyTo.send(queryBalance()); } else if (command == "deposit") { Purse source = mint.lookupPurse(message[2]); deposit(message[1], source); } else if (command == "sprout") { SendPort replyTo = message.last; Purse result = sproutPurse(); replyTo.send(result.port); } else { // TODO: Send an exception back. throw UnsupportedError("Unsupported commend: $command"); } }); } int queryBalance() { return balance; } Purse sproutPurse() { return mint.createPurse(0); } void deposit(int amount, Purse source) { // TODO: Throw an exception if the source purse doesn't hold // enough dough. balance += amount; source.balance -= amount; } } class PurseWrapper { SendPort _purse; PurseWrapper(this._purse) {} void _sendReceive(message, replyHandler(reply)) { ReceivePort reply = new ReceivePort(); _purse.send([message, reply.sendPort]); reply.first.then(replyHandler); } void queryBalance(handleBalance(int balance)) { _sendReceive("balance", handleBalance); } void sproutPurse(handleSprouted(PurseWrapper sprouted)) { _sendReceive("sprout", (SendPort sprouted) { handleSprouted(new PurseWrapper(sprouted)); }); } void deposit(PurseWrapper source, int amount) { _purse.send([ "deposit", amount, source._purse ]); } } mintMakerWrapper(SendPort replyPort) { ReceivePort receiver = new ReceivePort(); replyPort.send(receiver.sendPort); receiver.listen((SendPort replyTo) { Mint mint = new Mint(); replyTo.send(mint.port); }); } class MintMakerWrapper { final SendPort _port; static Future create() { ReceivePort reply = new ReceivePort(); return Isolate.spawn(mintMakerWrapper, reply.sendPort).then((_) => reply.first.then((port) => new MintMakerWrapper._(port))); } MintMakerWrapper._(this._port); void makeMint(handleMint(MintWrapper mint)) { ReceivePort reply = new ReceivePort(); reply.first.then((SendPort mint) { handleMint(new MintWrapper(mint)); }); _port.send(reply.sendPort); } } _checkBalance(PurseWrapper wrapper, expected) { wrapper.queryBalance(expectAsync((int balance) { expect(balance, equals(expected)); })); } void main([args, port]) { if (testRemote(main, port)) return; test("creating purse, deposit, and query balance", () { MintMakerWrapper.create().then(expectAsync((mintMaker) { mintMaker.makeMint(expectAsync((MintWrapper mint) { mint.createPurse(100, expectAsync((PurseWrapper purse) { _checkBalance(purse, 100); purse.sproutPurse(expectAsync((PurseWrapper sprouted) { _checkBalance(sprouted, 0); _checkBalance(purse, 100); sprouted.deposit(purse, 5); _checkBalance(sprouted, 0 + 5); _checkBalance(purse, 100 - 5); sprouted.deposit(purse, 42); _checkBalance(sprouted, 0 + 5 + 42); _checkBalance(purse, 100 - 5 - 42); })); })); })); })); }); }