home | downloads | recipes | blogs | staff | about us | *

The Art of Lightning
How about some free money? (additional free value objects)James Zimmerman4/25/2008

Once again the list of free stuff increases, this time for simple currency value types.


// http://www.zimms.com
// Copyright (c) 2002-2007
// by James Zimmerman
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in the
// Software without restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
// Software, and to permit persons to whom the Software is furnished to do so, subject
// to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies
// or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

using System;
using System.Globalization;
using System.Text.RegularExpressions;

/// <summary>
/// Simplistic value type for currency types.
/// </summary>
public struct Currency
{
    #region Fields

    private readonly Decimal value;
    private readonly RegionInfo region;
    private readonly Boolean isKnown;
    public static Currency Unknown = new Currency();

    #endregion

    #region Constructor

    private Currency(decimal value)
    {
        this.value = value;
        this.isKnown = false;
        this.region = null;
    }

    public Currency(Decimal value, RegionInfo region)
    {
        if (region == null) throw new ArgumentNullException("region");

        this.value = value;
        this.region = region;
        this.isKnown = true;
    }

    #endregion

    #region Properties

    public Decimal Value
    {
        get { return this.value; }
    }

    public RegionInfo Region
    {
        get { return this.region; }
    }

    public String CurrencyCode
    {
        get
        {
            return this.isKnown ? this.region.ISOCurrencySymbol : String.Empty;
        }
    }

    #endregion

    #region Factory

    public static Currency ParseByCurrencyISO(Decimal value, String s)
    {
        if (String.IsNullOrEmpty(s)) throw new ArgumentNullException("s");

        s = s.Trim().ToUpper();
        Regex re = new Regex(@"[A-Z]{3}");
        if (!re.IsMatch(s)) throw new FormatException("String '" + s + "' does not match any supported ISO currency code");

        RegionInfo region;
        switch (s)
        {
            case "AUD": region = new RegionInfo("AU"); break;
            case "BRL": region = new RegionInfo("BR"); break;
            case "CAD": region = new RegionInfo("CA"); break;
            case "DKK": region = new RegionInfo("DK"); break;
            case "EUR": region = new RegionInfo("GR"); break;
            case "JPY": region = new RegionInfo("JP"); break;
            case "NZD": region = new RegionInfo("NZ"); break;
            case "NOK": region = new RegionInfo("NO"); break;
            case "ZAR": region = new RegionInfo("ZA"); break;
            case "SEK": region = new RegionInfo("SE"); break;
            case "CHF": region = new RegionInfo("CH"); break;
            case "GBP": region = new RegionInfo("GB"); break;
            case "USD": region = new RegionInfo("US"); break;
            default: return new Currency(value);
        }

        return new Currency(value, region);
    }

    #endregion
}

And as always, the tests...

// http://www.zimms.com
// Copyright (c) 2002-2007
// by James Zimmerman
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in the
// Software without restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
// Software, and to permit persons to whom the Software is furnished to do so, subject
// to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies
// or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

using System;
using System.Globalization;
using NUnit.Framework;
using NUnit.Framework.SyntaxHelpers;

[TestFixture()]
public class CurrencyTests
{
    protected Decimal value = 8768768;

    [Test()]
    [ExpectedException(typeof(ArgumentNullException))]
    public void ConstructorRequiresRegion()
    {
        new Currency(value, null);
    }

    [Test()]
    public void DefaultConstructor()
    {
        Currency currency = new Currency();

        Assert.That(currency.Value, Is.EqualTo(0));
        Assert.That(currency.Region, Is.Null);
        Assert.That(currency.CurrencyCode, Is.Empty);
    }

    [Test()]
    public void ConstructorSetsProperties()
    {
        RegionInfo region = RegionInfo.CurrentRegion;
        Currency currency = new Currency(value, region);

        Assert.That(currency.CurrencyCode, Is.EqualTo("USD"));
        Assert.That(currency.Region, Is.EqualTo(region));
        Assert.That(currency.Value, Is.EqualTo(value));
    }

    [Test()]
    public void ParseByCurrencyISOParses()
    {
        String[] countries = new String[] {"AU", "BR", "CA", "DK", "GR", "JP", "NZ", "NO", "ZA", "SE", "CH", "GB", "US"};
        String[] currencies = new String[] {"AUD", "BRL", "CAD", "DKK", "EUR", "JPY", "NZD", "NOK", "ZAR", "SEK", "CHF", "GBP", "USD"} ;

        for (Int32 i = 0; i < currencies.Length; i++ )
        {
            Currency currency = Currency.ParseByCurrencyISO(value, currencies[i]);
            Assert.That(currency.Region.TwoLetterISORegionName , Is.EqualTo(countries[i]));
        }
    }

    [Test()]
    [ExpectedException(typeof(ArgumentNullException))]
    public void ParseByCurrencyISORequiresValue()
    {
        Currency.ParseByCurrencyISO(value, null);
    }

    [Test()]
    public void ParseByCurrencyISORequiresCorrectFormat()
    {
        String[] badCodes = new String[] {"768", "US", "US D"};

        foreach (String badCode in badCodes)
        {
            try
            {
                Currency.ParseByCurrencyISO(value, badCode);
                Assert.Fail("Exception should have been thrown for value '" + value + "'");
            }
            catch (FormatException) {}
        }
    }

    [Test()]
    public void UnknownCurrencyCodeCreatesUnknownCurrency()
    {
        Currency currency = Currency.ParseByCurrencyISO(value, "AAA");

        Assert.That(currency.Region, Is.Null);
        Assert.That(currency.CurrencyCode, Is.Empty);
        Assert.That(currency.Value, Is.EqualTo(value));
    }
}

Jimmy Zimms wants summer to finally get here
 

Look for more blogs |

(c) 2001-2009 Stuart Williams, E-Mail Stuart Williams