// Copyright (c) 2022, 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.

// Tests that Kernel Dump Info matches the original Dump Info's output after
// filtering non-live blocks.

// @dart = 2.7

import 'dart:convert';
import 'dart:io';
import 'package:_fe_analyzer_shared/src/testing/features.dart';
import 'package:async_helper/async_helper.dart';
import 'package:compiler/src/compiler.dart';
import 'package:compiler/src/dump_info.dart';
import 'package:compiler/src/elements/entities.dart';
import 'package:compiler/src/js_model/element_map.dart';
import 'package:compiler/src/js_model/js_world.dart';
import 'package:dart2js_info/info.dart' as info;
import 'package:dart2js_info/json_info_codec.dart' as info;
import 'package:kernel/ast.dart' as ir;
import '../equivalence/id_equivalence.dart';
import '../equivalence/id_equivalence_helper.dart';

final JsonEncoder encoder = const JsonEncoder();
final JsonEncoder indentedEncoder = const JsonEncoder.withIndent('  ');

String jsonEncode(Map object, {bool indent = true}) {
  final jsonEncoder = indent ? indentedEncoder : encoder;
  final transformedObject = transformJsonObjectForComparison(object);
  // Filter block comments since they interfere with ID test comments.
  final json = jsonEncoder
      .convert(transformedObject)
      .replaceAll('/*', '')
      .replaceAll('*/', '');
  return json;
}

/// Transforms a new DumpInfo or old DumpInfo object into a format that allows
/// for easier comparison.
Map transformJsonObjectForComparison(Map object) {
  Map newObject = {};
  object.forEach((key, value) {
    if (value == null) {
      newObject[key] = value;
      return;
    }

    dynamic newValue = value;
    // Ignore type fields since K-World and J-World type strings are
    // non-trivially different (though semantically identical).
    if (key == 'type' || key == 'returnType' || key == 'name') {
      return;
    }

    // Ignore sizes for output units, as these deviate by some constant when
    // `--new-dump-info` is enabled.
    if (object['kind'] == 'outputUnit' && key == 'size') {
      return;
    }

    // Remove disambiguation portions of names. E.g., name%N -> name.
    if (key == 'id' || key == 'name' || key == 'function' || key == 'parent') {
      newValue = value.replaceAll(RegExp(r'%\d+'), '');
    } else if (key == 'children') {
      List values = object[key];
      newValue =
          values.map((name) => name.replaceAll(RegExp(r'%\d+'), '')).toList();
    }

    newObject[key] = newValue;
  });
  return newObject;
}

Map filteredJsonObject(Map object, Set<String> filteredFields) {
  Map filteredObject = {};
  object.forEach((key, value) {
    if (filteredFields.contains(key)) return;
    filteredObject[key] = value;
  });
  return filteredObject;
}

void main(List<String> args) {
  // Do not allow these tests to regenerate annotations.
  final filteredArgs =
      args.where((arg) => arg != '--g' && arg != '--generate').toList();

  asyncTest(() async {
    Directory dataDir = Directory.fromUri(Platform.script.resolve('data'));
    print('Testing output of new-dump-info');
    print('==================================================================');
    await checkTests(dataDir, const DumpInfoDataComputer(),
        args: filteredArgs,
        testedConfigs: allSpecConfigs,
        options: ['--dump-info', '--new-dump-info', '--enable-asserts']);
  });
}

class Tags {
  static const String library = 'library';
  static const String clazz = 'class';
  static const String classType = 'classType';
  static const String closure = 'closure';
  static const String function = 'function';
  static const String typeDef = 'typedef';
  static const String field = 'field';
  static const String constant = 'constant';
  static const String holding = 'holding';
  static const String dependencies = 'dependencies';
  static const String outputUnits = 'outputUnits';
  static const String deferredFiles = 'deferredFiles';
}

class DumpInfoDataComputer extends DataComputer<Features> {
  const DumpInfoDataComputer();

  static const String wildcard = '%';

  @override
  void computeLibraryData(Compiler compiler, LibraryEntity library,
      Map<Id, ActualData<Features>> actualMap,
      {bool verbose}) {
    final converter = info.AllInfoToJsonConverter(isBackwardCompatible: true);
    DumpInfoStateData dumpInfoState = compiler.dumpInfoStateForTesting;
    TreeShakingInfoVisitor().filter(dumpInfoState.info);

    final features = Features();
    final libraryInfo = dumpInfoState.entityToInfo[library];
    if (libraryInfo == null) return;

    features.addElement(
        Tags.library, jsonEncode(libraryInfo.accept(converter)));

    // Store program-wide information on the main library.
    final name = '${library.canonicalUri.pathSegments.last}';
    if (name.startsWith('main')) {
      for (final constantInfo in dumpInfoState.info.constants) {
        features.addElement(
            Tags.constant, jsonEncode(constantInfo.accept(converter)));
      }
      features.addElement(
          Tags.dependencies, jsonEncode(dumpInfoState.info.dependencies));
      for (final outputUnit in dumpInfoState.info.outputUnits) {
        var outputUnitJsonObject = outputUnit.accept(converter);
        // Remove the size from output units due to high noise ratio.
        outputUnitJsonObject =
            filteredJsonObject(outputUnitJsonObject, {'size'});
        features.addElement(Tags.outputUnits, jsonEncode(outputUnitJsonObject));
      }
      features.addElement(
          Tags.deferredFiles, jsonEncode(dumpInfoState.info.deferredFiles));
    }

    final id = LibraryId(library.canonicalUri);
    actualMap[id] =
        ActualData<Features>(id, features, library.canonicalUri, -1, library);
  }

  @override
  void computeClassData(Compiler compiler, ClassEntity cls,
      Map<Id, ActualData<Features>> actualMap,
      {bool verbose: false}) {
    final converter = info.AllInfoToJsonConverter(isBackwardCompatible: true);
    DumpInfoStateData dumpInfoState = compiler.dumpInfoStateForTesting;
    TreeShakingInfoVisitor().filter(dumpInfoState.info);

    final features = Features();
    final classInfo = dumpInfoState.entityToInfo[cls];
    if (classInfo == null) return;

    features.addElement(Tags.clazz, jsonEncode(classInfo.accept(converter)));
    final classTypeInfos =
        dumpInfoState.info.classTypes.where((i) => i.name == classInfo.name);
    assert(
        classTypeInfos.length < 2,
        'Ambiguous class type info resolution. '
        'Expected 0 or 1 elements, found: $classTypeInfos');
    if (classTypeInfos.length == 1) {
      features.addElement(
          Tags.classType, jsonEncode(classTypeInfos.first.accept(converter)));
    }

    JsClosedWorld closedWorld = compiler.backendClosedWorldForTesting;
    JsToElementMap elementMap = closedWorld.elementMap;
    ir.Class node = elementMap.getClassDefinition(cls).node;
    ClassId id = ClassId(node.name);
    ir.TreeNode nodeWithOffset = computeTreeNodeWithOffset(node);
    actualMap[id] = ActualData<Features>(id, features,
        nodeWithOffset?.location?.file, nodeWithOffset?.fileOffset, cls);
  }

  @override
  void computeMemberData(Compiler compiler, MemberEntity member,
      Map<Id, ActualData<Features>> actualMap,
      {bool verbose: false}) {
    final converter = info.AllInfoToJsonConverter(isBackwardCompatible: true);
    DumpInfoStateData dumpInfoState = compiler.dumpInfoStateForTesting;
    TreeShakingInfoVisitor().filter(dumpInfoState.info);

    final features = Features();
    final functionInfo = dumpInfoState.entityToInfo[member];
    if (functionInfo == null ||
        functionInfo.treeShakenStatus != info.TreeShakenStatus.Live) return;

    if (functionInfo is info.FunctionInfo) {
      features.addElement(
          Tags.function, jsonEncode(functionInfo.accept(converter)));
      for (final use in functionInfo.uses) {
        features.addElement(Tags.holding,
            jsonEncode(converter.visitDependencyInfo(use), indent: false));
      }
      for (final closure in functionInfo.closures) {
        features.addElement(
            Tags.closure, jsonEncode(closure.accept(converter)));
        features.addElement(
            Tags.function, jsonEncode(closure.function.accept(converter)));
      }
    }

    if (functionInfo is info.FieldInfo) {
      features.addElement(
          Tags.function, jsonEncode(functionInfo.accept(converter)));
      for (final use in functionInfo.uses) {
        features.addElement(Tags.holding,
            jsonEncode(converter.visitDependencyInfo(use), indent: false));
      }
      for (final closure in functionInfo.closures) {
        features.addElement(
            Tags.closure, jsonEncode(closure.accept(converter)));
        features.addElement(
            Tags.function, jsonEncode(closure.function.accept(converter)));
      }
    }

    JsClosedWorld closedWorld = compiler.backendClosedWorldForTesting;
    JsToElementMap elementMap = closedWorld.elementMap;
    ir.Member node = elementMap.getMemberDefinition(member).node;
    Id id = computeMemberId(node);
    ir.TreeNode nodeWithOffset = computeTreeNodeWithOffset(node);
    actualMap[id] = ActualData<Features>(id, features,
        nodeWithOffset?.location?.file, nodeWithOffset?.fileOffset, member);
  }

  @override
  DataInterpreter<Features> get dataValidator =>
      const JsonFeaturesDataInterpreter(wildcard: wildcard);
}

/// Feature interpreter for Features with Json values.
///
/// The data annotation reader conserves whitespace visually while ignoring
/// them during comparison.
class JsonFeaturesDataInterpreter implements DataInterpreter<Features> {
  final String wildcard;
  const JsonFeaturesDataInterpreter({this.wildcard});

  @override
  String isAsExpected(Features actualFeatures, String expectedData) {
    if (wildcard != null && expectedData == wildcard) {
      return null;
    } else if (expectedData == '') {
      return actualFeatures.isNotEmpty ? "Expected empty data." : null;
    } else {
      List<String> errorsFound = [];
      Features expectedFeatures = Features.fromText(expectedData);
      Set<String> validatedFeatures = Set<String>();
      expectedFeatures.forEach((String key, Object expectedValue) {
        validatedFeatures.add(key);
        Object actualValue = actualFeatures[key];
        if (!actualFeatures.containsKey(key)) {
          errorsFound.add('No data found for $key');
        } else if (expectedValue == '') {
          if (actualValue != '') {
            errorsFound.add('Non-empty data found for $key');
          }
        } else if (wildcard != null && expectedValue == wildcard) {
          return;
        } else if (expectedValue is List) {
          if (actualValue is List) {
            List actualList = actualValue.toList();
            for (Object expectedObject in expectedValue) {
              String expectedText =
                  jsonEncode(jsonDecode(expectedObject), indent: false);
              bool matchFound = false;
              if (wildcard != null && expectedText.endsWith(wildcard)) {
                // Wildcard matcher.
                String prefix =
                    expectedText.substring(0, expectedText.indexOf(wildcard));
                List matches = [];
                for (Object actualObject in actualList) {
                  final formattedActualObject =
                      jsonEncode(jsonDecode(actualObject), indent: false);
                  if (formattedActualObject.startsWith(prefix)) {
                    matches.add(actualObject);
                    matchFound = true;
                  }
                }
                for (Object match in matches) {
                  actualList.remove(match);
                }
              } else {
                for (Object actualObject in actualList) {
                  final formattedActualObject =
                      jsonEncode(jsonDecode(actualObject), indent: false);
                  if (expectedText == formattedActualObject) {
                    actualList.remove(actualObject);
                    matchFound = true;
                    break;
                  }
                }
              }
              if (!matchFound) {
                errorsFound.add("No match found for $key=[$expectedText]");
              }
            }
            if (actualList.isNotEmpty) {
              errorsFound
                  .add("Extra data found $key=[${actualList.join(',')}]");
            }
          } else {
            errorsFound.add("List data expected for $key: "
                "expected '$expectedValue', found '${actualValue}'");
          }
        } else if (expectedValue != actualValue) {
          errorsFound.add("Mismatch for $key: expected '$expectedValue', "
              "found '${actualValue}'");
        }
      });
      actualFeatures.forEach((String key, Object value) {
        if (!validatedFeatures.contains(key)) {
          if (value == '') {
            errorsFound.add("Extra data found '$key'");
          } else {
            errorsFound.add("Extra data found $key=$value");
          }
        }
      });
      return errorsFound.isNotEmpty ? errorsFound.join('\n ') : null;
    }
  }

  @override
  String getText(Features actualData, [String indentation]) {
    return actualData.getText(indentation);
  }

  @override
  bool isEmpty(Features actualData) {
    return actualData == null || actualData.isEmpty;
  }
}
