commit 91f00219a6799aad4ca110510503048856b705d3
parent fbf0143888d418d809dc034a502eb71e744d60df
Author: mtmn <miro@haravara.org>
Date: Sun, 12 Apr 2026 22:25:12 +0200
feat: add tests
Diffstat:
| M | spago.lock | | | 107 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- |
| M | spago.yaml | | | 10 | +++++++++- |
| M | src/Types.purs | | | 15 | +++++++++++++++ |
| M | test/Main.purs | | | 89 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- |
4 files changed, 215 insertions(+), 6 deletions(-)
diff --git a/spago.lock b/spago.lock
@@ -45,7 +45,16 @@
]
},
"test": {
- "dependencies": []
+ "dependencies": [
+ "aff",
+ "argonaut",
+ "argonaut-core",
+ "arrays",
+ "either",
+ "maybe",
+ "spec",
+ "transformers"
+ ]
}
}
},
@@ -756,6 +765,16 @@
"prelude"
]
},
+ "ansi": {
+ "type": "registry",
+ "version": "7.0.0",
+ "integrity": "sha256-tOUaXJFzPSfBVAqLI8hc+Tz2M1rg16cXqyHaK/3SmFg=",
+ "dependencies": [
+ "foldable-traversable",
+ "lists",
+ "prelude"
+ ]
+ },
"argonaut": {
"type": "registry",
"version": "9.0.0",
@@ -858,6 +877,20 @@
"unsafe-coerce"
]
},
+ "avar": {
+ "type": "registry",
+ "version": "5.0.1",
+ "integrity": "sha256-8V4SxF4TIWZ9Ik1P4lPzIRUAZeFBe8w5WA2VcCEKsIk=",
+ "dependencies": [
+ "aff",
+ "effect",
+ "either",
+ "exceptions",
+ "functions",
+ "maybe",
+ "prelude"
+ ]
+ },
"bifunctors": {
"type": "registry",
"version": "6.1.0",
@@ -1529,6 +1562,23 @@
"prelude"
]
},
+ "mmorph": {
+ "type": "registry",
+ "version": "7.0.0",
+ "integrity": "sha256-Cfltaq+tfYjuSoSBN/b8cSQZbvZTqIRs6ebQewbIkGs=",
+ "dependencies": [
+ "bifunctors",
+ "either",
+ "free",
+ "functors",
+ "identity",
+ "maybe",
+ "newtype",
+ "prelude",
+ "transformers",
+ "tuples"
+ ]
+ },
"newtype": {
"type": "registry",
"version": "5.0.0",
@@ -1842,6 +1892,27 @@
"integrity": "sha256-mdrlJBAgFMh79hNRW39uv7c+BwnnaOrAMmdh7+VhEhs=",
"dependencies": []
},
+ "pipes": {
+ "type": "registry",
+ "version": "8.0.0",
+ "integrity": "sha256-dtUNpG8BGVr7pu6mQZyAnUAftUHgNS7f0QH3Kw5UTpQ=",
+ "dependencies": [
+ "aff",
+ "control",
+ "effect",
+ "either",
+ "foldable-traversable",
+ "identity",
+ "lists",
+ "maybe",
+ "mmorph",
+ "newtype",
+ "prelude",
+ "tailrec",
+ "transformers",
+ "tuples"
+ ]
+ },
"posix-types": {
"type": "registry",
"version": "6.0.0",
@@ -1928,6 +1999,40 @@
"unsafe-coerce"
]
},
+ "spec": {
+ "type": "registry",
+ "version": "8.1.2",
+ "integrity": "sha256-klPPJ6lBQI1CGOAdLJ+ZoGRt8XZippkTKjn53BrSkL0=",
+ "dependencies": [
+ "aff",
+ "ansi",
+ "arrays",
+ "avar",
+ "bifunctors",
+ "control",
+ "datetime",
+ "effect",
+ "either",
+ "exceptions",
+ "foldable-traversable",
+ "fork",
+ "identity",
+ "integers",
+ "lists",
+ "maybe",
+ "newtype",
+ "now",
+ "ordered-collections",
+ "parallel",
+ "pipes",
+ "prelude",
+ "refs",
+ "strings",
+ "tailrec",
+ "transformers",
+ "tuples"
+ ]
+ },
"st": {
"type": "registry",
"version": "6.2.0",
diff --git a/spago.yaml b/spago.yaml
@@ -40,7 +40,15 @@ package:
- web-html
test:
main: Test.Main
- dependencies: []
+ dependencies:
+ - spec
+ - aff
+ - argonaut
+ - argonaut-core
+ - either
+ - maybe
+ - transformers
+ - arrays
workspace:
packageSet:
registry: 75.9.0
diff --git a/src/Types.purs b/src/Types.purs
@@ -6,6 +6,7 @@ import Data.Argonaut (class DecodeJson, class EncodeJson, decodeJson, encodeJson
import Data.Argonaut.Core (jsonEmptyObject)
import Data.Maybe (Maybe)
import Data.Generic.Rep (class Generic)
+import Data.Show.Generic (genericShow)
newtype ListenBrainzResponse = ListenBrainzResponse
{ payload :: Payload
@@ -13,6 +14,8 @@ newtype ListenBrainzResponse = ListenBrainzResponse
derive instance eqListenBrainzResponse :: Eq ListenBrainzResponse
derive instance genericListenBrainzResponse :: Generic ListenBrainzResponse _
+instance showListenBrainzResponse :: Show ListenBrainzResponse where
+ show = genericShow
instance DecodeJson ListenBrainzResponse where
decodeJson json = do
@@ -31,6 +34,8 @@ newtype Payload = Payload
derive instance eqPayload :: Eq Payload
derive instance genericPayload :: Generic Payload _
+instance showPayload :: Show Payload where
+ show = genericShow
instance DecodeJson Payload where
decodeJson json = do
@@ -50,6 +55,8 @@ newtype Listen = Listen
derive instance eqListen :: Eq Listen
derive instance genericListen :: Generic Listen _
+instance showListen :: Show Listen where
+ show = genericShow
instance DecodeJson Listen where
decodeJson json = do
@@ -74,6 +81,8 @@ newtype TrackMetadata = TrackMetadata
derive instance eqTrackMetadata :: Eq TrackMetadata
derive instance genericTrackMetadata :: Generic TrackMetadata _
+instance showTrackMetadata :: Show TrackMetadata where
+ show = genericShow
instance DecodeJson TrackMetadata where
decodeJson json = do
@@ -101,6 +110,8 @@ newtype MbidMapping = MbidMapping
derive instance eqMbidMapping :: Eq MbidMapping
derive instance genericMbidMapping :: Generic MbidMapping _
+instance showMbidMapping :: Show MbidMapping where
+ show = genericShow
instance DecodeJson MbidMapping where
decodeJson json = do
@@ -122,6 +133,8 @@ newtype StatsEntry = StatsEntry
derive instance eqStatsEntry :: Eq StatsEntry
derive instance genericStatsEntry :: Generic StatsEntry _
+instance showStatsEntry :: Show StatsEntry where
+ show = genericShow
instance DecodeJson StatsEntry where
decodeJson json = do
@@ -144,6 +157,8 @@ newtype Stats = Stats
derive instance eqStats :: Eq Stats
derive instance genericStats :: Generic Stats _
+instance showStats :: Show Stats where
+ show = genericShow
instance DecodeJson Stats where
decodeJson json = do
diff --git a/test/Main.purs b/test/Main.purs
@@ -2,10 +2,91 @@ module Test.Main where
import Prelude
+import Data.Argonaut (decodeJson, encodeJson, parseJson)
+import Data.Array (length)
+import Data.Either (Either(..))
+import Data.Maybe (Maybe(..))
import Effect (Effect)
-import Effect.Class.Console (log)
+import Effect.Aff (launchAff_)
+import Test.Spec (describe, it)
+import Test.Spec.Assertions (shouldEqual, fail)
+import Test.Spec.Reporter.Console (consoleReporter)
+import Test.Spec.Runner (runSpec)
+import Types (Listen(..), ListenBrainzResponse(..), MbidMapping(..), Payload(..), Stats(..), StatsEntry(..), TrackMetadata(..))
+import Db (connect, initDb, checkExists, upsertScrobble, getScrobbles, initReleaseMetadata, upsertReleaseMetadata, getStats)
main :: Effect Unit
-main = do
- log "🍝"
- log "You should add some tests."
+main = launchAff_ $ runSpec [consoleReporter] do
+ describe "Scorpus Types" do
+ describe "MbidMapping Codecs" do
+ it "should roundtrip MbidMapping" do
+ let mbid = MbidMapping { releaseMbid: Just "release-123", caaReleaseMbid: Just "caa-456" }
+ decodeJson (encodeJson mbid) `shouldEqual` Right mbid
+
+ it "should decode MbidMapping with missing fields" do
+ let jsonStr = "{\"release_mbid\": \"abc\"}"
+ let expected = MbidMapping { releaseMbid: Just "abc", caaReleaseMbid: Nothing }
+ (parseJson jsonStr >>= decodeJson) `shouldEqual` Right expected
+
+ describe "TrackMetadata Codecs" do
+ it "should roundtrip TrackMetadata" do
+ let meta = TrackMetadata
+ { trackName: Just "Song"
+ , artistName: Just "Artist"
+ , releaseName: Just "Album"
+ , mbidMapping: Just (MbidMapping { releaseMbid: Just "rb", caaReleaseMbid: Nothing })
+ , genre: Just "Rock"
+ }
+ decodeJson (encodeJson meta) `shouldEqual` Right meta
+
+ describe "Listen Codecs" do
+ it "should roundtrip Listen" do
+ let listen = Listen
+ { trackMetadata: TrackMetadata
+ { trackName: Just "Song"
+ , artistName: Just "Artist"
+ , releaseName: Nothing
+ , mbidMapping: Nothing
+ , genre: Nothing
+ }
+ , listenedAt: Just 1600000000
+ }
+ decodeJson (encodeJson listen) `shouldEqual` Right listen
+
+ describe "Stats Codecs" do
+ it "should roundtrip Stats" do
+ let stats = Stats
+ { genres: [StatsEntry { name: "Rock", count: 10 }]
+ , labels: [StatsEntry { name: "Label", count: 5 }]
+ , years: [StatsEntry { name: "2023", count: 15 }]
+ }
+ decodeJson (encodeJson stats) `shouldEqual` Right stats
+
+ describe "ListenBrainzResponse Codecs" do
+ it "should decode a full ListenBrainz response" do
+ let jsonStr = """
+ {
+ "payload": {
+ "listens": [
+ {
+ "listened_at": 123456789,
+ "track_metadata": {
+ "track_name": "Test Track",
+ "artist_name": "Test Artist",
+ "release_name": "Test Album",
+ "mbid_mapping": {
+ "release_mbid": "rel-mbid",
+ "caa_release_mbid": "caa-mbid"
+ }
+ }
+ }
+ ]
+ }
+ }
+ """
+ let result = parseJson jsonStr >>= decodeJson
+ case result of
+ Right (ListenBrainzResponse { payload: Payload { listens } }) -> do
+ length listens `shouldEqual` 1
+ Left err ->
+ fail $ "Decoding failed: " <> show err