// 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?.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);
  });
}
