blob: acae8f2f9a30ddb4def6ff365897634f9865c641 [file]
// Copyright (c) 2024, 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.
import 'dart:convert';
import 'package:dart_model/dart_model.dart';
import 'package:test/test.dart';
void main() {
group('Model', () {
late Model model;
setUp(() {
Scope.macro.run(() {
model = Model()
..uris['package:dart_model/dart_model.dart'] = (Library()
..scopes['JsonData'] = (Interface(
properties: Properties(isClass: true), metadataAnnotations: [])
..members['_root'] = Member(
properties: Properties(isField: true, isStatic: false),
)));
});
});
final expected = {
'uris': {
'package:dart_model/dart_model.dart': {
'scopes': {
'JsonData': {
'metadataAnnotations': <Map<String, Object?>>[],
'members': {
'_root': {
'properties': {'isField': true, 'isStatic': false}
}
},
'properties': {'isClass': true}
}
}
}
}
};
test('maps to JSON', () {
expect(model as Map, expected);
});
test('maps to JSON after deserialization', () {
final deserializedModel = Model.fromJson(
json.decode(json.encode(model as Map)) as Map<String, Object?>);
expect(deserializedModel as Map, expected);
});
test('maps can be accessed as fields', () {
expect(model.uris['package:dart_model/dart_model.dart'],
expected['uris']!['package:dart_model/dart_model.dart']);
expect(
model.uris['package:dart_model/dart_model.dart']!.scopes['JsonData'],
expected['uris']!['package:dart_model/dart_model.dart']!['scopes']![
'JsonData']);
expect(
model.uris['package:dart_model/dart_model.dart']!.scopes['JsonData']!
.properties,
expected['uris']!['package:dart_model/dart_model.dart']!['scopes']![
'JsonData']!['properties']);
});
test('maps can be accessed as fields after deserialization', () {
final deserializedModel = Model.fromJson(
json.decode(json.encode(model as Map)) as Map<String, Object?>);
expect(
deserializedModel.uris['package:dart_model/dart_model.dart']!
.scopes['JsonData']!.properties,
expected['uris']!['package:dart_model/dart_model.dart']!['scopes']![
'JsonData']!['properties']);
});
test('lists can be accessed as fields', () {
expect(
model.uris['package:dart_model/dart_model.dart']!.scopes['JsonData']!
.members,
expected['uris']!['package:dart_model/dart_model.dart']!['scopes']![
'JsonData']!['members']);
});
test('lists can be accessed as fields after deserialization', () {
final deserializedModel = Model.fromJson(
json.decode(json.encode(model as Map)) as Map<String, Object?>);
expect(
deserializedModel.uris['package:dart_model/dart_model.dart']!
.scopes['JsonData']!.members,
expected['uris']!['package:dart_model/dart_model.dart']!['scopes']![
'JsonData']!['members']);
});
test('can give the path to Interfaces in buffer backed maps', () {
final interface =
model.uris['package:dart_model/dart_model.dart']!.scopes['JsonData']!;
expect(model.qualifiedNameOf(interface.node)!.asString,
'package:dart_model/dart_model.dart#JsonData');
});
test('can give the path to Members in buffer backed maps', () {
final member = model.uris['package:dart_model/dart_model.dart']!
.scopes['JsonData']!.members['_root']!;
expect(model.qualifiedNameOf(member.node)!.asString,
'package:dart_model/dart_model.dart#JsonData._root');
});
test('can give the path to Interfaces in SDK maps', () {
final copiedModel = Model.fromJson(_copyMap(model.node));
final interface = copiedModel
.uris['package:dart_model/dart_model.dart']!.scopes['JsonData']!;
expect(copiedModel.qualifiedNameOf(interface.node)!.asString,
'package:dart_model/dart_model.dart#JsonData');
});
test('can give the path to Members in SDK maps', () {
final copiedModel = Model.fromJson(_copyMap(model.node));
final member = copiedModel.uris['package:dart_model/dart_model.dart']!
.scopes['JsonData']!.members['_root']!;
expect(copiedModel.qualifiedNameOf(member.node)!.asString,
'package:dart_model/dart_model.dart#JsonData._root');
});
test('can give the path to Members in merged maps', () {
late final Member fooMember;
late final Model otherModel;
/// Create one model in a different scope so it gets a different buffer.
Scope.query.run(() {
otherModel = Model()
..uris['package:dart_model/dart_model.dart'] = (Library()
..scopes['JsonData'] = (Interface()
..members['foo'] =
Member(properties: Properties(isStatic: true))));
fooMember = otherModel.uris['package:dart_model/dart_model.dart']!
.scopes['JsonData']!.members['foo']!;
});
Scope.macro.run(() {
final rootMember = model.uris['package:dart_model/dart_model.dart']!
.scopes['JsonData']!.members['_root']!;
final mergedModel = model.mergeWith(otherModel);
expect(mergedModel.qualifiedNameOf(rootMember.node)!.asString,
'package:dart_model/dart_model.dart#JsonData._root');
expect(mergedModel.qualifiedNameOf(fooMember.node)!.asString,
'package:dart_model/dart_model.dart#JsonData::foo');
expect(model.qualifiedNameOf(fooMember.node), null);
expect(otherModel.qualifiedNameOf(rootMember.node), null);
});
});
test('path to Members works for cycles', () {
final copiedModel = Model.fromJson(_copyMap(model.node));
// Add an invalid link creating a loop in the map structure.
(copiedModel.node['uris'] as Map<String, Object?>)['loop'] = copiedModel;
final member = copiedModel.uris['package:dart_model/dart_model.dart']!
.scopes['JsonData']!.members['_root']!;
expect(
copiedModel.qualifiedNameOf(member.node),
QualifiedName(
uri: 'package:dart_model/dart_model.dart',
scope: 'JsonData',
name: '_root',
isStatic: false,
));
});
test('path to Members works for reused node', () {
final copiedModel = Model.fromJson(_copyMap(model.node));
// Reuse a node.
copiedModel.uris['duplicate'] =
copiedModel.uris['package:dart_model/dart_model.dart']!;
final member = copiedModel.uris['package:dart_model/dart_model.dart']!
.scopes['JsonData']!.members['_root']!;
expect(
copiedModel.qualifiedNameOf(member.node),
QualifiedName(
uri: 'package:dart_model/dart_model.dart',
scope: 'JsonData',
name: '_root',
isStatic: false,
));
});
test('path to Member returns null for Member in wrong Map', () {
final copiedModel = Model.fromJson(_copyMap(model.node));
final member = model.uris['package:dart_model/dart_model.dart']!
.scopes['JsonData']!.members['_root']!;
final copiedMember = Member.fromJson(_copyMap(model
.uris['package:dart_model/dart_model.dart']!
.scopes['JsonData']!
.members['_root']!
.node));
expect(copiedModel.qualifiedNameOf(member.node), null);
expect(model.qualifiedNameOf(copiedMember.node), null);
});
test('can produce and compare digests for buffer and SDK maps', () {
final copiedModel = Model.fromJson(_copyMap(model.node));
expect(model.digest, copiedModel.digest);
});
});
group('QualifiedName', () {
test('asString', () {
expect(QualifiedName(uri: 'package:foo/foo.dart', name: 'Foo').asString,
'package:foo/foo.dart#Foo');
expect(
QualifiedName(
uri: 'package:foo/foo.dart',
name: 'bar',
scope: 'Foo',
isStatic: false)
.asString,
'package:foo/foo.dart#Foo.bar');
expect(
QualifiedName(
uri: 'package:foo/foo.dart',
name: 'baz',
scope: 'Foo',
isStatic: true)
.asString,
'package:foo/foo.dart#Foo::baz');
});
test('parse', () {
expect(QualifiedName.parse('package:foo/foo.dart#Foo').uri,
'package:foo/foo.dart');
expect(QualifiedName.parse('package:foo/foo.dart#Foo').name, 'Foo');
final fooBar = QualifiedName.parse('package:foo/foo.dart#Foo.bar');
expect(fooBar.name, 'bar');
expect(fooBar.scope, 'Foo');
expect(fooBar.isStatic, false);
final fooBaz = QualifiedName.parse('package:foo/foo.dart#Foo::baz');
expect(fooBaz.name, 'baz');
expect(fooBaz.scope, 'Foo');
expect(fooBaz.isStatic, true);
});
});
}
Map<String, Object?> _copyMap(Map<String, Object?> map) {
final result = <String, Object?>{};
for (final entry in map.entries) {
if (entry.value is Map<String, Object?>) {
result[entry.key] = _copyMap(entry.value as Map<String, Object?>);
} else {
result[entry.key] = entry.value;
}
}
return result;
}