I am new to scalatest and a bit lost in the gigantic inconsistent mess of features
I am trying to write parameterized tests. It seems that the way to do that is via TableDrivenPropertyChecks
I managed to get it working with a test like:
import org.scalatest.funspec.AnyFunSpec
import org.scalatest.prop.TableDrivenPropertyChecks
class MyTest extends AnyFunSpec with TableDrivenPropertyChecks {
describe("the test") {
val cases = Table(
("label", "a", "b"),
("case 2 > 1", 1, 2),
("case 4 > 3", 3, 4),
)
it("should...") {
forAll(cases) { (name: String, a: Int, b: Int) =>
assert(b > a)
}
}
}
}
It's fine, but when I run it under sbt I just see:
[info] MyTest:
[info] the test
[info] - should...
If I inject a bad case into the table I can see the test fail so I know they are all being tested.
What I want is for the test runner to report something for each case in the table.
I have seen examples which look like they would provide this, e.g.: https://blog.knoldus.com/table-driven-testing-in-scala/
import org.scalatest.FreeSpec
import org.scalatest._
import org.scalatest.prop.TableDrivenPropertyChecks
class OrderValidationTableDrivenSpec extends FreeSpec with TableDrivenPropertyChecks with Matchers {
"Order Validation" - {
"should validate and return false if" - {
val orders = Table(
("statement" , "order")
, ("price is negative" , Order(quantity = 10, price = -2))
, ("quantity is negative" , Order(quantity = -10, price = 2))
, ("price and quantity are negative" , Order(quantity = -10, price = -2))
)
forAll(orders) {(statement, invalidOrder) =>
s"$statement" in {
OrderValidation.validateOrder(invalidOrder) shouldBe false
}
}
}
}
}
But if I try to do this in my test:
import org.scalatest.funspec.AnyFunSpec
import org.scalatest.prop.TableDrivenPropertyChecks
class MyTest extends AnyFunSpec with TableDrivenPropertyChecks {
describe("the test") {
val cases = Table(
("label", "a", "b"),
("case 2 > 1", 1, 2),
("case 3 > 4", 3, 4),
)
it("should...") {
forAll(cases) { (label: String, a: Int, b: Int) =>
s"$label" in {
assert(b > a)
}
}
}
}
}
...I get the error: value in is not a member of String from the s"$label" in { part.
How do I get my TableDrivenPropertyChecks to report something for each case in the table?
One of cool features of ScalaTest is that test is not a method, so you can define tests inside a loop:
Table(
("a", "b"),
(1, 2),
(3, 4)
).forEvery({ (a: Int, b: Int) => {
it(s"should pass if $b is greater then $a") {
assert(b > a)
}
}})
Or even without using Table, just with any collection:
Seq(
(1, 2),
(3, 4)
).foreach {
case (a: Int, b: Int) =>
it(s"should pass if $b is greater then $a") {
assert(b > a)
}
}
This way you will get one test per each iteration of a loop, so all the cases will be executed independently, while in case of a loop in a single test it will fail on first failed assertion and won't check remaining cases.
Related
I'm trying to create entity for a table like this:
import org.jetbrains.exposed.dao.Entity
import org.jetbrains.exposed.dao.id.EntityID
import org.jetbrains.exposed.sql.Column
import org.jetbrains.exposed.sql.Table
object TestTable: Table("tests") {
val id: Column<Long> = long("id").autoIncrement()
val name: Column<String> = varchar("name", 32)
override val primaryKey = PrimaryKey(id, name="pk_test_id")
}
class Test (id: EntityID<Long>): Entity<Long>(id) {
}
Something like this seems to work:
val testId = TestTable.insert {
it[name] = "test_name_1"
} get TestTable.id
Is it possible to create an entity and then insert it? Something, like this?:
val testEntity = Test()
...
db.insert(testEntity)
I'm not looking for a solution using IntTable, StringTable, ..., as in the exposed documentation. Just with a Table from exposed.
You can write insert method
object TestTable: LongIdTable("tests", columnName = "id") {
val name = varchar("name", 32)
}
class TestEntity (id: EntityID<Long>): LongEntity(id) {
companion object: LongEntityClass<TestEntity>(TestTable)
var name by TestTable.name
}
data class Result(
val id: Long,
val name:String
) {
companion object {
fun TestEntity.fromEntity(): Result = Result(
id = id.value,
name = name
)
fun fromRow(row: ResultRow) = Result(
id = row[TestTable.id].value,
name = row[TestTable.name]
)
}
}
fun insert(result: Result) = transaction {
return#transaction TestEntity.new {
this.name = result.name
}.fromEntity()
}
fun update(result: Result) = transaction {
return#transaction TestEntity.findById(result.id)?.apply {
this.name = result.name
}?.fromEntity()
}
fun firstSelect(name: String) = transaction {
return#transaction TestEntity.find {
TestTable.name eq name
}.map { it.fromEntity() }
}
fun secondSelect(name: String) = transaction {
return#transaction TestTable.select {
TestTable.name eq name
}.map { Result.fromRow(it) }
}
I am looking for a way to split an array into chunks with a max value, but can't seem to find a solution.
Lets say we have the following code:
struct FooBar {
let value: Int
}
let array: [FooBar] = [
FooBar(value: 1),
FooBar(value: 2),
FooBar(value: 1),
FooBar(value: 1),
FooBar(value: 1),
FooBar(value: 2),
FooBar(value: 2),
FooBar(value: 1)
]
And we want to split this into chunks where the maxSize of FooBar.value doesn't exceed 3. The end result should be something like:
let ExpectedEndResult: [[FooBar]] = [
[
FooBar(value: 1),
FooBar(value: 2)
],
[
FooBar(value: 1),
FooBar(value: 1),
FooBar(value: 1)
],
[
FooBar(value: 2),
],
[
FooBar(value: 2),
FooBar(value: 1)
]
]
I've written this so far, but there is an issue when a 3rd item could be added, also... I believe there must be simpler way but I just can't think of one right now:
extension Array where Element == FooBar {
func chunked(maxValue: Int) -> [[FooBar]] {
var chunks: [[FooBar]] = []
var chunk: [FooBar] = []
self.enumerated().forEach { key, value in
chunk.append(value)
if self.count-1 > key {
let next = self[key+1]
if next.value + value.value > maxValue {
chunks.append(chunk)
chunk = []
}
} else {
chunks.append(chunk)
}
}
return chunks
}
}
Any suggestions?
I would use reduce(into:) for this
let maxValue = 3 //limit
var currentValue = 0 // current total value for the last sub array
var index = 0 // index of last (current) sub array
let groups = array.reduce(into: [[]]) {
if $1.value > maxValue || $1.value + currentValue > maxValue {
$0.append([$1])
currentValue = $1.value
index += 1
} else {
$0[index].append($1)
currentValue += $1.value
}
}
To make it more universal, here is a generic function as an extension to Array that also uses a KeyPath for the value to chunk over
extension Array {
func chunk<ElementValue: Numeric & Comparable>(withLimit limit: ElementValue,
using keyPath: KeyPath<Element, ElementValue>) -> [[Element]] {
var currentValue = ElementValue.zero
var index = 0
return self.reduce(into: [[]]) {
let value = $1[keyPath: keyPath]
if value > limit || value + currentValue > limit {
$0.append([$1])
currentValue = value
index += 1
} else {
$0[index].append($1)
currentValue += value
}
}
}
}
Usage for the sample
let result = array.chunk(withLimit: 3, using: \.value)
Something like:
extension Array where Element == FooBar {
func chunked(maxValue: Int) -> [[FooBar]] {
var chunks: [[FooBar]] = []
var chunk: [FooBar] = []
let filtered = self.filter({ item in
item.value <= maxValue
})
filtered.enumerated().forEach { index, foo in
let currentTotal = chunk.reduce(0, { sum, nextFoo in sum + nextFoo.value })
let newValue = currentTotal + foo.value
if newValue < maxValue {
chunk.append(foo)
} else if newValue == maxValue {
chunk.append(foo)
chunks.append(chunk)
chunk = []
} else {
chunks.append(chunk)
chunk = [foo]
}
}
return chunks
}
}
It could be interesting to write something that goes looking in the array for the perfect groups. The problem with the sequential approach is that one can end up with groups are very low in value when there are perfectly good foos that could fit in the chunk, but they just aren't the next item.
Edit: Added a filter for values above maxValue ... just in case.
I came across a problem that required iterating over an array in pairs. What's the best way to do this? Or, as an alternative, what's the best way of transforming an Array into an Array of pairs (which could then be iterated normally)?
Here's the best I got. It requires output to be a var, and it's not really pretty. Is there a better way?
let input = [1, 2, 3, 4, 5, 6]
var output = [(Int, Int)]()
for i in stride(from: 0, to: input.count - 1, by: 2) {
output.append((input[i], input[i+1]))
}
print(output) // [(1, 2), (3, 4), (5, 6)]
// let desiredOutput = [(1, 2), (3, 4), (5, 6)]
// print(desiredOutput)
You can map the stride instead of iterating it, that
allows to get the result as a constant:
let input = [1, 2, 3, 4, 5, 6]
let output = stride(from: 0, to: input.count - 1, by: 2).map {
(input[$0], input[$0+1])
}
print(output) // [(1, 2), (3, 4), (5, 6)]
If you only need to iterate over the pairs and the given array is large
then it may be advantageous to avoid the creation of an intermediate
array with a lazy mapping:
for (left, right) in stride(from: 0, to: input.count - 1, by: 2)
.lazy
.map( { (input[$0], input[$0+1]) } ) {
print(left, right)
}
This is now available as
Sequence.chunks(ofCount: 2) of the swift-algorithms package
for chunk in input.chunks(ofCount: 2) {
print(chunk)
}
I don't think this is any better than Martin R's, but seems the OP needs something else...
struct PairIterator<C: IteratorProtocol>: IteratorProtocol {
private var baseIterator: C
init(_ iterator: C) {
baseIterator = iterator
}
mutating func next() -> (C.Element, C.Element)? {
if let left = baseIterator.next(), let right = baseIterator.next() {
return (left, right)
}
return nil
}
}
extension Sequence {
var pairs: AnySequence<(Self.Iterator.Element,Self.Iterator.Element)> {
return AnySequence({PairIterator(self.makeIterator())})
}
}
input.pairs.forEach{ print($0) }
let output = input.pairs.map{$0}
print(output) //->[(1, 2), (3, 4), (5, 6)]
Here's a version of #OOPer's answer that works with an odd number of elements in your list. You can leave off the conformance to CustomStringConvertible if you like, of course. But it gives prettier output for this example. : )
struct Pair<P: CustomStringConvertible>: CustomStringConvertible {
let left: P
let right: P?
var description: String {
if let right = right {
return "(\(left.description), \(right.description)"
}
return "(\(left.description), nil)"
}
}
struct PairIterator<C: IteratorProtocol>: IteratorProtocol where C.Element: CustomStringConvertible {
private var baseIterator: C
init(_ iterator: C) {
baseIterator = iterator
}
mutating func next() -> Pair<C.Element>? {
if let left = baseIterator.next() {
return Pair(left: left, right: baseIterator.next())
}
return nil
}
}
extension Sequence where Element: CustomStringConvertible {
var pairs: AnySequence<Pair<Self.Element>> {
return AnySequence({PairIterator(self.makeIterator())})
}
}
let input: [Int] = [1,2,3,4,5,6,7]
print(input.pairs)
print(Array(input.pairs))
//output:
AnySequence<Pair<Int>>(_box: Swift._SequenceBox<Swift._ClosureBasedSequence<__lldb_expr_27.PairIterator<Swift.IndexingIterator<Swift.Array<Swift.Int>>>>>)
[(1, 2, (3, 4, (5, 6, (7, nil)]
You don't need a custom type, like PairIterator as the above answers prescribe. Getting a paired sequence is a one-liner:
let xs = [1, 2, 3]
for pair in zip(xs, xs.dropFirst()) {
print(pair) // (1, 2) (2, 3)
}
If you intend to reuse that, you can place a pairs method inside an extension:
extension Sequence {
func pairs() -> AnySequence<(Element, Element)> {
AnySequence(zip(self, self.dropFirst()))
}
}
I have a simple code as follows,when I run it within IDE, nothing is printed on the console, could some one help take a look? Thanks
import org.apache.flink.api.java.tuple.Tuple
import org.apache.flink.streaming.api.scala._
import org.apache.flink.streaming.api.TimeCharacteristic
import org.apache.flink.streaming.api.scala.StreamExecutionEnvironment
import org.apache.flink.streaming.api.scala.function.ProcessWindowFunction
import org.apache.flink.streaming.api.windowing.time.Time
import org.apache.flink.streaming.api.windowing.windows.TimeWindow
import org.apache.flink.util.Collector
object WindowTest {
def main(args: Array[String]): Unit = {
val env = StreamExecutionEnvironment.getExecutionEnvironment
env.setStreamTimeCharacteristic(TimeCharacteristic.ProcessingTime)
val ds = env.fromElements(
(1, "a"), (2, "b"), (3, "c"), (4, "e"), (5, "f"), (6, "g"), (7, "h"), (8, "g"), (1, "1a"), (2, "2b"), (3, "3c"), (4, "4e"), (5, "5f"), (6, "g"), (7, "h"), (8, "g")
)
val ds2 = ds.keyBy(0).timeWindow(Time.seconds(10))
.process(new ProcessWindowFunction[(Int, String), String, Tuple, TimeWindow] {
override def process(key: Tuple, context: Context, elements: Iterable[(Int, String)], out: Collector[String]): Unit = {
val k = key.getField[Int](0)
val w = context.window
val start = w.getStart
val end = w.getEnd
val hc = context.window.hashCode()
//NOT CALLED
println(s"k=$k,start=$start, end=$end,hc=$hc")
}
})
ds2.print()
env.execute()
Thread.sleep(30 * 1000)
}
}
Your ProcessWindowFunction is never called because the window is never triggered. It's never triggered because it runs to completion in a couple of milliseconds (roughly speaking), so it's very unlikely to be running at a moment when the system clock time is exactly at a 10 second boundary, which is what would have to happen for this processing time window to be triggered.
I came across a problem that required iterating over an array in pairs. What's the best way to do this? Or, as an alternative, what's the best way of transforming an Array into an Array of pairs (which could then be iterated normally)?
Here's the best I got. It requires output to be a var, and it's not really pretty. Is there a better way?
let input = [1, 2, 3, 4, 5, 6]
var output = [(Int, Int)]()
for i in stride(from: 0, to: input.count - 1, by: 2) {
output.append((input[i], input[i+1]))
}
print(output) // [(1, 2), (3, 4), (5, 6)]
// let desiredOutput = [(1, 2), (3, 4), (5, 6)]
// print(desiredOutput)
You can map the stride instead of iterating it, that
allows to get the result as a constant:
let input = [1, 2, 3, 4, 5, 6]
let output = stride(from: 0, to: input.count - 1, by: 2).map {
(input[$0], input[$0+1])
}
print(output) // [(1, 2), (3, 4), (5, 6)]
If you only need to iterate over the pairs and the given array is large
then it may be advantageous to avoid the creation of an intermediate
array with a lazy mapping:
for (left, right) in stride(from: 0, to: input.count - 1, by: 2)
.lazy
.map( { (input[$0], input[$0+1]) } ) {
print(left, right)
}
This is now available as
Sequence.chunks(ofCount: 2) of the swift-algorithms package
for chunk in input.chunks(ofCount: 2) {
print(chunk)
}
I don't think this is any better than Martin R's, but seems the OP needs something else...
struct PairIterator<C: IteratorProtocol>: IteratorProtocol {
private var baseIterator: C
init(_ iterator: C) {
baseIterator = iterator
}
mutating func next() -> (C.Element, C.Element)? {
if let left = baseIterator.next(), let right = baseIterator.next() {
return (left, right)
}
return nil
}
}
extension Sequence {
var pairs: AnySequence<(Self.Iterator.Element,Self.Iterator.Element)> {
return AnySequence({PairIterator(self.makeIterator())})
}
}
input.pairs.forEach{ print($0) }
let output = input.pairs.map{$0}
print(output) //->[(1, 2), (3, 4), (5, 6)]
Here's a version of #OOPer's answer that works with an odd number of elements in your list. You can leave off the conformance to CustomStringConvertible if you like, of course. But it gives prettier output for this example. : )
struct Pair<P: CustomStringConvertible>: CustomStringConvertible {
let left: P
let right: P?
var description: String {
if let right = right {
return "(\(left.description), \(right.description)"
}
return "(\(left.description), nil)"
}
}
struct PairIterator<C: IteratorProtocol>: IteratorProtocol where C.Element: CustomStringConvertible {
private var baseIterator: C
init(_ iterator: C) {
baseIterator = iterator
}
mutating func next() -> Pair<C.Element>? {
if let left = baseIterator.next() {
return Pair(left: left, right: baseIterator.next())
}
return nil
}
}
extension Sequence where Element: CustomStringConvertible {
var pairs: AnySequence<Pair<Self.Element>> {
return AnySequence({PairIterator(self.makeIterator())})
}
}
let input: [Int] = [1,2,3,4,5,6,7]
print(input.pairs)
print(Array(input.pairs))
//output:
AnySequence<Pair<Int>>(_box: Swift._SequenceBox<Swift._ClosureBasedSequence<__lldb_expr_27.PairIterator<Swift.IndexingIterator<Swift.Array<Swift.Int>>>>>)
[(1, 2, (3, 4, (5, 6, (7, nil)]
You don't need a custom type, like PairIterator as the above answers prescribe. Getting a paired sequence is a one-liner:
let xs = [1, 2, 3]
for pair in zip(xs, xs.dropFirst()) {
print(pair) // (1, 2) (2, 3)
}
If you intend to reuse that, you can place a pairs method inside an extension:
extension Sequence {
func pairs() -> AnySequence<(Element, Element)> {
AnySequence(zip(self, self.dropFirst()))
}
}