blob: 1a621665d95bf7595923dec53aaeeec7507a366c [file] [edit]
// 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 'package:jnigen/jnigen.dart' as jnigen;
import 'package:jnigen/src/bindings/linker.dart';
import 'package:jnigen/src/bindings/renamer.dart';
import 'package:jnigen/src/elements/elements.dart' as ast;
import 'package:jnigen/src/elements/j_elements.dart';
import 'package:test/test.dart';
extension on Iterable<ast.Method> {
List<bool> get isExcludedValues =>
map((c) => c.userDefinedIsExcluded).toList();
}
extension on Iterable<ast.Field> {
List<bool> get isExcludedValues => map((c) => c.isExcluded).toList();
}
extension on Iterable<ast.Method> {
List<String> get finalNames => map((m) => m.finalName).toList();
}
extension on Iterable<ast.Param> {
List<String> get finalNames => map((p) => p.finalName).toList();
}
extension on Iterable<ast.Field> {
List<String> get finalNames => map((f) => f.finalName).toList();
}
// This is customizable by the user
class UserExcluder extends Visitor {
@override
void visitClass(ClassDecl c) {
if (c.binaryName.contains('y')) {
c.isExcluded = true;
}
}
@override
void visitMethod(Method method) {
if (method.name == 'Bar') {
method.isExcluded = true;
}
}
@override
void visitField(Field field) {
if (field.name == 'Bar') {
field.isExcluded = true;
}
}
}
// This is customizable by the user
class UserRenamer extends Visitor {
@override
void visitClass(ClassDecl c) {
if (c.originalName.contains('Foo')) {
c.name = c.originalName.replaceAll('Foo', 'Bar');
}
}
@override
void visitMethod(Method method) {
if (method.originalName.contains('Foo')) {
method.name = method.originalName.replaceAll('Foo', 'Bar');
}
if (method.isConstructor) {
method.name = 'constructor';
}
}
@override
void visitField(Field field) {
if (field.originalName.contains('Foo')) {
field.name = field.originalName.replaceAll('Foo', 'Bar');
}
}
@override
void visitParam(Param parameter) {
if (parameter.originalName.contains('Foo')) {
parameter.name = parameter.originalName.replaceAll('Foo', 'Bar');
}
}
}
Future<void> rename(ast.Classes classes) async {
final config = jnigen.Config(
outputConfig: jnigen.OutputConfig(
dartConfig: jnigen.DartCodeOutputConfig(
path: Uri.file('test.dart'),
structure: jnigen.OutputStructure.singleFile,
),
),
classes: []);
await classes.accept(Linker(config));
classes.accept(Renamer(config));
}
void main() {
test('Exclude something using the user excluder, Simple AST', () async {
final classes = ast.Classes({
'Foo': ast.ClassDecl(
binaryName: 'Foo',
declKind: ast.DeclKind.classKind,
superclass: ast.DeclaredType.object,
methods: [
ast.Method(name: 'foo', returnType: ast.DeclaredType.object),
ast.Method(name: 'Bar', returnType: ast.DeclaredType.object),
ast.Method(name: 'foo1', returnType: ast.DeclaredType.object),
ast.Method(name: 'Bar', returnType: ast.DeclaredType.object),
],
fields: [
ast.Field(name: 'foo', type: ast.DeclaredType.object),
ast.Field(name: 'Bar', type: ast.DeclaredType.object),
ast.Field(name: 'foo1', type: ast.DeclaredType.object),
ast.Field(name: 'Bar', type: ast.DeclaredType.object),
],
),
'y.Foo': ast.ClassDecl(
binaryName: 'y.Foo',
declKind: ast.DeclKind.classKind,
superclass: ast.DeclaredType.object,
methods: [
ast.Method(name: 'foo', returnType: ast.DeclaredType.object),
ast.Method(name: 'Bar', returnType: ast.DeclaredType.object),
],
fields: [
ast.Field(name: 'foo', type: ast.DeclaredType.object),
ast.Field(name: 'Bar', type: ast.DeclaredType.object),
]),
});
final simpleClasses = Classes(classes);
simpleClasses.accept(UserExcluder());
expect(classes.decls['y.Foo']?.isExcluded, true);
expect(classes.decls['Foo']?.isExcluded, false);
expect(classes.decls['Foo']?.fields.isExcludedValues,
[false, true, false, true]);
expect(classes.decls['Foo']?.methods.isExcludedValues,
[false, true, false, true]);
});
test('Rename classes, fields, methods and params using the user renamer',
() async {
final classes = ast.Classes({
'Foo': ast.ClassDecl(
binaryName: 'Foo',
declKind: ast.DeclKind.classKind,
superclass: ast.DeclaredType.object,
methods: [
ast.Method(name: 'Foo', returnType: ast.DeclaredType.object),
ast.Method(name: 'Foo', returnType: ast.DeclaredType.object),
ast.Method(name: 'Foo1', returnType: ast.DeclaredType.object),
ast.Method(name: 'Foo1', returnType: ast.DeclaredType.object),
],
fields: [
ast.Field(name: 'Foo', type: ast.DeclaredType.object),
ast.Field(name: 'Foo', type: ast.DeclaredType.object),
ast.Field(name: 'Foo1', type: ast.DeclaredType.object),
ast.Field(name: 'Foo1', type: ast.DeclaredType.object),
],
),
'y.Foo': ast.ClassDecl(
binaryName: 'y.Foo',
declKind: ast.DeclKind.classKind,
superclass: ast.DeclaredType.object,
methods: [
ast.Method(name: 'Foo', returnType: ast.DeclaredType.object, params: [
ast.Param(name: 'Foo', type: ast.DeclaredType.object),
ast.Param(name: 'Foo1', type: ast.DeclaredType.object),
]),
ast.Method(name: '<init>', returnType: ast.DeclaredType.object)
],
),
});
final simpleClasses = Classes(classes);
simpleClasses.accept(UserRenamer());
await rename(classes);
expect(classes.decls['Foo']?.finalName, 'Bar');
expect(classes.decls['y.Foo']?.finalName, r'Bar$1');
expect(classes.decls['Foo']?.fields.finalNames,
['Bar', r'Bar$1', 'Bar1', r'Bar1$1']);
expect(classes.decls['Foo']?.methods.finalNames,
[r'Bar$2', r'Bar$3', r'Bar1$2', r'Bar1$3']);
expect(classes.decls['y.Foo']?.methods.finalNames, [r'Bar', 'constructor']);
expect(classes.decls['y.Foo']?.methods.first.params.finalNames,
['Bar', 'Bar1']);
});
}