Skip to content

Commit 8fc919a

Browse files
Fixed bugs in setting profiles on Resources and Packages; created tests for that
1 parent da95051 commit 8fc919a

File tree

9 files changed

+126
-19
lines changed

9 files changed

+126
-19
lines changed

src/main/java/io/frictionlessdata/datapackage/JSONBase.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,16 @@ public abstract class JSONBase {
9999
/**
100100
* @param profile the profile to set
101101
*/
102-
public void setProfile(String profile){this.profile = profile;}
102+
public void setProfile(String profile){
103+
if (profile.equals(Profile.PROFILE_TABULAR_DATA_PACKAGE)) {
104+
if (this instanceof Package) {
105+
106+
} else if (this instanceof Resource) {
107+
throw new DataPackageValidationException("Cannot set "+Profile.PROFILE_TABULAR_DATA_PACKAGE+" on a resource");
108+
}
109+
}
110+
this.profile = profile;
111+
}
103112

104113
/**
105114
* @return the title

src/main/java/io/frictionlessdata/datapackage/Package.java

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,13 @@ public class Package extends JSONBase{
5555
private static final String JSON_KEY_CREATED = "created";
5656
private static final String JSON_KEY_CONTRIBUTORS = "contributors";
5757

58+
private static final List<String> wellKnownKeys = Arrays.asList(
59+
JSON_KEY_NAME, JSON_KEY_RESOURCES, JSON_KEY_ID, JSON_KEY_VERSION,
60+
JSON_KEY_HOMEPAGE, JSON_KEY_IMAGE, JSON_KEY_CREATED, JSON_KEY_CONTRIBUTORS,
61+
JSON_KEY_KEYWORDS, JSONBase.JSON_KEY_SCHEMA, JSONBase.JSON_KEY_NAME, JSONBase.JSON_KEY_DATA,
62+
JSONBase.JSON_KEY_DIALECT, JSONBase.JSON_KEY_LICENSES, JSONBase.JSON_KEY_SOURCES, JSONBase.JSON_KEY_PROFILE);
63+
64+
5865
// Filesystem path pointing to the Package; either ZIP file or directory
5966
private Object basePath = null;
6067
private String id;
@@ -222,7 +229,7 @@ public List<Resource> getResources(){
222229
}
223230

224231
/**
225-
* Return a List of of all Resources.
232+
* Return a List of all Resources.
226233
*
227234
* @return the resource names as a List.
228235
*/
@@ -402,6 +409,18 @@ public void setKeywords(Set<String> keywords) {
402409
this.keywords = new LinkedHashSet<>(keywords);
403410
}
404411

412+
/**
413+
* @param profile the profile to set
414+
*/
415+
public void setProfile(String profile){
416+
if (null != profile) {
417+
if ((profile.equals(Profile.PROFILE_DATA_RESOURCE_DEFAULT))
418+
|| (profile.equals(Profile.PROFILE_TABULAR_DATA_RESOURCE))) {
419+
throw new DataPackageValidationException("Cannot set profile " + profile + " on a data package");
420+
}
421+
}
422+
this.profile = profile;
423+
}
405424

406425
/**
407426
* Set a property and value on the Package. The value will be converted to a JsonObject and added to the
@@ -417,7 +436,6 @@ public void setProperty(String key, JsonNode value) throws DataPackageException{
417436
this.jsonObject.set(key, value);
418437
}
419438

420-
421439
/**
422440
* Set a number of properties at once. The `mapping` holds the properties as
423441
* key/value pairs
@@ -622,7 +640,10 @@ protected ObjectNode getJsonNode(){
622640
ObjectNode objectNode = (ObjectNode) JsonUtil.getInstance().createNode(this);
623641
// update any manually set properties
624642
this.jsonObject.fields().forEachRemaining(f->{
625-
objectNode.set(f.getKey(), f.getValue());
643+
// but do not overwrite properties set via the API
644+
if (!wellKnownKeys.contains(f.getKey())) {
645+
objectNode.set(f.getKey(), f.getValue());
646+
}
626647
});
627648

628649
Iterator<Resource> resourceIter = resources.iterator();

src/main/java/io/frictionlessdata/datapackage/resource/AbstractReferencebasedResource.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import io.frictionlessdata.tableschema.tabledatasource.TableDataSource;
77
import io.frictionlessdata.tableschema.util.JsonUtil;
88

9-
import java.nio.charset.Charset;
109
import java.util.ArrayList;
1110
import java.util.Collection;
1211
import java.util.List;

src/main/java/io/frictionlessdata/datapackage/resource/AbstractResource.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
import org.apache.commons.csv.CSVFormat;
2424

2525
import java.io.IOException;
26-
import java.io.OutputStream;
2726
import java.io.Writer;
2827
import java.net.URI;
2928
import java.net.URISyntaxException;
@@ -460,6 +459,20 @@ public void setDialect(Dialect dialect) {
460459
this.dialect = dialect;
461460
}
462461

462+
/**
463+
* @param profile the profile to set
464+
*/
465+
@Override
466+
public void setProfile(String profile){
467+
if (null != profile) {
468+
if ((profile.equals(Profile.PROFILE_TABULAR_DATA_PACKAGE))
469+
|| (profile.equals(Profile.PROFILE_DATA_PACKAGE_DEFAULT))) {
470+
throw new DataPackageValidationException("Cannot set profile " + profile + " on a resource");
471+
}
472+
}
473+
this.profile = profile;
474+
}
475+
463476
@Override
464477
public String getFormat() {
465478
return format;

src/main/java/io/frictionlessdata/datapackage/resource/Resource.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,11 @@
1515
import io.frictionlessdata.tableschema.tabledatasource.TableDataSource;
1616
import io.frictionlessdata.tableschema.util.JsonUtil;
1717
import org.apache.commons.lang3.StringUtils;
18-
import org.locationtech.jts.io.OutStream;
1918

20-
import java.io.*;
19+
import java.io.File;
20+
import java.io.FileNotFoundException;
21+
import java.io.IOException;
22+
import java.io.Writer;
2123
import java.net.MalformedURLException;
2224
import java.net.URL;
2325
import java.nio.charset.Charset;

src/main/java/io/frictionlessdata/datapackage/resource/URLbasedResource.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import io.frictionlessdata.tableschema.Table;
44

55
import java.net.URL;
6-
import java.nio.charset.Charset;
76
import java.util.ArrayList;
87
import java.util.Collection;
98
import java.util.List;

src/test/java/io/frictionlessdata/datapackage/PackageTest.java

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@
1515
import io.frictionlessdata.tableschema.schema.Schema;
1616
import io.frictionlessdata.tableschema.tabledatasource.TableDataSource;
1717
import io.frictionlessdata.tableschema.util.JsonUtil;
18-
import org.junit.jupiter.api.*;
18+
import org.junit.jupiter.api.Assertions;
19+
import org.junit.jupiter.api.BeforeAll;
20+
import org.junit.jupiter.api.DisplayName;
21+
import org.junit.jupiter.api.Test;
1922

2023
import java.io.File;
2124
import java.io.FileNotFoundException;
@@ -29,6 +32,7 @@
2932
import java.nio.file.attribute.FileAttribute;
3033
import java.util.*;
3134

35+
import static io.frictionlessdata.datapackage.Profile.*;
3236
import static io.frictionlessdata.datapackage.TestUtil.getBasePath;
3337
import static org.junit.jupiter.api.Assertions.assertThrows;
3438

@@ -359,13 +363,49 @@ public void testAddValidResource() throws Exception{
359363
}
360364
Resource resource = Resource.build("new-resource", files, basePath, TableDataSource.getDefaultEncoding());
361365
Assertions.assertTrue(resource instanceof FilebasedResource);
362-
dp.addResource((FilebasedResource)resource);
366+
dp.addResource(resource);
363367
Assertions.assertEquals(6, dp.getResources().size());
364368

365369
Resource gotResource = dp.getResource("new-resource");
366370
Assertions.assertNotNull(gotResource);
367371
}
368-
372+
373+
374+
@Test
375+
@DisplayName("Test setting the 'profile' property")
376+
public void testSetProfile() throws Exception {
377+
Path tempDirPath = Files.createTempDirectory("datapackage-");
378+
String fName = "/fixtures/datapackages/employees/datapackage.json";
379+
Path resourcePath = TestUtil.getResourcePath(fName);
380+
Package dp = new Package(resourcePath, true);
381+
382+
Assertions.assertEquals(Profile.PROFILE_TABULAR_DATA_PACKAGE, dp.getProfile());
383+
384+
dp.setProfile(PROFILE_DATA_PACKAGE_DEFAULT);
385+
Assertions.assertEquals(Profile.PROFILE_DATA_PACKAGE_DEFAULT, dp.getProfile());
386+
387+
File outFile = new File (tempDirPath.toFile(), "datapackage.json");
388+
dp.writeJson(outFile);
389+
String content = String.join("\n", Files.readAllLines(outFile.toPath()));
390+
JsonNode jsonNode = JsonUtil.getInstance().readValue(content);
391+
String profile = jsonNode.get("profile").asText();
392+
Assertions.assertEquals(Profile.PROFILE_DATA_PACKAGE_DEFAULT, profile);
393+
Assertions.assertEquals(Profile.PROFILE_DATA_PACKAGE_DEFAULT, dp.getProfile());
394+
}
395+
396+
@Test
397+
@DisplayName("Test setting invalid 'profile' property, must throw")
398+
public void testSetInvalidProfile() throws Exception {
399+
String fName = "/fixtures/datapackages/employees/datapackage.json";
400+
Path resourcePath = TestUtil.getResourcePath(fName);
401+
Package dp = new Package(resourcePath, true);
402+
403+
Assertions.assertThrows(DataPackageValidationException.class,
404+
() -> dp.setProfile(PROFILE_DATA_RESOURCE_DEFAULT));
405+
Assertions.assertThrows(DataPackageValidationException.class,
406+
() -> dp.setProfile(PROFILE_TABULAR_DATA_RESOURCE));
407+
}
408+
369409
@Test
370410
public void testCreateInvalidJSONResource() throws Exception {
371411
Package dp = this.getDataPackageFromFilePath(true);

src/test/java/io/frictionlessdata/datapackage/ValidatorTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ public void testValidationWithInvalidProfileId() throws Exception {
5454
Package dp = new Package(url, true);
5555

5656
String invalidProfileId = "INVALID_PROFILE_ID";
57-
dp.setProperty("profile", invalidProfileId);
57+
dp.setProfile(invalidProfileId);
5858

5959
exception.expectMessage("Invalid profile id: " + invalidProfileId);
6060
dp.validate();
@@ -79,7 +79,7 @@ public void testValidationWithInvalidProfileUrl() throws Exception {
7979

8080
String invalidProfileUrl = "https://raw.githubusercontent.com/frictionlessdata/datapackage-java" +
8181
"/master/src/main/resources/schemas/INVALID.json";
82-
dp.setProperty("profile", invalidProfileUrl);
82+
dp.setProfile(invalidProfileUrl);
8383

8484
exception.expectMessage("Invalid profile schema URL: " + invalidProfileUrl);
8585
dp.validate();

src/test/java/io/frictionlessdata/datapackage/resource/ResourceTest.java

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import io.frictionlessdata.datapackage.PackageTest;
77
import io.frictionlessdata.datapackage.Profile;
88
import io.frictionlessdata.datapackage.exceptions.DataPackageException;
9+
import io.frictionlessdata.datapackage.exceptions.DataPackageValidationException;
910
import io.frictionlessdata.tableschema.schema.Schema;
1011
import io.frictionlessdata.tableschema.util.JsonUtil;
1112
import org.junit.jupiter.api.Assertions;
@@ -23,6 +24,7 @@
2324
import java.time.Year;
2425
import java.util.*;
2526

27+
import static io.frictionlessdata.datapackage.Profile.*;
2628
import static io.frictionlessdata.datapackage.TestUtil.getTestDataDirectory;
2729

2830
/**
@@ -451,6 +453,16 @@ public void testReadFromZipFile() throws Exception{
451453
Resource r = dp.getResource("currencies");
452454

453455
List<Object[]> data = r.getData(false, false, false, false);
456+
Assertions.assertEquals(2, data.size());
457+
Object[] row1 = data.get(0);
458+
Assertions.assertEquals("USD", row1[0]);
459+
Assertions.assertEquals("US Dollar", row1[1]);
460+
Assertions.assertEquals("$", row1[2]);
461+
462+
Object[] row2 = data.get(1);
463+
Assertions.assertEquals("GBP", row2[0]);
464+
Assertions.assertEquals("Pound Sterling", row2[1]);
465+
Assertions.assertEquals("£", row2[2]);
454466
}
455467

456468
@Test
@@ -487,7 +499,7 @@ public void readCreateInvalidResourceContainingAbsolutePaths() throws Exception{
487499
files.add(sourceFileAbsPathU2);
488500

489501
Exception dpe = Assertions.assertThrows(DataPackageException.class, () -> {
490-
FilebasedResource r = new FilebasedResource("resource-one", files, getBasePath());
502+
new FilebasedResource("resource-one", files, getBasePath());
491503
});
492504
Assertions.assertEquals("Path entries for file-based Resources cannot be absolute", dpe.getMessage());
493505
}
@@ -501,7 +513,7 @@ public void testReadMapped1() throws Exception{
501513
{"london","2017","8780000"},
502514
{"paris","2017","2240000"},
503515
{"rome","2017","2860000"}};
504-
Resource resource = buildResource("/fixtures/data/population.csv");
516+
Resource<?, ?> resource = buildResource("/fixtures/data/population.csv");
505517
Schema schema = Schema.fromJson(new File(getTestDataDirectory()
506518
, "/fixtures/schema/population_schema.json"), true);
507519
// Set the profile to tabular data resource.
@@ -530,8 +542,20 @@ public void testReadMapped1() throws Exception{
530542
Assertions.assertEquals(refRow[2], testData.get(testDataColKeys.get(2)).toString());//BigInteger value for population
531543
}
532544
}
545+
@Test
546+
@DisplayName("Test setting invalid 'profile' property, must throw")
547+
public void testSetInvalidProfile() throws Exception {
548+
Resource<?,?> resource = buildResource("/fixtures/data/population.csv");
549+
550+
Assertions.assertThrows(DataPackageValidationException.class,
551+
() -> resource.setProfile(PROFILE_DATA_PACKAGE_DEFAULT));
552+
Assertions.assertThrows(DataPackageValidationException.class,
553+
() -> resource.setProfile(PROFILE_TABULAR_DATA_PACKAGE));
554+
Assertions.assertDoesNotThrow(() -> resource.setProfile(PROFILE_DATA_RESOURCE_DEFAULT));
555+
Assertions.assertDoesNotThrow(() -> resource.setProfile(PROFILE_TABULAR_DATA_RESOURCE));
556+
}
533557

534-
private static Resource buildResource(String relativeInPath) throws URISyntaxException {
558+
private static Resource<?,?> buildResource(String relativeInPath) throws URISyntaxException {
535559
URL sourceFileUrl = ResourceTest.class.getResource(relativeInPath);
536560
Path path = Paths.get(sourceFileUrl.toURI());
537561
Path parent = path.getParent();
@@ -561,7 +585,7 @@ private static String getFileContents(String fileName) {
561585
}
562586

563587
private List<String[]> getExpectedPopulationData(){
564-
List<String[]> expectedData = new ArrayList();
588+
List<String[]> expectedData = new ArrayList<>();
565589
//expectedData.add(new String[]{"city", "year", "population"});
566590
expectedData.add(new String[]{"london", "2017", "8780000"});
567591
expectedData.add(new String[]{"paris", "2017", "2240000"});
@@ -571,7 +595,7 @@ private List<String[]> getExpectedPopulationData(){
571595
}
572596

573597
private List<String[]> getExpectedAlternatePopulationData(){
574-
List<String[]> expectedData = new ArrayList();
598+
List<String[]> expectedData = new ArrayList<>();
575599
expectedData.add(new String[]{"2017", "london", "8780000"});
576600
expectedData.add(new String[]{"2017", "paris", "2240000"});
577601
expectedData.add(new String[]{"2017", "rome", "2860000"});

0 commit comments

Comments
 (0)