• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

hyperledger / identus-cloud-agent / 10833924030

12 Sep 2024 03:25PM CUT coverage: 48.864% (+0.07%) from 48.793%
10833924030

Pull #1351

CryptoKnightIOG
ATL-7660: Credential Schema as List

Signed-off-by: Bassam Riman <bassam.riman@iohk.io>
Pull Request #1351: feat: Support Array Of Credential Schema

15 of 28 new or added lines in 3 files covered. (53.57%)

222 existing lines in 68 files now uncovered.

7530 of 15410 relevant lines covered (48.86%)

0.49 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

86.08
/shared/json/src/main/scala/org/hyperledger/identus/shared/json/JsonSchema.scala
1
package org.hyperledger.identus.shared.json
2

3
import com.fasterxml.jackson.databind.{JsonNode, ObjectMapper}
4
import com.networknt.schema.*
5
import com.networknt.schema.SpecVersion.VersionFlag
6
import org.hyperledger.identus.shared.json.JsonSchemaError.{
7
  JsonSchemaParsingError,
8
  UnexpectedError,
9
  UnsupportedJsonSchemaSpecVersion
10
}
11
import zio.*
12
import zio.json.*
13
import zio.json.ast.Json
14

15
import scala.io.Source
16

17
sealed trait JsonSchemaError {
18
  def error: String
19
}
20

21
object JsonSchemaError {
22
  case class JsonSchemaParsingError(error: String) extends JsonSchemaError
23

24
  case class JsonValidationErrors(errors: Seq[String]) extends JsonSchemaError {
25
    def error: String = errors.mkString(";")
1✔
26
  }
27

28
  case class UnsupportedJsonSchemaSpecVersion(error: String) extends JsonSchemaError
29

30
  case class UnexpectedError(error: String) extends JsonSchemaError
31
}
32

33
trait JsonSchemaValidator {
34
  def validate(claims: String): IO[JsonSchemaError, Unit]
35

36
  def validate(claimsJsonNode: JsonNode): IO[JsonSchemaError, Unit] = {
1✔
37
    validate(claimsJsonNode.toString)
1✔
38
  }
39
}
40

41
case class JsonSchemaValidatorImpl(schemaValidator: JsonSchema) extends JsonSchemaValidator {
42
  override def validate(jsonString: String): IO[JsonSchemaError, Unit] = {
1✔
43
    import scala.jdk.CollectionConverters.*
44
    for {
1✔
45
      // Convert claims to JsonNode
46
      jsonClaims <- JsonSchemaUtils.toJsonNode(jsonString)
1✔
47

48
      // Validate claims JsonNode
49
      validationMessages <- ZIO
1✔
50
        .attempt(schemaValidator.validate(jsonClaims).asScala.toSeq)
1✔
51
        .mapError(t => JsonSchemaError.JsonValidationErrors(Seq(t.getMessage)))
×
52

53
      validationResult <-
1✔
54
        if (validationMessages.isEmpty) ZIO.unit
1✔
55
        else ZIO.fail(JsonSchemaError.JsonValidationErrors(validationMessages.map(_.getMessage)))
1✔
56
    } yield validationResult
57
  }
58

59
}
60

61
object JsonSchemaValidatorImpl {
62
  def from(schema: Json): IO[JsonSchemaError, JsonSchemaValidator] = {
1✔
63
    for {
1✔
64
      jsonSchema <- JsonSchemaUtils.from(schema, IndexedSeq(SpecVersion.VersionFlag.V202012))
1✔
65
    } yield JsonSchemaValidatorImpl(jsonSchema)
66
  }
67

68
  def draft7Meta: ZIO[Scope, JsonSchemaError, JsonSchemaValidator] =
1✔
69
    ZIO
1✔
70
      .acquireRelease {
71
        ZIO
1✔
72
          .attempt(Source.fromResource("json-schema/draft-07.json"))
1✔
73
          .mapError(e => UnexpectedError(e.getMessage))
×
74
      }(src => ZIO.attempt(src).orDie)
1✔
75
      .map(_.mkString)
1✔
76
      .flatMap(schema => JsonSchemaUtils.jsonSchemaAtVersion(schema, SpecVersion.VersionFlag.V7))
1✔
77
      .map(JsonSchemaValidatorImpl(_))
78
}
79

80
object JsonSchemaUtils {
81

82
  /** Create a json schema where the version is inferred from $schema field with optional supported version check */
83
  def jsonSchema(
1✔
84
      schema: String,
85
      supportedVersions: IndexedSeq[VersionFlag] = IndexedSeq.empty
1✔
86
  ): IO[JsonSchemaError, JsonSchema] = {
87
    for {
1✔
88
      jsonSchemaNode <- toJsonNode(schema)
1✔
89
      specVersion <- ZIO
1✔
90
        .attempt(SpecVersionDetector.detect(jsonSchemaNode))
1✔
91
        .mapError(t => UnexpectedError(t.getMessage))
×
92
      _ <-
1✔
93
        if (supportedVersions.nonEmpty && !supportedVersions.contains(specVersion))
1✔
94
          ZIO.fail(
×
95
            UnsupportedJsonSchemaSpecVersion(
96
              s"Unsupported JsonSchemaVersion. Current:$specVersion ExpectedOneOf:${supportedVersions.map(_.getId)}"
×
97
            )
98
          )
99
        else ZIO.unit
1✔
100
      jsonSchema <- jsonSchemaAtVersion(schema, specVersion)
1✔
101
    } yield jsonSchema
102
  }
103

104
  /** Create a json schema at specific version */
105
  def jsonSchemaAtVersion(
1✔
106
      schema: String,
107
      specVersion: VersionFlag
108
  ): IO[JsonSchemaError, JsonSchema] = {
109
    for {
1✔
110
      jsonSchemaNode <- toJsonNode(schema)
1✔
111
      mapper <- ZIO.attempt(new ObjectMapper()).mapError(t => UnexpectedError(t.getMessage))
1✔
112
      factory <- ZIO
1✔
113
        .attempt(JsonSchemaFactory.builder(JsonSchemaFactory.getInstance(specVersion)).jsonMapper(mapper).build)
1✔
114
        .mapError(t => UnexpectedError(t.getMessage))
×
115
      jsonSchema <- ZIO.attempt(factory.getSchema(jsonSchemaNode)).mapError(t => UnexpectedError(t.getMessage))
1✔
116
    } yield jsonSchema
117
  }
118

119
  def from(
1✔
120
      schema: Json,
121
      supportedVersions: IndexedSeq[VersionFlag] = IndexedSeq.empty
×
122
  ): IO[JsonSchemaError, JsonSchema] = {
123
    jsonSchema(schema.toString(), supportedVersions)
1✔
124
  }
125

126
  def toJsonNode(json: Json): IO[JsonSchemaError, JsonNode] = {
1✔
127
    toJsonNode(json.toString())
1✔
128
  }
129

130
  def toJsonNode(json: String): IO[JsonSchemaError, JsonNode] = {
1✔
131
    for {
1✔
UNCOV
132
      mapper <- ZIO.attempt(new ObjectMapper()).mapError(t => UnexpectedError(t.getMessage))
×
133
      jsonSchemaNode <- ZIO
1✔
134
        .attempt(mapper.readTree(json))
1✔
135
        .mapError(t => JsonSchemaParsingError(t.getMessage))
×
136
    } yield jsonSchemaNode
137
  }
138
}
139

140
class SchemaSerDes[S](jsonSchemaSchemaStr: String) {
141

142
  def initialiseJsonSchema: IO[JsonSchemaError, JsonSchema] =
1✔
143
    JsonSchemaUtils.jsonSchema(jsonSchemaSchemaStr)
1✔
144

145
  def serializeToJsonString(instance: S)(using encoder: JsonEncoder[S]): String = {
1✔
146
    instance.toJson
1✔
147
  }
148

149
  def serialize(instance: S)(using encoder: JsonEncoder[S]): Either[String, Json] = {
1✔
150
    instance.toJsonAST
1✔
151
  }
152

153
  def deserialize(
×
154
      schema: zio.json.ast.Json
155
  )(using decoder: JsonDecoder[S]): IO[JsonSchemaError, S] = {
156
    deserialize(schema.toString())
×
157
  }
158

159
  def deserialize(
1✔
160
      jsonString: String
161
  )(using decoder: JsonDecoder[S]): IO[JsonSchemaError, S] = {
162
    for {
1✔
163
      _ <- validate(jsonString)
1✔
164
      schema <-
1✔
165
        ZIO
1✔
166
          .fromEither(decoder.decodeJson(jsonString))
1✔
167
          .mapError(JsonSchemaError.JsonSchemaParsingError.apply)
168
    } yield schema
169
  }
170

171
  def deserializeAsJson(jsonString: String): IO[JsonSchemaError, Json] = {
1✔
172
    for {
1✔
173
      _ <- validate(jsonString)
1✔
174
      json <-
1✔
175
        ZIO
1✔
176
          .fromEither(jsonString.fromJson[Json])
1✔
177
          .mapError(JsonSchemaError.JsonSchemaParsingError.apply)
178
    } yield json
179
  }
180

181
  def validate(jsonString: String): IO[JsonSchemaError, Unit] = {
1✔
182
    for {
1✔
183
      jsonSchemaSchema <- JsonSchemaUtils.jsonSchema(jsonSchemaSchemaStr)
1✔
184
      schemaValidator = JsonSchemaValidatorImpl(jsonSchemaSchema)
185
      result <- schemaValidator.validate(jsonString)
1✔
186
    } yield result
187
  }
188

189
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc