Skip to content

Commit 7d974d2

Browse files
authored
Added test cases for saveGraphJSON (#1653)
1 parent d7d24f2 commit 7d974d2

4 files changed

Lines changed: 53 additions & 11 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,12 @@
88

99
### 🐛 Bug fixes
1010

11+
- Fixed a bug where duplicate graph components were being added
12+
1113
### 🔧 Internal changes
1214

1315
- Refactor GraphDropdown component from being a child of Graph to being a child of NavBar
16+
- Added test cases for the saveGraphJSON function in `Controllers/Graph`
1417

1518
## [0.7.2] - 2025-12-10
1619

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ Harsh Patel,
139139
Eleonora Scognamiglio,
140140
Sam Shaftoe,
141141
Ian Stewart-Binks,
142+
Alan Su,
142143
Maryam Taj,
143144
Betty Wang,
144145
Fullchee Zhang,

app/Models/Graph.hs

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,13 @@ module Models.Graph
44

55
import Config (runDb)
66
import Data.Aeson (Value, object, toJSON)
7-
import Data.List (partition)
87
import qualified Data.Text as T (Text)
98
import Database.DataType (ShapeType (BoolNode, Hybrid, Node))
109
import Database.Persist.Sqlite (Entity, PersistEntity, PersistValue (PersistInt64), SqlPersistM,
1110
entityKey, entityVal, insert, insertMany_, keyToValues, selectFirst,
1211
selectList, (<-.), (==.))
1312
import Database.Tables hiding (paths, shapes, texts)
14-
import Svg.Builder (buildEllipses, buildPath, buildRect, intersectsWithShape)
13+
import Svg.Builder (buildEllipses, buildPath, buildRect)
1514
import Util.Helpers
1615

1716
getGraph :: T.Text -> IO (Maybe Value)
@@ -44,15 +43,11 @@ getGraph graphName = runDb $ do
4443
graphpaths = zipWith (buildPath rects ellipses)
4544
(map entityVal sqlPaths)
4645
(map keyAsInt sqlPaths)
47-
(regions, _) = partition pathIsRegion graphpaths
48-
regionTexts = filter (not .
49-
intersectsWithShape (rects ++ ellipses))
50-
graphtexts
5146

5247
response = object [
53-
("texts", toJSON $ graphtexts ++ regionTexts),
48+
("texts", toJSON graphtexts),
5449
("shapes", toJSON $ rects ++ ellipses),
55-
("paths", toJSON $ graphpaths ++ regions),
50+
("paths", toJSON graphpaths),
5651
("width", toJSON $ graphWidth $ entityVal graph),
5752
("height", toJSON $ graphHeight $ entityVal graph)
5853
]

backend-test/Controllers/GraphControllerTests.hs

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,20 @@ module Controllers.GraphControllerTests
1010
) where
1111

1212
import Config (runDb)
13-
import Controllers.Graph (index)
13+
import Control.Monad.IO.Class (liftIO)
14+
import Controllers.Graph (index, saveGraphJSON)
15+
import Data.Aeson (Value (Number, Object), decode)
16+
import qualified Data.Aeson.Key as Key
17+
import qualified Data.Aeson.KeyMap as KeyMap
1418
import qualified Data.ByteString.Lazy.Char8 as BL
1519
import qualified Data.Text as T
1620
import Database.Persist.Sqlite (SqlPersistM, insert_)
1721
import Database.Tables (Graph (..))
1822
import Happstack.Server (rsBody)
23+
import Models.Graph (getGraph)
1924
import Test.Tasty (TestTree)
2025
import Test.Tasty.HUnit (assertEqual, testCase)
21-
import TestHelpers (clearDatabase, runServerPart, withDatabase)
26+
import TestHelpers (clearDatabase, mockPutRequest, runServerPart, runServerPartWith, withDatabase)
2227

2328
-- | List of test cases as (label, input graphs, expected output)
2429
indexTestCases :: [(String, [T.Text], String)]
@@ -59,6 +64,44 @@ runIndexTest label graphs expected =
5964
runIndexTests :: [TestTree]
6065
runIndexTests = map (\(label, graphs, expected) -> runIndexTest label graphs expected) indexTestCases
6166

67+
-- | Helper function to add the default width and height to graph JSON
68+
addDefaults :: Value -> Value
69+
addDefaults (Object obj) = Object $
70+
KeyMap.insert (Key.fromString "width") (Number 256) $
71+
KeyMap.insert (Key.fromString "height") (Number 256) obj
72+
addDefaults v = v
73+
74+
-- | List of test cases as (label, graph JSON payload)
75+
saveGraphJSONTestCases :: [(String, BL.ByteString)]
76+
saveGraphJSONTestCases =
77+
[ ("Empty graph",
78+
"{\"texts\":[],\"shapes\":[],\"paths\":[]}"
79+
),
80+
81+
("Single shape graph",
82+
"{\"texts\":[],\"shapes\":[{\"graph\": 1, \"id_\": \"s1\", \"pos\": [100.0, 100.0], \"width\": 50.0, \"height\": 50.0, \"fill\": \"white\", \"stroke\": \"black\", \"text\": [], \"type_\": \"Node\", \"transform\": [1.0, 0.0, 0.0, 1.0, 0.0, 0.0]}],\"paths\":[]}"
83+
),
84+
85+
("Multi-node graph",
86+
"{\"texts\":[{\"graph\":1,\"rId\":\"t1\",\"pos\":[10.0,10.0],\"text\":\"Graph text 1\",\"align\":\"left\",\"fill\":\"black\",\"transform\":[1.0,0.0,0.0,1.0,0.0,0.0]},{\"graph\":1,\"rId\":\"t2\",\"pos\":[20.0,20.0],\"text\":\"Graph text 2\",\"align\":\"center\",\"fill\":\"blue\",\"transform\":[1.0,0.0,0.0,1.0,0.0,0.0]}],\"shapes\":[{\"graph\":1,\"id_\":\"s1\",\"pos\":[100.0,100.0],\"width\":100.0,\"height\":50.0,\"fill\":\"white\",\"stroke\":\"black\",\"text\":[],\"type_\":\"Node\",\"transform\":[1.0,0.0,0.0,1.0,0.0,0.0]},{\"graph\":1,\"id_\":\"h2\",\"pos\":[200.0,200.0],\"width\":50.0,\"height\":10.0,\"fill\":\"green\",\"stroke\":\"blue\",\"text\":[],\"type_\":\"Hybrid\",\"transform\":[1.0,0.0,0.0,1.0,0.0,0.0]},{\"graph\":1,\"id_\":\"s3\",\"pos\":[300.0,300.0],\"width\":30.0,\"height\":30.0,\"fill\":\"red\",\"stroke\":\"purple\",\"text\":[],\"type_\":\"BoolNode\",\"transform\":[1.0,0.0,0.0,1.0,0.0,0.0]}],\"paths\":[{\"graph\":1,\"id_\":\"p1\",\"points\":[[50.0,50.0],[150.0,50.0]],\"fill\":\"white\",\"stroke\":\"black\",\"isRegion\":false,\"source\":\"s1\",\"target\":\"h2\",\"transform\":[1.0,0.0,0.0,1.0,0.0,0.0]},{\"graph\":1,\"id_\":\"p2\",\"points\":[[100.0,20.0],[30.0,40.0]],\"fill\":\"yellow\",\"stroke\":\"orange\",\"isRegion\":false,\"source\":\"h2\",\"target\":\"s3\",\"transform\":[1.0,0.0,0.0,1.0,0.0,0.0]}]}"
87+
)
88+
]
89+
90+
-- | Run a test case (case, graph JSON payload)
91+
runSaveGraphJSONTest :: String -> BL.ByteString -> TestTree
92+
runSaveGraphJSONTest label payload =
93+
testCase label $ do
94+
runDb clearDatabase
95+
let graphName = "Test Graph Name"
96+
_ <- runServerPartWith Controllers.Graph.saveGraphJSON $ mockPutRequest "/graph-save" [("nameData", T.unpack graphName), ("jsonData", BL.unpack payload)] ""
97+
retrievedResult <- liftIO $ Models.Graph.getGraph graphName
98+
let expectedValue = fmap addDefaults (decode payload :: Maybe Value)
99+
assertEqual ("Unexpected response for " ++ label) expectedValue retrievedResult
100+
101+
-- | Run all save graph test cases
102+
runSaveGraphJSONTests :: [TestTree]
103+
runSaveGraphJSONTests = map (uncurry runSaveGraphJSONTest) saveGraphJSONTestCases
104+
62105
-- | Test suite for Graph Controller Module
63106
test_graphController :: TestTree
64-
test_graphController = withDatabase "Graph Controller tests" runIndexTests
107+
test_graphController = withDatabase "Graph Controller tests" (runIndexTests ++ runSaveGraphJSONTests)

0 commit comments

Comments
 (0)