From 657c3ee1e4faaf38f9d36ebe55f49f5cf2a10f42 Mon Sep 17 00:00:00 2001 From: Markus Richter <8398165+mqus@users.noreply.github.com> Date: Wed, 11 Mar 2020 13:39:53 +0100 Subject: [PATCH] Add unit tests --- .../test/processor/view_processor_test.dart | 274 ++++++++++++++++++ .../test/value_object/view_test.dart | 94 ++++++ 2 files changed, 368 insertions(+) create mode 100644 floor_generator/test/processor/view_processor_test.dart create mode 100644 floor_generator/test/value_object/view_test.dart diff --git a/floor_generator/test/processor/view_processor_test.dart b/floor_generator/test/processor/view_processor_test.dart new file mode 100644 index 00000000..299e100f --- /dev/null +++ b/floor_generator/test/processor/view_processor_test.dart @@ -0,0 +1,274 @@ +import 'package:analyzer/dart/element/element.dart'; +import 'package:build_test/build_test.dart'; +import 'package:floor_generator/processor/view_processor.dart'; +import 'package:floor_generator/processor/field_processor.dart'; +import 'package:floor_generator/value_object/view.dart'; + +import 'package:source_gen/source_gen.dart'; +import 'package:test/test.dart'; + +void main() { + test('Process view', () async { + final classElement = await _createClassElement(''' + @DatabaseView("SELECT * from otherentity") + class Person { + final int id; + + final String name; + + Person(this.id, this.name); + } + '''); + + final actual = ViewProcessor(classElement).process(); + + const name = 'Person'; + final fields = classElement.fields + .map((fieldElement) => FieldProcessor(fieldElement).process()) + .toList(); + const query = 'SELECT * from otherentity'; + const constructor = "Person(row['id'] as int, row['name'] as String)"; + final expected = View( + classElement, + name, + fields, + query, + constructor, + ); + expect(actual, equals(expected)); + }); + + test('Process view with dedicated name', () async { + final classElement = await _createClassElement(''' + @DatabaseView("SELECT * from otherentity",viewName: "personview") + class Person { + final int id; + + final String name; + + Person(this.id, this.name); + } + '''); + + final actual = ViewProcessor(classElement).process(); + + const name = 'personview'; + final fields = classElement.fields + .map((fieldElement) => FieldProcessor(fieldElement).process()) + .toList(); + const query = 'SELECT * from otherentity'; + const constructor = "Person(row['id'] as int, row['name'] as String)"; + final expected = View( + classElement, + name, + fields, + query, + constructor, + ); + expect(actual, equals(expected)); + }); + + test('Ignore hashCode field', () async { + final classElement = await _createClassElement(''' + @DatabaseView("SELECT * from otherentity") + class Person { + final int id; + + final String name; + + Person(this.id, this.name); + + @override + int get hashCode => id.hashCode ^ name.hashCode; + } + '''); + + final actual = ViewProcessor(classElement).process(); + + expect(actual.fields.length, equals(2)); + }); + + test('Ignore static field', () async { + final classElement = await _createClassElement(''' + @DatabaseView("SELECT * from otherentity") + class Person { + final int id; + + final String name; + + Person(this.id, this.name); + + static String foo = 'foo'; + } + '''); + + final actual = ViewProcessor(classElement).process(); + + expect(actual.fields.length, equals(2)); + }); + + group('Constructors', () { + test('generate simple constructor', () async { + final classElement = await _createClassElement(''' + @DatabaseView("SELECT * from otherentity") + class Person { + final int id; + + final String name; + + Person(this.id, this.name); + } + '''); + + final actual = ViewProcessor(classElement).process().constructor; + + const expected = "Person(row['id'] as int, row['name'] as String)"; + expect(actual, equals(expected)); + }); + + test('generate constructor with named argument', () async { + final classElement = await _createClassElement(''' + @DatabaseView("SELECT * from otherentity") + class Person { + final int id; + + final String name; + + final String bar; + + Person(this.id, this.name, {this.bar}); + } + '''); + + final actual = ViewProcessor(classElement).process().constructor; + + const expected = + "Person(row['id'] as int, row['name'] as String, bar: row['bar'] as String)"; + expect(actual, equals(expected)); + }); + + test('generate constructor with named arguments', () async { + final classElement = await _createClassElement(''' + @DatabaseView("SELECT * from otherentity") + class Person { + final int id; + + final String name; + + final String bar; + + Person({this.id, this.name, this.bar}); + } + '''); + + final actual = ViewProcessor(classElement).process().constructor; + + const expected = + "Person(id: row['id'] as int, name: row['name'] as String, bar: row['bar'] as String)"; + expect(actual, equals(expected)); + }); + + test('generate constructor with optional argument', () async { + final classElement = await _createClassElement(''' + @DatabaseView("SELECT * from otherentity") + class Person { + final int id; + + final String name; + + final String bar; + + Person(this.id, this.name, [this.bar]); + } + '''); + + final actual = ViewProcessor(classElement).process().constructor; + + const expected = + "Person(row['id'] as int, row['name'] as String, row['bar'] as String)"; + expect(actual, equals(expected)); + }); + + test('generate constructor with optional arguments', () async { + final classElement = await _createClassElement(''' + @DatabaseView("SELECT * from otherentity") + class Person { + final int id; + + final String name; + + final String bar; + + Person([this.id, this.name, this.bar]); + } + '''); + + final actual = ViewProcessor(classElement).process().constructor; + + const expected = + "Person(row['id'] as int, row['name'] as String, row['bar'] as String)"; + expect(actual, equals(expected)); + }); + }); + + group('@Ignore', () { + test('ignore field not present in constructor', () async { + final classElement = await _createClassElement(''' + @DatabaseView("SELECT * from otherentity") + class Person { + final int id; + + final String name; + + @ignore + String foo; + + Person(this.id, this.name); + } + '''); + + final actual = ViewProcessor(classElement) + .process() + .fields + .map((field) => field.name); + + const expected = 'foo'; + expect(actual, isNot(contains(expected))); + }); + + test('ignore field present in constructor', () async { + final classElement = await _createClassElement(''' + @DatabaseView("SELECT * from otherentity") + class Person { + final int id; + + final String name; + + @ignore + String foo; + + Person(this.id, this.name, [this.foo = 'foo']); + } + '''); + + final actual = ViewProcessor(classElement).process().constructor; + + const expected = "Person(row['id'] as int, row['name'] as String)"; + expect(actual, equals(expected)); + }); + }); +} + +Future _createClassElement(final String clazz) async { + final library = await resolveSource(''' + library test; + + import 'package:floor_annotation/floor_annotation.dart'; + + $clazz + ''', (resolver) async { + return LibraryReader(await resolver.findLibraryByName('test')); + }); + + return library.classes.first; +} diff --git a/floor_generator/test/value_object/view_test.dart b/floor_generator/test/value_object/view_test.dart new file mode 100644 index 00000000..c0685e9c --- /dev/null +++ b/floor_generator/test/value_object/view_test.dart @@ -0,0 +1,94 @@ +import 'package:floor_generator/misc/constants.dart'; +import 'package:floor_generator/value_object/view.dart'; +import 'package:floor_generator/value_object/field.dart'; +import 'package:mockito/mockito.dart'; +import 'package:test/test.dart'; + +import '../mocks.dart'; + +void main() { + final mockClassElement = MockClassElement(); + final mockFieldElement = MockFieldElement(); + final mockDartType = MockDartType(); + + final field = Field( + mockFieldElement, + 'field1Name', + 'field1ColumnName', + false, + SqlType.INTEGER, + ); + final nullableField = Field( + mockFieldElement, + 'field2Name', + 'field2ColumnName', + true, + SqlType.TEXT, + ); + final allFields = [field, nullableField]; + + tearDown(() { + clearInteractions(mockClassElement); + clearInteractions(mockFieldElement); + clearInteractions(mockDartType); + reset(mockClassElement); + reset(mockFieldElement); + reset(mockDartType); + }); + + group('statement', () { + test('Create view statement with simple query', () { + final view = View( + mockClassElement, + 'entityName', + allFields, + 'select * from x', + '', + ); + + final actual = view.getCreateViewStatement(); + + final expected = + 'CREATE VIEW IF NOT EXISTS `${view.name}` AS ${view.query}'; + expect(actual, equals(expected)); + }); + }); + + group('Value mapping', () { + final view = View( + mockClassElement, + 'entityName', + [nullableField], + 'select * from x', + '', + ); + const fieldElementDisplayName = 'foo'; + + setUp(() { + when(mockFieldElement.displayName).thenReturn(fieldElementDisplayName); + when(mockFieldElement.type).thenReturn(mockDartType); + }); + + test('Get value mapping', () { + when(mockDartType.isDartCoreBool).thenReturn(false); + + final actual = view.getValueMapping(); + + final expected = '{' + "'${nullableField.columnName}': item.$fieldElementDisplayName" + '}'; + expect(actual, equals(expected)); + }); + + test('Get boolean value mapping', () { + when(mockDartType.isDartCoreBool).thenReturn(true); + + final actual = view.getValueMapping(); + + final expected = '{' + "'${nullableField.columnName}': item.$fieldElementDisplayName ? 1 : 0" + '}'; + expect(actual, equals(expected)); + }); + }); +}