// 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.

// Dart test program for testing serialization of messages.
// VMOptions=--enable_type_checks --enable_asserts

library TypedDataMessageTest;
import 'dart:isolate';
import 'dart:typed_data';
import 'package:unittest/unittest.dart';

// ---------------------------------------------------------------------------
// Message passing test.
// ---------------------------------------------------------------------------

List elements;

void initializeList() {
  elements = new List(3);
  elements[0] = new Int8List(10);
  for (int j = 0; j < 10; j++) {
    elements[0][j] = j;
  }
  elements[1] = new ByteData.view(elements[0].buffer, 0, 10);
  for (int j = 0; j < 10; j++) {
    elements[1].setInt8(j, j + 100);
  }
  elements[2] = new Int8List.view(new Int8List(100).buffer, 50, 10);
  for (int j = 0; j < 10; j++) {
    elements[2][j] = j + 250;
  }
}

void VerifyList(List expected, List actual) {
  for (int i = 0; i < expected.length; i++) {
    expect(actual[i], expected[i]);
  }
}

void VerifyBytedata(ByteData expected, ByteData actual) {
  for (int i = 0; i < expected.length; i++) {
    expect(actual.getInt8(i), expected.getInt8(i));
  }
}

void VerifyObject(int index, var actual) {
  var expected = elements[index];
  if (expected is List) {
    expect(actual, isList);
    VerifyList(expected, actual);
  } else {
    expect(true, actual is ByteData);
    VerifyBytedata(expected, actual);
  }
  expect(actual.length, expected.length);
}

pingPong(SendPort initialReplyTo) {
  var port = new ReceivePort();
  initialReplyTo.send(port.sendPort);
  initializeList();
  int count = 0;
  port.listen((var message) {
    var data = message[0];
    SendPort replyTo = message[1];
    if (data == -1) {
      port.close();
      replyTo.send(count);
    } else {
      // Check if the received object is correct.
      if (count < elements.length) {
        VerifyObject(count, data);
      }
      // Bounce the received object back so that the sender
      // can make sure that the object matches.
      replyTo.send(data);
      count++;
    }
  });
}

Future sendReceive(SendPort port, msg) {
  ReceivePort response = new ReceivePort();
  port.send([msg, response.sendPort]);
  return response.first;
}

main() {
  initializeList();
  test("send objects and receive them back", () {
    ReceivePort response = new ReceivePort();
    Isolate.spawn(pingPong, response.sendPort);
    response.first.then((SendPort remote) {
      // Send objects and receive them back.
      for (int i = 0; i < elements.length; i++) {
        var sentObject = elements[i];
        var idx = i;
        sendReceive(remote, sentObject).then(expectAsync1((var receivedObject) {
          VerifyObject(idx, receivedObject);
        }));
      }

      // Shutdown the MessageServer.
      sendReceive(remote, -1).then(expectAsync1((int message) {
          expect(message, elements.length);
        }));
    });
  });
}
