]> gitweb.michael.orlitzky.com - hath.git/blobdiff - src/IPv4Address.hs
Add a test for the Cidr 'enumerate' function.
[hath.git] / src / IPv4Address.hs
index dac7ddaf0596e9fba46b077d4321e88149d23b88..f4bfc9749cab1adb63ffcb7b0907d0ce3c9ebae2 100644 (file)
@@ -1,20 +1,19 @@
-module IPv4Address
-( ipv4address_tests,
+module IPv4Address(
   IPv4Address(..),
-  max_address,
-  min_address,
-  most_sig_bit_different,
-where
+  ipv4address_properties,
+  ipv4address_tests,
+  most_sig_bit_different )
+where
 
-import Data.Maybe (fromJust)
 import Test.HUnit (assertEqual)
 import Test.Framework (Test, testGroup)
 import Test.Framework.Providers.HUnit (testCase)
-import Test.QuickCheck (Arbitrary(..), Gen)
+import Test.Framework.Providers.QuickCheck2 (testProperty)
+import Test.QuickCheck (Arbitrary(..), Gen, Property, (==>))
 
-import Maskable
-import Maskbits
-import Octet
+import Maskable (Maskable(..))
+import Maskbits (Maskbits(..))
+import Octet (Octet(..))
 
 data IPv4Address =
   IPv4Address { octet1 :: Octet,
@@ -165,18 +164,49 @@ instance Maskable IPv4Address where
        new_addr3 { octet1 = (apply_mask oct1 Zero bit) }
 
 
-
--- | The minimum possible IPv4 address, 0.0.0.0.
-min_address :: IPv4Address
-min_address =
-  IPv4Address min_octet min_octet min_octet min_octet
-
-
--- | The maximum possible IPv4 address, 255.255.255.255.
-max_address :: IPv4Address
-max_address =
-  IPv4Address max_octet max_octet max_octet max_octet
-
+instance Bounded IPv4Address where
+  -- | The minimum possible IPv4 address, 0.0.0.0.
+  minBound = IPv4Address minBound minBound minBound minBound
+
+  -- | The maximum possible IPv4 address, 255.255.255.255.
+  maxBound = IPv4Address maxBound maxBound maxBound maxBound
+
+
+
+
+instance Enum IPv4Address where
+  -- | Convert an 'Int' @x@ to an 'IPv4Address'. Each octet of @x@ is
+  --   right-shifted by the appropriate number of bits, and the fractional
+  --   part is dropped.
+  toEnum x =
+    IPv4Address oct1 oct2 oct3 oct4
+    where
+      -- Chop off the higher octets. x1 = x `mod` 2^32, would be
+      -- redundant.
+      x2 = x `mod` 2^(24 :: Integer)
+      x3 = x `mod` 2^(16 :: Integer)
+      x4 = x `mod` 2^(8  :: Integer)
+      -- Perform right-shifts. x4 doesn't need a shift.
+      shifted_x1 = x `quot` 2^(24 :: Integer)
+      shifted_x2 = x2 `quot` 2^(16 :: Integer)
+      shifted_x3 = x3 `quot` 2^(8 :: Integer)
+      oct1 = toEnum shifted_x1
+      oct2 = toEnum shifted_x2
+      oct3 = toEnum shifted_x3
+      oct4 = toEnum x4
+
+  -- | Convert @addr@ to an 'Int' by converting each octet to an 'Int'
+  --   and shifting the result to the left by 0,8.16, or 24 bits.
+  fromEnum addr =
+    (shifted_oct1) + (shifted_oct2) + (shifted_oct3) + oct4
+    where
+      oct1 = fromEnum (octet1 addr)
+      oct2 = fromEnum (octet2 addr)
+      oct3 = fromEnum (octet3 addr)
+      oct4 = fromEnum (octet4 addr)
+      shifted_oct1 = oct1 * 2^(24 :: Integer)
+      shifted_oct2 = oct2 * 2^(16 :: Integer)
+      shifted_oct3 = oct3 * 2^(8 :: Integer)
 
 -- | Given two addresses, find the number of the most significant bit
 --   where they differ. If the addresses are the same, return
@@ -292,17 +322,66 @@ most_sig_bit_different addr1 addr2
     oct4b = (octet4 addr2)
 
 
+-- Test lists.
+ipv4address_tests :: Test
+ipv4address_tests =
+  testGroup "IPv4 Address Tests" [
+    test_enum,
+    test_maxBound,
+    test_minBound,
+    test_most_sig_bit_different1,
+    test_most_sig_bit_different2,
+    test_to_enum ]
+
+ipv4address_properties :: Test
+ipv4address_properties =
+  testGroup
+    "IPv4 Address Properties "
+    [ testProperty
+        "fromEnum/toEnum are inverses"
+        prop_from_enum_to_enum_inverses ]
+
+-- QuickCheck properties
+prop_from_enum_to_enum_inverses :: Int -> Property
+prop_from_enum_to_enum_inverses x =
+  (0 <= x) && (x <= 2^(32 :: Integer) - 1) ==>
+    fromEnum (toEnum x :: IPv4Address) == x
 
 -- HUnit Tests
 mk_testaddr :: Int -> Int -> Int -> Int -> IPv4Address
 mk_testaddr a b c d =
   IPv4Address oct1 oct2 oct3 oct4
   where
-    oct1 = fromJust $ octet_from_int a
-    oct2 = fromJust $ octet_from_int b
-    oct3 = fromJust $ octet_from_int c
-    oct4 = fromJust $ octet_from_int d
+    oct1 = toEnum a
+    oct2 = toEnum b
+    oct3 = toEnum c
+    oct4 = toEnum d
+
+test_minBound :: Test
+test_minBound =
+  testCase desc $ assertEqual desc expected actual
+  where
+    desc = "minBound should be 0.0.0.0"
+    expected = mk_testaddr 0 0 0 0
+    actual = minBound :: IPv4Address
 
+test_maxBound :: Test
+test_maxBound =
+  testCase desc $ assertEqual desc expected actual
+  where
+    desc = "maxBound should be 255.255.255.255"
+    expected = mk_testaddr 255 255 255 255
+    actual = maxBound :: IPv4Address
+
+test_enum :: Test
+test_enum =
+  testCase desc $ assertEqual desc expected actual
+  where
+    desc = "enumerating a /24 gives the correct addresses"
+    expected = ["192.168.0." ++ (show x) | x <- [0..255::Int] ]
+    lb = mk_testaddr 192 168 0 0
+    ub = mk_testaddr 192 168 0 255
+    actual = map show [lb..ub]
 
 test_most_sig_bit_different1 :: Test
 test_most_sig_bit_different1 =
@@ -329,8 +408,10 @@ test_most_sig_bit_different2 =
     bit = most_sig_bit_different addr1 addr2
 
 
-ipv4address_tests :: Test
-ipv4address_tests =
-  testGroup "IPv4 Address Tests" [
-    test_most_sig_bit_different1,
-    test_most_sig_bit_different2 ]
+test_to_enum :: Test
+test_to_enum =
+  testCase desc $ assertEqual desc expected actual
+  where
+    desc     = "192.168.0.0 in base-10 is 3232235520"
+    expected = mk_testaddr 192 168 0 0
+    actual   = toEnum 3232235520