Skip to content
Open
Show file tree
Hide file tree
Changes from 2 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
19 changes: 18 additions & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,19 @@ uploadNotebooks := {
uploadToBlob(localNotebooksFolder, blobNotebooksFolder, "docs")
}

// Scoverage configuration: exclude legitimately untestable code
// These are either build-time utilities or require external environments
val coverageExclusions = Seq(
// Build-time code generation utilities (not runtime code - invoked during sbt build)
"com\\.microsoft\\.azure\\.synapse\\.ml\\.codegen\\..*",
// Generated BuildInfo classes (auto-generated by sbt-buildinfo)
"com\\.microsoft\\.azure\\.synapse\\.ml\\.build\\..*",
// Microsoft Fabric integration (requires Fabric environment files at specific paths)
"com\\.microsoft\\.azure\\.synapse\\.ml\\.fabric\\..*",
// Fabric-specific logging/telemetry (requires Fabric environment)
"com\\.microsoft\\.azure\\.synapse\\.ml\\.logging\\.fabric\\..*"
).mkString(";")

val settings = Seq(
Test / scalastyleConfig := (ThisBuild / baseDirectory).value / "scalastyle-test-config.xml",
Test / logBuffered := false,
Expand All @@ -281,7 +294,11 @@ val settings = Seq(
assembly / assemblyOption := (assembly / assemblyOption).value.copy(includeScala = false),
autoAPIMappings := true,
pomPostProcess := pomPostFunc,
sbtPlugin := false
sbtPlugin := false,
// Scoverage settings
coverageExcludedPackages := coverageExclusions,
coverageFailOnMinimum := false,
coverageHighlighting := true
)
ThisBuild / publishMavenStyle := true

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ object PyCodegen {
| long_description="SynapseML contains Microsoft's open source "
| + "contributions to the Apache Spark ecosystem",
| license="MIT",
| license_expression="MIT",
| packages=find_namespace_packages(include=['synapse.ml.*']) ${extraPackage},
| url="https://github.com/Microsoft/SynapseML",
| author="Microsoft",
Expand All @@ -108,8 +109,6 @@ object PyCodegen {
| "Intended Audience :: Developers",
| "Intended Audience :: Science/Research",
| "Topic :: Software Development :: Libraries",
| "License :: OSI Approved :: MIT License",
| "Programming Language :: Python :: 2",
| "Programming Language :: Python :: 3",
| ],
| zip_safe=True,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
// Copyright (C) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See LICENSE in project root for information.

package com.microsoft.azure.synapse.ml.core.contracts

import com.microsoft.azure.synapse.ml.core.test.base.TestBase

class VerifyMetrics extends TestBase {

test("TypedMetric stores name and value correctly") {
val metric = TypedMetric("accuracy", 0.95)
assert(metric.name === "accuracy")
assert(metric.value === 0.95)
}

test("TypedMetric works with different types") {
val doubleMetric = TypedMetric[Double]("score", 1.5)
val stringMetric = TypedMetric[String]("label", "positive")
val intMetric = TypedMetric[Int]("count", 42)

assert(doubleMetric.value === 1.5)
assert(stringMetric.value === "positive")
assert(intMetric.value === 42)
}

test("DoubleMetric stores name and double value") {
val metric = DoubleMetric("precision", 0.85)
assert(metric.name === "precision")
assert(metric.value === 0.85)
}

test("StringMetric stores name and string value") {
val metric = StringMetric("category", "classification")
assert(metric.name === "category")
assert(metric.value === "classification")
}

test("IntegralMetric stores name and long value") {
val metric = IntegralMetric("count", 1000L)
assert(metric.name === "count")
assert(metric.value === 1000L)
}

test("TypenameMetricGroup stores name and values map") {
val metrics = Map(
"group1" -> Seq(DoubleMetric("m1", 1.0), DoubleMetric("m2", 2.0)),
"group2" -> Seq(StringMetric("s1", "test"))
)
val group = TypenameMetricGroup("myGroup", metrics)
assert(group.name === "myGroup")
assert(group.values.size === 2)
assert(group.values("group1").length === 2)
}

test("MetricData stores data, metricType, and modelName") {
val data = Map("accuracy" -> Seq(0.9, 0.91, 0.92))
val metricData = MetricData(data, "classification", "logisticRegression")

assert(metricData.data === data)
assert(metricData.metricType === "classification")
assert(metricData.modelName === "logisticRegression")
}

test("MetricData.create converts single values to sequences") {
val singleValues = Map("accuracy" -> 0.95, "precision" -> 0.90)
val metricData = MetricData.create(singleValues, "classification", "svm")

assert(metricData.data("accuracy") === List(0.95))
assert(metricData.data("precision") === List(0.90))
assert(metricData.metricType === "classification")
assert(metricData.modelName === "svm")
}

test("MetricData.createTable preserves sequences") {
val tableData = Map(
"mse" -> Seq(0.1, 0.2, 0.3),
"rmse" -> Seq(0.316, 0.447, 0.548)
)
val metricData = MetricData.createTable(tableData, "regression", "linearRegression")

assert(metricData.data("mse") === Seq(0.1, 0.2, 0.3))
assert(metricData.data("rmse").length === 3)
assert(metricData.metricType === "regression")
assert(metricData.modelName === "linearRegression")
}

test("MetricData.create handles empty map") {
val metricData = MetricData.create(Map.empty[String, Double], "test", "model")
assert(metricData.data.isEmpty)
}

test("MetricData.createTable handles empty map") {
val metricData = MetricData.createTable(Map.empty[String, Seq[Double]], "test", "model")
assert(metricData.data.isEmpty)
}

test("ConvenienceTypes type aliases work correctly") {
import ConvenienceTypes._
val name: UniqueName = "testMetric"
val table: MetricTable = Map(name -> Seq(TypedMetric("m1", 1.0)))

assert(name === "testMetric")
assert(table.contains("testMetric"))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
// Copyright (C) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See LICENSE in project root for information.

package com.microsoft.azure.synapse.ml.core.contracts

import com.microsoft.azure.synapse.ml.core.test.base.TestBase
import org.apache.spark.ml.param.ParamMap
import org.apache.spark.ml.util.Identifiable

// Test implementations of the param traits
class TestHasInputCol(override val uid: String)
extends HasInputCol {
def this() = this(Identifiable.randomUID("TestHasInputCol"))
override def copy(extra: ParamMap): TestHasInputCol = defaultCopy(extra)
}

class TestHasOutputCol(override val uid: String)
extends HasOutputCol {
def this() = this(Identifiable.randomUID("TestHasOutputCol"))
override def copy(extra: ParamMap): TestHasOutputCol = defaultCopy(extra)
}

class TestHasInputCols(override val uid: String)
extends HasInputCols {
def this() = this(Identifiable.randomUID("TestHasInputCols"))
override def copy(extra: ParamMap): TestHasInputCols = defaultCopy(extra)
}

class TestHasOutputCols(override val uid: String)
extends HasOutputCols {
def this() = this(Identifiable.randomUID("TestHasOutputCols"))
override def copy(extra: ParamMap): TestHasOutputCols = defaultCopy(extra)
}

class TestHasLabelCol(override val uid: String)
extends HasLabelCol {
def this() = this(Identifiable.randomUID("TestHasLabelCol"))
override def copy(extra: ParamMap): TestHasLabelCol = defaultCopy(extra)
}

class TestHasFeaturesCol(override val uid: String)
extends HasFeaturesCol {
def this() = this(Identifiable.randomUID("TestHasFeaturesCol"))
override def copy(extra: ParamMap): TestHasFeaturesCol = defaultCopy(extra)
}

class TestHasWeightCol(override val uid: String)
extends HasWeightCol {
def this() = this(Identifiable.randomUID("TestHasWeightCol"))
override def copy(extra: ParamMap): TestHasWeightCol = defaultCopy(extra)
}

class TestHasScoredLabelsCol(override val uid: String)
extends HasScoredLabelsCol {
def this() = this(Identifiable.randomUID("TestHasScoredLabelsCol"))
override def copy(extra: ParamMap): TestHasScoredLabelsCol = defaultCopy(extra)
}

class TestHasScoresCol(override val uid: String)
extends HasScoresCol {
def this() = this(Identifiable.randomUID("TestHasScoresCol"))
override def copy(extra: ParamMap): TestHasScoresCol = defaultCopy(extra)
}

class TestHasScoredProbabilitiesCol(override val uid: String)
extends HasScoredProbabilitiesCol {
def this() = this(Identifiable.randomUID("TestHasScoredProbabilitiesCol"))
override def copy(extra: ParamMap): TestHasScoredProbabilitiesCol = defaultCopy(extra)
}

class TestHasEvaluationMetric(override val uid: String)
extends HasEvaluationMetric {
def this() = this(Identifiable.randomUID("TestHasEvaluationMetric"))
override def copy(extra: ParamMap): TestHasEvaluationMetric = defaultCopy(extra)
}

class TestHasValidationIndicatorCol(override val uid: String)
extends HasValidationIndicatorCol {
def this() = this(Identifiable.randomUID("TestHasValidationIndicatorCol"))
override def copy(extra: ParamMap): TestHasValidationIndicatorCol = defaultCopy(extra)
}

class TestHasInitScoreCol(override val uid: String)
extends HasInitScoreCol {
def this() = this(Identifiable.randomUID("TestHasInitScoreCol"))
override def copy(extra: ParamMap): TestHasInitScoreCol = defaultCopy(extra)
}

class TestHasGroupCol(override val uid: String)
extends HasGroupCol {
def this() = this(Identifiable.randomUID("TestHasGroupCol"))
override def copy(extra: ParamMap): TestHasGroupCol = defaultCopy(extra)
}

class VerifyParams extends TestBase {

test("HasInputCol set and get work correctly") {
val obj = new TestHasInputCol()
obj.setInputCol("myInput")
assert(obj.getInputCol === "myInput")
}

test("HasOutputCol set and get work correctly") {
val obj = new TestHasOutputCol()
obj.setOutputCol("myOutput")
assert(obj.getOutputCol === "myOutput")
}

test("HasInputCols set and get work correctly") {
val obj = new TestHasInputCols()
val cols = Array("col1", "col2", "col3")
obj.setInputCols(cols)
assert(obj.getInputCols.sameElements(cols))
}

test("HasOutputCols set and get work correctly") {
val obj = new TestHasOutputCols()
val cols = Array("out1", "out2")
obj.setOutputCols(cols)
assert(obj.getOutputCols.sameElements(cols))
}

test("HasLabelCol set and get work correctly") {
val obj = new TestHasLabelCol()
obj.setLabelCol("target")
assert(obj.getLabelCol === "target")
}

test("HasFeaturesCol set and get work correctly") {
val obj = new TestHasFeaturesCol()
obj.setFeaturesCol("features")
assert(obj.getFeaturesCol === "features")
}

test("HasWeightCol set and get work correctly") {
val obj = new TestHasWeightCol()
obj.setWeightCol("weight")
assert(obj.getWeightCol === "weight")
}

test("HasScoredLabelsCol set and get work correctly") {
val obj = new TestHasScoredLabelsCol()
obj.setScoredLabelsCol("scoredLabels")
assert(obj.getScoredLabelsCol === "scoredLabels")
}

test("HasScoresCol set and get work correctly") {
val obj = new TestHasScoresCol()
obj.setScoresCol("scores")
assert(obj.getScoresCol === "scores")
}

test("HasScoredProbabilitiesCol set and get work correctly") {
val obj = new TestHasScoredProbabilitiesCol()
obj.setScoredProbabilitiesCol("probs")
assert(obj.getScoredProbabilitiesCol === "probs")
}

test("HasEvaluationMetric set and get work correctly") {
val obj = new TestHasEvaluationMetric()
obj.setEvaluationMetric("accuracy")
assert(obj.getEvaluationMetric === "accuracy")
}

test("HasValidationIndicatorCol set and get work correctly") {
val obj = new TestHasValidationIndicatorCol()
obj.setValidationIndicatorCol("isValidation")
assert(obj.getValidationIndicatorCol === "isValidation")
}

test("HasInitScoreCol set and get work correctly") {
val obj = new TestHasInitScoreCol()
obj.setInitScoreCol("initScore")
assert(obj.getInitScoreCol === "initScore")
}

test("HasGroupCol set and get work correctly") {
val obj = new TestHasGroupCol()
obj.setGroupCol("group")
assert(obj.getGroupCol === "group")
}

// Test chaining
test("param setters return this for chaining") {
val obj = new TestHasInputCol()
val result = obj.setInputCol("test")
assert(result eq obj)
}
}
Loading
Loading