Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions dataframe-operations/src/DataFrame/Operations/Subset.hs
Original file line number Diff line number Diff line change
Expand Up @@ -176,12 +176,16 @@ dropLast n d =
range :: (Int, Int) -> DataFrame -> DataFrame
range (start, end) d =
d
{ columns = V.map (sliceColumn (clip start 0 r) n') (columns d)
{ columns = V.map (sliceColumn start' n') (columns d)
, dataframeDimensions = (n', c)
}
where
(r, c) = dataframeDimensions d
n' = clip (end - start) 0 r
start' = clip start 0 r
-- Clamp both endpoints before subtracting: end - start' on an unclamped
-- end wraps for very negative values and reopens the range.
end' = clip end start' r
n' = end' - start'

clip :: Int -> Int -> Int -> Int
clip n left right = min right $ max n left
Expand Down
5 changes: 5 additions & 0 deletions tests/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,10 @@ main = do
mapM
(quickCheckWithResult stdArgs)
Operations.Subset.tests
subsetPropRes <-
mapM
(quickCheckWithResult stdArgs)
Operations.Subset.properties
monadRes <- mapM (quickCheckWithResult stdArgs) Monad.tests
cbRes <-
mapM
Expand All @@ -151,6 +155,7 @@ main = do
propsRes <- mapM (quickCheckWithResult stdArgs) Properties.tests
catRes <- mapM (quickCheckWithResult stdArgs) Properties.Categorical.tests
if not (all isSuccessful propRes)
|| not (all isSuccessful subsetPropRes)
|| not (all isSuccessful cbRes)
|| not (all isSuccessful monadRes)
|| not (all isSuccessful propsRes)
Expand Down
51 changes: 51 additions & 0 deletions tests/Operations/Subset.hs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ import qualified DataFrame as D
import qualified DataFrame.Internal.Column as Col
import DataFrame.Internal.DataFrame
import DataFrame.Operations.Merge ()
import GenDataFrame ()
import System.Random
import Test.HUnit
import Test.QuickCheck (Property, property)

prop_dropZero :: DataFrame -> Bool
prop_dropZero df = D.drop 0 df == df
Expand Down Expand Up @@ -53,6 +55,17 @@ prop_rangeFull df =
let rows = fst (dataframeDimensions df)
in D.range (0, rows) df == df

prop_rangeClampsToBounds :: DataFrame -> Int -> Int -> Bool
prop_rangeClampsToBounds df a b =
fst (dataframeDimensions (D.range (a, b) df)) == expected
where
rows = fst (dataframeDimensions df)
-- Rows in [a, b) that actually exist. Clamps before subtracting so the
-- oracle itself cannot overflow on extreme endpoints.
lo = min (max a 0) rows
hi = min (max b lo) rows
expected = hi - lo

prop_selectAll :: DataFrame -> Bool
prop_selectAll df = D.select (D.columnNames df) df == df

Expand Down Expand Up @@ -177,6 +190,37 @@ unit_stratifiedSplit_proportions =
)
(abs (vaProp - origProp) < tol)

tenRows :: DataFrame
tenRows = fromNamedColumns [("x", Col.fromList ([0 .. 9] :: [Int]))]

-- Endpoints that overflow Int if the length is computed before clamping.
unit_rangeExtremeEndpoints :: Test
unit_rangeExtremeEndpoints =
TestCase
( assertEqual
"range (1, minBound) is empty, not a wrapped-around full range"
0
(fst (dataframeDimensions (D.range (1, minBound) tenRows)))
)

unit_rangeEndPastEnd :: Test
unit_rangeEndPastEnd =
TestCase
( assertEqual
"range (8, 20) on a 10-row frame yields rows 8 and 9"
(Just (Col.fromList ([8, 9] :: [Int])))
(getColumn "x" (D.range (8, 20) tenRows))
)

unit_rangeStartBeforeZero :: Test
unit_rangeStartBeforeZero =
TestCase
( assertEqual
"range (-5, 3) on a 10-row frame yields rows 0 to 2"
(Just (Col.fromList ([0, 1, 2] :: [Int])))
(getColumn "x" (D.range (-5, 3) tenRows))
)

hunitTests :: [Test]
hunitTests =
[ TestLabel "unit_stratifiedSample_full" unit_stratifiedSample_full
Expand All @@ -185,8 +229,15 @@ hunitTests =
"unit_stratifiedSplit_singleRowStratum"
unit_stratifiedSplit_singleRowStratum
, TestLabel "unit_stratifiedSplit_proportions" unit_stratifiedSplit_proportions
, TestLabel "unit_rangeEndPastEnd" unit_rangeEndPastEnd
, TestLabel "unit_rangeExtremeEndpoints" unit_rangeExtremeEndpoints
, TestLabel "unit_rangeStartBeforeZero" unit_rangeStartBeforeZero
]

-- Properties whose shape does not fit [DataFrame -> Bool].
properties :: [Property]
properties = [property prop_rangeClampsToBounds]

tests :: [DataFrame -> Bool]
tests =
[ prop_dropZero
Expand Down
Loading