// Copyright (c) 2017, 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 = 2.9

import 'dart:convert';
import 'dart:io';

import 'package:kernel/ast.dart';
import 'package:kernel/binary/ast_from_binary.dart';
import 'package:kernel/binary/ast_to_binary.dart';
import 'package:kernel/text/ast_to_text.dart';
import 'package:test/test.dart';
import 'package:front_end/src/compute_platform_binaries_location.dart'
    show computePlatformBinariesLocation;

/// Test metadata: to each node we attach a metadata that contains
/// * node formatted as string
/// * reference to its enclosing member
/// * type representing the first type parameter of its enclosing function
class Metadata {
  final String string;
  final Reference _memberRef;
  final DartType type;

  Member get member => _memberRef?.asMember;

  Metadata.forNode(TreeNode n)
      : this(
            n.leakingDebugToString(),
            // Refers to the member, not about the function => use getter.
            getMemberReferenceGetter(getMemberForMetadata(n)),
            getTypeForMetadata(n));

  Metadata(this.string, this._memberRef, this.type);
}

Member getMemberForMetadata(TreeNode node) {
  final parent = node.parent;
  if (parent == null) return null;
  if (parent is Member) return parent;
  return getMemberForMetadata(parent);
}

DartType getTypeForMetadata(TreeNode node) {
  final parent = node.parent;
  if (parent == null) return const VoidType();
  if (parent is FunctionNode) {
    if (parent.typeParameters.isEmpty) {
      return const VoidType();
    }
    return new TypeParameterType(parent.typeParameters[0], Nullability.legacy);
  }
  return getTypeForMetadata(parent);
}

class TestMetadataRepository extends MetadataRepository<Metadata> {
  static const kTag = 'kernel.metadata.test';

  final String tag = kTag;

  final Map<TreeNode, Metadata> mapping = <TreeNode, Metadata>{};

  void writeToBinary(Metadata metadata, Node node, BinarySink sink) {
    expect(metadata, equals(mapping[node]));
    sink.writeByteList(utf8.encode(metadata.string));
    sink.writeStringReference(metadata.string);
    sink.writeNullAllowedCanonicalNameReference(
        metadata.member?.reference?.canonicalName);
    sink.writeDartType(metadata.type);
  }

  Metadata readFromBinary(Node node, BinarySource source) {
    final string1 = utf8.decode(source.readByteList());
    final string2 = source.readStringReference();
    final memberRef = source.readNullableCanonicalNameReference()?.reference;
    final type = source.readDartType();
    expect(string1, equals(string2));
    return new Metadata(string2, memberRef, type);
  }
}

class BytesBuilderSink implements Sink<List<int>> {
  final builder = new BytesBuilder(copy: false);

  @override
  void add(List<int> bytes) {
    builder.add(bytes);
  }

  @override
  void close() {}
}

typedef NodePredicate = bool Function(TreeNode node);

/// Visitor calling [handle] function on every node which can have metadata
/// associated with it and also satisfies the given [predicate].
class Visitor extends RecursiveVisitor {
  final NodePredicate predicate;
  final void Function(TreeNode) handle;

  Visitor(this.predicate, this.handle);

  defaultTreeNode(TreeNode node) {
    super.defaultTreeNode(node);
    if (MetadataRepository.isSupported(node) && predicate(node)) {
      handle(node);
    }
  }
}

/// Visit the given component assigning [Metadata] object created with
/// [Metadata.forNode] to each supported node in the component which matches
/// [shouldAnnotate] predicate.
void annotate(Component p, NodePredicate shouldAnnotate) {
  globalDebuggingNames = new NameSystem();
  final repository = p.metadata[TestMetadataRepository.kTag];
  p.accept(new Visitor(shouldAnnotate, (node) {
    repository.mapping[node] = new Metadata.forNode(node);
  }));
}

/// Visit the given component and checks that each supported node in the
/// component matching [shouldAnnotate] predicate has correct metadata.
void validate(Component p, NodePredicate shouldAnnotate) {
  globalDebuggingNames = new NameSystem();
  final repository = p.metadata[TestMetadataRepository.kTag];
  p.accept(new Visitor(shouldAnnotate, (node) {
    final m = repository.mapping[node];
    final expected = new Metadata.forNode(node);

    expect(m, isNotNull);
    expect(m.string, equals(expected.string));
    expect(m.member, equals(expected.member));
    expect(m.type, equals(expected.type));
  }));
}

Component fromBinary(List<int> bytes) {
  var component = new Component();
  component.addMetadataRepository(new TestMetadataRepository());
  new BinaryBuilderWithMetadata(bytes).readComponent(component);
  return component;
}

List<int> toBinary(Component p) {
  final sink = new BytesBuilderSink();
  new BinaryPrinter(sink).writeComponentFile(p);
  return sink.builder.takeBytes();
}

main() async {
  bool anyNode(TreeNode node) => true;
  bool onlyMethods(TreeNode node) =>
      node is Procedure &&
      node.kind == ProcedureKind.Method &&
      node.enclosingClass != null;

  final Uri platform = computePlatformBinariesLocation(forceBuildDir: true)
      .resolve("vm_platform_strong.dill");
  final List<int> platformBinary =
      await new File(platform.toFilePath()).readAsBytes();

  Future<void> testRoundTrip(List<int> Function(List<int>) binaryTransformer,
      NodePredicate shouldAnnotate) async {
    final component = fromBinary(platformBinary);
    annotate(component, shouldAnnotate);
    validate(component, shouldAnnotate);
    expect(component.metadata[TestMetadataRepository.kTag].mapping.length,
        greaterThan(0));

    final annotatedComponentBinary = binaryTransformer(toBinary(component));
    final annotatedComponentFromBinary = fromBinary(annotatedComponentBinary);
    validate(annotatedComponentFromBinary, shouldAnnotate);
    expect(
        annotatedComponentFromBinary
            .metadata[TestMetadataRepository.kTag].mapping.length,
        greaterThan(0));
  }

  test('annotate-serialize-deserialize-validate', () async {
    await testRoundTrip((binary) => binary, anyNode);
  });

  test('annotate-serialize-deserialize-validate-only-methods', () async {
    await testRoundTrip((binary) => binary, onlyMethods);
  });

  test('annotate-serialize-deserialize-twice-then-validate', () async {
    // This test validates that serializing a component that was just
    // deserialized (without visiting anything) works.
    await testRoundTrip((binary) => toBinary(fromBinary(binary)), anyNode);
  });

  test('annotate-serialize-deserialize-twice-then-validate-only-methods',
      () async {
    // This test validates that serializing a component that was just
    // deserialized (without visiting anything) works.
    await testRoundTrip((binary) => toBinary(fromBinary(binary)), onlyMethods);
  });
}
