Skip to content

Commit 6a112fb

Browse files
committed
Update to a newer version of Scalaz and associated libraries. Closes #110
1 parent d4e58a5 commit 6a112fb

30 files changed

+322
-305
lines changed

csv-validator-cmd/src/main/scala/uk/gov/nationalarchives/csv/validator/cmd/CsvValidatorCmdApp.scala

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -149,16 +149,16 @@ object CsvValidatorCmdApp extends App {
149149

150150
private def containsError(l: NonEmptyList[FailMessage]) : Boolean = {
151151
l.list.find(_ match {
152-
case ErrorMessage(_, _, _) => true
152+
case FailMessage(ValidationError, _, _, _) => true
153153
case _ => false
154154
}).nonEmpty
155155
}
156156

157157
private def prettyPrint(l: NonEmptyList[FailMessage]): String = l.list.map { i =>
158158
i match {
159-
case WarningMessage(err,_,_) => "Warning: " + err
160-
case ErrorMessage(err,_,_) => "Error: " + err
161-
case SchemaMessage(err,_,_) => err
159+
case FailMessage(ValidationWarning, err,_,_) => "Warning: " + err
160+
case FailMessage(ValidationError, err,_,_) => "Error: " + err
161+
case FailMessage(SchemaDefinitionError, err,_,_) => err
162162
}
163-
}.mkString(sys.props("line.separator"))
163+
}.toList.mkString(sys.props("line.separator"))
164164
}

csv-validator-core/pom.xml

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -99,18 +99,13 @@
9999
<dependency>
100100
<groupId>org.scalaz.stream</groupId>
101101
<artifactId>scalaz-stream_${scala.version}</artifactId>
102-
<version>0.6a</version> <!-- version 0.5a is compatible with scalaz-core 7.1.0 -->
102+
<version>0.7.3a</version>
103103
</dependency>
104104
<dependency>
105-
<groupId>org.typelevel</groupId>
106-
<artifactId>scodec-bits_${scala.version}</artifactId>
107-
<version>1.0.4</version>
108-
</dependency>
109-
<!-- dependency>
110105
<groupId>org.scodec</groupId>
111106
<artifactId>scodec-bits_${scala.version}</artifactId>
112107
<version>1.0.6</version>
113-
</dependency -->
108+
</dependency>
114109
<dependency>
115110
<groupId>org.scalaz</groupId>
116111
<artifactId>scalaz-concurrent_${scala.version}</artifactId>

csv-validator-core/src/main/scala/uk/gov/nationalarchives/csv/validator/FailFastMetaDataValidator.scala

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,11 @@ import uk.gov.nationalarchives.csv.validator.metadata.Row
2222

2323
trait FailFastMetaDataValidator extends MetaDataValidator {
2424

25+
//TODO(AR) work on removing use of `Any`
26+
2527
override def validateRows(rows: Iterator[Row], schema: Schema): MetaDataValidation[Any] = {
2628

27-
def containsErrors(e: MetaDataValidation[Any]): Boolean = e.fold(_.list.exists(_.isInstanceOf[ErrorMessage]), _ => false)
29+
def containsErrors(e: MetaDataValidation[Any]): Boolean = e.fold(_.list.collectFirst(FailMessage.isError).nonEmpty, _ => false)
2830

2931
@tailrec
3032
def validateRows(results: List[MetaDataValidation[Any]] = List.empty[MetaDataValidation[Any]]) : List[MetaDataValidation[Any]] = {

csv-validator-core/src/main/scala/uk/gov/nationalarchives/csv/validator/MetaDataValidator.scala

Lines changed: 36 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,26 @@ import uk.gov.nationalarchives.csv.validator.metadata.Row
2525
import scala.annotation.tailrec
2626
import uk.gov.nationalarchives.csv.validator.api.TextFile
2727

28-
sealed abstract class FailMessage(val msg:String, val lineNr:Option[Int], val colIdx:Option[Int])
29-
case class WarningMessage(message:String, lineNumber: Option[Int] = None, columnIndex: Option[Int] = None) extends FailMessage(message, lineNumber, columnIndex)
30-
case class ErrorMessage(message:String, lineNumber: Option[Int] = None, columnIndex: Option[Int] = None) extends FailMessage(message, lineNumber, columnIndex)
31-
case class SchemaMessage(message:String, lineNumber: Option[Int] = None, columnIndex: Option[Int] = None) extends FailMessage(message, lineNumber, columnIndex)
28+
29+
//error reporting classes
30+
sealed trait ErrorType
31+
case object ValidationWarning extends ErrorType
32+
case object ValidationError extends ErrorType
33+
case object SchemaDefinitionError extends ErrorType
34+
case class FailMessage(`type`: ErrorType, message : String, lineNumber: Option[Int] = None, columnIndex: Option[Int] = None) //TODO(AR) consider a better name, e.g. CsvValidationFailure
35+
object FailMessage {
36+
def isWarning : PartialFunction[FailMessage, FailMessage] = {
37+
case fm @ FailMessage(ValidationWarning, _, _, _) => fm
38+
}
39+
40+
def isError : PartialFunction[FailMessage, FailMessage] = {
41+
case fm @ FailMessage(ValidationError, _, _, _) => fm
42+
}
43+
44+
def isSchemaDefinitionError : PartialFunction[FailMessage, FailMessage] = {
45+
case fm @ FailMessage(SchemaDefinitionError, _, _, _) => fm
46+
}
47+
}
3248

3349
case class ProgressFor(rowsToValidate: Int, progress: ProgressCallback)
3450

@@ -88,16 +104,16 @@ trait MetaDataValidator {
88104
val maybeNoData =
89105
if (schema.globalDirectives.contains(NoHeader())) {
90106
if (!rowIt.hasNext && !schema.globalDirectives.contains(PermitEmpty())) {
91-
Some(ErrorMessage("metadata file is empty but this has not been permitted").failNel[Any])
107+
Some(FailMessage(ValidationError, "metadata file is empty but this has not been permitted").failureNel[Any])
92108
} else {
93109
None
94110
}
95111
} else {
96112
if(!rowIt.hasNext) {
97-
Some(ErrorMessage("metadata file is empty but should contain at least a header").failNel[Any])
113+
Some(FailMessage(ValidationError, "metadata file is empty but should contain at least a header").failureNel[Any])
98114
} else {
99115
if(!rowIt.hasNext && !schema.globalDirectives.contains(PermitEmpty())) {
100-
Some(ErrorMessage("metadata file has a header but no data and this has not been permitted").failNel[Any])
116+
Some(FailMessage(ValidationError, "metadata file has a header but no data and this has not been permitted").failureNel[Any])
101117
} else {
102118
None
103119
}
@@ -143,19 +159,19 @@ trait MetaDataValidator {
143159
val maybeNoData =
144160
if (schema.globalDirectives.contains(NoHeader())) {
145161
if (!rowIt.hasNext && !schema.globalDirectives.contains(PermitEmpty())) {
146-
Some(ErrorMessage("metadata file is empty but this has not been permitted").failureNel[Any])
162+
Some(FailMessage(ValidationError, "metadata file is empty but this has not been permitted").failureNel[Any])
147163
} else {
148164
None
149165
}
150166
} else {
151167
if(!rowIt.hasNext) {
152-
Some(ErrorMessage("metadata file is empty but should contain at least a header").failureNel[Any])
168+
Some(FailMessage(ValidationError, "metadata file is empty but should contain at least a header").failureNel[Any])
153169
} else {
154170
val header = rowIt.skipHeader()
155171
val headerValidation = validateHeader(header, schema)
156-
headerValidation.orElse{
172+
headerValidation.orElse {
157173
if(!rowIt.hasNext && !schema.globalDirectives.contains(PermitEmpty())) {
158-
Some(ErrorMessage("metadata file has a header but no data and this has not been permitted").failureNel[Any])
174+
Some(FailMessage(ValidationError, "metadata file has a header but no data and this has not been permitted").failureNel[Any])
159175
} else {
160176
None
161177
}
@@ -175,9 +191,9 @@ trait MetaDataValidator {
175191
metadataValidation
176192

177193
case Left(ts) =>
178-
//TODO emit all errors not just first!
179-
ErrorMessage(ts(0).toString).failureNel[Any]
180-
//ts.toList.map(t => ErrorMessage(t.toString).failureNel[Any]).sequence[MetaDataValidation, Any]
194+
//TODO(AR) emit all errors not just first!
195+
FailMessage(ValidationError, ts(0).toString).failureNel[Any]
196+
// ts.toList.map(t => FailMessage(ValidationError, t.toString).failureNel[Any]).sequence[MetaDataValidation, Any]
181197
}
182198
}
183199

@@ -211,7 +227,7 @@ trait MetaDataValidator {
211227
if (headerList.sameElements(schemaHeader))
212228
None
213229
else
214-
Some(ErrorMessage(s"Metadata header, cannot find the column headers - ${Util.diff(schemaHeader.toSet, headerList.toSet).mkString(", ")} - .${if (icnc.isEmpty) " (Case sensitive)" else ""}").failNel[Any])
230+
Some(FailMessage(ValidationError, s"Metadata header, cannot find the column headers - ${Util.diff(schemaHeader.toSet, headerList.toSet).mkString(", ")} - .${if (icnc.isEmpty) " (Case sensitive)" else ""}").failureNel[Any])
215231
}
216232

217233
def validateRow(row: Row, schema: Schema, mayBeLast: Option[Boolean] = None): MetaDataValidation[Any] = {
@@ -236,7 +252,7 @@ trait MetaDataValidator {
236252
case None => true.successNel
237253
case Some(nel) => {
238254
val ret = nel.reverse.map {
239-
case (offset, message) => ErrorMessage(s"[UTF-8 Error][@$offset] ${message}")
255+
case (offset, message) => FailMessage(ValidationError, s"[UTF-8 Error][@$offset] ${message}")
240256
}
241257
ret.failure
242258
}
@@ -249,20 +265,20 @@ trait MetaDataValidator {
249265
}
250266

251267
if (tc.isEmpty || tc.get.numberOfColumns == row.cells.length) true.successNel[FailMessage]
252-
else ErrorMessage(s"Expected @totalColumns of ${tc.get.numberOfColumns} and found ${row.cells.length} on line ${row.lineNumber}", Some(row.lineNumber), Some(row.cells.length)).failureNel[Any]
268+
else FailMessage(ValidationError, s"Expected @totalColumns of ${tc.get.numberOfColumns} and found ${row.cells.length} on line ${row.lineNumber}", Some(row.lineNumber), Some(row.cells.length)).failureNel[Any]
253269
}
254270

255271
protected def rules(row: Row, schema: Schema, mayBeLast: Option[Boolean] = None): MetaDataValidation[List[Any]]
256272

257273
protected def validateCell(columnIndex: Int, cells: (Int) => Option[Cell], row: Row, schema: Schema, mayBeLast: Option[Boolean] = None): MetaDataValidation[Any] = {
258274
cells(columnIndex) match {
259275
case Some(c) => rulesForCell(columnIndex, row, schema, mayBeLast)
260-
case _ => ErrorMessage(s"Missing value at line: ${row.lineNumber}, column: ${schema.columnDefinitions(columnIndex).id}", Some(row.lineNumber), Some(columnIndex)).failureNel[Any]
276+
case _ => FailMessage(ValidationError, s"Missing value at line: ${row.lineNumber}, column: ${schema.columnDefinitions(columnIndex).id}", Some(row.lineNumber), Some(columnIndex)).failureNel[Any]
261277
}
262278
}
263279

264-
protected def toWarnings(results: Rule#RuleValidation[Any], lineNumber: Int, columnIndex: Int): MetaDataValidation[Any] = results.leftMap(_.map(WarningMessage(_, Some(lineNumber), Some(columnIndex))))
265-
protected def toErrors(results: Rule#RuleValidation[Any], lineNumber: Int, columnIndex: Int): MetaDataValidation[Any] = results.leftMap(_.map(ErrorMessage(_, Some(lineNumber), Some(columnIndex))))
280+
protected def toWarnings(results: Rule#RuleValidation[Any], lineNumber: Int, columnIndex: Int): MetaDataValidation[Any] = results.leftMap(_.map(FailMessage(ValidationWarning, _, Some(lineNumber), Some(columnIndex))))
281+
protected def toErrors(results: Rule#RuleValidation[Any], lineNumber: Int, columnIndex: Int): MetaDataValidation[Any] = results.leftMap(_.map(FailMessage(ValidationError, _, Some(lineNumber), Some(columnIndex))))
266282

267283
protected def rulesForCell(columnIndex: Int, row: Row, schema: Schema, mayBeLast: Option[Boolean] = None): MetaDataValidation[Any]
268284

csv-validator-core/src/main/scala/uk/gov/nationalarchives/csv/validator/Util.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@ object Util {
2626

2727
def checkFilesReadable(files: List[Path]) = files.map(fileReadable).sequence[AppValidation, FailMessage]
2828

29-
def fileReadable(file: Path): AppValidation[FailMessage] = if (file.exists && file.canRead) SchemaMessage(file.path).successNel[FailMessage] else fileNotReadableMessage(file).failureNel[FailMessage]
29+
def fileReadable(file: Path): AppValidation[FailMessage] = if (file.exists && file.canRead) FailMessage(SchemaDefinitionError, file.path).successNel[FailMessage] else fileNotReadableMessage(file).failureNel[FailMessage]
3030

31-
def fileNotReadableMessage(file: Path) = SchemaMessage("Unable to read file : " + file.path)
31+
def fileNotReadableMessage(file: Path) = FailMessage(SchemaDefinitionError, "Unable to read file : " + file.path)
3232

3333
/**
3434
* Check if the list l1 contain all element in l2

csv-validator-core/src/main/scala/uk/gov/nationalarchives/csv/validator/schema/SchemaParser.scala

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,14 @@ import java.io.Reader
1818
import scalaz._
1919
import Scalaz._
2020

21-
import uk.gov.nationalarchives.csv.validator.{SchemaMessage, FailMessage}
21+
import uk.gov.nationalarchives.csv.validator.{SchemaDefinitionError, FailMessage}
2222

2323
/**
2424
* CSV Schema Parser
2525
*
2626
* Uses Scala Parser Combinators to parse the CSV Schema language defined in
2727
* the specification document
28+
*
2829
* @see http://digital-preservation.github.io/csv-validator/csv-schema-1.0.html
2930
*/
3031
trait SchemaParser extends RegexParsers
@@ -122,9 +123,9 @@ with TraceableParsers {
122123
parse(reader) match {
123124
case s @ Success(schema: Schema, next) => {
124125
val errors = SchemaValidator.validate(schema)
125-
if (errors.isEmpty) schema.successNel[FailMessage] else SchemaMessage(errors).failureNel[Schema]
126+
if (errors.isEmpty) schema.successNel[FailMessage] else FailMessage(SchemaDefinitionError, errors).failureNel[Schema]
126127
}
127-
case n: NoSuccess => SchemaMessage(formatNoSuccessMessageForPlatform(n.toString)).failureNel[Schema]
128+
case n: NoSuccess => FailMessage(SchemaDefinitionError, formatNoSuccessMessageForPlatform(n.toString)).failureNel[Schema]
128129
}
129130
}
130131

0 commit comments

Comments
 (0)