001/* 002 * GeoAPI - Java interfaces for OGC/ISO standards 003 * http://www.geoapi.org 004 * 005 * Copyright (C) 2018-2019 Open Geospatial Consortium, Inc. 006 * All Rights Reserved. http://www.opengeospatial.org/ogc/legal 007 * 008 * Permission to use, copy, and modify this software and its documentation, with 009 * or without modification, for any purpose and without fee or royalty is hereby 010 * granted, provided that you include the following on ALL copies of the software 011 * and documentation or portions thereof, including modifications, that you make: 012 * 013 * 1. The full text of this NOTICE in a location viewable to users of the 014 * redistributed or derivative work. 015 * 2. Notice of any changes or modifications to the OGC files, including the 016 * date changes were made. 017 * 018 * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS MAKE 019 * NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 020 * TO, WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT 021 * THE USE OF THE SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE ANY THIRD PARTY 022 * PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. 023 * 024 * COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL OR 025 * CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE SOFTWARE OR DOCUMENTATION. 026 * 027 * The name and trademarks of copyright holders may NOT be used in advertising or 028 * publicity pertaining to the software without specific, written prior permission. 029 * Title to copyright in this software and any associated documentation will at all 030 * times remain with copyright holders. 031 */ 032package org.opengis.test.dataset; 033 034import java.io.File; 035import java.net.URL; 036import java.net.URI; 037import java.net.URISyntaxException; 038import java.io.EOFException; 039import java.io.IOException; 040import java.io.InputStream; 041import java.io.FileOutputStream; 042 043import static org.junit.Assert.*; 044 045 046/** 047 * Provides access to small built-in test files. 048 * Data can be obtained as {@link URL}, {@link File}, {@link InputStream} or {@code byte[]} array. 049 * 050 * @author Martin Desruisseaux (Geomatys) 051 * @version 3.1 052 * @since 3.1 053 */ 054public enum TestData { 055 /** 056 * A two-dimensional netCDF file using a geographic CRS for global data over the world. 057 * The file contains temperature data from model analysis, without missing values. 058 * 059 * <ul> 060 * <li><b>Data type:</b> 16 bits signed integers (only the positive range is used)</li> 061 * <li><b>Coordinate Reference System:</b> two-dimensional geographic</li> 062 * <li><b>Geographic area:</b> world, with latitudes ranging from 90°S to 90°N and longitudes from 180°E to 180°W</li> 063 * <li><b>Size:</b> 73 × 73 cells in a file of 12.7 kilobytes</li> 064 * </ul> 065 * <table class="ogc"> 066 * <caption>Global attributes</caption> 067 * <tr><th>Name</th><th>Value</th></tr> 068 * <tr><td>{@code Conventions}</td><td>CF-1.4</td></tr> 069 * <tr><td>{@code Metadata_Conventions}</td><td>Unidata Dataset Discovery v1.0</td></tr> 070 * <tr><td>{@code title}</td><td>Test data from Sea Surface Temperature Analysis Model</td></tr> 071 * <tr><td>{@code purpose}</td><td>GeoAPI conformance tests</td></tr> 072 * <tr><td>{@code summary}</td><td>Global, two-dimensional model data</td></tr> 073 * <tr><td>{@code keywords}</td><td>{@literal EARTH SCIENCE > Oceans > Ocean Temperature > Sea Surface Temperature}</td></tr> 074 * <tr><td>{@code keywords_vocabulary}</td><td>GCMD Science Keywords</td></tr> 075 * <tr><td>{@code geospatial_lat_min}</td><td>-90.0</td></tr> 076 * <tr><td>{@code geospatial_lat_max}</td><td>90.0</td></tr> 077 * <tr><td>{@code geospatial_lon_min}</td><td>-180.0</td></tr> 078 * <tr><td>{@code geospatial_lon_max}</td><td>180.0</td></tr> 079 * <tr><td>{@code geospatial_vertical_min}</td><td>0.0</td></tr> 080 * <tr><td>{@code geospatial_vertical_max}</td><td>0.0</td></tr> 081 * <tr><td>{@code time_coverage_start}</td><td>2005-09-22T00:00</td></tr> 082 * <tr><td>{@code time_coverage_duration}</td><td>0.0</td></tr> 083 * <tr><td>{@code cdm_data_type}</td><td>Grid</td></tr> 084 * <tr><td>{@code id}</td><td>NCEP/SST/Global_5x2p5deg/SST_Global_5x2p5deg_20050922_0000.nc</td></tr> 085 * <tr><td>{@code naming_authority}</td><td>edu.ucar.unidata</td></tr> 086 * <tr><td>{@code creator_name}</td><td>NOAA/NWS/NCEP</td></tr> 087 * <tr><td>{@code date_created}</td><td>2005-09-22T00:00</td></tr> 088 * <tr><td>{@code date_modified}</td><td>2018-05-15T13:00</td></tr> 089 * <tr><td>{@code date_metadata_modified}</td><td>2018-05-15T13:01</td></tr> 090 * <tr><td>{@code history}</td><td>Decimated and modified by GeoAPI for inclusion in conformance test suite.</td></tr> 091 * <tr><td>{@code comment}</td><td>For testing purpose only.</td></tr> 092 * <tr><td>{@code license}</td><td>Freely available</td></tr> 093 * </table> 094 * 095 * In this file, all global attributes are character sequences, including the attributes that should 096 * be floating points numbers ({@code geospatial_lat_min}, {@code geospatial_lat_max}, <i>etc.</i>). 097 * Implementations are encouraged to be tolerant. 098 */ 099 NETCDF_2D_GEOGRAPHIC("Cube2D_geographic_packed.nc", 12988), 100 101 /** 102 * A four-dimensional netCDF file using a projected CRS with elevation and time. 103 * The file contains <cite>Current Icing Product</cite> data without missing values. 104 * The coordinate reference system contains also an height axis and a time axis. 105 * 106 * <ul> 107 * <li><b>Data type:</b> 32 bits floating point numbers</li> 108 * <li><b>Coordinate Reference System:</b> four-dimensional projected + elevation + temporal</li> 109 * <li><b>Geographic area:</b> East part of North America</li> 110 * <li><b>Size:</b> 38 × 19 × 4 × 1 cells in a file of 14.2 kilobytes</li> 111 * </ul> 112 * <table class="ogc"> 113 * <caption>Global attributes</caption> 114 * <tr><th>Name</th><th>Value</th></tr> 115 * <tr><td>{@code Conventions}</td><td>CF-1.4</td></tr> 116 * <tr><td>{@code title}</td><td>Test data from Current Icing Product (CIP)</td></tr> 117 * <tr><td>{@code purpose}</td><td>GeoAPI conformance tests</td></tr> 118 * <tr><td>{@code summary}</td><td>Hourly, three-dimensional diagnosis of the icing environment.</td></tr> 119 * <tr><td>{@code source}</td><td>U.S. National Weather Service - NCEP (WMC)</td></tr> 120 * <tr><td>{@code institution}</td><td>UCAR</td></tr> 121 * <tr><td>{@code topic_category}</td><td>climatology meteorology atmosphere</td></tr> 122 * <tr><td>{@code geospatial_lat_min}</td><td>15.94</td></tr> 123 * <tr><td>{@code geospatial_lat_max}</td><td>58.37</td></tr> 124 * <tr><td>{@code geospatial_lon_min}</td><td>-107.75</td></tr> 125 * <tr><td>{@code geospatial_lon_max}</td><td>-56.66</td></tr> 126 * <tr><td>{@code geospatial_vertical_min}</td><td>300.0</td></tr> 127 * <tr><td>{@code geospatial_vertical_max}</td><td>4875.0</td></tr> 128 * <tr><td>{@code geospatial_vertical_positive}</td><td>up</td></tr> 129 * <tr><td>{@code geospatial_lat_resolution}</td><td>0.93</td></tr> 130 * <tr><td>{@code geospatial_lon_resolution}</td><td>1.34</td></tr> 131 * <tr><td>{@code creator_name}</td><td>John Doe</td></tr> 132 * <tr><td>{@code creator_email}</td><td>john.doe@example.org</td></tr> 133 * <tr><td>{@code date_modified}</td><td>2012-02-21T21:14Z</td></tr> 134 * <tr><td>{@code date_metadata_modified}</td><td>2018-05-14T14:45Z</td></tr> 135 * <tr><td>{@code history}</td><td>Decimated and modified by GeoAPI for inclusion in conformance test suite.</td></tr> 136 * <tr><td>{@code comment}</td><td>For testing purpose only.</td></tr> 137 * </table> 138 * 139 * If this file, all global attribute for numeric values use the {@code float} type. 140 */ 141 NETCDF_4D_PROJECTED("Cube4D_projected_float.nc", 14544); 142 143 /** 144 * Name of the test file, located in the same directory (after JAR packaging) than the {@code TestData.class} file. 145 */ 146 private final String filename; 147 148 /** 149 * Expected length in bytes. 150 */ 151 private final int length; 152 153 /** 154 * Path to the (possibly temporary) file, or {@code null} if not yet created. 155 */ 156 private transient File file; 157 158 /** 159 * Creates a new enumeration value. 160 */ 161 private TestData(final String filename, final int length) { 162 this.filename = filename; 163 this.length = length; 164 } 165 166 /** 167 * Returns a URL to the test file. 168 * The URL is not necessary a file on the default file system; it may be an entry inside a JAR file. 169 * If a path on the file system is desired, use {@link #file()} instead. 170 * 171 * @return a URL to the test file, possibly as an entry inside a JAR file. 172 */ 173 public URL location() { 174 final URL location = TestData.class.getResource(filename); 175 assertNotNull(filename, location); 176 return location; 177 } 178 179 /** 180 * Returns a path on the file system to the test file. If the test file is inside a JAR file, 181 * then it will be copied in a temporary directory and the path to the temporary file will be returned. 182 * 183 * @return a path on the default file system, possible as a temporary file. 184 * @throws IOException if a copy operation was necessary but failed. 185 */ 186 public synchronized File file() throws IOException { 187 if (file == null) { 188 final URI location; 189 try { 190 location = location().toURI(); 191 } catch (URISyntaxException e) { 192 throw new IOException(e); 193 } try { 194 file = new File(location); 195 } catch (IllegalArgumentException e) { 196 try { 197 final byte[] data = content(); 198 final File tmp = File.createTempFile("geoapi", filename.substring(filename.lastIndexOf('.'))); 199 tmp.deleteOnExit(); 200 try (FileOutputStream out = new FileOutputStream(tmp)) { 201 out.write(data); 202 } 203 file = tmp; // Set only on success. 204 } catch (IOException fe) { 205 fe.addSuppressed(e); 206 throw fe; 207 } 208 } 209 } 210 return file; 211 } 212 213 /** 214 * Opens an input stream on the test file. 215 * It is caller responsibility to close the stream after usage. 216 * 217 * @return an input stream on the test file. 218 */ 219 public InputStream open() { 220 final InputStream stream = TestData.class.getResourceAsStream(filename); 221 assertNotNull(filename, stream); 222 return stream; 223 } 224 225 /** 226 * Returns the full content of the test file as an array of bytes. 227 * 228 * @return the test file content. 229 * @throws IOException if an error occurred while reading the test file. 230 */ 231 public byte[] content() throws IOException { 232 /* 233 * We rely on the file having exactly the expected length, for avoiding array reallocations. 234 * This assumption is verified by the TestDataTest. 235 */ 236 final byte[] content = new byte[length]; 237 try (InputStream stream = open()) { 238 int offset = 0, r, n; 239 do { // TODO: replace this loop by stream.readNBytes(content, 0, length) in JDK9. 240 r = length - offset; 241 n = stream.read(content, offset, r); 242 if (n < 0) throw new EOFException(filename); 243 } while (r != n); 244 if (stream.read() >= 0) { 245 throw new IOException("Unexpected file length."); 246 } 247 } 248 return content; 249 } 250}