hoodoo 1.12.4 → 1.13.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -570,6 +570,99 @@ describe Hoodoo::Presenters::Hash do
570
570
 
571
571
  ############################################################################
572
572
 
573
+ class TestHashSpecificKeyTypes < Hoodoo::Presenters::Base
574
+ schema do
575
+ hash :specific_key_types, :default => { 'array' => [ 1, 2, 3 ], 'float' => 0.5 } do
576
+ key :array, :type => :array
577
+ key :boolean, :type => :boolean
578
+ key :date, :type => :date
579
+ key :date_time, :type => :date_time
580
+ key :decimal, :type => :decimal, :field_precision => 2
581
+ key :enum, :type => :enum, :field_from => [ :one, :two, :three ]
582
+ key :float, :type => :float
583
+ key :integer, :type => :integer, :field_default => 1 # ":field_default" (sic.)
584
+ key :string, :type => :string, :field_length => 4
585
+ key :tags, :type => :tags, :default => 'default,tags' # ":default" (sic.)
586
+ key :text, :type => :text
587
+ key :uuid, :type => :uuid
588
+ key :field
589
+ end
590
+ end
591
+ end
592
+
593
+ ############################################################################
594
+
595
+ context 'specific keys with elementary types and defaults' do
596
+ KEY_DATA = {
597
+ 'array' => { :valid => [ [ 2, 3, 4 ] ], :invalid => [ 4, { :one => 1 } ] },
598
+ 'boolean' => { :valid => [ true ], :invalid => [ 4.51, 'false' ] },
599
+ 'date' => { :valid => [ Date.today.iso8601 ], :invalid => [ Date.today, '23rd January 2041' ] },
600
+ 'date_time' => { :valid => [ DateTime.now.iso8601 ], :invalid => [ DateTime.now, '2017-01-27 12:00' ] },
601
+ 'decimal' => { :valid => [ BigDecimal.new(4.51, 2) ], :invalid => [ 4.51, '4.51' ] },
602
+ 'enum' => { :valid => [ 'one' ], :invalid => [ 'One', 1 ] },
603
+ 'float' => { :valid => [ 4.51 ], :invalid => [ BigDecimal.new(4.51, 2), '4.51' ] },
604
+ 'integer' => { :valid => [ 4 ], :invalid => [ '4' ] },
605
+ 'string' => { :valid => [ 'four' ], :invalid => [ 'toolong', 4, true ] },
606
+ 'tags' => { :valid => [ 'tag_a,tag_b,tag_c' ], :invalid => [ 4, true ] },
607
+ 'text' => { :valid => [ 'hello world' ], :invalid => [ 4, true ] },
608
+ 'uuid' => { :valid => [ Hoodoo::UUID.generate() ], :invalid => [ '123456', 4, true ] },
609
+ 'field' => { :valid => [ 4, '4', { :one => 1 } ], :invalid => [ ] }
610
+ }
611
+
612
+ context '#render' do
613
+ it 'renders correctly with whole-hash defaults' do
614
+ expected_data = { 'specific_key_types' => { 'array' => [ 1, 2, 3 ],
615
+ 'float' => 0.5,
616
+ 'integer' => 1,
617
+ 'tags' => 'default,tags' } }
618
+
619
+ expect( TestHashSpecificKeyTypes.render( {} ) ).to eq( expected_data )
620
+ expect( TestHashSpecificKeyTypes.render( nil ) ).to eq( expected_data )
621
+ end
622
+ end
623
+
624
+ KEY_DATA.each do | field, values |
625
+ context '#render' do
626
+ values[ :valid ].each_with_index do | value, index |
627
+ it "renders correctly for '#{ field }' (#{ index + 1 })" do
628
+
629
+ # Start with the defaults we expect given KEY_DATA definitions
630
+ # above then merge in the under-test field value. Only the inner
631
+ # field defaults are carried because we are passing a non-empty
632
+ # Hash in the top level for rendering, which overrides therefore
633
+ # the top-level Hash default.
634
+ #
635
+ expected_data = { 'specific_key_types' => { 'integer' => 1,
636
+ 'tags' => 'default,tags' } }
637
+
638
+ data = { 'specific_key_types' => { field => value } }
639
+ expected_data = Hoodoo::Utilities.deep_merge_into( expected_data, data )
640
+
641
+ expect( TestHashSpecificKeyTypes.render( data ) ).to eq( expected_data )
642
+ end
643
+ end
644
+ end
645
+
646
+ context '#validate' do
647
+ values[ :valid ].each_with_index do | value, index |
648
+ it "accepts a valid value for '#{ field }' (#{ index + 1 })" do
649
+ data = { 'specific_key_types' => { field => value } }
650
+ expect( TestHashSpecificKeyTypes.validate( data ).errors.size ).to( eql( 0 ) )
651
+ end
652
+ end
653
+
654
+ values[ :invalid ].each_with_index do | value, index |
655
+ it "rejects an invalid value for '#{ field }' (#{ index + 1 })" do
656
+ data = { 'specific_key_types' => { field => value } }
657
+ expect( TestHashSpecificKeyTypes.validate( data ).errors.size ).to( eql( 1 ) )
658
+ end
659
+ end
660
+ end
661
+ end
662
+ end
663
+
664
+ ############################################################################
665
+
573
666
  class TestHashGenericKeyPresenterNoValues < Hoodoo::Presenters::Base
574
667
  schema do
575
668
  hash :generic do
@@ -1066,4 +1159,501 @@ describe Hoodoo::Presenters::Hash do
1066
1159
  end
1067
1160
  end
1068
1161
 
1162
+ ############################################################################
1163
+
1164
+ KEYS_DATA = {
1165
+ 'array' => { :definition => { :length => 9, :type => :array }, :valid => [ [ 2, 3, 4 ] ], :invalid => [ 4, { :one => 1 } ] },
1166
+ 'boolean' => { :definition => { :length => 9, :type => :boolean }, :valid => [ true ], :invalid => [ 4.51, 'false' ] },
1167
+ 'date' => { :definition => { :length => 9, :type => :date }, :valid => [ Date.today.iso8601 ], :invalid => [ Date.today, '23rd January 2041' ] },
1168
+ 'date_time' => { :definition => { :length => 9, :type => :date_time }, :valid => [ DateTime.now.iso8601 ], :invalid => [ DateTime.now, '2017-01-27 12:00' ] },
1169
+ 'decimal' => { :definition => { :length => 9, :type => :decimal, :field_precision => 2 }, :valid => [ BigDecimal.new(4.51, 2) ], :invalid => [ 4.51, '4.51' ] },
1170
+ 'enum' => { :definition => { :length => 9, :type => :enum, :field_from => [ :one, :two, :three ] }, :valid => [ 'one' ], :invalid => [ 'One', 1 ] },
1171
+ 'float' => { :definition => { :length => 9, :type => :float }, :valid => [ 4.51 ], :invalid => [ BigDecimal.new(4.51, 2), '4.51' ] },
1172
+ 'integer' => { :definition => { :length => 9, :type => :integer }, :valid => [ 4 ], :invalid => [ '4' ] },
1173
+ 'string' => { :definition => { :length => 9, :type => :string, :field_length => 4 }, :valid => [ 'four' ], :invalid => [ 'toolong', 4, true ] },
1174
+ 'tags' => { :definition => { :length => 9, :type => :tags }, :valid => [ 'tag_a,tag_b,tag_c' ], :invalid => [ 4, true ] },
1175
+ 'text' => { :definition => { :length => 9, :type => :text }, :valid => [ 'hello world' ], :invalid => [ 4, true ] },
1176
+ 'uuid' => { :definition => { :length => 9, :type => :uuid }, :valid => [ Hoodoo::UUID.generate() ], :invalid => [ '123456', 4, true ] },
1177
+ 'field' => { :definition => { :length => 9 }, :valid => [ 4, '4', { :one => 1 } ], :invalid => [ ] },
1178
+ '1234567890' => { :definition => { :length => 9 }, :valid => [ ], :invalid => [ 'Any value; key is too long' ] },
1179
+ }
1180
+
1181
+ KEYS_DATA.each do | field, values |
1182
+ context "keys with elementary type '#{ values[ :definition ][ :type ] || 'field' }'" do
1183
+ before :all do
1184
+
1185
+ # Flatten local scope to access 'values' inside the class definition;
1186
+ # see e.g.:
1187
+ #
1188
+ # https://gist.github.com/Integralist/a29212a8eb10bc8154b7#file-07-flattening-the-scope-aka-nested-lexical-scopes-rb
1189
+ #
1190
+ # Per-key defaults don't apply to generic Hashes because a key is
1191
+ # either given to validate or render with in the caller-provided
1192
+ # input parameters, in which case it already must have a value -
1193
+ # even if explicitly "nil" - or the key is absent, in which case
1194
+ # we have nothing to associate a daefault value with.
1195
+ #
1196
+ # Per-hash full defaults are supported but we can't really do those
1197
+ # here as valid defaults will change for every line in KEYS_DATA
1198
+ # with the changing types required by the keys.
1199
+ #
1200
+ @test_class = Class.new( Hoodoo::Presenters::Base ) do
1201
+ schema do
1202
+ hash :keys_types do
1203
+ keys( values[ :definition ] )
1204
+ end
1205
+ end
1206
+ end
1207
+ end
1208
+
1209
+ context '#render' do
1210
+ values[ :valid ].each_with_index do | value, index |
1211
+ it "renders correctly for '#{ field }' (#{ index + 1 })" do
1212
+ data = { 'keys_types' => { field => value } }
1213
+ expect( @test_class.render( data ) ).to eq( data )
1214
+ end
1215
+ end
1216
+ end
1217
+
1218
+ context '#validate' do
1219
+ values[ :valid ].each_with_index do | value, index |
1220
+ it "accepts a valid value for '#{ field }' (#{ index + 1 })" do
1221
+ data = { 'keys_types' => { field => value } }
1222
+ expect( @test_class.validate( data ).errors.size ).to( eql( 0 ) )
1223
+ end
1224
+ end
1225
+
1226
+ values[ :invalid ].each_with_index do | value, index |
1227
+ it "rejects an invalid value for '#{ field }' (#{ index + 1 })" do
1228
+ data = { 'keys_types' => { field => value } }
1229
+ expect( @test_class.validate( data ).errors.size ).to( eql( 1 ) )
1230
+ end
1231
+ end
1232
+ end
1233
+ end
1234
+ end
1235
+
1236
+ ############################################################################
1237
+
1238
+ class TestHashKeyDefaultAggregation < Hoodoo::Presenters::Base
1239
+ schema do
1240
+ hash :test, :default => { :three => 3 } do
1241
+
1242
+ key :one, :default => { :foo => 'bar' }
1243
+ key :two, :default => { 'bar' => :baz }
1244
+ key :three, :type => :integer
1245
+
1246
+ end
1247
+ end
1248
+ end
1249
+
1250
+ it 'aggregates default shallow Hash and key values' do
1251
+ expected = {
1252
+ 'test' => {
1253
+ 'one' => { 'foo' => 'bar' },
1254
+ 'two' => { 'bar' => :baz },
1255
+ 'three' => 3
1256
+ }
1257
+ }
1258
+
1259
+ expect( TestHashKeyDefaultAggregation.render( {} ) ).to eql( expected )
1260
+ end
1261
+
1262
+ it 'overrides default shallow Hash values' do
1263
+ data = {
1264
+ 'test' => {}
1265
+ }
1266
+
1267
+ expected = {
1268
+ 'test' => {
1269
+ 'one' => { 'foo' => 'bar' }, # From the key default
1270
+ 'two' => { 'bar' => :baz } # From the key default
1271
+ # No 'three'; we fully overrode the top-level Hash default in 'data'
1272
+ }
1273
+ }
1274
+
1275
+ expect( TestHashKeyDefaultAggregation.render( data ) ).to eql( expected )
1276
+ end
1277
+
1278
+ it 'overrides shallow default key values' do
1279
+ data = {
1280
+ 'test' => {
1281
+ 'two' => { 'foo' => 'baz' }
1282
+ }
1283
+ }
1284
+
1285
+ expected = {
1286
+ 'test' => {
1287
+ 'one' => { 'foo' => 'bar' }, # From the key default
1288
+ 'two' => { 'foo' => 'baz' } # From 'data' above
1289
+ # No 'three'; we fully overrode the top-level Hash default in 'data'
1290
+ }
1291
+ }
1292
+
1293
+ expect( TestHashKeyDefaultAggregation.render( data ) ).to eql( expected )
1294
+ end
1295
+
1296
+ # TODO: This class does not work as originally hoped.
1297
+ # TODO: Illustrates workaround in https://github.com/LoyaltyNZ/hoodoo/issues/194
1298
+ # TODO: Move default off ":two" and into ":inner_two" if above is addressed.
1299
+ #
1300
+ class TestHashKeyDeepDefaultAggregation < Hoodoo::Presenters::Base
1301
+ schema do
1302
+ hash :test do # A default here would implicitly override anything on :two below
1303
+
1304
+ key :one, :default => { :foo => 'bar' }
1305
+ key :three, :type => :integer
1306
+
1307
+ key :two, :default => { 'inner_two' => { 'inner_three' => 'three' } } do
1308
+ hash :inner_two do
1309
+ key :inner_one, :default => { :bar => 'baz' }
1310
+ key :inner_three, :type => :text
1311
+ end
1312
+ end
1313
+ end
1314
+ end
1315
+ end
1316
+
1317
+ it 'aggregates default deep Hash and key values' do
1318
+ expected = {
1319
+ 'test' => {
1320
+ 'one' => { 'foo' => 'bar' },
1321
+ 'two' => {
1322
+ 'inner_two' => {
1323
+ 'inner_one' => { 'bar' => 'baz' },
1324
+ 'inner_three' => 'three'
1325
+ }
1326
+ }
1327
+ }
1328
+ }
1329
+
1330
+ expect( TestHashKeyDeepDefaultAggregation.render( {} ) ).to eql( expected )
1331
+ end
1332
+
1333
+ it 'overrides shallow deep Hash values, preserving deep values' do
1334
+ data = {
1335
+ 'test' => {}
1336
+ }
1337
+
1338
+ expected = {
1339
+ 'test' => {
1340
+ 'one' => { 'foo' => 'bar' }, # From the key default
1341
+ # No 'three'; we fully overrode the top-level Hash default in 'data'
1342
+ 'two' => {
1343
+ 'inner_two' => {
1344
+ 'inner_one' => { 'bar' => 'baz' }, # From the key default
1345
+ 'inner_three' => 'three' # From the deep Hash default
1346
+ }
1347
+ }
1348
+ }
1349
+ }
1350
+
1351
+ expect( TestHashKeyDeepDefaultAggregation.render( data ) ).to eql( expected )
1352
+ end
1353
+
1354
+ it 'overrides default deep Hash values' do
1355
+ data = {
1356
+ 'test' => {
1357
+ 'two' => {
1358
+ }
1359
+ }
1360
+ }
1361
+
1362
+ expected = {
1363
+ 'test' => {
1364
+ 'one' => { 'foo' => 'bar' }, # From the key default
1365
+ # No 'three'; we fully overrode the top-level Hash default in 'data'
1366
+ 'two' => {
1367
+ 'inner_two' => {
1368
+ 'inner_one' => { 'bar' => 'baz' } # From the key default
1369
+ # No 'inner_three'; we overrode the deep Hash default in 'data'
1370
+ }
1371
+ }
1372
+ }
1373
+ }
1374
+
1375
+ expect( TestHashKeyDeepDefaultAggregation.render( data ) ).to eql( expected )
1376
+ end
1377
+
1378
+ it 'overrides deep deep key values' do
1379
+ data = {
1380
+ 'test' => {
1381
+ 'two' => {
1382
+ 'inner_two' => {
1383
+ 'inner_one' => { 'bar' => 'hello' }
1384
+ }
1385
+ }
1386
+ }
1387
+ }
1388
+
1389
+ expected = {
1390
+ 'test' => {
1391
+ 'one' => { 'foo' => 'bar' }, # From the key default
1392
+ # No 'three'; we fully overrode the top-level Hash default in 'data'
1393
+ 'two' => {
1394
+ 'inner_two' => {
1395
+ 'inner_one' => { 'bar' => 'hello' } # From 'data' above
1396
+ # No 'inner_three'; we overrode the deep Hash default in 'data'
1397
+ }
1398
+ }
1399
+ }
1400
+ }
1401
+
1402
+ expect( TestHashKeyDeepDefaultAggregation.render( data ) ).to eql( expected )
1403
+ end
1404
+
1405
+ ############################################################################
1406
+
1407
+ context 'RDoc examples' do
1408
+ class TestHypotheticaHashCurrency < Hoodoo::Presenters::Base
1409
+ schema do
1410
+ string :currency_code, :length => 16
1411
+ integer :precision
1412
+ end
1413
+ end
1414
+
1415
+ context 'CurrencyHash' do
1416
+ class TestCurrencyHash < Hoodoo::Presenters::Base
1417
+ schema do
1418
+ hash :currencies do
1419
+ keys :length => 16 do
1420
+ type TestHypotheticaHashCurrency
1421
+ end
1422
+ end
1423
+ end
1424
+ end
1425
+
1426
+ let( :valid_data ) do
1427
+ {
1428
+ 'currencies' => {
1429
+ 'one' => {
1430
+ 'currency_code' => 'X_HOODOO_LO',
1431
+ 'precision' => 1
1432
+ },
1433
+ '0123456789ABCDEF' => {
1434
+ 'currency_code' => 'X_HOODOO_HI',
1435
+ 'precision' => 4
1436
+ }
1437
+ }
1438
+ }
1439
+ end
1440
+
1441
+ context '#validate' do
1442
+ it 'enforces field and key restrictions' do
1443
+ data = {
1444
+ 'currencies' => {
1445
+ 'one' => {
1446
+ 'currency_code' => 'too long a currency code',
1447
+ 'precision' => 1
1448
+ },
1449
+ '0123456789ABCDEF' => {
1450
+ 'currency_code' => 'X_HOODOO_HI',
1451
+ 'precision' => 'not an integer'
1452
+ },
1453
+ 'too long a key name overall' => {
1454
+ 'currency_code' => 'X_HOODOO_LO',
1455
+ 'precision' => 1
1456
+ }
1457
+ }
1458
+ }
1459
+
1460
+ errors = TestCurrencyHash.validate( data ).errors
1461
+
1462
+ expect( errors.size ).to( eql( 3 ) )
1463
+
1464
+ expect( errors[ 0 ][ 'code' ] ).to( eql( 'generic.invalid_string' ) )
1465
+ expect( errors[ 0 ][ 'reference' ] ).to( eql( 'currencies.one.currency_code' ) )
1466
+
1467
+ expect( errors[ 1 ][ 'code' ] ).to( eql( 'generic.invalid_integer' ) )
1468
+ expect( errors[ 1 ][ 'reference' ] ).to( eql( 'currencies.0123456789ABCDEF.precision' ) )
1469
+
1470
+ expect( errors[ 2 ][ 'code' ] ).to( eql( 'generic.invalid_string' ) )
1471
+ expect( errors[ 2 ][ 'reference' ] ).to( eql( 'currencies.too long a key name overall' ) )
1472
+ end
1473
+
1474
+ it 'is happy with valid data' do
1475
+ expect( TestCurrencyHash.validate( valid_data() ).errors.size ).to( eql( 0 ) )
1476
+ end
1477
+ end
1478
+
1479
+ context '#render' do
1480
+ it 'renders valid data' do
1481
+ expect( TestCurrencyHash.render( valid_data() ) ).to( eql( valid_data() ) )
1482
+ end
1483
+ end
1484
+ end
1485
+
1486
+ context 'AltCurrencyHash' do
1487
+ class TestAltCurrencyHash < Hoodoo::Presenters::Base
1488
+ schema do
1489
+ hash :currencies do
1490
+ key :one do
1491
+ type TestHypotheticaHashCurrency
1492
+ end
1493
+
1494
+ key :two do
1495
+ text :title
1496
+ text :description
1497
+ end
1498
+ end
1499
+ end
1500
+ end
1501
+
1502
+ let( :valid_data ) do
1503
+ {
1504
+ 'currencies' => {
1505
+ 'one' => {
1506
+ 'currency_code' => 'X_HOODOO_LO',
1507
+ 'precision' => 1
1508
+ },
1509
+ 'two' => {
1510
+ 'title' => 'Optional title text',
1511
+ 'description' => 'Optional description text'
1512
+ }
1513
+ }
1514
+ }
1515
+ end
1516
+
1517
+ context '#validate' do
1518
+ it 'enforces field restrictions' do
1519
+ data = {
1520
+ 'currencies' => {
1521
+ 'one' => {
1522
+ 'currency_code' => 'too long a currency code',
1523
+ 'precision' => 1
1524
+ }
1525
+ }
1526
+ }
1527
+
1528
+ errors = TestAltCurrencyHash.validate( data ).errors
1529
+
1530
+ expect( errors.size ).to( eql( 1 ) )
1531
+ expect( errors[ 0 ][ 'code' ] ).to( eql( 'generic.invalid_string' ) )
1532
+ expect( errors[ 0 ][ 'reference' ] ).to( eql( 'currencies.one.currency_code' ) )
1533
+ end
1534
+
1535
+ it 'enforces key name restrictions' do
1536
+ data = {
1537
+ 'currencies' => {
1538
+ 'unrecognised' => {
1539
+ 'currency_code' => 'X_HOODOO_LO',
1540
+ 'precision' => 1
1541
+ }
1542
+ }
1543
+ }
1544
+
1545
+ errors = TestAltCurrencyHash.validate( data ).errors
1546
+
1547
+ expect( errors.size ).to( eql( 1 ) )
1548
+ expect( errors[ 0 ][ 'code' ] ).to( eql( 'generic.invalid_hash' ) )
1549
+ expect( errors[ 0 ][ 'reference' ] ).to( eql( 'currencies' ) )
1550
+ end
1551
+
1552
+ it 'is happy with valid data' do
1553
+ expect( TestAltCurrencyHash.validate( valid_data() ).errors.size ).to( eql( 0 ) )
1554
+ end
1555
+ end
1556
+
1557
+ context '#render' do
1558
+ it 'renders valid data' do
1559
+ expect( TestAltCurrencyHash.render( valid_data() ) ).to( eql( valid_data() ) )
1560
+ end
1561
+ end
1562
+ end
1563
+
1564
+ context 'Person' do
1565
+ class TestPerson < Hoodoo::Presenters::Base
1566
+ schema do
1567
+ hash :name do
1568
+ key :first, :type => :text
1569
+ key :last, :type => :text
1570
+ end
1571
+
1572
+ hash :address do
1573
+ keys :type => :text
1574
+ end
1575
+
1576
+ hash :identifiers, :required => true do
1577
+ keys :length => 8, :type => :string, :field_length => 32
1578
+ end
1579
+ end
1580
+ end
1581
+
1582
+ let( :valid_data ) do
1583
+ {
1584
+ 'name' => {
1585
+ 'first' => 'Test',
1586
+ 'last' => 'Testy'
1587
+ },
1588
+ 'address' => {
1589
+ 'road' => '1 Test Street',
1590
+ 'city' => 'Testville',
1591
+ 'post_code' => 'T01 C41'
1592
+ },
1593
+ 'identifiers' => {
1594
+ 'primary' => '9759c77d188f4bfe85959738dc6f8505',
1595
+ 'postgres' => '1442'
1596
+ }
1597
+ }
1598
+ end
1599
+
1600
+ context '#validate' do
1601
+ it 'enforces a required hash' do
1602
+ data = Hoodoo::Utilities.deep_dup( valid_data() )
1603
+ data.delete( 'identifiers' )
1604
+
1605
+ errors = TestPerson.validate( data ).errors
1606
+
1607
+ expect( errors.size ).to( eql( 1 ) )
1608
+ expect( errors[ 0 ][ 'code' ] ).to( eql( 'generic.required_field_missing' ) )
1609
+ expect( errors[ 0 ][ 'reference' ] ).to( eql( 'identifiers' ) )
1610
+ end
1611
+
1612
+ it 'enforces field and key restrictions' do
1613
+ data = {
1614
+ 'name' => {
1615
+ 'first' => 'Test',
1616
+ 'surname' => 'Testy' # Invalid key name
1617
+ },
1618
+ 'address' => {
1619
+ 'road' => '1 Test Street',
1620
+ 'city' => 'Testville',
1621
+ 'zip' => 90421 # Integer, not Text
1622
+ },
1623
+ 'identifiers' => {
1624
+ 'primary' => '9759c77d188f4bfe85959738dc6f8505_441', # Value too long
1625
+ 'postgresql' => '1442' # Key name too long
1626
+ }
1627
+ }
1628
+
1629
+ errors = TestPerson.validate( data ).errors
1630
+
1631
+ expect( errors.size ).to( eql( 4 ) )
1632
+
1633
+ expect( errors[ 0 ][ 'code' ] ).to( eql( 'generic.invalid_hash' ) )
1634
+ expect( errors[ 0 ][ 'reference' ] ).to( eql( 'name' ) )
1635
+
1636
+ expect( errors[ 1 ][ 'code' ] ).to( eql( 'generic.invalid_string' ) )
1637
+ expect( errors[ 1 ][ 'reference' ] ).to( eql( 'address.zip' ) )
1638
+
1639
+ expect( errors[ 2 ][ 'code' ] ).to( eql( 'generic.invalid_string' ) )
1640
+ expect( errors[ 2 ][ 'reference' ] ).to( eql( 'identifiers.primary' ) )
1641
+
1642
+ expect( errors[ 3 ][ 'code' ] ).to( eql( 'generic.invalid_string' ) )
1643
+ expect( errors[ 3 ][ 'reference' ] ).to( eql( 'identifiers.postgresql' ) )
1644
+ end
1645
+
1646
+ it 'is happy with valid data' do
1647
+ expect( TestPerson.validate( valid_data() ).errors.size ).to( eql( 0 ) )
1648
+ end
1649
+ end
1650
+
1651
+ context '#render' do
1652
+ it 'renders valid data' do
1653
+ expect( TestPerson.render( valid_data() ) ).to( eql( valid_data() ) )
1654
+ end
1655
+ end
1656
+ end
1657
+ end
1658
+
1069
1659
  end