From 019969580704d0b807529bfd776ef9398715fd89 Mon Sep 17 00:00:00 2001 From: Jeff Ashton Date: Fri, 11 Dec 2020 13:01:44 -0500 Subject: [PATCH] Importing AttributeValueAssert (#2) --- .github/workflows/build.yml | 40 +- D2L.DynamoDBv2.NUnitHelpers.sln | 1 + .../AmazonDynamoDBAssert.cs | 59 ++ .../AmazonDynamoDBLocal.cs | 33 + .../AttributeValueAssert.cs | 227 ++++++ .../AmazonDynamoDBAssertTests.cs | 224 ++++++ .../AttributeValueAssertTests.cs | 725 ++++++++++++++++++ .../D2L.DynamoDBv2.NUnitHelpers.Tests.csproj | 1 + 8 files changed, 1303 insertions(+), 7 deletions(-) create mode 100644 src/D2L.DynamoDBv2.NUnitHelpers/AmazonDynamoDBAssert.cs create mode 100644 src/D2L.DynamoDBv2.NUnitHelpers/AmazonDynamoDBLocal.cs create mode 100644 src/D2L.DynamoDBv2.NUnitHelpers/AttributeValueAssert.cs create mode 100644 test/D2L.DynamoDBv2.NUnitHelpers.Tests/AmazonDynamoDBAssertTests.cs create mode 100644 test/D2L.DynamoDBv2.NUnitHelpers.Tests/AttributeValueAssertTests.cs diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b2f96ee..75b8fbe 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -5,7 +5,30 @@ env: VERSION_PREFIX: "0.0.1" jobs: - build: + + # Need to test and pack separately because github actions only support docker services in linux, + # but linux doesn't support targetting net45 framework. + test: + runs-on: ubuntu-latest + + services: + dynamo: + image: amazon/dynamodb-local + ports: [ '8000:8000' ] + + steps: + + - uses: Brightspace/third-party-actions@actions/checkout + + - name: Setup .NET Core + uses: Brightspace/third-party-actions@actions/setup-dotnet + with: + dotnet-version: 3.1.x + + - name: dotnet test --framework "netcoreapp3.1" + run: dotnet test --configuration Release --framework "netcoreapp3.1" + + pack: runs-on: windows-latest steps: @@ -23,11 +46,14 @@ jobs: - name: Generate version properties run: dotnet ci-version-properties --output VersionInfo.props && cat VersionInfo.props - - name: dotnet restore - run: dotnet restore + - name: dotnet test + run: dotnet pack --configuration Release - - name: dotnet build - run: dotnet build --configuration Release + - name: Copy *.nuget to dist/ + run: mkdir dist/ && cp src/D2L.DynamoDBv2.NUnitHelpers/bin/Release/*.nupkg dist/ - - name: dotnet test - run: dotnet test --configuration Release --no-build + - name: Archive dist/ + uses: actions/upload-artifact@v1 + with: + name: dist + path: dist/ diff --git a/D2L.DynamoDBv2.NUnitHelpers.sln b/D2L.DynamoDBv2.NUnitHelpers.sln index 327f6e8..919f6ce 100644 --- a/D2L.DynamoDBv2.NUnitHelpers.sln +++ b/D2L.DynamoDBv2.NUnitHelpers.sln @@ -8,6 +8,7 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{356A87B5-A285-4018-8923-D8409A373B54}" ProjectSection(SolutionItems) = preProject .editorconfig = .editorconfig + .github\workflows\build.yml = .github\workflows\build.yml Directory.Build.props = Directory.Build.props EndProjectSection EndProject diff --git a/src/D2L.DynamoDBv2.NUnitHelpers/AmazonDynamoDBAssert.cs b/src/D2L.DynamoDBv2.NUnitHelpers/AmazonDynamoDBAssert.cs new file mode 100644 index 0000000..8786393 --- /dev/null +++ b/src/D2L.DynamoDBv2.NUnitHelpers/AmazonDynamoDBAssert.cs @@ -0,0 +1,59 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Amazon.DynamoDBv2; +using Amazon.DynamoDBv2.Model; +using NUnit.Framework; + +namespace D2L.DynamoDBv2.NUnitHelpers { + + public static class AmazonDynamoDBAssert { + + public static async Task AssertItemAsync( + this IAmazonDynamoDB db, + string tableName, + Dictionary key, + Dictionary expectedItem + ) { + + GetItemRequest request = new GetItemRequest { + TableName = tableName, + Key = key, + ConsistentRead = true + }; + + GetItemResponse response = await db + .GetItemAsync( request ) + .ConfigureAwait( false ); + + if( !response.IsItemSet ) { + Assert.Fail( "Item should exist." ); + } + + AttributeValueAssert.AreEqual( + actual: response.Item, + expected: expectedItem + ); + } + + public static async Task AssertItemDoesNotExistAsync( + this IAmazonDynamoDB db, + string tableName, + Dictionary key + ) { + + GetItemRequest request = new GetItemRequest { + TableName = tableName, + Key = key, + ConsistentRead = true + }; + + GetItemResponse response = await db + .GetItemAsync( request ) + .ConfigureAwait( false ); + + if( response.IsItemSet ) { + Assert.Fail( "Item should not exist." ); + } + } + } +} diff --git a/src/D2L.DynamoDBv2.NUnitHelpers/AmazonDynamoDBLocal.cs b/src/D2L.DynamoDBv2.NUnitHelpers/AmazonDynamoDBLocal.cs new file mode 100644 index 0000000..4d9e4ad --- /dev/null +++ b/src/D2L.DynamoDBv2.NUnitHelpers/AmazonDynamoDBLocal.cs @@ -0,0 +1,33 @@ +using System; +using Amazon.DynamoDBv2; +using Amazon.Runtime; + +namespace D2L.DynamoDBv2.NUnitHelpers { + + public static class AmazonDynamoDBLocal { + + /// + /// Creates an client for DynamoDB local. + /// + /// The service url is defined by the environment variable DYNAMODB_LOCAL_SERVICE_URL if set; otherwise http://localhost:8000 will be used. + /// + /// Returns an Amazon DynamoDB client. + public static IAmazonDynamoDB CreateClient() { + + string? serviceUrl = Environment.GetEnvironmentVariable( "DYNAMODB_LOCAL_SERVICE_URL" ); + if( serviceUrl == null ) { + serviceUrl = "http://localhost:8000"; + } + + return new AmazonDynamoDBClient( + credentials: new BasicAWSCredentials( + accessKey: "accessKey", + secretKey: "secretKey" + ), + clientConfig: new AmazonDynamoDBConfig { + ServiceURL = serviceUrl + } + ); + } + } +} diff --git a/src/D2L.DynamoDBv2.NUnitHelpers/AttributeValueAssert.cs b/src/D2L.DynamoDBv2.NUnitHelpers/AttributeValueAssert.cs new file mode 100644 index 0000000..58b26b8 --- /dev/null +++ b/src/D2L.DynamoDBv2.NUnitHelpers/AttributeValueAssert.cs @@ -0,0 +1,227 @@ +using System; +using System.Collections.Generic; +using System.IO; +using Amazon.DynamoDBv2.Model; +using NUnit.Framework; + +namespace D2L.DynamoDBv2.NUnitHelpers { + + public static class AttributeValueAssert { + + public static void AreEqual( + Dictionary actual, + Dictionary expected + ) { + + AssertMapAttributes( + path: "M", + actual: actual, + expected: expected + ); + } + + public static void AreEqual( + AttributeValue actual, + AttributeValue expected + ) { + + AssertAttributeValue( + path: string.Empty, + actual: actual, + expected: expected + ); + } + + private static void AssertListAttributes( + string path, + List actual, + List expected + ) { + + Assert.That( + actual.Count, + Is.EqualTo( expected.Count ), + "List length must be equal ({0})", + path + ); + + for( int i = 0; i < actual.Count; i++ ) { + + AssertAttributeValue( + path: $"{ path }[{ i }].", + actual: actual[ i ], + expected: expected[ i ] + ); + } + } + + private static void AssertMapAttributes( + string path, + Dictionary actual, + Dictionary expected + ) { + + Assert.That( + actual.Keys, + Is.EquivalentTo( expected.Keys ), + "{0}.Keys must be equivalent", + path + ); + + foreach( KeyValuePair pair in actual ) { + + AssertAttributeValue( + path: $"{ path }[{ pair.Key }].", + actual: pair.Value, + expected: expected[ pair.Key ] + ); + } + } + + private static void AssertAttributeValue( + string path, + AttributeValue actual, + AttributeValue expected + ) { + + if( actual.B != null && expected.B != null ) { + + Assert.That( + actual.B.ToArray(), + Is.EqualTo( expected.B.ToArray() ), + "{0}B must be equal", + path + ); + + } else { + + Assert.That( + actual.B, + Is.EqualTo( expected.B ), + "{0}B must be equal", + path + ); + } + + Assert.That( + actual.IsBOOLSet, + Is.EqualTo( expected.IsBOOLSet ), + "{0}IsBOOLSet must be equal", + path + ); + + Assert.That( + actual.BOOL, + Is.EqualTo( expected.BOOL ), + "{0}BOOL must be equal", + path + ); + + Assert.That( + actual.BS, + Is.EquivalentTo( expected.BS ).Using( MemoryStreamEqualityComparer.Instance ), + "{0}BS must be equivalent", + path + ); + + Assert.That( + actual.IsLSet, + Is.EqualTo( expected.IsLSet ), + "{0}IsLSet must be equal", + path + ); + + AssertListAttributes( + path: $"{ path }L", + actual: actual.L, + expected: expected.L + ); + + Assert.That( + actual.IsMSet, + Is.EqualTo( expected.IsMSet ), + "{0}IsMSet must be equal", + path + ); + + AssertMapAttributes( + path: $"{ path }M", + actual: actual.M, + expected: expected.M + ); + + Assert.That( + actual.N, + Is.EqualTo( expected.N ), + "{0}N must be equal", + path + ); + + Assert.That( + actual.NULL, + Is.EqualTo( expected.NULL ), + "{0}NULL must be equal", + path + ); + + Assert.That( + actual.NS, + Is.EquivalentTo( expected.NS ), + "{0}NS must be equivalent", + path + ); + + Assert.That( + actual.S, + Is.EqualTo( expected.S ), + "{0}S must be equal", + path + ); + + Assert.That( + actual.SS, + Is.EquivalentTo( expected.SS ), + "{0}SS must be equivalent", + path + ); + } + + private sealed class MemoryStreamEqualityComparer : IEqualityComparer { + + internal static readonly IEqualityComparer Instance = new MemoryStreamEqualityComparer(); + private MemoryStreamEqualityComparer() { } + + bool IEqualityComparer.Equals( MemoryStream? x, MemoryStream? y ) { + + if( ReferenceEquals( x, y ) ) { + return true; + } + + if( x != null && y != null ) { + + if( x.Length != y.Length ) { + return false; + } + + byte[] xBytes = x.ToArray(); + byte[] yBytes = y.ToArray(); + + for( int i = 0; i < xBytes.Length; i++ ) { + + if( xBytes[ i ] != yBytes[ i ] ) { + return false; + } + } + + return true; + } + + return false; + } + + int IEqualityComparer.GetHashCode( MemoryStream obj ) { + throw new NotImplementedException(); + } + } + } +} diff --git a/test/D2L.DynamoDBv2.NUnitHelpers.Tests/AmazonDynamoDBAssertTests.cs b/test/D2L.DynamoDBv2.NUnitHelpers.Tests/AmazonDynamoDBAssertTests.cs new file mode 100644 index 0000000..788bff0 --- /dev/null +++ b/test/D2L.DynamoDBv2.NUnitHelpers.Tests/AmazonDynamoDBAssertTests.cs @@ -0,0 +1,224 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Amazon.DynamoDBv2; +using Amazon.DynamoDBv2.Model; +using NUnit.Framework; + +namespace D2L.DynamoDBv2.NUnitHelpers.Tests { + + [TestFixture] + internal sealed class AmazonDynamoDBAssertTests { + + private IAmazonDynamoDB m_db; + private string m_tableName; + + [OneTimeSetUp] + public async Task OneTimeSetUp() { + + m_db = AmazonDynamoDBLocal.CreateClient(); + m_tableName = Guid.NewGuid().ToString(); + + await m_db + .CreateTableAsync( + tableName: m_tableName, + keySchema: new List { + new KeySchemaElement( "key", KeyType.HASH ) + }, + attributeDefinitions: new List { + new AttributeDefinition( "key", ScalarAttributeType.S ) + }, + provisionedThroughput: new ProvisionedThroughput( 1, 1 ) + ) + .ConfigureAwait( continueOnCapturedContext: false ); + } + + [OneTimeTearDown] + public async Task OneTimeTearDown() { + + await m_db + .DeleteTableAsync( m_tableName ) + .ConfigureAwait( continueOnCapturedContext: false ); + + m_db.Dispose(); + } + + private AttributeValue GenerateKey() { + return new AttributeValue( Guid.NewGuid().ToString() ); + } + + #region AssertItemAsync Tests + + [Test] + public async Task AssertItemAsync_WhenExistsAndEqual() { + + AttributeValue key = GenerateKey(); + + Dictionary item = new Dictionary { + { "key", key }, + { "age", new AttributeValue { N = "111" } } + }; + + await m_db + .PutItemAsync( m_tableName, item ) + .ConfigureAwait( continueOnCapturedContext: false ); + + Assert.DoesNotThrowAsync( async () => { + + await AmazonDynamoDBAssert + .AssertItemAsync( + m_db, + m_tableName, + key: new Dictionary { + { "key", key } + }, + expectedItem: item + ) + .ConfigureAwait( continueOnCapturedContext: false ); + } ); + } + + [Test] + public async Task AssertItemAsync_WhenExistsAndNotEqual() { + + AttributeValue key = GenerateKey(); + + Dictionary item = new Dictionary { + { "key", key }, + { "age", new AttributeValue { N = "222" } } + }; + + await m_db + .PutItemAsync( m_tableName, item ) + .ConfigureAwait( continueOnCapturedContext: false ); + + Dictionary itemKey = new Dictionary { + { "key", key } + }; + + Dictionary expectedItem = new Dictionary { + { "key", key }, + { "age", new AttributeValue { N = "333" } } + }; + + var err = Assert.Throws( () => { + + AmazonDynamoDBAssert + .AssertItemAsync( + m_db, + m_tableName, + key: itemKey, + expectedItem: expectedItem + ) + .ConfigureAwait( continueOnCapturedContext: false ) + .GetAwaiter() + .GetResult(); + } ); + + Assert.That( + err.Message, + Does.StartWith( " M[age].N must be equal" ) + ); + } + + [Test] + public void AssertItemAsync_WhenDoesNotExist() { + + AttributeValue key = GenerateKey(); + + Dictionary itemKey = new Dictionary { + { "key", key } + }; + + Dictionary expectedItem = new Dictionary { + { "key", key }, + { "age", new AttributeValue { N = "555" } } + }; + + var err = Assert.Throws( () => { + + AmazonDynamoDBAssert + .AssertItemAsync( + m_db, + m_tableName, + key: itemKey, + expectedItem: expectedItem + ) + .ConfigureAwait( continueOnCapturedContext: false ) + .GetAwaiter() + .GetResult(); + } ); + + Assert.That( + err.Message, + Is.EqualTo( "Item should exist." ) + ); + } + + #endregion + + #region AssertItemDoesNotExistAsync Tests + + [Test] + public void AssertItemDoesNotExistAsync_WhenDoesNotExist() { + + AttributeValue key = GenerateKey(); + + Dictionary itemKey = new Dictionary { + { "key", key } + }; + + Assert.DoesNotThrowAsync( async () => { + + await AmazonDynamoDBAssert + .AssertItemDoesNotExistAsync( + m_db, + m_tableName, + key: itemKey + ) + .ConfigureAwait( continueOnCapturedContext: false ); + } ); + } + + [Test] + public async Task AssertItemDoesNotExistAsync_WhenExists() { + + AttributeValue key = GenerateKey(); + + await m_db + .PutItemAsync( + m_tableName, + item: new Dictionary { + { "key", key }, + { "age", new AttributeValue { N = "111" } } + } + ) + .ConfigureAwait( continueOnCapturedContext: false ); + + Dictionary itemKey = new Dictionary { + { "key", key } + }; + + var err = Assert.Throws( () => { + + AmazonDynamoDBAssert + .AssertItemDoesNotExistAsync( + m_db, + m_tableName, + key: itemKey + ) + .ConfigureAwait( continueOnCapturedContext: false ) + .GetAwaiter() + .GetResult(); + } ); + + Assert.That( + err.Message, + Is.EqualTo( "Item should not exist." ) + ); + } + + #endregion + + } +} diff --git a/test/D2L.DynamoDBv2.NUnitHelpers.Tests/AttributeValueAssertTests.cs b/test/D2L.DynamoDBv2.NUnitHelpers.Tests/AttributeValueAssertTests.cs new file mode 100644 index 0000000..5be934b --- /dev/null +++ b/test/D2L.DynamoDBv2.NUnitHelpers.Tests/AttributeValueAssertTests.cs @@ -0,0 +1,725 @@ +using System.Collections.Generic; +using System.IO; +using Amazon.DynamoDBv2.Model; +using NUnit.Framework; + +namespace D2L.DynamoDBv2.NUnitHelpers { + + [TestFixture] + internal sealed class AttributeValueAssertTests { + + #region Dictionary + + [Test] + [TestCaseSource( nameof( EqualMapTestCases ) )] + public void AreEqual_Dictionary_WhenEquivalent( + Dictionary x, + Dictionary y + ) { + + AttributeValueAssert.AreEqual( x, y ); + } + + [Test] + [TestCaseSource( nameof( NotEqualMapTestCases ) )] + public void AreEqual_Dictionary_WhenNotEqual( + Dictionary x, + Dictionary y, + string expectedMessage + ) { + + var err = Assert.Throws( () => { + AttributeValueAssert.AreEqual( x, y ); + } ); + + Assert.That( + err.Message, + Does.StartWith( expectedMessage ) + ); + } + + #endregion + + #region B + + [Test] + [TestCase( new byte[ 0 ] )] + [TestCase( new byte[] { 0x1 } )] + [TestCase( new byte[] { 0x1, 0x2, 0x3, 0x4 } )] + public void AreEqual_Numeric_WhenEqual( byte[] bytes ) { + + AttributeValueAssert.AreEqual( + new AttributeValue { B = new MemoryStream( bytes ) }, + new AttributeValue { B = new MemoryStream( bytes ) } + ); + } + + [Test] + [TestCase( new byte[] { 0x1 }, new byte[] { 0x2 } )] + [TestCase( new byte[] { 0x1, 0x5 }, new byte[] { 0x2, 0x6 } )] + public void AreEqual_Numeric_WhenNotEqual( + byte[] x, + byte[] y + ) { + + var err = Assert.Throws( () => { + AttributeValueAssert.AreEqual( + new AttributeValue { B = new MemoryStream( x ) }, + new AttributeValue { B = new MemoryStream( y ) } + ); + } ); + + Assert.That( + err.Message, + Does.StartWith( " B must be equal" ) + ); + } + + #endregion + + #region BS + + private static IEnumerable EqualBinarySetTestCases() { + + yield return new TestCaseData( + new List { + new MemoryStream() + }, + new List { + new MemoryStream() + } + ) + .SetName( "1 empty stream" ); + + yield return new TestCaseData( + new List { + new MemoryStream( new byte[] { 0x1, 0x2 } ) + }, + new List { + new MemoryStream( new byte[] { 0x1, 0x2 } ) + } + ) + .SetName( "1 non-empty stream" ); + + yield return new TestCaseData( + new List { + new MemoryStream( new byte[] { 0x1 } ), + new MemoryStream( new byte[] { 0x2 } ) + }, + new List { + new MemoryStream( new byte[] { 0x2 } ), + new MemoryStream( new byte[] { 0x1 } ) + } + ) + .SetName( "2 non-empty streams" ); + } + + [Test] + [TestCaseSource( nameof( EqualBinarySetTestCases ) )] + public void AreEqual_BinarySet_WhenEquivalent( + List x, + List y + ) { + + AttributeValueAssert.AreEqual( + new AttributeValue { BS = x }, + new AttributeValue { BS = y } + ); + } + + private static IEnumerable NotEqualBinarySetTestCases() { + + yield return new TestCaseData( + new List { + new MemoryStream( new byte[] { 0x1 } ), + new MemoryStream( new byte[] { 0x2 } ) + }, + new List { + new MemoryStream( new byte[] { 0x1 } ) + } + ); + + yield return new TestCaseData( + new List { + new MemoryStream( new byte[] { 0x1, 0x2 } ) + }, + new List { + new MemoryStream( new byte[] { 0x2, 0x1 } ) + } + ); + + yield return new TestCaseData( + new List { + new MemoryStream( new byte[] { 0x1, 0x2 } ), + new MemoryStream( new byte[] { 0x3, 0x4 } ) + }, + new List { + new MemoryStream( new byte[] { 0x5, 0x6 } ), + new MemoryStream( new byte[] { 0x7 } ) + } + ); + + yield return new TestCaseData( + new List(), + new List { + new MemoryStream( new byte[] { 0x1 } ) + } + ); + + yield return new TestCaseData( + new List { + new MemoryStream( new byte[] { 0x1 } ) + }, + new List() + ); + } + + [Test] + [TestCaseSource( nameof( NotEqualBinarySetTestCases ) )] + public void AreEqual_BinarySet_WhenNotEqual( + List x, + List y + ) { + + var err = Assert.Throws( () => { + AttributeValueAssert.AreEqual( + new AttributeValue { BS = x }, + new AttributeValue { BS = y } + ); + } ); + + Assert.That( + err.Message, + Does.StartWith( " BS must be equivalent" ) + ); + } + + #endregion + + #region BOOL + + [Test] + public void AreEqual_Boolean_WhenEqual( [Values] bool value ) { + + AttributeValueAssert.AreEqual( + new AttributeValue { BOOL = value }, + new AttributeValue { BOOL = value } + ); + } + + [Test] + public void AreEqual_Boolean_WhenNotEqual() { + + var err = Assert.Throws( () => { + AttributeValueAssert.AreEqual( + new AttributeValue { BOOL = true }, + new AttributeValue { BOOL = false } + ); + } ); + + Assert.That( + err.Message, + Does.StartWith( " BOOL must be equal" ) + ); + } + + [Test] + public void AreEqual_Boolean_WhenBooleanNotSet() { + + var err = Assert.Throws( () => { + AttributeValueAssert.AreEqual( + new AttributeValue { BOOL = true }, + new AttributeValue { S = "abc" } + ); + } ); + + Assert.That( + err.Message, + Does.StartWith( " IsBOOLSet must be equal" ) + ); + } + + #endregion + + #region L + + private static IEnumerable EqualListTestCases() { + + yield return new TestCaseData( + new List { }, + new List { } + ); + + yield return new TestCaseData( + new List { + new AttributeValue{ N = "34.8" } + }, + new List { + new AttributeValue{ N = "34.8" } + } + ); + + yield return new TestCaseData( + new List { + new AttributeValue{ N = "34.8" }, + new AttributeValue{ BOOL = true } + }, + new List { + new AttributeValue{ N = "34.8" }, + new AttributeValue{ BOOL = true } + } + ); + } + + [Test] + [TestCaseSource( nameof( EqualListTestCases ) )] + public void AreEqual_List_WhenEquivalent( + List x, + List y + ) { + + AttributeValueAssert.AreEqual( + new AttributeValue { L = x }, + new AttributeValue { L = y } + ); + } + + private static IEnumerable NotEqualListTestCases() { + + yield return new TestCaseData( + new List { + new AttributeValue{ N = "33" } + }, + new List { + new AttributeValue{ N = "44" } + }, + " L[0].N must be equal" + ); + + yield return new TestCaseData( + new List { + new AttributeValue{ N = "33" }, + new AttributeValue{ S = "abc" } + }, + new List { + new AttributeValue{ N = "33" }, + new AttributeValue{ S = "def" } + }, + " L[1].S must be equal" + ); + } + + [Test] + [TestCaseSource( nameof( NotEqualListTestCases ) )] + public void AreEqual_List_WhenNotEqual( + List x, + List y, + string expectedMessage + ) { + + var err = Assert.Throws( () => { + AttributeValueAssert.AreEqual( + new AttributeValue { L = x }, + new AttributeValue { L = y } + ); + } ); + + Assert.That( + err.Message, + Does.StartWith( expectedMessage ) + ); + } + + [Test] + public void AreEqual_List_WhenListNotSet() { + + var err = Assert.Throws( () => { + AttributeValueAssert.AreEqual( + new AttributeValue { + L = new List { + new AttributeValue { N = "23.88" } + } + }, + new AttributeValue { S = "abc" } + ); + } ); + + Assert.That( + err.Message, + Does.StartWith( " IsLSet must be equal" ) + ); + } + + #endregion + + #region M + + private static IEnumerable EqualMapTestCases() { + + yield return new TestCaseData( + new Dictionary { }, + new Dictionary { } + ); + + yield return new TestCaseData( + new Dictionary { + { "x", new AttributeValue{ N = "34.8" } } + }, + new Dictionary { + { "x", new AttributeValue{ N = "34.8" } } + } + ); + + yield return new TestCaseData( + new Dictionary { + { "x", new AttributeValue{ N = "34.8" } }, + { "y", new AttributeValue{ BOOL = true } } + }, + new Dictionary { + { "x", new AttributeValue{ N = "34.8" } }, + { "y", new AttributeValue{ BOOL = true } } + } + ); + } + + [Test] + [TestCaseSource( nameof( EqualMapTestCases ) )] + public void AreEqual_Map_WhenEquivalent( + Dictionary x, + Dictionary y + ) { + + AttributeValueAssert.AreEqual( + new AttributeValue { M = x }, + new AttributeValue { M = y } + ); + } + + private static IEnumerable NotEqualMapTestCases() { + + yield return new TestCaseData( + new Dictionary { + { "x", new AttributeValue{ N = "34.8" } } + }, + new Dictionary { + { "x", new AttributeValue{ N = "88.3" } } + }, + " M[x].N must be equal" + ); + + yield return new TestCaseData( + new Dictionary { + { "x", new AttributeValue{ N = "34.8" } } + }, + new Dictionary { + { "y", new AttributeValue{ N = "34.8" } } + }, + " M.Keys must be equivalent" + ); + + yield return new TestCaseData( + new Dictionary { + { "root", new AttributeValue{ + M = new Dictionary { + { "child", new AttributeValue { BOOL = true } } + } + } } + }, + new Dictionary { + { "root", new AttributeValue{ + M = new Dictionary { + { "child", new AttributeValue { BOOL = false } } + } + } } + }, + " M[root].M[child].BOOL must be equal" + ); + } + + [Test] + [TestCaseSource( nameof( NotEqualMapTestCases ) )] + public void AreEqual_Map_WhenNotEqual( + Dictionary x, + Dictionary y, + string expectedMessage + ) { + + var err = Assert.Throws( () => { + AttributeValueAssert.AreEqual( + new AttributeValue { M = x }, + new AttributeValue { M = y } + ); + } ); + + Assert.That( + err.Message, + Does.StartWith( expectedMessage ) + ); + } + + [Test] + public void AreEqual_Map_WhenMapNotSet() { + + var err = Assert.Throws( () => { + AttributeValueAssert.AreEqual( + new AttributeValue { + M = new Dictionary{ + { "x", new AttributeValue { N = "23.88" } } + } + }, + new AttributeValue { S = "abc" } + ); + } ); + + Assert.That( + err.Message, + Does.StartWith( " IsMSet must be equal" ) + ); + } + + #endregion + + #region N + + [Test] + [TestCase( "-80" )] + [TestCase( "0" )] + [TestCase( "1" )] + [TestCase( "2.3" )] + public void AreEqual_Numeric_WhenEqual( string value ) { + + AttributeValueAssert.AreEqual( + new AttributeValue { N = value }, + new AttributeValue { N = value } + ); + } + + [Test] + [TestCase( "33", "45" )] + [TestCase( "33", null )] + [TestCase( null, "44" )] + public void AreEqual_Numeric_WhenNotEqual( string x, string y ) { + + var err = Assert.Throws( () => { + AttributeValueAssert.AreEqual( + new AttributeValue { N = "33" }, + new AttributeValue { N = "45" } + ); + } ); + + Assert.That( + err.Message, + Does.StartWith( " N must be equal" ) + ); + } + + #endregion + + #region NS + + private static IEnumerable EqualNumericSetTestCases() { + + yield return new TestCaseData( + new List(), + new List() + ); + + yield return new TestCaseData( + new List { "123.5" }, + new List { "123.5" } + ); + + yield return new TestCaseData( + new List { "55", "44" }, + new List { "44", "55" } + ); + } + + [Test] + [TestCaseSource( nameof( EqualNumericSetTestCases ) )] + public void AreEqual_NumericSet_WhenEquivalent( + List x, + List y + ) { + + AttributeValueAssert.AreEqual( + new AttributeValue { NS = x }, + new AttributeValue { NS = y } + ); + } + + private static IEnumerable NotEqualNumericSetTestCases() { + + yield return new TestCaseData( + new List { "1" }, + new List { "1", "2" } + ); + + yield return new TestCaseData( + new List { "66" }, + new List { "77" } + ); + + yield return new TestCaseData( + new List { "9", "8" }, + new List { "3", "2", "1" } + ); + } + + [Test] + [TestCaseSource( nameof( NotEqualNumericSetTestCases ) )] + public void AreEqual_NumericSet_WhenNotEqual( + List x, + List y + ) { + + var err = Assert.Throws( () => { + AttributeValueAssert.AreEqual( + new AttributeValue { NS = x }, + new AttributeValue { NS = y } + ); + } ); + + Assert.That( + err.Message, + Does.StartWith( " NS must be equivalent" ) + ); + } + + #endregion + + #region NULL + + [Test] + public void AreEqual_Null_WhenEqual( [Values] bool value ) { + + AttributeValueAssert.AreEqual( + new AttributeValue { NULL = value }, + new AttributeValue { NULL = value } + ); + } + + [Test] + public void AreEqual_Null_WhenNotEqual() { + + var err = Assert.Throws( () => { + AttributeValueAssert.AreEqual( + new AttributeValue { NULL = true }, + new AttributeValue { NULL = false } + ); + } ); + + Assert.That( + err.Message, + Does.StartWith( " NULL must be equal" ) + ); + } + + #endregion + + #region S + + [Test] + [TestCase( "" )] + [TestCase( "abc" )] + public void AreEqual_String_WhenEqual( string value ) { + + AttributeValueAssert.AreEqual( + new AttributeValue { S = value }, + new AttributeValue { S = value } + ); + } + + [Test] + public void AreEqual_String_WhenNotEqual() { + + var err = Assert.Throws( () => { + AttributeValueAssert.AreEqual( + new AttributeValue { S = "x" }, + new AttributeValue { S = "y" } + ); + } ); + + Assert.That( + err.Message, + Does.StartWith( " S must be equal" ) + ); + } + + #endregion + + #region SS + + private static IEnumerable EqualStringSetTestCases() { + + yield return new TestCaseData( + new List(), + new List() + ); + + yield return new TestCaseData( + new List { "abc" }, + new List { "abc" } + ); + + yield return new TestCaseData( + new List { "x", "y" }, + new List { "y", "x" } + ); + } + + [Test] + [TestCaseSource( nameof( EqualStringSetTestCases ) )] + public void AreEqual_StringSet_WhenEquivalent( + List x, + List y + ) { + + AttributeValueAssert.AreEqual( + new AttributeValue { SS = x }, + new AttributeValue { SS = y } + ); + } + + private static IEnumerable NotEqualStringSetTestCases() { + + yield return new TestCaseData( + new List { "x" }, + new List { "x", "y" } + ); + + yield return new TestCaseData( + new List { "x" }, + new List { "y" } + ); + + yield return new TestCaseData( + new List { "cats", "meow" }, + new List { "dogs", "like", "bones" } + ); + } + + [Test] + [TestCaseSource( nameof( NotEqualStringSetTestCases ) )] + public void AreEqual_StringSet_WhenNotEqual( + List x, + List y + ) { + + var err = Assert.Throws( () => { + AttributeValueAssert.AreEqual( + new AttributeValue { SS = x }, + new AttributeValue { SS = y } + ); + } ); + + Assert.That( + err.Message, + Does.StartWith( " SS must be equivalent" ) + ); + } + + #endregion + + } +} diff --git a/test/D2L.DynamoDBv2.NUnitHelpers.Tests/D2L.DynamoDBv2.NUnitHelpers.Tests.csproj b/test/D2L.DynamoDBv2.NUnitHelpers.Tests/D2L.DynamoDBv2.NUnitHelpers.Tests.csproj index 1afe24c..83e061e 100644 --- a/test/D2L.DynamoDBv2.NUnitHelpers.Tests/D2L.DynamoDBv2.NUnitHelpers.Tests.csproj +++ b/test/D2L.DynamoDBv2.NUnitHelpers.Tests/D2L.DynamoDBv2.NUnitHelpers.Tests.csproj @@ -1,5 +1,6 @@  + disable Library net45;netcoreapp3.1