blob: d8d6081963bd92c1c7bb72132607973c251f7d75 [file] [log] [blame] [edit]
// Copyright (c) 2023, 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.
// These tests validate individual characteristics in summary
// For example, the values of methods, arguments, types, generic params etc...
// ignore: library_annotations
@Tags(['summarizer_test'])
import 'package:jnigen/src/elements/elements.dart';
import 'package:jnigen/src/summary/summary.dart';
import 'package:test/test.dart';
import 'test_util/summary_util.dart';
import 'test_util/test_util.dart';
const jnigenPackage = 'com.github.dart_lang.jnigen';
const simplePackage = '$jnigenPackage.simple_package';
extension on Classes {
ClassDecl getClassBySimpleName(String simpleName) {
return decls.values.firstWhere((c) => c.name == simpleName);
}
ClassDecl getClass(String dirName, String className) {
return decls['$jnigenPackage.$dirName.$className']!;
}
ClassDecl getExampleClass() {
return getClass('simple_package', 'Example');
}
}
extension on ClassDecl {
Method getMethod(String name) => methods.firstWhere((m) => m.name == name);
Field getField(String name) => fields.firstWhere((f) => f.name == name);
}
void registerCommonTests(Classes classes) {
test('static modifier', () {
final example = classes.getExampleClass();
final containsStatic = contains('static');
final notContainsStatic = isNot(containsStatic);
expect(example.getMethod('max4').modifiers, containsStatic);
expect(example.getMethod('getCodename').modifiers, notContainsStatic);
expect(example.getField('ON').modifiers, containsStatic);
expect(example.getField('codename').modifiers, notContainsStatic);
final nested = classes.getClassBySimpleName('Example\$Nested');
expect(nested.modifiers, containsStatic);
final nonStaticNested =
classes.getClassBySimpleName('Example\$NonStaticNested');
expect(nonStaticNested.modifiers, notContainsStatic);
});
test('Public, protected and private modifiers', () {
final example = classes.getExampleClass();
final hasPrivate = contains('private');
final hasProtected = contains('protected');
final hasPublic = contains('public');
final isPrivate = allOf(hasPrivate, isNot(hasProtected), isNot(hasPublic));
final isProtected =
allOf(isNot(hasPrivate), hasProtected, isNot(hasPublic));
final isPublic = allOf(isNot(hasPrivate), isNot(hasProtected), hasPublic);
expect(example.getMethod('getNumber').modifiers, isPublic);
expect(example.getMethod('privateMethod').modifiers, isPrivate);
expect(example.getMethod('protectedMethod').modifiers, isProtected);
expect(example.getField('OFF').modifiers, isPublic);
expect(example.getField('number').modifiers, isPrivate);
expect(example.getField('protectedField').modifiers, isProtected);
});
test('final modifier', () {
final example = classes.getExampleClass();
final isFinal = contains('final');
expect(example.getField('PI').modifiers, isFinal);
expect(example.getField('unusedRandom').modifiers, isFinal);
expect(example.getField('number').modifiers, isNot(isFinal));
expect(example.getMethod('finalMethod').modifiers, isFinal);
});
void assertToBeStringListType(TypeUsage listType) {
expect(listType.kind, equals(Kind.declared));
final listClassType = listType.type as DeclaredType;
expect(listClassType.binaryName, equals('java.util.List'));
expect(listClassType.params, hasLength(1));
final listTypeParam = listClassType.params[0];
expect(listTypeParam.kind, equals(Kind.declared));
expect(listTypeParam.type.name, equals('java.lang.String'));
}
test('return types', () {
final example = classes.getExampleClass();
expect(example.getMethod('getNumber').returnType.shorthand, equals('int'));
expect(example.getMethod('getName').returnType.shorthand,
equals('java.lang.String'));
expect(example.getMethod('getNestedInstance').returnType.name,
equals('$simplePackage.Example\$Nested'));
final listType = example.getMethod('getList').returnType;
assertToBeStringListType(listType);
});
test('parameter types', () {
final example = classes.getExampleClass();
final joinStrings = example.getMethod('joinStrings');
final listType = joinStrings.params[0].type;
assertToBeStringListType(listType);
final stringType = joinStrings.params[1].type;
expect(stringType.kind, Kind.declared);
expect((stringType.type as DeclaredType).binaryName, 'java.lang.String');
});
test('Parameters of several types', () {
final example = classes.getExampleClass();
final method = example.getMethod('methodWithSeveralParams');
expect(method.typeParams, hasLength(1));
expect(method.typeParams[0].name, 'T');
expect(method.typeParams[0].bounds[0].name, 'java.lang.CharSequence');
final charParam = method.params[0];
expect(charParam.type.kind, equals(Kind.primitive));
expect(charParam.type.name, equals('char'));
final stringParam = method.params[1];
expect(stringParam.type.kind, equals(Kind.declared));
expect((stringParam.type.type as DeclaredType).binaryName,
equals('java.lang.String'));
final arrayParam = method.params[2];
expect(arrayParam.type.kind, equals(Kind.array));
expect((arrayParam.type.type as ArrayType).type.name, equals('int'));
final typeVarParam = method.params[3];
expect(typeVarParam.type.kind, equals(Kind.typeVariable));
expect((typeVarParam.type.type as TypeVar).name, equals('T'));
final listParam = method.params[4];
expect(listParam.type.kind, equals(Kind.declared));
final listType = listParam.type.type as DeclaredType;
expect(listType.binaryName, equals('java.util.List'));
expect(listType.params, hasLength(1));
final tType = listType.params[0];
expect(tType.kind, Kind.typeVariable);
expect((tType.type as TypeVar).name, equals('T'));
final wildcardMapParam = method.params[5];
expect(wildcardMapParam.type.kind, equals(Kind.declared));
final mapType = wildcardMapParam.type.type as DeclaredType;
expect(mapType.binaryName, equals('java.util.Map'));
expect(mapType.params, hasLength(2));
final strType = mapType.params[0];
expect(strType.name, 'java.lang.String');
// TODO(#141): Wildcard implementation.
/*
final wildcardType = mapType.params[1];
expect(wildcardType.kind, equals(Kind.wildcard));
expect((wildcardType.type as Wildcard).extendsBound?.name,
equals('java.lang.CharSequence'));
*/
});
test('superclass', () {
final baseClass = classes.getClass('inheritance', 'BaseClass');
expect(baseClass.typeParams, hasLength(1));
final typeParam = baseClass.typeParams.single;
expect(typeParam.bounds.map((b) => b.name).toList(),
['java.lang.CharSequence']);
final specific = classes.getClass('inheritance', 'SpecificDerivedClass');
expect(specific.typeParams, hasLength(0));
expect(specific.superclass, isNotNull);
final specificSuper = specific.superclass!.type as DeclaredType;
expect(specificSuper.params[0].type, isA<DeclaredType>());
expect(specificSuper.params[0].type.name, equals('java.lang.String'));
final generic = classes.getClass('inheritance', 'GenericDerivedClass');
expect(generic.typeParams, hasLength(1));
expect(generic.typeParams[0].name, equals('T'));
expect(generic.typeParams[0].bounds.map((b) => b.name).toList(),
['java.lang.CharSequence']);
expect(generic.superclass, isNotNull);
final genericSuper = generic.superclass!.type as DeclaredType;
expect(genericSuper.params[0].type, isA<TypeVar>());
expect(genericSuper.params[0].type.name, equals('T'));
});
test('constructor is included', () {
final example = classes.getExampleClass();
void assertOneCtorExistsWithArity(List<String> paramTypes) {
final arityCtors = example.methods
.where(
(m) => m.name == '<init>' && m.params.length == paramTypes.length)
.toList();
expect(arityCtors, hasLength(1));
final ctor = arityCtors[0];
expect(ctor.params.map((p) => p.type.name), equals(paramTypes));
}
assertOneCtorExistsWithArity([]);
assertOneCtorExistsWithArity(['int']);
assertOneCtorExistsWithArity(['int', 'boolean']);
assertOneCtorExistsWithArity(['int', 'boolean', 'java.lang.String']);
});
test('Overloaded methods', () {
final methods = classes
.getExampleClass()
.methods
.where((m) => m.name == 'overloaded')
.toList();
final signatures =
methods.map((m) => m.params.map((p) => p.type.name).toList()).toSet();
expect(
signatures,
equals({
<String>[],
['int'],
['int', 'java.lang.String'],
['java.util.List'],
['java.util.List', 'java.lang.String'],
}),
);
});
test('Declaration type (class vs interface vs enum)', () {
final example = classes.getExampleClass();
expect(example.declKind, DeclKind.classKind);
final myInterface = classes.getClass('interfaces', 'MyInterface');
expect(myInterface.declKind, DeclKind.interfaceKind);
final color = classes.getClass('simple_package', 'Color');
expect(color.declKind, DeclKind.enumKind);
});
test('Enum values', () {
final example = classes.getExampleClass();
expect(example.values, anyOf(isNull, isEmpty));
final color = classes.getClass('simple_package', 'Color');
const expectedEnumValues = {
'RED',
'BLUE',
'BLACK',
'GREEN',
'YELLOW',
'LIME'
};
expect(color.values?.toSet(), expectedEnumValues);
});
test('Static final field values', () {
final example = classes.getExampleClass();
expect(example.getField('ON').defaultValue, equals(1));
expect(example.getField('OFF').defaultValue, equals(0));
expect(example.getField('PI').defaultValue, closeTo(3.14159, 0.001));
expect(
example.getField('SEMICOLON').defaultValue, equals(';'.codeUnitAt(0)));
expect(example.getField('SEMICOLON_STRING').defaultValue, equals(';'));
});
test('self referencing generic parameters', () {
final gp = classes.getClass('generics', 'GenericTypeParams');
final typeParams = gp.typeParams;
expect(typeParams[0].name, equals('S'));
expect(typeParams[0].bounds.map((e) => e.name), ['java.lang.CharSequence']);
expect(typeParams[1].name, equals('K'));
final selfBound = typeParams[1].bounds[0];
expect(selfBound.kind, Kind.declared);
expect(selfBound.name,
equals('com.github.dart_lang.jnigen.generics.GenericTypeParams'));
final selfBoundType = selfBound.type as DeclaredType;
expect(selfBoundType.params, hasLength(2));
expect(selfBoundType.params.map((e) => e.name), ['S', 'K']);
expect(selfBoundType.params.map((e) => e.kind),
[Kind.typeVariable, Kind.typeVariable]);
});
}
void main() async {
await checkLocallyBuiltDependencies();
final tempDir = getTempDir('jnigen_summary_tests_');
final sourceConfig =
getSummaryGenerationConfig(sourcePath: [simplePackagePath]);
final parsedFromSource = await getSummary(sourceConfig);
final targetDir = tempDir.createTempSync('compiled_classes_test_');
await compileJavaFiles(simplePackageDir, targetDir);
final classConfig = getSummaryGenerationConfig(classPath: [targetDir.path]);
final parsedFromClasses = await getSummary(classConfig);
group('source summary', () {
registerCommonTests(parsedFromSource);
});
group('compiled summary', () {
registerCommonTests(parsedFromClasses);
});
group('source-based summary features', () {
final classes = parsedFromSource;
test('Parameter names', () {
final example = classes.getExampleClass();
final joinStrings = example.getMethod('joinStrings');
expect(
joinStrings.params.map((p) => p.name).toList(), ['values', 'delim']);
final methodWithSeveralParams =
example.getMethod('methodWithSeveralParams');
expect(methodWithSeveralParams.params.map((p) => p.name).toList(),
['ch', 's', 'a', 't', 'lt', 'wm']);
});
test('Javadoc comment', () {
final example = classes.getExampleClass();
final joinStrings = example.getMethod('joinStrings');
expect(joinStrings.javadoc?.comment,
contains('Joins the strings in the list using the given delimiter.'));
});
});
tearDownAll(() => tempDir.deleteSync(recursive: true));
}