Skip to content

Commit

Permalink
GH-197: added dynamic xlsx sheets support
Browse files Browse the repository at this point in the history
If xlsx sheets have the same structure, it's now possible to retrieve data from multiple sources with `additionalSources` builder method.
  • Loading branch information
sskorol committed Aug 2, 2023
1 parent f281962 commit 5faea76
Show file tree
Hide file tree
Showing 19 changed files with 234 additions and 77 deletions.
15 changes: 7 additions & 8 deletions .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,20 +30,19 @@ ToDo

### Environment

| Component | Version |
|---------------------|-------------------|
| Test Data Supplier | 2.2.0 |
| TestNG | 7.7.1 |
| Build tool | gradle@7.6.0 |
| IDE | IntelliJ@2022.2.3 |
| JDK | temurin-17.0.6 |
| Component | Version |
|---------------------|-----------------|
| Test Data Supplier | 2.2.0 |
| TestNG | 7.8.0 |
| Build tool | gradle@8.2.1 |
| IDE | IntelliJ@2023.2 |
| JDK | temurin-17.0.8 |

### Can be reproduced via

- [ ] Bash
- [ ] Maven
- [ ] Gradle
- [ ] Eclipse
- [ ] IntelliJ

### Expected behavior
Expand Down
15 changes: 7 additions & 8 deletions .github/ISSUE_TEMPLATE/feature_request.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,20 +30,19 @@ ToDo

### Environment

| Component | Version |
|--------------------|-------------------|
| Test Data Supplier | 2.2.0 |
| TestNG | 7.7.1 |
| Build tool | gradle@7.6.0 |
| IDE | IntelliJ@2022.2.3 |
| JDK | temurin-17.0.6 |
| Component | Version |
|--------------------|-----------------|
| Test Data Supplier | 2.2.0 |
| TestNG | 7.8.0 |
| Build tool | gradle@8.2.1 |
| IDE | IntelliJ@2023.2 |
| JDK | temurin-17.0.8 |

### Can be reproduced via

- [ ] Bash
- [ ] Maven
- [ ] Gradle
- [ ] Eclipse
- [ ] IntelliJ

### Expected behavior
Expand Down
2 changes: 2 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,5 @@ Closes #
### Checklist
- [ ] Added unit / integration tests
- [ ] Added documentation
- [ ] Updated configuration
- [ ] None of the above is required
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,6 @@ jobs:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
run: ./gradlew clean sonar
- name: Built and Test on Depenabot PR
- name: Built and Test on Dependabot PR
if: ${{ github.actor == 'dependabot[bot]' }}
run: ./gradlew clean test
20 changes: 15 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -416,8 +416,8 @@ dependencies {
agent "org.aspectj:aspectjweaver:${aspectjVersion}"
implementation(
"org.aspectj:aspectjweaver:${aspectjVersion}",
'org.testng:testng:7.7.1',
'io.github.sskorol:test-data-supplier:2.2.0'
'org.testng:testng:7.8.0',
'io.github.sskorol:test-data-supplier:2.3.0'
)
}
Expand Down Expand Up @@ -454,12 +454,12 @@ test {
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>7.7.1</version>
<version>7.8.0</version>
</dependency>
<dependency>
<groupId>io.github.sskorol</groupId>
<artifactId>test-data-supplier</artifactId>
<version>2.2.0</version>
<version>2.3.0</version>
</dependency>
</dependencies>

Expand Down Expand Up @@ -629,6 +629,8 @@ Since 2.1.0, there's a custom implementation with similar approach, but minor im

In terms of fields' mapping, you can use custom `@Column` annotation (don't confuse with ZeroCell Column).
You should also make sure you provided a sheet name via corresponding `@Sheet` annotation. Otherwise, the first one will be used.
In case if you have a similar structure on multiple sheets, you can use a repeatable `@Sheets` annotation.
Dynamic sheets' specification is also possible via `withAdditionalSources` builder method (see examples below).

Similarly to ZeroCell, you can use either default or custom fields' converters. Here's a list of defaults:

Expand Down Expand Up @@ -694,8 +696,16 @@ public StreamEx<User> getUsers() {
}
```

```java
@DataSupplier
public StreamEx<User> getUsers() {
return use(XlsxReader.class).withTarget(User.class).withAdditionalSources("Sheet1", "Sheet2").read();
}
```

If you want to specify a custom source in runtime, you can remove **@Source** annotation and use **withSource** builder
method instead.
`withAdditionalSources` builder method is experimental and implemented for `XlsxReader` as a dynamic sheets provider.

Note that in case of a data reading error or any kind of exception thrown in a `@DataSupplier` body,
the corresponding test will be skipped. That's a default TestNG behaviour.
Expand Down Expand Up @@ -856,7 +866,7 @@ Note that in case if you want to manage **DataProviderTransformer** manually, yo

```groovy
dependencies {
implementation 'io.github.sskorol:test-data-supplier:2.2.0:spi-off'
implementation 'io.github.sskorol:test-data-supplier:2.3.0:spi-off'
}
```

Expand Down
50 changes: 33 additions & 17 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ plugins {
jacoco
`maven-publish`
signing
id("io.github.gradle-nexus.publish-plugin") version "1.3.0"
id("io.github.gradle-nexus.publish-plugin") version "2.0.0-rc-1"
id("org.sonarqube") version "4.3.0.3225"
id("net.researchgate.release") version "3.0.2"
id("com.github.ben-manes.versions") version "0.47.0"
Expand All @@ -22,9 +22,21 @@ val projectUrl by extra("https://github.com/sskorol/test-data-supplier")
val moduleName by extra("io.github.sskorol.testdatasupplier")

val aspectjVersion by extra("1.9.19")
val jacksonVersion by extra("2.14.2")
val lombokVersion by extra("1.18.26")
val jacksonVersion by extra("2.15.2")
val lombokVersion by extra("1.18.28")
val poiVersion by extra("5.2.3")
val joorVersion by extra ("0.9.14")
val testngVersion by extra("7.8.0")
val streamexVersion by extra("0.8.1")
// Don't update to the latest, as it's outdated
val vavrVersion by extra("0.10.4")
val reflectionsVersion by extra("0.10.2")
val commonsCsvVersion by extra("1.10.0")
val gsonVersion by extra("2.10.1")
val assertjVersion by extra("3.24.2")
val logbackVersion by extra("1.4.8")
val log4jVersion by extra("2.20.0")
val mockitoVersion by extra("5.4.0")

val agent: Configuration by configurations.creating

Expand Down Expand Up @@ -63,24 +75,24 @@ dependencies {
testCompileOnly("org.projectlombok:lombok:${lombokVersion}")
annotationProcessor("org.projectlombok:lombok:${lombokVersion}")
testAnnotationProcessor("org.projectlombok:lombok:${lombokVersion}")
api("org.jooq:joor:0.9.14")
api("org.testng:testng:7.8.0")
api("one.util:streamex:0.8.1")
api("io.vavr:vavr:0.10.4")
api("org.jooq:joor:${joorVersion}")
api("org.testng:testng:${testngVersion}")
api("one.util:streamex:${streamexVersion}")
api("io.vavr:vavr:${vavrVersion}")
api("org.aspectj:aspectjrt:${aspectjVersion}")
api("org.reflections:reflections:0.10.2")
api("org.apache.commons:commons-csv:1.10.0")
api("com.google.code.gson:gson:2.10.1")
api("org.reflections:reflections:${reflectionsVersion}")
api("org.apache.commons:commons-csv:${commonsCsvVersion}")
api("com.google.code.gson:gson:${gsonVersion}")
api("com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:${jacksonVersion}")
api("com.fasterxml.jackson.core:jackson-databind:${jacksonVersion}")
api("org.apache.poi:poi:${poiVersion}")
api("org.apache.poi:poi-ooxml:${poiVersion}")
api("org.assertj:assertj-core:3.24.2")
api("org.assertj:assertj-core:${assertjVersion}")
// Transitive dependency: <=1.33 version has vulnerabilities. Remove when updated by top-level packages.
api("org.yaml:snakeyaml:2.0")
testImplementation("ch.qos.logback:logback-classic:1.4.8")
testImplementation("org.apache.logging.log4j:log4j-core:2.20.0")
testImplementation("org.mockito:mockito-core:5.4.0")
testImplementation("ch.qos.logback:logback-classic:${logbackVersion}")
testImplementation("org.apache.logging.log4j:log4j-core:${log4jVersion}")
testImplementation("org.mockito:mockito-core:${mockitoVersion}")
}

jacoco.toolVersion = "0.8.8"
Expand Down Expand Up @@ -128,7 +140,7 @@ tasks.withType<JacocoReport> {
}

tasks.withType(Wrapper::class) {
gradleVersion = "8.0.1"
gradleVersion = "8.2.1"
}

tasks.compileJava {
Expand Down Expand Up @@ -231,7 +243,7 @@ publishing {
developers {
developer {
id.set("sskorol")
name.set("Sergey Korol")
name.set("Serhii Korol")
email.set("[email protected]")
}
}
Expand All @@ -250,7 +262,7 @@ publishing {
}

nexusPublishing {
repositories {
this.repositories {
sonatype {
val osshUsername = System.getenv("OSSH_USERNAME") ?: ""
val osshPassword = System.getenv("OSSH_PASSWORD") ?: ""
Expand Down Expand Up @@ -295,6 +307,8 @@ tasks.jar {
}

tasks.register<Jar>("sourceJar") {
group = "sourceJar"
description = "Build a jar from sources"
dependsOn(tasks.classes)
inputs.property("moduleName", moduleName)
manifest {
Expand All @@ -315,6 +329,8 @@ tasks.register<Jar>("sourceJar") {
}

tasks.register<Jar>("spiOffJar") {
group = "spiOffJar"
description = "Build a jar from sources excluding SPI"
dependsOn(tasks.classes)
inputs.property("moduleName", moduleName)
manifest {
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
version=2.2.1
version=2.3.0
systemProp.sonar.host.url=https://sonarcloud.io
systemProp.sonar.projectKey=io.github.sskorol:test-data-supplier
systemProp.sonar.organization=sskorol-github
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
5 changes: 5 additions & 0 deletions src/main/java/io/github/sskorol/data/DataReader.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import java.io.IOException;
import java.net.URL;
import java.util.List;

import static io.github.sskorol.utils.ReflectionUtils.getSourcePath;

Expand All @@ -15,6 +16,10 @@ public interface DataReader<T> {

String getPath();

default DataReader<T> additionalSources(final List<String> names) {
return this;
}

default URL getUrl() throws IOException {
return getPath().isEmpty() ? getSourcePath(getEntityClass()) : getSourcePath(getPath());
}
Expand Down
6 changes: 2 additions & 4 deletions src/main/java/io/github/sskorol/data/Sheet.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
package io.github.sskorol.data;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.annotation.*;

/**
* Use this annotation to provide Excel sheet name. If none is specified hte first one is used.
*/
@Repeatable(Sheets.class)
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Sheet {
Expand Down
12 changes: 12 additions & 0 deletions src/main/java/io/github/sskorol/data/Sheets.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package io.github.sskorol.data;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Sheets {
Sheet[] value();
}
15 changes: 14 additions & 1 deletion src/main/java/io/github/sskorol/data/TestDataReader.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import lombok.AllArgsConstructor;
import one.util.streamex.StreamEx;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

import static org.joor.Reflect.onClass;
Expand Down Expand Up @@ -37,21 +39,32 @@ public static class DataBuilder<T, E> {

private final Class<T> dataReaderClass;
private final Class<E> entityClass;
private final List<String> additionalSources;
private String path;

public DataBuilder(final Class<T> dataReaderClass, final Class<E> entityClass) {
this.dataReaderClass = dataReaderClass;
this.entityClass = entityClass;
this.additionalSources = new ArrayList<>();
}

public DataBuilder<T, E> withSource(final String path) {
this.path = path;
return this;
}

public DataBuilder<T, E> withAdditionalSources(final String... names) {
this.additionalSources.addAll(List.of(names));
return this;
}

public StreamEx<E> read() {
var args = StreamEx.of(entityClass, path).filter(Objects::nonNull).toArray();
return onClass(dataReaderClass).create(args).call("read").get();
return onClass(dataReaderClass)
.create(args)
.call("additionalSources", additionalSources)
.call("read")
.get();
}
}
}
6 changes: 4 additions & 2 deletions src/main/java/io/github/sskorol/data/XlsxCellMapper.java
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,12 @@ private IConverter<T> findMatchingConverter() {
.map(Column::converter)
.map(converterClass -> (IConverter<T>) onClass(converterClass).create().get())
.filter(converterInstance -> converterInstance.getType().equals(getFieldType()))
.orElseGet(() -> StreamEx.of(defaultIConverters)
.orElseGet(() -> StreamEx
.of(defaultIConverters)
.findFirst(converterInstance -> converterInstance.getType().equals(getFieldType()))
.orElseThrow(() -> new IllegalStateException(format(
"There's no matching converter found for %s field of type %s", getFieldName(), getFieldType()))
"There's no matching converter found for %s field of type %s",
getFieldName(), getFieldType()))
)
);
}
Expand Down
Loading

0 comments on commit 5faea76

Please sign in to comment.