From 30a627b018b814c7f382e6d7ea7abcf5cfbf8a61 Mon Sep 17 00:00:00 2001 From: David Morgan Date: Sun, 11 Sep 2016 14:11:38 +0200 Subject: [PATCH] Generate builder if none is written by hand. toString appends commas. Improve examples and tests. Fix double null checking. --- CHANGELOG.md | 7 + built_value/pubspec.yaml | 2 +- .../lib/src/source_class.dart | 71 +++++--- .../lib/src/source_class.g.dart | 45 ++---- .../lib/src/source_field.dart | 77 +++++++-- .../lib/src/source_field.g.dart | 32 ++-- built_value_generator/pubspec.yaml | 6 +- .../test/built_value_generator_test.dart | 10 -- example/lib/collections.dart | 36 +++++ example/lib/collections.g.dart | 139 ++++++++++++++++ example/lib/compound_value.dart | 29 +--- example/lib/compound_value.g.dart | 39 +++-- example/lib/simple_value.dart | 25 +++ example/lib/simple_value.g.dart | 60 +++++++ example/lib/validated_value.dart | 25 +++ example/lib/validated_value.g.dart | 62 +++++++ example/lib/value.dart | 67 -------- example/lib/value.g.dart | 90 ----------- example/lib/value_with_code.dart | 32 ++++ example/lib/value_with_code.g.dart | 61 +++++++ example/lib/value_with_defaults.dart | 42 +++++ example/lib/value_with_defaults.g.dart | 58 +++++++ example/pubspec.yaml | 10 +- example/test/collections_test.dart | 74 +++++++++ example/test/compound_value_test.dart | 20 ++- example/test/simple_value_test.dart | 95 +++++++++++ example/test/validated_value_test.dart | 18 +++ example/test/value_test.dart | 152 ------------------ example/test/value_with_code_test.dart | 26 +++ example/test/value_with_defaults_test.dart | 14 ++ 30 files changed, 978 insertions(+), 446 deletions(-) create mode 100644 example/lib/collections.dart create mode 100644 example/lib/collections.g.dart create mode 100644 example/lib/simple_value.dart create mode 100644 example/lib/simple_value.g.dart create mode 100644 example/lib/validated_value.dart create mode 100644 example/lib/validated_value.g.dart delete mode 100644 example/lib/value.dart delete mode 100644 example/lib/value.g.dart create mode 100644 example/lib/value_with_code.dart create mode 100644 example/lib/value_with_code.g.dart create mode 100644 example/lib/value_with_defaults.dart create mode 100644 example/lib/value_with_defaults.g.dart create mode 100644 example/test/collections_test.dart create mode 100644 example/test/simple_value_test.dart create mode 100644 example/test/validated_value_test.dart delete mode 100644 example/test/value_test.dart create mode 100644 example/test/value_with_code_test.dart create mode 100644 example/test/value_with_defaults_test.dart diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b5770a8..535d272f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## 0.1.3 + +- Generate builder if it's not written by hand. +- Make toString append commas for improved clarity. +- Improve examples and tests. +- Fix double null checking. + ## 0.1.2 - Refactor generator to split into logical classes. diff --git a/built_value/pubspec.yaml b/built_value/pubspec.yaml index 5df1265a..0b7aebc8 100644 --- a/built_value/pubspec.yaml +++ b/built_value/pubspec.yaml @@ -1,5 +1,5 @@ name: built_value -version: 0.1.2 +version: 0.1.3 description: > Value types with builders. This library is the runtime dependency. authors: diff --git a/built_value_generator/lib/src/source_class.dart b/built_value_generator/lib/src/source_class.dart index 9761404e..18e9a144 100644 --- a/built_value_generator/lib/src/source_class.dart +++ b/built_value_generator/lib/src/source_class.dart @@ -50,12 +50,12 @@ abstract class SourceClass implements Built { .map((constructor) => constructor.computeNode().toSource())) ..valueClassFactories.replace(classElement.constructors .where((constructor) => constructor.isFactory) - .map((factory) => factory.computeNode().toSource())); + .map((factory) => factory.computeNode().toSource())) + ..fields.replace( + SourceField.fromClassElements(classElement, builderClassElement)); if (hasBuilder) { result - ..fields.replace( - SourceField.fromClassElements(classElement, builderClassElement)) ..builderClassIsAbstract = builderClassElement.isAbstract ..builderClassConstructors.replace(builderClassElement.constructors .where((constructor) => @@ -127,10 +127,7 @@ abstract class SourceClass implements Built { Iterable _checkBuilderClass() { final result = []; - - if (!hasBuilder) { - return ['Add abstract class: ${name}Builder']; - } + if (!hasBuilder) return result; if (!builderClassIsAbstract) { result.add('Make builder class abstract.'); @@ -154,6 +151,7 @@ abstract class SourceClass implements Built { } Iterable _checkFieldList() { + if (!hasBuilder) return []; return fields.any((field) => !field.builderFieldExists) ? [ 'Make builder have exactly these fields: ' + @@ -172,6 +170,7 @@ abstract class SourceClass implements Built { for (final field in fields) { result.writeln('final ${field.type} ${field.name};'); } + result.writeln(); if (fields.isEmpty) { result.write('_\$$name._() : super._() {'); @@ -184,14 +183,25 @@ abstract class SourceClass implements Built { result.writeln("if (${field.name} == null) " "throw new ArgumentError('null ${field.name}');"); } - result.write('}'); + result.writeln('}'); + result.writeln(); result.writeln('factory _\$$name([updates(${name}Builder b)]) ' '=> (new ${name}Builder()..update(updates)).build();'); + result.writeln(); + result.writeln('$name rebuild(updates(${name}Builder b)) ' '=> (toBuilder()..update(updates)).build();'); - result.writeln('_\$${name}Builder toBuilder() ' - '=> new _\$${name}Builder()..replace(this);'); + result.writeln(); + + if (hasBuilder) { + result.writeln('_\$${name}Builder toBuilder() ' + '=> new _\$${name}Builder()..replace(this);'); + } else { + result.writeln('${name}Builder toBuilder() ' + '=> new ${name}Builder()..replace(this);'); + } + result.writeln(); result.writeln('bool operator==(other) {'); result.writeln(' if (other is! $name) return false;'); @@ -205,6 +215,7 @@ abstract class SourceClass implements Built { result.writeln(';'); } result.writeln('}'); + result.writeln(); result.writeln('int get hashCode {'); if (fields.length == 0) { @@ -215,6 +226,7 @@ abstract class SourceClass implements Built { result.writeln(']);'); } result.writeln('}'); + result.writeln(); result.writeln('String toString() {'); if (fields.length == 0) { @@ -222,35 +234,54 @@ abstract class SourceClass implements Built { } else { result.writeln("return '$name {'"); result.writeln(fields - .map((field) => "'${field.name}=\${${field.name}.toString()}\\n'") + .map((field) => "'${field.name}=\${${field.name}.toString()},\\n'") .join('')); result.writeln("'}'"); result.writeln(';'); } result.writeln('}'); + result.writeln(); result.writeln('}'); - result.writeln('class _\$${name}Builder extends ${name}Builder {'); - result.writeln(); - result.writeln('_\$${name}Builder() : super._();'); + if (hasBuilder) { + result.writeln('class _\$${name}Builder extends ${name}Builder {'); + result.writeln('_\$${name}Builder() : super._();'); + } else { + result.writeln( + 'class ${name}Builder implements Builder<$name, ${name}Builder>{'); + result.writeln('${name}Builder();'); + } + + if (!hasBuilder) { + for (final field in fields) { + // Nested builders are initialized to an empty builder, unless the + // field is nullable. + if (field.isNestedBuilder && !field.isNullable) { + result.writeln('${field.typeInBuilder} ${field.name} = new ${field.typeInBuilder}();'); + } else { + result.writeln('${field.typeInBuilder} ${field.name};'); + } + } + result.writeln(); + } result.writeln('void replace(${name} other) {'); result.writeln((fields.map((field) { + final superOrThis = hasBuilder ? 'super' : 'this'; return field.isNestedBuilder - ? 'super.${field.name} = other.${field.name}?.toBuilder();' - : 'super.${field.name} = other.${field.name};'; + ? '$superOrThis.${field.name} = other.${field.name}?.toBuilder();' + : '$superOrThis.${field.name} = other.${field.name};'; })) .join('\n')); result.writeln('}'); + result.writeln(); result.writeln('void update(updates(${name}Builder b)) {' ' if (updates != null) updates(this); }'); + result.writeln(); + result.writeln('$name build() {'); - for (final field in fields.where((field) => !field.isNullable)) { - result.writeln("if (${field.name} == null) " - "throw new ArgumentError('null ${field.name}');"); - } result.writeln('return new _\$$name._('); result.write(fields.map((field) { return field.isNestedBuilder diff --git a/built_value_generator/lib/src/source_class.g.dart b/built_value_generator/lib/src/source_class.g.dart index 2e355e8b..33924259 100644 --- a/built_value_generator/lib/src/source_class.g.dart +++ b/built_value_generator/lib/src/source_class.g.dart @@ -19,6 +19,7 @@ class _$SourceClass extends SourceClass { final bool builderClassIsAbstract; final BuiltList builderClassConstructors; final BuiltList builderClassFactories; + _$SourceClass._( {this.name, this.hasBuilder, @@ -51,11 +52,15 @@ class _$SourceClass extends SourceClass { if (builderClassFactories == null) throw new ArgumentError('null builderClassFactories'); } + factory _$SourceClass([updates(SourceClassBuilder b)]) => (new SourceClassBuilder()..update(updates)).build(); + SourceClass rebuild(updates(SourceClassBuilder b)) => (toBuilder()..update(updates)).build(); + _$SourceClassBuilder toBuilder() => new _$SourceClassBuilder()..replace(this); + bool operator ==(other) { if (other is! SourceClass) return false; return name == other.name && @@ -89,17 +94,17 @@ class _$SourceClass extends SourceClass { String toString() { return 'SourceClass {' - 'name=${name.toString()}\n' - 'hasBuilder=${hasBuilder.toString()}\n' - 'fields=${fields.toString()}\n' - 'partStatement=${partStatement.toString()}\n' - 'hasPartStatement=${hasPartStatement.toString()}\n' - 'valueClassIsAbstract=${valueClassIsAbstract.toString()}\n' - 'valueClassConstructors=${valueClassConstructors.toString()}\n' - 'valueClassFactories=${valueClassFactories.toString()}\n' - 'builderClassIsAbstract=${builderClassIsAbstract.toString()}\n' - 'builderClassConstructors=${builderClassConstructors.toString()}\n' - 'builderClassFactories=${builderClassFactories.toString()}\n' + 'name=${name.toString()},\n' + 'hasBuilder=${hasBuilder.toString()},\n' + 'fields=${fields.toString()},\n' + 'partStatement=${partStatement.toString()},\n' + 'hasPartStatement=${hasPartStatement.toString()},\n' + 'valueClassIsAbstract=${valueClassIsAbstract.toString()},\n' + 'valueClassConstructors=${valueClassConstructors.toString()},\n' + 'valueClassFactories=${valueClassFactories.toString()},\n' + 'builderClassIsAbstract=${builderClassIsAbstract.toString()},\n' + 'builderClassConstructors=${builderClassConstructors.toString()},\n' + 'builderClassFactories=${builderClassFactories.toString()},\n' '}'; } } @@ -126,24 +131,6 @@ class _$SourceClassBuilder extends SourceClassBuilder { } SourceClass build() { - if (name == null) throw new ArgumentError('null name'); - if (hasBuilder == null) throw new ArgumentError('null hasBuilder'); - if (fields == null) throw new ArgumentError('null fields'); - if (partStatement == null) throw new ArgumentError('null partStatement'); - if (hasPartStatement == null) - throw new ArgumentError('null hasPartStatement'); - if (valueClassIsAbstract == null) - throw new ArgumentError('null valueClassIsAbstract'); - if (valueClassConstructors == null) - throw new ArgumentError('null valueClassConstructors'); - if (valueClassFactories == null) - throw new ArgumentError('null valueClassFactories'); - if (builderClassIsAbstract == null) - throw new ArgumentError('null builderClassIsAbstract'); - if (builderClassConstructors == null) - throw new ArgumentError('null builderClassConstructors'); - if (builderClassFactories == null) - throw new ArgumentError('null builderClassFactories'); return new _$SourceClass._( name: name, hasBuilder: hasBuilder, diff --git a/built_value_generator/lib/src/source_field.dart b/built_value_generator/lib/src/source_field.dart index fe10cc14..c945b6d8 100644 --- a/built_value_generator/lib/src/source_field.dart +++ b/built_value_generator/lib/src/source_field.dart @@ -5,11 +5,20 @@ library built_value_generator.source_field; import 'package:analyzer/dart/element/element.dart'; +import 'package:analyzer/dart/element/type.dart'; import 'package:built_collection/built_collection.dart'; import 'package:built_value/built_value.dart'; part 'source_field.g.dart'; +BuiltSet _builtCollectionNames = new BuiltSet([ + 'BuiltList', + 'BuiltListMultimap', + 'BuiltMap', + 'BuiltSet', + 'BuiltSetMultimap', +]); + abstract class SourceField implements Built { String get name; String get type; @@ -17,7 +26,6 @@ abstract class SourceField implements Built { bool get isNullable; bool get builderFieldExists; bool get builderFieldIsNormalField; - @nullable String get typeInBuilder; bool get isNestedBuilder; @@ -26,22 +34,35 @@ abstract class SourceField implements Built { factory SourceField.fromFieldElements( FieldElement fieldElement, FieldElement builderFieldElement) { - return new SourceField((b) => b + final result = new SourceFieldBuilder(); + final builderFieldExists = builderFieldElement != null; + final type = fieldElement.getter.returnType.displayName; + result ..name = fieldElement.displayName - ..type = fieldElement.getter.returnType.displayName - ..typeInBuilder = builderFieldElement?.getter?.returnType?.displayName + ..type = type ..isGetter = fieldElement.getter != null && !fieldElement.getter.isSynthetic ..isNullable = fieldElement.getter.metadata.any( - (metadata) => metadata.constantValue.toStringValue() == 'nullable') - ..builderFieldExists = builderFieldElement != null - ..builderFieldIsNormalField = builderFieldElement != null && - builderFieldElement.getter != null && - !builderFieldElement.getter.isAbstract && - builderFieldElement.getter.isSynthetic - ..isNestedBuilder = builderFieldElement?.getter?.returnType?.displayName - ?.contains('Builder') ?? - false); + (metadata) => metadata.constantValue.toStringValue() == 'nullable'); + + if (builderFieldExists) { + result + ..builderFieldExists = true + ..builderFieldIsNormalField = builderFieldElement.getter != null && + !builderFieldElement.getter.isAbstract && + builderFieldElement.getter.isSynthetic + ..typeInBuilder = builderFieldElement.getter?.returnType?.displayName + ..isNestedBuilder = builderFieldElement.getter?.returnType?.displayName + ?.contains('Builder') ?? + false; + } else { + result + ..builderFieldExists = false + ..builderFieldIsNormalField = true + ..typeInBuilder = _toBuilderType(fieldElement.getter.returnType) + ..isNestedBuilder = _needsNestedBuilder(fieldElement.getter.returnType); + } + return result.build(); } static BuiltList fromClassElements( @@ -52,7 +73,7 @@ abstract class SourceField implements Built { if (!field.isStatic && field.getter != null && (field.getter.isAbstract || field.getter.isSynthetic)) { - final builderField = builderClassElement.getField(field.name); + final builderField = builderClassElement?.getField(field.name); result.add(new SourceField.fromFieldElements(field, builderField)); } } @@ -60,6 +81,34 @@ abstract class SourceField implements Built { return result.build(); } + static bool _needsNestedBuilder(DartType type) { + return _isBuiltValue(type) || _isBuiltCollection(type); + } + + static bool _isBuiltValue(DartType type) { + if (type.element is! ClassElement) return false; + return (type.element as ClassElement) + .allSupertypes + .any((interfaceType) => interfaceType.name == 'Built'); + } + + static bool _isBuiltCollection(DartType type) { + return _builtCollectionNames + .any((name) => type.displayName.startsWith('${name}<')); + } + + static String _toBuilderType(DartType type) { + if (_isBuiltCollection(type)) { + return type.displayName + .replaceFirst('Built', '') + .replaceFirst('<', 'Builder<'); + } else if (_isBuiltValue(type)) { + return '${type.displayName}Builder'; + } else { + return type.displayName; + } + } + Iterable computeErrors() { final result = []; diff --git a/built_value_generator/lib/src/source_field.g.dart b/built_value_generator/lib/src/source_field.g.dart index 7f3ef206..e506526e 100644 --- a/built_value_generator/lib/src/source_field.g.dart +++ b/built_value_generator/lib/src/source_field.g.dart @@ -16,6 +16,7 @@ class _$SourceField extends SourceField { final bool builderFieldIsNormalField; final String typeInBuilder; final bool isNestedBuilder; + _$SourceField._( {this.name, this.type, @@ -34,14 +35,19 @@ class _$SourceField extends SourceField { throw new ArgumentError('null builderFieldExists'); if (builderFieldIsNormalField == null) throw new ArgumentError('null builderFieldIsNormalField'); + if (typeInBuilder == null) throw new ArgumentError('null typeInBuilder'); if (isNestedBuilder == null) throw new ArgumentError('null isNestedBuilder'); } + factory _$SourceField([updates(SourceFieldBuilder b)]) => (new SourceFieldBuilder()..update(updates)).build(); + SourceField rebuild(updates(SourceFieldBuilder b)) => (toBuilder()..update(updates)).build(); + _$SourceFieldBuilder toBuilder() => new _$SourceFieldBuilder()..replace(this); + bool operator ==(other) { if (other is! SourceField) return false; return name == other.name && @@ -69,14 +75,14 @@ class _$SourceField extends SourceField { String toString() { return 'SourceField {' - 'name=${name.toString()}\n' - 'type=${type.toString()}\n' - 'isGetter=${isGetter.toString()}\n' - 'isNullable=${isNullable.toString()}\n' - 'builderFieldExists=${builderFieldExists.toString()}\n' - 'builderFieldIsNormalField=${builderFieldIsNormalField.toString()}\n' - 'typeInBuilder=${typeInBuilder.toString()}\n' - 'isNestedBuilder=${isNestedBuilder.toString()}\n' + 'name=${name.toString()},\n' + 'type=${type.toString()},\n' + 'isGetter=${isGetter.toString()},\n' + 'isNullable=${isNullable.toString()},\n' + 'builderFieldExists=${builderFieldExists.toString()},\n' + 'builderFieldIsNormalField=${builderFieldIsNormalField.toString()},\n' + 'typeInBuilder=${typeInBuilder.toString()},\n' + 'isNestedBuilder=${isNestedBuilder.toString()},\n' '}'; } } @@ -99,16 +105,6 @@ class _$SourceFieldBuilder extends SourceFieldBuilder { } SourceField build() { - if (name == null) throw new ArgumentError('null name'); - if (type == null) throw new ArgumentError('null type'); - if (isGetter == null) throw new ArgumentError('null isGetter'); - if (isNullable == null) throw new ArgumentError('null isNullable'); - if (builderFieldExists == null) - throw new ArgumentError('null builderFieldExists'); - if (builderFieldIsNormalField == null) - throw new ArgumentError('null builderFieldIsNormalField'); - if (isNestedBuilder == null) - throw new ArgumentError('null isNestedBuilder'); return new _$SourceField._( name: name, type: type, diff --git a/built_value_generator/pubspec.yaml b/built_value_generator/pubspec.yaml index fbb90715..9f48e4de 100644 --- a/built_value_generator/pubspec.yaml +++ b/built_value_generator/pubspec.yaml @@ -1,5 +1,5 @@ name: built_value_generator -version: 0.1.2 +version: 0.1.3 description: > Value types with builders. This library is the dev dependency. authors: @@ -13,7 +13,9 @@ dependencies: analyzer: '>=0.27.1 <0.28.0' build: '^0.3.0' built_collection: '^1.0.0' - built_value: '^0.1.2' +# built_value: '^0.1.2' + built_value: + path: ../built_value source_gen: '>=0.5.0+03 <0.6.0' quiver: '>=0.21.0 <0.22.0' diff --git a/built_value_generator/test/built_value_generator_test.dart b/built_value_generator/test/built_value_generator_test.dart index 796eda7a..d2473fa2 100644 --- a/built_value_generator/test/built_value_generator_test.dart +++ b/built_value_generator/test/built_value_generator_test.dart @@ -100,16 +100,6 @@ abstract class ValueBuilder extends Builder { "factory Value([updates(ValueBuilder b)]) = _\$Value;")); }); - test('suggests to add builder class', () async { - expect(await generate('''library value; -import 'package:built_value/built_value.dart'; -part 'value.g.dart'; -abstract class Value extends Built { - Value._(); - factory Value([updates(ValueBuilder b)]) = _\$Value; -}'''), contains("1. Add abstract class: ValueBuilder")); - }); - test('suggests to make builder class abstract', () async { expect(await generate('''library value; import 'package:built_value/built_value.dart'; diff --git a/example/lib/collections.dart b/example/lib/collections.dart new file mode 100644 index 00000000..e51a729a --- /dev/null +++ b/example/lib/collections.dart @@ -0,0 +1,36 @@ +// Copyright (c) 2016, Google Inc. 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. + +library collections; + +import 'package:built_collection/built_collection.dart'; +import 'package:built_value/built_value.dart'; + +part 'collections.g.dart'; + +/// Example of how to use built_value. +/// +/// Classes can contain collections; these must be from built_collection. In +/// the builder, the builder corresponding to the collection is provided. +abstract class Collections implements Built { + BuiltList get list; + BuiltSet get set; + BuiltMap get map; + BuiltListMultimap get listMultimap; + BuiltSetMultimap get setMultimap; + + @nullable + BuiltList get nullableList; + @nullable + BuiltSet get nullableSet; + @nullable + BuiltMap get nullableMap; + @nullable + BuiltListMultimap get nullableListMultimap; + @nullable + BuiltSetMultimap get nullableSetMultimap; + + Collections._(); + factory Collections([updates(CollectionsBuilder b)]) = _$Collections; +} diff --git a/example/lib/collections.g.dart b/example/lib/collections.g.dart new file mode 100644 index 00000000..13fc12e6 --- /dev/null +++ b/example/lib/collections.g.dart @@ -0,0 +1,139 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of collections; + +// ************************************************************************** +// Generator: BuiltValueGenerator +// Target: abstract class Collections +// ************************************************************************** + +class _$Collections extends Collections { + final BuiltList list; + final BuiltSet set; + final BuiltMap map; + final BuiltListMultimap listMultimap; + final BuiltSetMultimap setMultimap; + final BuiltList nullableList; + final BuiltSet nullableSet; + final BuiltMap nullableMap; + final BuiltListMultimap nullableListMultimap; + final BuiltSetMultimap nullableSetMultimap; + + _$Collections._( + {this.list, + this.set, + this.map, + this.listMultimap, + this.setMultimap, + this.nullableList, + this.nullableSet, + this.nullableMap, + this.nullableListMultimap, + this.nullableSetMultimap}) + : super._() { + if (list == null) throw new ArgumentError('null list'); + if (set == null) throw new ArgumentError('null set'); + if (map == null) throw new ArgumentError('null map'); + if (listMultimap == null) throw new ArgumentError('null listMultimap'); + if (setMultimap == null) throw new ArgumentError('null setMultimap'); + } + + factory _$Collections([updates(CollectionsBuilder b)]) => + (new CollectionsBuilder()..update(updates)).build(); + + Collections rebuild(updates(CollectionsBuilder b)) => + (toBuilder()..update(updates)).build(); + + CollectionsBuilder toBuilder() => new CollectionsBuilder()..replace(this); + + bool operator ==(other) { + if (other is! Collections) return false; + return list == other.list && + set == other.set && + map == other.map && + listMultimap == other.listMultimap && + setMultimap == other.setMultimap && + nullableList == other.nullableList && + nullableSet == other.nullableSet && + nullableMap == other.nullableMap && + nullableListMultimap == other.nullableListMultimap && + nullableSetMultimap == other.nullableSetMultimap; + } + + int get hashCode { + return hashObjects([ + list, + set, + map, + listMultimap, + setMultimap, + nullableList, + nullableSet, + nullableMap, + nullableListMultimap, + nullableSetMultimap + ]); + } + + String toString() { + return 'Collections {' + 'list=${list.toString()},\n' + 'set=${set.toString()},\n' + 'map=${map.toString()},\n' + 'listMultimap=${listMultimap.toString()},\n' + 'setMultimap=${setMultimap.toString()},\n' + 'nullableList=${nullableList.toString()},\n' + 'nullableSet=${nullableSet.toString()},\n' + 'nullableMap=${nullableMap.toString()},\n' + 'nullableListMultimap=${nullableListMultimap.toString()},\n' + 'nullableSetMultimap=${nullableSetMultimap.toString()},\n' + '}'; + } +} + +class CollectionsBuilder implements Builder { + CollectionsBuilder(); + ListBuilder list = new ListBuilder(); + SetBuilder set = new SetBuilder(); + MapBuilder map = new MapBuilder(); + ListMultimapBuilder listMultimap = + new ListMultimapBuilder(); + SetMultimapBuilder setMultimap = + new SetMultimapBuilder(); + ListBuilder nullableList; + SetBuilder nullableSet; + MapBuilder nullableMap; + ListMultimapBuilder nullableListMultimap; + SetMultimapBuilder nullableSetMultimap; + + void replace(Collections other) { + this.list = other.list?.toBuilder(); + this.set = other.set?.toBuilder(); + this.map = other.map?.toBuilder(); + this.listMultimap = other.listMultimap?.toBuilder(); + this.setMultimap = other.setMultimap?.toBuilder(); + this.nullableList = other.nullableList?.toBuilder(); + this.nullableSet = other.nullableSet?.toBuilder(); + this.nullableMap = other.nullableMap?.toBuilder(); + this.nullableListMultimap = other.nullableListMultimap?.toBuilder(); + this.nullableSetMultimap = other.nullableSetMultimap?.toBuilder(); + } + + void update(updates(CollectionsBuilder b)) { + if (updates != null) updates(this); + } + + Collections build() { + return new _$Collections._( + list: list?.build(), + set: set?.build(), + map: map?.build(), + listMultimap: listMultimap?.build(), + setMultimap: setMultimap?.build(), + nullableList: nullableList?.build(), + nullableSet: nullableSet?.build(), + nullableMap: nullableMap?.build(), + nullableListMultimap: nullableListMultimap?.build(), + nullableSetMultimap: nullableSetMultimap?.build()); + } +} diff --git a/example/lib/compound_value.dart b/example/lib/compound_value.dart index 1b566edc..f535aebb 100644 --- a/example/lib/compound_value.dart +++ b/example/lib/compound_value.dart @@ -6,36 +6,21 @@ library compound_value; import 'package:built_value/built_value.dart'; -import 'value.dart'; +import 'package:example/validated_value.dart'; +import 'simple_value.dart'; part 'compound_value.g.dart'; /// Example of how to use built_value. /// -/// The value class must implement [Built]. It must be abstract, and have -/// fields declared as abstract getters. Finally, it must have a particular -/// constructor and factory, as shown here. +/// Other built_value classes can be used as fields. In the builder they are +/// represented as nested builders. abstract class CompoundValue implements Built { - Value get value; + SimpleValue get simpleValue; + @nullable + ValidatedValue get validatedValue; CompoundValue._(); factory CompoundValue([updates(CompoundValueBuilder b)]) = _$CompoundValue; } - -/// The builder class must implement [Builder]. It must be abstract, and have -/// fields declared as normal public fields. Finally, it must have a particular -/// constructor and factory, as shown here. -/// -/// Defaults can be specified by assigning them to fields here. -/// -/// Validation can be done by overriding the [build] method. -abstract class CompoundValueBuilder - implements Builder { - ValueBuilder value = new ValueBuilder() - ..anInt = 0 - ..aString = '1'; - - CompoundValueBuilder._(); - factory CompoundValueBuilder() = _$CompoundValueBuilder; -} diff --git a/example/lib/compound_value.g.dart b/example/lib/compound_value.g.dart index f488662f..499bee48 100644 --- a/example/lib/compound_value.g.dart +++ b/example/lib/compound_value.g.dart @@ -8,36 +8,48 @@ part of compound_value; // ************************************************************************** class _$CompoundValue extends CompoundValue { - final Value value; - _$CompoundValue._({this.value}) : super._() { - if (value == null) throw new ArgumentError('null value'); + final SimpleValue simpleValue; + final ValidatedValue validatedValue; + + _$CompoundValue._({this.simpleValue, this.validatedValue}) : super._() { + if (simpleValue == null) throw new ArgumentError('null simpleValue'); } + factory _$CompoundValue([updates(CompoundValueBuilder b)]) => (new CompoundValueBuilder()..update(updates)).build(); + CompoundValue rebuild(updates(CompoundValueBuilder b)) => (toBuilder()..update(updates)).build(); - _$CompoundValueBuilder toBuilder() => - new _$CompoundValueBuilder()..replace(this); + + CompoundValueBuilder toBuilder() => new CompoundValueBuilder()..replace(this); + bool operator ==(other) { if (other is! CompoundValue) return false; - return value == other.value; + return simpleValue == other.simpleValue && + validatedValue == other.validatedValue; } int get hashCode { - return hashObjects([value]); + return hashObjects([simpleValue, validatedValue]); } String toString() { return 'CompoundValue {' - 'value=${value.toString()}\n' + 'simpleValue=${simpleValue.toString()},\n' + 'validatedValue=${validatedValue.toString()},\n' '}'; } } -class _$CompoundValueBuilder extends CompoundValueBuilder { - _$CompoundValueBuilder() : super._(); +class CompoundValueBuilder + implements Builder { + CompoundValueBuilder(); + SimpleValueBuilder simpleValue = new SimpleValueBuilder(); + ValidatedValueBuilder validatedValue; + void replace(CompoundValue other) { - super.value = other.value?.toBuilder(); + this.simpleValue = other.simpleValue?.toBuilder(); + this.validatedValue = other.validatedValue?.toBuilder(); } void update(updates(CompoundValueBuilder b)) { @@ -45,7 +57,8 @@ class _$CompoundValueBuilder extends CompoundValueBuilder { } CompoundValue build() { - if (value == null) throw new ArgumentError('null value'); - return new _$CompoundValue._(value: value?.build()); + return new _$CompoundValue._( + simpleValue: simpleValue?.build(), + validatedValue: validatedValue?.build()); } } diff --git a/example/lib/simple_value.dart b/example/lib/simple_value.dart new file mode 100644 index 00000000..101174b7 --- /dev/null +++ b/example/lib/simple_value.dart @@ -0,0 +1,25 @@ +// Copyright (c) 2016, Google Inc. 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. + +library simple_value; + +import 'package:built_value/built_value.dart'; + +part 'simple_value.g.dart'; + +/// Example of how to use built_value. +/// +/// The value class must implement [Built]. It must be abstract, and have +/// fields declared as abstract getters. Finally, it must have a particular +/// constructor and factory, as shown here. +abstract class SimpleValue implements Built { + int get anInt; + + // Only fields marked @nullable can hold null. + @nullable + String get aString; + + SimpleValue._(); + factory SimpleValue([updates(SimpleValueBuilder b)]) = _$SimpleValue; +} diff --git a/example/lib/simple_value.g.dart b/example/lib/simple_value.g.dart new file mode 100644 index 00000000..9b2506ae --- /dev/null +++ b/example/lib/simple_value.g.dart @@ -0,0 +1,60 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of simple_value; + +// ************************************************************************** +// Generator: BuiltValueGenerator +// Target: abstract class SimpleValue +// ************************************************************************** + +class _$SimpleValue extends SimpleValue { + final int anInt; + final String aString; + + _$SimpleValue._({this.anInt, this.aString}) : super._() { + if (anInt == null) throw new ArgumentError('null anInt'); + } + + factory _$SimpleValue([updates(SimpleValueBuilder b)]) => + (new SimpleValueBuilder()..update(updates)).build(); + + SimpleValue rebuild(updates(SimpleValueBuilder b)) => + (toBuilder()..update(updates)).build(); + + SimpleValueBuilder toBuilder() => new SimpleValueBuilder()..replace(this); + + bool operator ==(other) { + if (other is! SimpleValue) return false; + return anInt == other.anInt && aString == other.aString; + } + + int get hashCode { + return hashObjects([anInt, aString]); + } + + String toString() { + return 'SimpleValue {' + 'anInt=${anInt.toString()},\n' + 'aString=${aString.toString()},\n' + '}'; + } +} + +class SimpleValueBuilder implements Builder { + SimpleValueBuilder(); + int anInt; + String aString; + + void replace(SimpleValue other) { + this.anInt = other.anInt; + this.aString = other.aString; + } + + void update(updates(SimpleValueBuilder b)) { + if (updates != null) updates(this); + } + + SimpleValue build() { + return new _$SimpleValue._(anInt: anInt, aString: aString); + } +} diff --git a/example/lib/validated_value.dart b/example/lib/validated_value.dart new file mode 100644 index 00000000..5c806be3 --- /dev/null +++ b/example/lib/validated_value.dart @@ -0,0 +1,25 @@ +// Copyright (c) 2016, Google Inc. 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. + +library validated_value; + +import 'package:built_value/built_value.dart'; + +part 'validated_value.g.dart'; + +/// Example of how to use built_value. +/// +/// Validation can be done in the constructor. +abstract class ValidatedValue + implements Built { + int get anInt; + @nullable + String get aString; + + ValidatedValue._() { + if (anInt == 7) throw 'anInt may not be 7'; + } + + factory ValidatedValue([updates(ValidatedValueBuilder b)]) = _$ValidatedValue; +} diff --git a/example/lib/validated_value.g.dart b/example/lib/validated_value.g.dart new file mode 100644 index 00000000..370ca5f1 --- /dev/null +++ b/example/lib/validated_value.g.dart @@ -0,0 +1,62 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of validated_value; + +// ************************************************************************** +// Generator: BuiltValueGenerator +// Target: abstract class ValidatedValue +// ************************************************************************** + +class _$ValidatedValue extends ValidatedValue { + final int anInt; + final String aString; + + _$ValidatedValue._({this.anInt, this.aString}) : super._() { + if (anInt == null) throw new ArgumentError('null anInt'); + } + + factory _$ValidatedValue([updates(ValidatedValueBuilder b)]) => + (new ValidatedValueBuilder()..update(updates)).build(); + + ValidatedValue rebuild(updates(ValidatedValueBuilder b)) => + (toBuilder()..update(updates)).build(); + + ValidatedValueBuilder toBuilder() => + new ValidatedValueBuilder()..replace(this); + + bool operator ==(other) { + if (other is! ValidatedValue) return false; + return anInt == other.anInt && aString == other.aString; + } + + int get hashCode { + return hashObjects([anInt, aString]); + } + + String toString() { + return 'ValidatedValue {' + 'anInt=${anInt.toString()},\n' + 'aString=${aString.toString()},\n' + '}'; + } +} + +class ValidatedValueBuilder + implements Builder { + ValidatedValueBuilder(); + int anInt; + String aString; + + void replace(ValidatedValue other) { + this.anInt = other.anInt; + this.aString = other.aString; + } + + void update(updates(ValidatedValueBuilder b)) { + if (updates != null) updates(this); + } + + ValidatedValue build() { + return new _$ValidatedValue._(anInt: anInt, aString: aString); + } +} diff --git a/example/lib/value.dart b/example/lib/value.dart deleted file mode 100644 index e00615aa..00000000 --- a/example/lib/value.dart +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (c) 2015, Google Inc. 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. - -library value; - -import 'package:built_collection/built_collection.dart'; -import 'package:built_value/built_value.dart'; - -part 'value.g.dart'; - -/// Example of how to use built_value. -/// -/// The value class must implement [Built]. It must be abstract, and have -/// fields declared as abstract getters. Finally, it must have a particular -/// constructor and factory, as shown here. -/// -/// Custom validation can be done in the constructor. -abstract class Value implements Built { - static final int youCanHaveStaticFields = 3; - - int get anInt; - String get aString; - @nullable - Object get anObject; - int get aDefaultInt; - BuiltList get listOfInt; - @nullable - BuiltSet get setOfString; - - int get youCanWriteDerivedGetters => anInt + aDefaultInt; - - Value._() { - // All fields are initialized before the constructor runs. So, custom - // validation can be done here. - if (anInt == 7) throw 'anInt may not be 7'; - } - factory Value([updates(ValueBuilder b)]) = _$Value; - - factory Value.fromCustomFactory() => new Value((b) => b - ..anInt = 1 - ..aString = 'two'); -} - -/// The builder class must implement [Builder]. It must be abstract, and have -/// fields declared as normal public fields. Finally, it must have a particular -/// constructor and factory, as shown here. -/// -/// Defaults can be specified by assigning them to fields here. -abstract class ValueBuilder implements Builder { - int anInt; - String aString; - @nullable - Object anObject; - int aDefaultInt = 7; - ListBuilder listOfInt = new ListBuilder(); - @nullable - SetBuilder setOfString; - - ValueBuilder._(); - factory ValueBuilder() = _$ValueBuilder; - - set youCanWriteExtraSetters(int value) { - anInt = value; - aDefaultInt = value; - } -} diff --git a/example/lib/value.g.dart b/example/lib/value.g.dart deleted file mode 100644 index 7fe5f27d..00000000 --- a/example/lib/value.g.dart +++ /dev/null @@ -1,90 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of value; - -// ************************************************************************** -// Generator: BuiltValueGenerator -// Target: abstract class Value -// ************************************************************************** - -class _$Value extends Value { - final int anInt; - final String aString; - final Object anObject; - final int aDefaultInt; - final BuiltList listOfInt; - final BuiltSet setOfString; - _$Value._( - {this.anInt, - this.aString, - this.anObject, - this.aDefaultInt, - this.listOfInt, - this.setOfString}) - : super._() { - if (anInt == null) throw new ArgumentError('null anInt'); - if (aString == null) throw new ArgumentError('null aString'); - if (aDefaultInt == null) throw new ArgumentError('null aDefaultInt'); - if (listOfInt == null) throw new ArgumentError('null listOfInt'); - } - factory _$Value([updates(ValueBuilder b)]) => - (new ValueBuilder()..update(updates)).build(); - Value rebuild(updates(ValueBuilder b)) => - (toBuilder()..update(updates)).build(); - _$ValueBuilder toBuilder() => new _$ValueBuilder()..replace(this); - bool operator ==(other) { - if (other is! Value) return false; - return anInt == other.anInt && - aString == other.aString && - anObject == other.anObject && - aDefaultInt == other.aDefaultInt && - listOfInt == other.listOfInt && - setOfString == other.setOfString; - } - - int get hashCode { - return hashObjects( - [anInt, aString, anObject, aDefaultInt, listOfInt, setOfString]); - } - - String toString() { - return 'Value {' - 'anInt=${anInt.toString()}\n' - 'aString=${aString.toString()}\n' - 'anObject=${anObject.toString()}\n' - 'aDefaultInt=${aDefaultInt.toString()}\n' - 'listOfInt=${listOfInt.toString()}\n' - 'setOfString=${setOfString.toString()}\n' - '}'; - } -} - -class _$ValueBuilder extends ValueBuilder { - _$ValueBuilder() : super._(); - void replace(Value other) { - super.anInt = other.anInt; - super.aString = other.aString; - super.anObject = other.anObject; - super.aDefaultInt = other.aDefaultInt; - super.listOfInt = other.listOfInt?.toBuilder(); - super.setOfString = other.setOfString?.toBuilder(); - } - - void update(updates(ValueBuilder b)) { - if (updates != null) updates(this); - } - - Value build() { - if (anInt == null) throw new ArgumentError('null anInt'); - if (aString == null) throw new ArgumentError('null aString'); - if (aDefaultInt == null) throw new ArgumentError('null aDefaultInt'); - if (listOfInt == null) throw new ArgumentError('null listOfInt'); - return new _$Value._( - anInt: anInt, - aString: aString, - anObject: anObject, - aDefaultInt: aDefaultInt, - listOfInt: listOfInt?.build(), - setOfString: setOfString?.build()); - } -} diff --git a/example/lib/value_with_code.dart b/example/lib/value_with_code.dart new file mode 100644 index 00000000..04413676 --- /dev/null +++ b/example/lib/value_with_code.dart @@ -0,0 +1,32 @@ +// Copyright (c) 2016, Google Inc. 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. + +library value_with_code; + +import 'package:built_value/built_value.dart'; + +part 'value_with_code.g.dart'; + +/// Example of how to use built_value. +/// +/// You can add static fields and methods, implement interfaces, add additonal +/// factory constructor, and generally use the class as a normal class. +abstract class ValueWithCode + implements Built { + static final int youCanHaveStaticFields = 3; + + int get anInt; + @nullable + String get aString; + + String get youCanWriteDerivedGetters => anInt.toString() + aString; + + ValueWithCode._(); + factory ValueWithCode([updates(ValueWithCodeBuilder b)]) = _$ValueWithCode; + + factory ValueWithCode.fromCustomFactory(int anInt) => + new ValueWithCode((b) => b + ..anInt = anInt + ..aString = 'two'); +} diff --git a/example/lib/value_with_code.g.dart b/example/lib/value_with_code.g.dart new file mode 100644 index 00000000..7faaa66e --- /dev/null +++ b/example/lib/value_with_code.g.dart @@ -0,0 +1,61 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of value_with_code; + +// ************************************************************************** +// Generator: BuiltValueGenerator +// Target: abstract class ValueWithCode +// ************************************************************************** + +class _$ValueWithCode extends ValueWithCode { + final int anInt; + final String aString; + + _$ValueWithCode._({this.anInt, this.aString}) : super._() { + if (anInt == null) throw new ArgumentError('null anInt'); + } + + factory _$ValueWithCode([updates(ValueWithCodeBuilder b)]) => + (new ValueWithCodeBuilder()..update(updates)).build(); + + ValueWithCode rebuild(updates(ValueWithCodeBuilder b)) => + (toBuilder()..update(updates)).build(); + + ValueWithCodeBuilder toBuilder() => new ValueWithCodeBuilder()..replace(this); + + bool operator ==(other) { + if (other is! ValueWithCode) return false; + return anInt == other.anInt && aString == other.aString; + } + + int get hashCode { + return hashObjects([anInt, aString]); + } + + String toString() { + return 'ValueWithCode {' + 'anInt=${anInt.toString()},\n' + 'aString=${aString.toString()},\n' + '}'; + } +} + +class ValueWithCodeBuilder + implements Builder { + ValueWithCodeBuilder(); + int anInt; + String aString; + + void replace(ValueWithCode other) { + this.anInt = other.anInt; + this.aString = other.aString; + } + + void update(updates(ValueWithCodeBuilder b)) { + if (updates != null) updates(this); + } + + ValueWithCode build() { + return new _$ValueWithCode._(anInt: anInt, aString: aString); + } +} diff --git a/example/lib/value_with_defaults.dart b/example/lib/value_with_defaults.dart new file mode 100644 index 00000000..c8130b00 --- /dev/null +++ b/example/lib/value_with_defaults.dart @@ -0,0 +1,42 @@ +// Copyright (c) 2016, Google Inc. 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. + +library value_with_defaults; + +import 'package:built_value/built_value.dart'; + +part 'value_with_defaults.g.dart'; + +/// Example of how to use built_value. +/// +/// To provide defaults, write the builder as an explicit class instead of +/// letting it be fully generated. See below. +abstract class ValueWithDefaults + implements Built { + int get anInt; + @nullable + String get aString; + + ValueWithDefaults._(); + factory ValueWithDefaults([updates(ValueWithDefaultsBuilder b)]) = + _$ValueWithDefaults; +} + +/// The builder class must implement [Builder]. It must be abstract, and have +/// fields declared as normal public fields. Finally, it must have a particular +/// constructor and factory, as shown here. +/// +/// Defaults can be specified by assigning them to fields here. +/// +/// You can further customize the builder by adding methods and setters +/// and implementing interfaces. +abstract class ValueWithDefaultsBuilder + implements Builder { + int anInt = 7; + @nullable + String aString; + + ValueWithDefaultsBuilder._(); + factory ValueWithDefaultsBuilder() = _$ValueWithDefaultsBuilder; +} diff --git a/example/lib/value_with_defaults.g.dart b/example/lib/value_with_defaults.g.dart new file mode 100644 index 00000000..7072858e --- /dev/null +++ b/example/lib/value_with_defaults.g.dart @@ -0,0 +1,58 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of value_with_defaults; + +// ************************************************************************** +// Generator: BuiltValueGenerator +// Target: abstract class ValueWithDefaults +// ************************************************************************** + +class _$ValueWithDefaults extends ValueWithDefaults { + final int anInt; + final String aString; + + _$ValueWithDefaults._({this.anInt, this.aString}) : super._() { + if (anInt == null) throw new ArgumentError('null anInt'); + } + + factory _$ValueWithDefaults([updates(ValueWithDefaultsBuilder b)]) => + (new ValueWithDefaultsBuilder()..update(updates)).build(); + + ValueWithDefaults rebuild(updates(ValueWithDefaultsBuilder b)) => + (toBuilder()..update(updates)).build(); + + _$ValueWithDefaultsBuilder toBuilder() => + new _$ValueWithDefaultsBuilder()..replace(this); + + bool operator ==(other) { + if (other is! ValueWithDefaults) return false; + return anInt == other.anInt && aString == other.aString; + } + + int get hashCode { + return hashObjects([anInt, aString]); + } + + String toString() { + return 'ValueWithDefaults {' + 'anInt=${anInt.toString()},\n' + 'aString=${aString.toString()},\n' + '}'; + } +} + +class _$ValueWithDefaultsBuilder extends ValueWithDefaultsBuilder { + _$ValueWithDefaultsBuilder() : super._(); + void replace(ValueWithDefaults other) { + super.anInt = other.anInt; + super.aString = other.aString; + } + + void update(updates(ValueWithDefaultsBuilder b)) { + if (updates != null) updates(this); + } + + ValueWithDefaults build() { + return new _$ValueWithDefaults._(anInt: anInt, aString: aString); + } +} diff --git a/example/pubspec.yaml b/example/pubspec.yaml index c6877eda..e034eab9 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,5 +1,5 @@ name: example -version: 0.1.2 +version: 0.1.3 description: > Just an example, not for publishing. authors: @@ -11,8 +11,12 @@ environment: dependencies: built_collection: '^1.0.0' - built_value: '^0.1.2' +# built_value: '^0.1.3' + built_value: + path: ../built_value dev_dependencies: - built_value_generator: '^0.1.2' +# built_value_generator: '^0.1.3' + built_value_generator: + path: ../built_value_generator test: any diff --git a/example/test/collections_test.dart b/example/test/collections_test.dart new file mode 100644 index 00000000..c4de0266 --- /dev/null +++ b/example/test/collections_test.dart @@ -0,0 +1,74 @@ +// Copyright (c) 2016, Google Inc. 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:built_collection/built_collection.dart'; +import 'package:example/collections.dart'; +import 'package:test/test.dart'; + +void main() { + group('Collections', () { + test('can be instantiated', () { + new Collections(); + }); + + test('default to empty if not nullable', () { + expect(new Collections().list.isEmpty, true); + expect(new Collections().set.isEmpty, true); + expect(new Collections().map.isEmpty, true); + expect(new Collections().listMultimap.isEmpty, true); + expect(new Collections().setMultimap.isEmpty, true); + }); + + test('default to null if nullable', () { + expect(new Collections().nullableList, null); + expect(new Collections().nullableSet, null); + expect(new Collections().nullableMap, null); + expect(new Collections().nullableListMultimap, null); + expect(new Collections().nullableSetMultimap, null); + }); + + test('can be updated via builder', () { + final collections = new Collections((b) => b + ..list.add(1) + ..set.add('two') + ..map['three'] = 4 + ..listMultimap.add(5, true) + ..setMultimap.add('six', false)); + + expect(collections.list, [1]); + expect(collections.set, ['two']); + expect(collections.map.toMap(), {'three': 4}); + expect(collections.listMultimap.toMap(), { + 5: [true] + }); + expect(collections.setMultimap.toMap(), { + 'six': [false] + }); + }); + + test('can be set from null via builder', () { + final collections = new Collections((b) => b + ..nullableList = new ListBuilder() + ..nullableSet = new SetBuilder() + ..nullableMap = new MapBuilder() + ..nullableListMultimap = new ListMultimapBuilder() + ..nullableSetMultimap = new SetMultimapBuilder() + ..nullableList.add(1) + ..nullableSet.add('two') + ..nullableMap['three'] = 4 + ..nullableListMultimap.add(5, true) + ..nullableSetMultimap.add('six', false)); + + expect(collections.nullableList, [1]); + expect(collections.nullableSet, ['two']); + expect(collections.nullableMap.toMap(), {'three': 4}); + expect(collections.nullableListMultimap.toMap(), { + 5: [true] + }); + expect(collections.nullableSetMultimap.toMap(), { + 'six': [false] + }); + }); + }); +} diff --git a/example/test/compound_value_test.dart b/example/test/compound_value_test.dart index 662133dc..3ec63204 100644 --- a/example/test/compound_value_test.dart +++ b/example/test/compound_value_test.dart @@ -3,20 +3,30 @@ // license that can be found in the LICENSE file. import 'package:example/compound_value.dart'; +import 'package:example/validated_value.dart'; import 'package:test/test.dart'; void main() { - group('compound value', () { + group('CompoundValue', () { test('can be instantiated', () { - new CompoundValue(); + new CompoundValue((b) => b..simpleValue.anInt = 1); }); test('allows nested updates', () { expect( - new CompoundValue((b) => b.value - ..anInt = 1 - ..anObject = 2).value.anInt, + new CompoundValue((b) => b + ..simpleValue.anInt = 1 + ..simpleValue.aString = 'two').simpleValue.anInt, 1); }); + + test('nullable nested builders can be assigned', () { + expect( + new CompoundValue((b) => b + ..simpleValue.anInt = 1 + ..validatedValue = new ValidatedValueBuilder() + ..validatedValue.anInt = 2).validatedValue.anInt, + 2); + }); }); } diff --git a/example/test/simple_value_test.dart b/example/test/simple_value_test.dart new file mode 100644 index 00000000..e196456c --- /dev/null +++ b/example/test/simple_value_test.dart @@ -0,0 +1,95 @@ +// Copyright (c) 2016, Google Inc. 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:example/simple_value.dart'; +import 'package:test/test.dart'; + +void main() { + group('SimpleValue', () { + test('can be instantiated', () { + new SimpleValue((b) => b..anInt = 0); + }); + + test('throws on null for non-nullable fields on build', () { + expect(() => new SimpleValue(), throws); + }); + + test('throws on wrong type assign', () { + expect(() => new SimpleValue((b) => b..anInt = '0'), throws); + }); + + test('fields can be set via build constructor', () { + final value = new SimpleValue((b) => b + ..anInt = 1 + ..aString = 'two'); + expect(value.anInt, 1); + expect(value.aString, 'two'); + }); + + test('fields can be updated via rebuild method', () { + final value = new SimpleValue((b) => b + ..anInt = 0 + ..aString = '').rebuild((b) => b + ..anInt = 1 + ..aString = 'two'); + expect(value.anInt, 1); + expect(value.aString, 'two'); + }); + + test('builder can be instantiated', () { + new SimpleValueBuilder(); + }); + + test('compares equal when equal', () { + final value1 = new SimpleValue((b) => b + ..anInt = 0 + ..aString = ''); + final value2 = new SimpleValue((b) => b + ..anInt = 0 + ..aString = ''); + expect(value1, value2); + }); + + test('compares not equal when not equal', () { + final value1 = new SimpleValue((b) => b + ..anInt = 0 + ..aString = ''); + final value2 = new SimpleValue((b) => b + ..anInt = 1 + ..aString = ''); + expect(value1, isNot(equals(value2))); + }); + + test('hashes equal when equal', () { + final value1 = new SimpleValue((b) => b + ..anInt = 0 + ..aString = ''); + final value2 = new SimpleValue((b) => b + ..anInt = 0 + ..aString = ''); + expect(value1.hashCode, value2.hashCode); + }); + + test('hashes not equal when not equal', () { + final value1 = new SimpleValue((b) => b + ..anInt = 0 + ..aString = ''); + final value2 = new SimpleValue((b) => b + ..anInt = 1 + ..aString = ''); + expect(value1.hashCode, isNot(equals(value2.hashCode))); + }); + + test('has toString', () { + final value1 = new SimpleValue((b) => b + ..anInt = 0 + ..aString = ''); + expect( + value1.toString(), + '''SimpleValue {anInt=0, +aString=, +}'''); + }); + }); +} diff --git a/example/test/validated_value_test.dart b/example/test/validated_value_test.dart new file mode 100644 index 00000000..f7af63cf --- /dev/null +++ b/example/test/validated_value_test.dart @@ -0,0 +1,18 @@ +// Copyright (c) 2015, Google Inc. 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:example/validated_value.dart'; +import 'package:test/test.dart'; + +void main() { + group('ValidatedValue', () { + test('can be instantiated', () { + new ValidatedValue((b) => b..anInt = 1); + }); + + test('does custom validation', () { + expect(() => new ValidatedValue((b) => b..anInt = 7), throws); + }); + }); +} diff --git a/example/test/value_test.dart b/example/test/value_test.dart deleted file mode 100644 index d3f9c153..00000000 --- a/example/test/value_test.dart +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright (c) 2015, Google Inc. 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:built_collection/built_collection.dart'; -import 'package:example/value.dart'; -import 'package:test/test.dart'; - -void main() { - group('value', () { - test('can be instantiated', () { - new Value((b) => b - ..anInt = 0 - ..aString = ''); - }); - - test('can be instantiated via custom factory', () { - expect( - new Value.fromCustomFactory(), - new Value((b) => b - ..anInt = 1 - ..aString = 'two')); - }); - - test('has defaults', () { - expect( - new Value((b) => b - ..anInt = 0 - ..aString = '').aDefaultInt, - 7); - }); - - test('throws on null for non-nullable fields on build', () { - expect(() => new Value(), throws); - }); - - test('throws on wrong type assign', () { - expect( - () => new Value((b) => b - ..anInt = '0' - ..aString = ''), - throws); - }); - - test('does custom validation', () { - expect( - () => new Value((b) => b - ..anInt = 7 - ..aString = ''), - throws); - }); - - test('fields can be set via build constructor', () { - final value = new Value((b) => b - ..anInt = 1 - ..aString = 'two' - ..anObject = 3); - expect(value.anInt, 1); - expect(value.aString, 'two'); - expect(value.anObject, 3); - }); - - test('fields can be updated via rebuild method', () { - final value = new Value((b) => b - ..anInt = 0 - ..aString = '').rebuild((b) => b - ..anInt = 1 - ..aString = 'two' - ..anObject = 3); - expect(value.anInt, 1); - expect(value.aString, 'two'); - expect(value.anObject, 3); - }); - - test('builder can be instantiated', () { - new ValueBuilder(); - }); - - test('collections can be updated using builder', () { - final value = new Value((b) => b - ..anInt = 1 - ..aString = 'two' - ..listOfInt.update((b) => b - ..addAll([3, 2, 1]) - ..sort())); - expect(value.listOfInt, [1, 2, 3]); - }); - - test('nullable builders can be updated', () { - final value = new Value((b) => b - ..anInt = 1 - ..aString = 'two' - ..setOfString = new SetBuilder(['1', '2', '3'])); - expect(value.setOfString, ['1', '2', '3']); - }); - - test('compares equal when equal', () { - final value1 = new Value((b) => b - ..anInt = 0 - ..aString = ''); - final value2 = new Value((b) => b - ..anInt = 0 - ..aString = ''); - expect(value1, value2); - }); - - test('compares not equal when not equal', () { - final value1 = new Value((b) => b - ..anInt = 0 - ..aString = ''); - final value2 = new Value((b) => b - ..anInt = 1 - ..aString = ''); - expect(value1, isNot(equals(value2))); - }); - - test('hashes equal when equal', () { - final value1 = new Value((b) => b - ..anInt = 0 - ..aString = ''); - final value2 = new Value((b) => b - ..anInt = 0 - ..aString = ''); - expect(value1.hashCode, value2.hashCode); - }); - - test('hashes not equal when not equal', () { - final value1 = new Value((b) => b - ..anInt = 0 - ..aString = ''); - final value2 = new Value((b) => b - ..anInt = 1 - ..aString = ''); - expect(value1.hashCode, isNot(equals(value2.hashCode))); - }); - - test('has toString', () { - final value1 = new Value((b) => b - ..anInt = 0 - ..aString = ''); - expect( - value1.toString(), - '''Value {anInt=0 -aString= -anObject=null -aDefaultInt=7 -listOfInt=[] -setOfString=null -}'''); - }); - }); -} diff --git a/example/test/value_with_code_test.dart b/example/test/value_with_code_test.dart new file mode 100644 index 00000000..2346c9b2 --- /dev/null +++ b/example/test/value_with_code_test.dart @@ -0,0 +1,26 @@ +// Copyright (c) 2016, Google Inc. 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:example/value_with_code.dart'; +import 'package:test/test.dart'; + +void main() { + group('ValueWithCode', () { + test('can be instantiated via custom factory', () { + expect( + new ValueWithCode.fromCustomFactory(12), + new ValueWithCode((b) => b + ..anInt = 12 + ..aString = 'two')); + }); + + test('has derived getter', () { + expect( + new ValueWithCode((b) => b + ..anInt = 12 + ..aString = 'two').youCanWriteDerivedGetters, + '12two'); + }); + }); +} diff --git a/example/test/value_with_defaults_test.dart b/example/test/value_with_defaults_test.dart new file mode 100644 index 00000000..e8129333 --- /dev/null +++ b/example/test/value_with_defaults_test.dart @@ -0,0 +1,14 @@ +// Copyright (c) 2016, Google Inc. 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:example/value_with_defaults.dart'; +import 'package:test/test.dart'; + +void main() { + group('ValueWithDefaults', () { + test('has defaults', () { + expect(new ValueWithDefaults().anInt, 7); + }); + }); +}