// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// ignore_for_file: implementation_imports
import 'package:lib.app.dart/logging.dart';
import 'package:sledge/src/document/values/map_value.dart';
import 'package:test/test.dart';

import '../crdt_test_framework/crdt_test_framework.dart';
import '../crdt_test_framework/evaluation_order.dart';

// Wraps the construction of Fleet of PosNegCounter.
class MapFleetFactory<K, V> {
  const MapFleetFactory();

  Fleet<MapValue<K, V>> newFleet(int count) {
    return new Fleet<MapValue<K, V>>(count, (index) => new MapValue<K, V>());
  }
}

const MapFleetFactory<int, int> intMapFleetFactory =
    const MapFleetFactory<int, int>();

class ValuesAreUniqueChecker<K, V> extends Checker<MapValue<K, V>> {
  @override
  void check(Map<K, V> m) {
    final valueSet = m.values.toSet();
    expect(m.values.length, equals(valueSet.length));
  }
}

void main() async {
  setupLogger();

  test('Checker fails.', () async {
    final fleet = intMapFleetFactory.newFleet(2)
      ..runInTransaction(0, (MapValue<int, int> m0) async {
        m0[1] = 2;
      })
      ..runInTransaction(0, (MapValue<int, int> m0) async {
        m0[2] = 4;
      })
      ..runInTransaction(1, (MapValue<int, int> m1) async {
        m1[1] = 4;
        m1[2] = 2;
      })
      ..synchronize([0, 1])
      ..addChecker(() => new ValuesAreUniqueChecker<int, int>());
    try {
      await fleet.testAllOrders();
      // If SingleOrderTestFailure wasn't thrown, fail. Note that fail will
      // throw another exception, not caught in the following code.
      fail('Expected testAllOrders to fail.');
    } on SingleOrderTestFailure catch (failure) {
      final nodeIds = failure.order.nodes.map((node) => node.nodeId);
      // Check that the EvaluationOrder is correctly reproduced with the list of
      // nodeIds.
      expect(new EvaluationOrder.fromIds(nodeIds, fleet.graph.nodes),
          equals(failure.order));

      try {
        await fleet.testSingleOrder(order: failure.order);
        // If SingleOrderTestFailure wasn't thrown, fail. Note that fail will
        // throw another exception, not caught in the following code.
        fail('Expected testSingleOrder to fail.');
      } on SingleOrderTestFailure catch (secondFailure) {
        expect(secondFailure.order, equals(failure.order));
      }
    }
  });

  test('Checker fails. Random orders. Random sync.', () async {
    final fleet = intMapFleetFactory.newFleet(2)
      ..runInTransaction(0, (MapValue<int, int> m0) {
        m0[1] = 2;
      })
      ..synchronize([0, 1])
      ..runInTransaction(1, (MapValue<int, int> m1) {
        m1[1] = 4;
        m1[2] = 2;
      })
      ..runInTransaction(0, (MapValue<int, int> m0) {
        m0[2] = 4;
      })
      ..setRandomSynchronizationsRate(1.0)
      ..addChecker(() => new ValuesAreUniqueChecker<int, int>());
    try {
      // 1/2 probability of the correct order.
      // 1/2 probability of synchronization after the last modification.
      // In average, an exception is thrown every 4 runs.
      // With a 100 runs, the probability of not having an exception thrown is:
      // (3/4)^100 < 3.21e-13
      await fleet.testRandomOrders(100);
      // If SingleOrderTestFailure wasn't thrown, fail. Note that fail will
      // throw another exception, not caught in the following code.
      fail('Expected testRandomOrders to fail.');
    } on SingleOrderTestFailure catch (failure) {
      final nodeIds = failure.order.nodes.map((node) => node.nodeId);
      // Check that the EvaluationOrder is correctly reproduced with the list of
      // nodeIds.
      expect(
          new EvaluationOrder.fromIds(nodeIds, fleet.graph.nodes,
              allowGenerated: true),
          equals(failure.order));

      // Check that generated synchronization nodes are also reproduced.
      //
      // If we only keep the order and choose synchronizations randomly,
      // the probability of throwing TestFailure is 1/2.
      // So probability to throw TestFailure 20 times in a row is < 1e-6
      for (int it = 0; it < 20; it++) {
        try {
          await fleet
              .testFixedOrder(failure.order.nodes.map((node) => node.nodeId));
          // If SingleOrderTestFailure wasn't thrown, fail. Note that fail will
          // throw another exception, not caught in the following code.
          fail('Expected testFixedOrder to fail.');
        } on SingleOrderTestFailure catch (doublingFailure) {
          expect(doublingFailure.order, equals(failure.order));
        }
      }
    }
  });
}
