// 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:async';
import 'dart:isolate';
import 'dart:typed_data';
import 'package:unittest/unittest.dart';
import "../remote_unittest_helper.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.lengthInBytes; 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;
}

void main([args, port]) {
  if (testRemote(main, port)) return;
  initializeList();
  test("send objects and receive them back", () {
    ReceivePort response = new ReceivePort();
    Isolate.spawn(pingPong, response.sendPort);
    response.first.then((_remote) {
      SendPort remote = _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(expectAsync((var receivedObject) {
          VerifyObject(idx, receivedObject);
        }));
      }

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