FILEUPLOAD-283: add tests for the portlet package
diff --git a/src/test/java/org/apache/commons/fileupload/Constants.java b/src/test/java/org/apache/commons/fileupload/Constants.java
new file mode 100644
index 0000000..69eaa53
--- /dev/null
+++ b/src/test/java/org/apache/commons/fileupload/Constants.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.fileupload;
+
+/**
+ * Constants used for testing.
+ *
+ * @since 1.4
+ */
+public final class Constants {
+
+    /**
+     * The content type used in several tests.
+     */
+    public static final String CONTENT_TYPE = "multipart/form-data; boundary=---1234";
+
+    private Constants() {}
+}
diff --git a/src/test/java/org/apache/commons/fileupload/DiskFileUploadTest.java b/src/test/java/org/apache/commons/fileupload/DiskFileUploadTest.java
new file mode 100644
index 0000000..49f65f0
--- /dev/null
+++ b/src/test/java/org/apache/commons/fileupload/DiskFileUploadTest.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.fileupload;
+
+import static org.junit.Assert.fail;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Test for {@link DiskFileUpload}. Remove when deprecated class is removed.
+ *
+ * @since 1.4
+ */
+@SuppressWarnings({"deprecation"}) // unit tests for deprecated class
+public class DiskFileUploadTest {
+
+    private DiskFileUpload upload;
+
+    @Before
+    public void setUp() {
+        upload = new DiskFileUpload();
+    }
+
+    @Test
+    public void testWithInvalidRequest() {
+        HttpServletRequest req = HttpServletRequestFactory.createInvalidHttpServletRequest();
+
+        try {
+            upload.parseRequest(req);
+            fail("testWithInvalidRequest: expected exception was not thrown");
+        } catch (FileUploadException expected) {
+            // this exception is expected
+        }
+    }
+
+    @Test
+    public void testWithNullContentType() {
+        HttpServletRequest req = HttpServletRequestFactory.createHttpServletRequestWithNullContentType();
+
+        try {
+            upload.parseRequest(req);
+            fail("testWithNullContentType: expected exception was not thrown");
+        } catch (DiskFileUpload.InvalidContentTypeException expected) {
+            // this exception is expected
+        } catch (FileUploadException unexpected) {
+            fail("testWithNullContentType: unexpected exception was thrown");
+        }
+    }
+
+}
diff --git a/src/test/java/org/apache/commons/fileupload/ServletFileUploadTest.java b/src/test/java/org/apache/commons/fileupload/FileUploadTest.java
similarity index 77%
rename from src/test/java/org/apache/commons/fileupload/ServletFileUploadTest.java
rename to src/test/java/org/apache/commons/fileupload/FileUploadTest.java
index 4b36f56..a795c7e 100644
--- a/src/test/java/org/apache/commons/fileupload/ServletFileUploadTest.java
+++ b/src/test/java/org/apache/commons/fileupload/FileUploadTest.java
@@ -20,62 +20,52 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
 
 import java.io.IOException;
 import java.io.UnsupportedEncodingException;
 import java.util.List;
-import java.util.Map;
 
-import javax.servlet.http.HttpServletRequest;
-
-import org.apache.commons.fileupload.disk.DiskFileItemFactory;
-import org.apache.commons.fileupload.servlet.ServletFileUpload;
+import org.apache.commons.fileupload.portlet.PortletFileUploadTest;
+import org.apache.commons.fileupload.servlet.ServletFileUploadTest;
 import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
 
 /**
- * Unit tests {@link org.apache.commons.fileupload.DiskFileUpload}.
+ * Common tests for implementations of {@link FileUpload}. This is a parameterized test.
+ * Tests must be valid and common to all implementations of FileUpload added as parameter
+ * in this class.
+ *
+ * @see ServletFileUploadTest
+ * @see PortletFileUploadTest
+ * @since 1.4
  */
-@SuppressWarnings({"deprecation", "javadoc"}) // unit tests for deprecated class
-public class ServletFileUploadTest extends FileUploadTestCase {
+@RunWith(Parameterized.class)
+public class FileUploadTest {
 
-    @Test
-    public void testWithInvalidRequest() {
-        FileUploadBase fu = null;
-
-        fu = new DiskFileUpload();
-
-        HttpServletRequest req = HttpServletRequestFactory.createInvalidHttpServletRequest();
-
-
-        try {
-            fu.parseRequest(req);
-            fail("testWithInvalidRequest: expected exception was not thrown");
-        } catch (FileUploadException expected) {
-            // this exception is expected
-        }
+    /**
+     * @return {@link FileUpload} classes under test.
+     */
+    @Parameters(name="{0}")
+    public static Iterable<? extends Object> data() {
+        return Util.fileUploadImplementations();
     }
 
-    @Test
-    public void testWithNullContentType() {
-        FileUploadBase fu = new DiskFileUpload();
+    /**
+     * Current parameterized FileUpload.
+     */
+    @Parameter
+    public FileUpload upload;
 
-        HttpServletRequest req = HttpServletRequestFactory.createHttpServletRequestWithNullContentType();
-
-        try {
-            fu.parseRequest(req);
-            fail("testWithNullContentType: expected exception was not thrown");
-        } catch (DiskFileUpload.InvalidContentTypeException expected) {
-            // this exception is expected
-        } catch (FileUploadException unexpected) {
-            fail("testWithNullContentType: unexpected exception was thrown");
-        }
-    }
+    // --- Test methods common to all implementations of a FileUpload
 
     @Test
     public void testFileUpload()
             throws IOException, FileUploadException {
-        List<FileItem> fileItems = parseUpload("-----1234\r\n" +
+        List<FileItem> fileItems = Util.parseUpload(upload, 
+                                               "-----1234\r\n" +
                                                "Content-Disposition: form-data; name=\"file\"; filename=\"foo.tab\"\r\n" +
                                                "Content-Type: text/whatever\r\n" +
                                                "\r\n" +
@@ -122,7 +112,8 @@
     @Test
     public void testFilenameCaseSensitivity()
             throws IOException, FileUploadException {
-        List<FileItem> fileItems = parseUpload("-----1234\r\n" +
+        List<FileItem> fileItems = Util.parseUpload(upload,
+                                               "-----1234\r\n" +
                                                "Content-Disposition: form-data; name=\"FiLe\"; filename=\"FOO.tab\"\r\n" +
                                                "Content-Type: text/whatever\r\n" +
                                                "\r\n" +
@@ -142,7 +133,8 @@
     @Test
     public void testEmptyFile()
             throws UnsupportedEncodingException, FileUploadException {
-        List<FileItem> fileItems = parseUpload ("-----1234\r\n" +
+        List<FileItem> fileItems = Util.parseUpload (upload,
+                                                "-----1234\r\n" +
                                                 "Content-Disposition: form-data; name=\"file\"; filename=\"\"\r\n" +
                                                 "\r\n" +
                                                 "\r\n" +
@@ -163,7 +155,8 @@
     @Test
     public void testIE5MacBug()
             throws UnsupportedEncodingException, FileUploadException {
-        List<FileItem> fileItems = parseUpload("-----1234\r\n" +
+        List<FileItem> fileItems = Util.parseUpload(upload,
+                                               "-----1234\r\n" +
                                                "Content-Disposition: form-data; name=\"field1\"\r\n" +
                                                "\r\n" +
                                                "fieldValue\r\n" +
@@ -232,7 +225,7 @@
             "...contents of file2.gif...\r\n" +
             "--BbC04y--\r\n" +
             "--AaB03x--";
-        List<FileItem> fileItems = parseUpload(request.getBytes("US-ASCII"), contentType);
+        List<FileItem> fileItems = Util.parseUpload(upload, request.getBytes("US-ASCII"), contentType);
         assertEquals(3, fileItems.size());
         FileItem item0 = fileItems.get(0);
         assertEquals("field1", item0.getFieldName());
@@ -254,7 +247,7 @@
     @Test
     public void testFoldedHeaders()
             throws IOException, FileUploadException {
-        List<FileItem> fileItems = parseUpload("-----1234\r\n" +
+        List<FileItem> fileItems = Util.parseUpload(upload, "-----1234\r\n" +
                 "Content-Disposition: form-data; name=\"file\"; filename=\"foo.tab\"\r\n" +
                 "Content-Type: text/whatever\r\n" +
                 "\r\n" +
@@ -314,7 +307,8 @@
         {
             "present", "Is there", "Here", "Is That"
         };
-        List<FileItem> fileItems = parseUpload("-----1234\r\n" +
+        List<FileItem> fileItems = Util.parseUpload(upload, 
+                                               "-----1234\r\n" +
                                                "Content-Disposition: form-data; name=\"file\"; filename=\"foo.tab\"\r\n" +
                                                "Content-Type: text/whatever\r\n" +
                                                headerNames[0] + ": " + headerValues[0] + "\r\n" +
@@ -355,67 +349,27 @@
     }
 
     /**
-     * Test case for <a href="http://issues.apache.org/jira/browse/FILEUPLOAD-210">
-     */
-    @Test
-    public void parseParameterMap()
-            throws Exception {
-        String text = "-----1234\r\n" +
-                      "Content-Disposition: form-data; name=\"file\"; filename=\"foo.tab\"\r\n" +
-                      "Content-Type: text/whatever\r\n" +
-                      "\r\n" +
-                      "This is the content of the file\n" +
-                      "\r\n" +
-                      "-----1234\r\n" +
-                      "Content-Disposition: form-data; name=\"field\"\r\n" +
-                      "\r\n" +
-                      "fieldValue\r\n" +
-                      "-----1234\r\n" +
-                      "Content-Disposition: form-data; name=\"multi\"\r\n" +
-                      "\r\n" +
-                      "value1\r\n" +
-                      "-----1234\r\n" +
-                      "Content-Disposition: form-data; name=\"multi\"\r\n" +
-                      "\r\n" +
-                      "value2\r\n" +
-                      "-----1234--\r\n";
-        byte[] bytes = text.getBytes("US-ASCII");
-        ServletFileUpload upload = new ServletFileUpload(new DiskFileItemFactory());
-        HttpServletRequest request = new MockHttpServletRequest(bytes, CONTENT_TYPE);
-
-        Map<String, List<FileItem>> mappedParameters = upload.parseParameterMap(request);
-        assertTrue(mappedParameters.containsKey("file"));
-        assertEquals(1, mappedParameters.get("file").size());
-
-        assertTrue(mappedParameters.containsKey("field"));
-        assertEquals(1, mappedParameters.get("field").size());
-
-        assertTrue(mappedParameters.containsKey("multi"));
-        assertEquals(2, mappedParameters.get("multi").size());
-    }
-
-    /**
      * Test for <a href="http://issues.apache.org/jira/browse/FILEUPLOAD-239">FILEUPLOAD-239</a>
      */
     @Test
     public void testContentTypeAttachment()
             throws IOException, FileUploadException {
-        List<FileItem> fileItems = parseUpload(
-        		"-----1234\r\n" +
-        		"content-disposition: form-data; name=\"field1\"\r\n" +
-        		"\r\n" +
-        		"Joe Blow\r\n" +
-        		"-----1234\r\n" +
-        		"content-disposition: form-data; name=\"pics\"\r\n" +
-        		"Content-type: multipart/mixed, boundary=---9876\r\n" +
-        		"\r\n" +
-        		"-----9876\r\n" +
-        		"Content-disposition: attachment; filename=\"file1.txt\"\r\n" +
-        		"Content-Type: text/plain\r\n" +
-        		"\r\n" + 
-        		"... contents of file1.txt ...\r\n" +
-        		"-----9876--\r\n" +
-        		"-----1234--\r\n");        				
+        List<FileItem> fileItems = Util.parseUpload(upload,
+                "-----1234\r\n" +
+                "content-disposition: form-data; name=\"field1\"\r\n" +
+                "\r\n" +
+                "Joe Blow\r\n" +
+                "-----1234\r\n" +
+                "content-disposition: form-data; name=\"pics\"\r\n" +
+                "Content-type: multipart/mixed, boundary=---9876\r\n" +
+                "\r\n" +
+                "-----9876\r\n" +
+                "Content-disposition: attachment; filename=\"file1.txt\"\r\n" +
+                "Content-Type: text/plain\r\n" +
+                "\r\n" + 
+                "... contents of file1.txt ...\r\n" +
+                "-----9876--\r\n" +
+                "-----1234--\r\n");
         assertEquals(2, fileItems.size());
 
         FileItem field = fileItems.get(0);
@@ -432,8 +386,8 @@
     }
 
     private void assertHeaders(String[] pHeaderNames, String[] pHeaderValues,
-                               FileItem pItem, int pIndex) {
-        for (int i = 0;  i < pHeaderNames.length;  i++) {
+            FileItem pItem, int pIndex) {
+        for (int i = 0; i < pHeaderNames.length; i++) {
             final String value = pItem.getHeaders().getHeader(pHeaderNames[i]);
             if (i == pIndex) {
                 assertEquals(pHeaderValues[i], value);
@@ -442,5 +396,4 @@
             }
         }
     }
-
 }
diff --git a/src/test/java/org/apache/commons/fileupload/FileUploadTestCase.java b/src/test/java/org/apache/commons/fileupload/FileUploadTestCase.java
deleted file mode 100644
index f93ebb4..0000000
--- a/src/test/java/org/apache/commons/fileupload/FileUploadTestCase.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.fileupload;
-
-import java.io.UnsupportedEncodingException;
-import java.util.List;
-
-import javax.servlet.http.HttpServletRequest;
-
-import org.apache.commons.fileupload.disk.DiskFileItemFactory;
-import org.apache.commons.fileupload.servlet.ServletFileUpload;
-
-/**
- * Base class for deriving test cases.
- */
-public abstract class FileUploadTestCase {
-
-    protected static final String CONTENT_TYPE = "multipart/form-data; boundary=---1234";
-
-    protected List<FileItem> parseUpload(byte[] bytes) throws FileUploadException {
-        return parseUpload(bytes, CONTENT_TYPE);
-    }
-
-    protected List<FileItem> parseUpload(byte[] bytes, String contentType) throws FileUploadException {
-        ServletFileUpload upload = new ServletFileUpload(new DiskFileItemFactory());
-        HttpServletRequest request = new MockHttpServletRequest(bytes, contentType);
-
-        List<FileItem> fileItems = upload.parseRequest(request);
-        return fileItems;
-    }
-
-    protected List<FileItem> parseUpload(String content)
-        throws UnsupportedEncodingException, FileUploadException {
-        byte[] bytes = content.getBytes("US-ASCII");
-        return parseUpload(bytes, CONTENT_TYPE);
-    }
-
-}
diff --git a/src/test/java/org/apache/commons/fileupload/MockHttpServletRequest.java b/src/test/java/org/apache/commons/fileupload/MockHttpServletRequest.java
index 0d04ed1..7df2bdd 100644
--- a/src/test/java/org/apache/commons/fileupload/MockHttpServletRequest.java
+++ b/src/test/java/org/apache/commons/fileupload/MockHttpServletRequest.java
@@ -32,7 +32,7 @@
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpSession;
 
-class MockHttpServletRequest implements HttpServletRequest {
+public class MockHttpServletRequest implements HttpServletRequest {
 
     private final InputStream m_requestData;
 
diff --git a/src/test/java/org/apache/commons/fileupload/MultipartStreamTest.java b/src/test/java/org/apache/commons/fileupload/MultipartStreamTest.java
index a7d3eec..edbc370 100644
--- a/src/test/java/org/apache/commons/fileupload/MultipartStreamTest.java
+++ b/src/test/java/org/apache/commons/fileupload/MultipartStreamTest.java
@@ -46,7 +46,6 @@
         assertNotNull(ms);
     }
 
-    @SuppressWarnings("unused")
     @Test(expected=IllegalArgumentException.class)
     public void testSmallBuffer() throws Exception {
         final String strData = "foobar";
diff --git a/src/test/java/org/apache/commons/fileupload/ProgressListenerTest.java b/src/test/java/org/apache/commons/fileupload/ProgressListenerTest.java
index 30aa1de..721498f 100644
--- a/src/test/java/org/apache/commons/fileupload/ProgressListenerTest.java
+++ b/src/test/java/org/apache/commons/fileupload/ProgressListenerTest.java
@@ -23,14 +23,15 @@
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
 
 import org.apache.commons.fileupload.servlet.ServletFileUpload;
 import org.junit.Test;
 
 /**
- * Tests the progress listener.
+ * Tests the {@link ProgressListener}.
  */
-public class ProgressListenerTest extends FileUploadTestCase {
+public class ProgressListenerTest {
 
     private class ProgressListenerImpl implements ProgressListener {
 
@@ -76,18 +77,18 @@
             String header = "-----1234\r\n"
                 + "Content-Disposition: form-data; name=\"field" + (i+1) + "\"\r\n"
                 + "\r\n";
-            baos.write(header.getBytes("US-ASCII"));
+            baos.write(header.getBytes(StandardCharsets.US_ASCII.name()));
             for (int j = 0;  j < 16384+i;  j++) {
                 baos.write((byte) j);
             }
-            baos.write("\r\n".getBytes("US-ASCII"));
+            baos.write("\r\n".getBytes(StandardCharsets.US_ASCII.name()));
         }
-        baos.write("-----1234--\r\n".getBytes("US-ASCII"));
+        baos.write("-----1234--\r\n".getBytes(StandardCharsets.US_ASCII.name()));
         byte[] contents = baos.toByteArray();
 
-        MockHttpServletRequest request = new MockHttpServletRequest(contents, "multipart/form-data; boundary=---1234");
+        MockHttpServletRequest request = new MockHttpServletRequest(contents, Constants.CONTENT_TYPE);
         runTest(NUM_ITEMS, contents.length, request);
-        request = new MockHttpServletRequest(contents, "multipart/form-data; boundary=---1234"){
+        request = new MockHttpServletRequest(contents, Constants.CONTENT_TYPE){
             @Override
             public int getContentLength() {
                 return -1;
diff --git a/src/test/java/org/apache/commons/fileupload/SizesTest.java b/src/test/java/org/apache/commons/fileupload/SizesTest.java
index 806f793..f328d41 100644
--- a/src/test/java/org/apache/commons/fileupload/SizesTest.java
+++ b/src/test/java/org/apache/commons/fileupload/SizesTest.java
@@ -24,6 +24,7 @@
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
 import java.util.Iterator;
 import java.util.List;
 
@@ -39,7 +40,7 @@
 /**
  * Unit test for items with varying sizes.
  */
-public class SizesTest extends FileUploadTestCase {
+public class SizesTest {
 
     /**
      * Runs a test with varying file sizes.
@@ -65,7 +66,8 @@
         }
         baos.write("-----1234--\r\n".getBytes("US-ASCII"));
 
-        List<FileItem> fileItems = parseUpload(baos.toByteArray());
+        List<FileItem> fileItems =
+                Util.parseUpload(new ServletFileUpload(new DiskFileItemFactory()), baos.toByteArray());
         Iterator<FileItem> fileIter = fileItems.iterator();
         add = 16;
         num = 0;
@@ -100,7 +102,8 @@
 
         ServletFileUpload upload = new ServletFileUpload(new DiskFileItemFactory());
         upload.setFileSizeMax(-1);
-        HttpServletRequest req = new MockHttpServletRequest(request.getBytes("US-ASCII"), CONTENT_TYPE);
+        HttpServletRequest req = new MockHttpServletRequest(
+                request.getBytes(StandardCharsets.US_ASCII.name()), Constants.CONTENT_TYPE);
         List<FileItem> fileItems = upload.parseRequest(req);
         assertEquals(1, fileItems.size());
         FileItem item = fileItems.get(0);
@@ -108,7 +111,7 @@
 
         upload = new ServletFileUpload(new DiskFileItemFactory());
         upload.setFileSizeMax(40);
-        req = new MockHttpServletRequest(request.getBytes("US-ASCII"), CONTENT_TYPE);
+        req = new MockHttpServletRequest(request.getBytes(StandardCharsets.US_ASCII.name()), Constants.CONTENT_TYPE);
         fileItems = upload.parseRequest(req);
         assertEquals(1, fileItems.size());
         item = fileItems.get(0);
@@ -116,7 +119,7 @@
 
         upload = new ServletFileUpload(new DiskFileItemFactory());
         upload.setFileSizeMax(30);
-        req = new MockHttpServletRequest(request.getBytes("US-ASCII"), CONTENT_TYPE);
+        req = new MockHttpServletRequest(request.getBytes(StandardCharsets.US_ASCII.name()), Constants.CONTENT_TYPE);
         try {
             upload.parseRequest(req);
             fail("Expected exception.");
@@ -142,7 +145,8 @@
 
         ServletFileUpload upload = new ServletFileUpload(new DiskFileItemFactory());
         upload.setFileSizeMax(-1);
-        HttpServletRequest req = new MockHttpServletRequest(request.getBytes("US-ASCII"), CONTENT_TYPE);
+        HttpServletRequest req = new MockHttpServletRequest(
+                request.getBytes(StandardCharsets.US_ASCII.name()), Constants.CONTENT_TYPE);
         List<FileItem> fileItems = upload.parseRequest(req);
         assertEquals(1, fileItems.size());
         FileItem item = fileItems.get(0);
@@ -150,7 +154,7 @@
 
         upload = new ServletFileUpload(new DiskFileItemFactory());
         upload.setFileSizeMax(40);
-        req = new MockHttpServletRequest(request.getBytes("US-ASCII"), CONTENT_TYPE);
+        req = new MockHttpServletRequest(request.getBytes(StandardCharsets.US_ASCII.name()), Constants.CONTENT_TYPE);
         fileItems = upload.parseRequest(req);
         assertEquals(1, fileItems.size());
         item = fileItems.get(0);
@@ -159,7 +163,7 @@
         // provided Content-Length is larger than the FileSizeMax -> handled by ctor
         upload = new ServletFileUpload(new DiskFileItemFactory());
         upload.setFileSizeMax(5);
-        req = new MockHttpServletRequest(request.getBytes("US-ASCII"), CONTENT_TYPE);
+        req = new MockHttpServletRequest(request.getBytes(StandardCharsets.US_ASCII.name()), Constants.CONTENT_TYPE);
         try {
             upload.parseRequest(req);
             fail("Expected exception.");
@@ -170,7 +174,7 @@
         // provided Content-Length is wrong, actual content is larger -> handled by LimitedInputStream
         upload = new ServletFileUpload(new DiskFileItemFactory());
         upload.setFileSizeMax(15);
-        req = new MockHttpServletRequest(request.getBytes("US-ASCII"), CONTENT_TYPE);
+        req = new MockHttpServletRequest(request.getBytes(StandardCharsets.US_ASCII.name()), Constants.CONTENT_TYPE);
         try {
             upload.parseRequest(req);
             fail("Expected exception.");
@@ -204,14 +208,14 @@
         upload.setFileSizeMax(-1);
         upload.setSizeMax(200);
 
-        MockHttpServletRequest req = new MockHttpServletRequest(request.getBytes("US-ASCII"), CONTENT_TYPE);
+        MockHttpServletRequest req = new MockHttpServletRequest(
+                request.getBytes(StandardCharsets.US_ASCII.name()), Constants.CONTENT_TYPE);
         try {
             upload.parseRequest(req);
             fail("Expected exception.");
         } catch (FileUploadBase.SizeLimitExceededException e) {
             assertEquals(200, e.getPermittedSize());
         }
-
     }
 
     @Test
@@ -241,7 +245,8 @@
         // set the read limit to 10 to simulate a "real" stream
         // otherwise the buffer would be immediately filled
 
-        MockHttpServletRequest req = new MockHttpServletRequest(request.getBytes("US-ASCII"), CONTENT_TYPE);
+        MockHttpServletRequest req = new MockHttpServletRequest(
+                request.getBytes(StandardCharsets.US_ASCII.name()), Constants.CONTENT_TYPE);
         req.setContentLength(-1);
         req.setReadLimit(10);
 
@@ -277,7 +282,6 @@
         } catch (FileUploadIOException e) {
             // expected
         }
-
     }
 
 }
diff --git a/src/test/java/org/apache/commons/fileupload/Util.java b/src/test/java/org/apache/commons/fileupload/Util.java
new file mode 100644
index 0000000..42041e3
--- /dev/null
+++ b/src/test/java/org/apache/commons/fileupload/Util.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.fileupload;
+
+import java.io.UnsupportedEncodingException;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.commons.fileupload.disk.DiskFileItemFactory;
+import org.apache.commons.fileupload.portlet.PortletFileUpload;
+import org.apache.commons.fileupload.servlet.ServletFileUpload;
+import org.apache.commons.fileupload.servlet.ServletRequestContext;
+
+/**
+ * Test utility methods.
+ *
+ * @since 1.4
+ */
+public class Util {
+
+    public static List<FileItem> parseUpload(FileUpload upload, byte[] bytes) throws FileUploadException {
+        return parseUpload(upload, bytes, Constants.CONTENT_TYPE);
+    }
+
+    public static List<FileItem> parseUpload(FileUpload upload, byte[] bytes, String contentType) throws FileUploadException {
+        final HttpServletRequest request = new MockHttpServletRequest(bytes, contentType);
+        List<FileItem> fileItems = upload.parseRequest(new ServletRequestContext(request));
+        return fileItems;
+    }
+
+    public static List<FileItem> parseUpload(FileUpload upload, String content)
+        throws UnsupportedEncodingException, FileUploadException {
+        byte[] bytes = content.getBytes(StandardCharsets.US_ASCII.name());
+        return parseUpload(upload, bytes, Constants.CONTENT_TYPE);
+    }
+
+    /**
+     * Return a list of {@link FileUpload} implementations for parameterized tests.
+     * @return a list of {@link FileUpload} implementations
+     */
+    public static List<FileUpload> fileUploadImplementations() {
+        return Arrays.asList(
+                new ServletFileUpload(new DiskFileItemFactory()),
+                new PortletFileUpload(new DiskFileItemFactory()));
+    }
+}
diff --git a/src/test/java/org/apache/commons/fileupload/portlet/MockPortletActionRequest.java b/src/test/java/org/apache/commons/fileupload/portlet/MockPortletActionRequest.java
new file mode 100644
index 0000000..5f13788
--- /dev/null
+++ b/src/test/java/org/apache/commons/fileupload/portlet/MockPortletActionRequest.java
@@ -0,0 +1,271 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.fileupload.portlet;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.security.Principal;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Locale;
+import java.util.Map;
+
+import javax.portlet.ActionRequest;
+import javax.portlet.PortalContext;
+import javax.portlet.PortletMode;
+import javax.portlet.PortletPreferences;
+import javax.portlet.PortletSession;
+import javax.portlet.WindowState;
+
+import org.apache.commons.fileupload.FileUploadBase;
+
+/**
+ * Mock class for tests. Implements an {@link ActionRequest}.
+ *
+ * @see PortletFileUploadTest
+ * @since 1.4
+ */
+@SuppressWarnings("rawtypes") // because of the portlet ActionRequest API does not use generics
+public class MockPortletActionRequest implements ActionRequest {
+
+    private final Hashtable<String, Object> attributes = new Hashtable<String, Object>();
+
+    private final Map<String, String> parameters = new HashMap<String, String>();
+
+    private String characterEncoding;
+    private int length;
+    private final String contentType;
+    private final InputStream requestData;
+
+    public MockPortletActionRequest(final byte[] requestData, final String contentType) {
+        this(new ByteArrayInputStream(requestData), requestData.length, contentType);
+    }
+
+    public MockPortletActionRequest(ByteArrayInputStream byteArrayInputStream, int requestLength, String contentType) {
+        this.requestData = byteArrayInputStream;
+        length = requestLength;
+        this.contentType = contentType;
+        attributes.put(FileUploadBase.CONTENT_TYPE, contentType);
+    }
+
+    @Override
+    public Object getAttribute(String key) {
+        return attributes.get(key);
+    }
+
+    @Override
+    public Enumeration getAttributeNames() {
+        return attributes.keys();
+    }
+
+    @Override
+    public String getAuthType() {
+        return null;
+    }
+
+    @Override
+    public String getContextPath() {
+        return null;
+    }
+
+    @Override
+    public Locale getLocale() {
+        return Locale.getDefault();
+    }
+
+    @Override
+    public Enumeration getLocales() {
+        return Collections.enumeration(Arrays.asList(Locale.getAvailableLocales()));
+    }
+
+    @Override
+    public String getParameter(String key) {
+        return parameters.get(key);
+    }
+
+    @Override
+    public Map getParameterMap() {
+        return Collections.unmodifiableMap(parameters);
+    }
+
+    @Override
+    public Enumeration getParameterNames() {
+        return Collections.enumeration(parameters.keySet());
+    }
+
+    @Override
+    public String[] getParameterValues(String arg0) {
+        return null;
+    }
+
+    @Override
+    public PortalContext getPortalContext() {
+        return null;
+    }
+
+    @Override
+    public PortletMode getPortletMode() {
+        return null;
+    }
+
+    @Override
+    public PortletSession getPortletSession() {
+        return null;
+    }
+
+    @Override
+    public PortletSession getPortletSession(boolean arg0) {
+        return null;
+    }
+
+    @Override
+    public PortletPreferences getPreferences() {
+        return null;
+    }
+
+    @Override
+    public Enumeration getProperties(String arg0) {
+        return null;
+    }
+
+    @Override
+    public String getProperty(String arg0) {
+        return null;
+    }
+
+    @Override
+    public Enumeration getPropertyNames() {
+        return null;
+    }
+
+    @Override
+    public String getRemoteUser() {
+        return null;
+    }
+
+    @Override
+    public String getRequestedSessionId() {
+        return null;
+    }
+
+    @Override
+    public String getResponseContentType() {
+        return null;
+    }
+
+    @Override
+    public Enumeration getResponseContentTypes() {
+        return null;
+    }
+
+    @Override
+    public String getScheme() {
+        return null;
+    }
+
+    @Override
+    public String getServerName() {
+        return null;
+    }
+
+    @Override
+    public int getServerPort() {
+        return 0;
+    }
+
+    @Override
+    public Principal getUserPrincipal() {
+        return null;
+    }
+
+    @Override
+    public WindowState getWindowState() {
+        return null;
+    }
+
+    @Override
+    public boolean isPortletModeAllowed(PortletMode arg0) {
+        return false;
+    }
+
+    @Override
+    public boolean isRequestedSessionIdValid() {
+        return false;
+    }
+
+    @Override
+    public boolean isSecure() {
+        return false;
+    }
+
+    @Override
+    public boolean isUserInRole(String arg0) {
+        return false;
+    }
+
+    @Override
+    public boolean isWindowStateAllowed(WindowState arg0) {
+        return false;
+    }
+
+    @Override
+    public void removeAttribute(String key) {
+        attributes.remove(key);
+    }
+
+    @Override
+    public void setAttribute(String key, Object value) {
+        attributes.put(key, value);
+    }
+
+    @Override
+    public String getCharacterEncoding() {
+        return characterEncoding;
+    }
+
+    @Override
+    public int getContentLength() {
+        return length;
+    }
+
+    @Override
+    public String getContentType() {
+        return contentType;
+    }
+
+    @Override
+    public InputStream getPortletInputStream() throws IOException {
+        return requestData;
+    }
+
+    @Override
+    public BufferedReader getReader() throws UnsupportedEncodingException, IOException {
+        return null;
+    }
+
+    @Override
+    public void setCharacterEncoding(String characterEncoding) throws UnsupportedEncodingException {
+        this.characterEncoding = characterEncoding;
+    }
+
+}
diff --git a/src/test/java/org/apache/commons/fileupload/portlet/PortletFileUploadTest.java b/src/test/java/org/apache/commons/fileupload/portlet/PortletFileUploadTest.java
new file mode 100644
index 0000000..7b2aa80
--- /dev/null
+++ b/src/test/java/org/apache/commons/fileupload/portlet/PortletFileUploadTest.java
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.fileupload.portlet;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+import java.util.Map;
+
+import javax.portlet.ActionRequest;
+
+import org.apache.commons.fileupload.Constants;
+import org.apache.commons.fileupload.FileItem;
+import org.apache.commons.fileupload.FileUploadTest;
+import org.apache.commons.fileupload.disk.DiskFileItemFactory;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Test for {@link PortletFileUpload}.
+ *
+ * @see FileUploadTest
+ * @since 1.4
+ */
+public class PortletFileUploadTest {
+
+    private PortletFileUpload upload;
+
+    @Before
+    public void setUp() {
+        upload = new PortletFileUpload(new DiskFileItemFactory());
+    }
+
+    @Test
+    public void parseParameterMap()
+            throws Exception {
+        String text = "-----1234\r\n" +
+                      "Content-Disposition: form-data; name=\"file\"; filename=\"foo.tab\"\r\n" +
+                      "Content-Type: text/whatever\r\n" +
+                      "\r\n" +
+                      "This is the content of the file\n" +
+                      "\r\n" +
+                      "-----1234\r\n" +
+                      "Content-Disposition: form-data; name=\"field\"\r\n" +
+                      "\r\n" +
+                      "fieldValue\r\n" +
+                      "-----1234\r\n" +
+                      "Content-Disposition: form-data; name=\"multi\"\r\n" +
+                      "\r\n" +
+                      "value1\r\n" +
+                      "-----1234\r\n" +
+                      "Content-Disposition: form-data; name=\"multi\"\r\n" +
+                      "\r\n" +
+                      "value2\r\n" +
+                      "-----1234--\r\n";
+        byte[] bytes = text.getBytes(StandardCharsets.US_ASCII.name());
+        ActionRequest request = new MockPortletActionRequest(bytes, Constants.CONTENT_TYPE);
+
+        Map<String, List<FileItem>> mappedParameters = upload.parseParameterMap(request);
+        assertTrue(mappedParameters.containsKey("file"));
+        assertEquals(1, mappedParameters.get("file").size());
+
+        assertTrue(mappedParameters.containsKey("field"));
+        assertEquals(1, mappedParameters.get("field").size());
+
+        assertTrue(mappedParameters.containsKey("multi"));
+        assertEquals(2, mappedParameters.get("multi").size());
+    }
+
+}
diff --git a/src/test/java/org/apache/commons/fileupload/servlet/ServletFileUploadTest.java b/src/test/java/org/apache/commons/fileupload/servlet/ServletFileUploadTest.java
new file mode 100644
index 0000000..69480d7
--- /dev/null
+++ b/src/test/java/org/apache/commons/fileupload/servlet/ServletFileUploadTest.java
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.fileupload.servlet;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.commons.fileupload.Constants;
+import org.apache.commons.fileupload.FileItem;
+import org.apache.commons.fileupload.MockHttpServletRequest;
+import org.apache.commons.fileupload.disk.DiskFileItemFactory;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Test for {@link ServletFileUpload}.
+ *
+ * @see FileUploadTest
+ * @since 1.4
+ */
+public class ServletFileUploadTest {
+
+    private ServletFileUpload upload;
+
+    @Before
+    public void setUp() {
+        upload = new ServletFileUpload(new DiskFileItemFactory());
+    }
+
+    /**
+     * Test case for <a href="http://issues.apache.org/jira/browse/FILEUPLOAD-210">
+     */
+    @Test
+    public void parseParameterMap()
+            throws Exception {
+        String text = "-----1234\r\n" +
+                      "Content-Disposition: form-data; name=\"file\"; filename=\"foo.tab\"\r\n" +
+                      "Content-Type: text/whatever\r\n" +
+                      "\r\n" +
+                      "This is the content of the file\n" +
+                      "\r\n" +
+                      "-----1234\r\n" +
+                      "Content-Disposition: form-data; name=\"field\"\r\n" +
+                      "\r\n" +
+                      "fieldValue\r\n" +
+                      "-----1234\r\n" +
+                      "Content-Disposition: form-data; name=\"multi\"\r\n" +
+                      "\r\n" +
+                      "value1\r\n" +
+                      "-----1234\r\n" +
+                      "Content-Disposition: form-data; name=\"multi\"\r\n" +
+                      "\r\n" +
+                      "value2\r\n" +
+                      "-----1234--\r\n";
+        byte[] bytes = text.getBytes(StandardCharsets.US_ASCII.name());
+        HttpServletRequest request = new MockHttpServletRequest(bytes, Constants.CONTENT_TYPE);
+
+        Map<String, List<FileItem>> mappedParameters = upload.parseParameterMap(request);
+        assertTrue(mappedParameters.containsKey("file"));
+        assertEquals(1, mappedParameters.get("file").size());
+
+        assertTrue(mappedParameters.containsKey("field"));
+        assertEquals(1, mappedParameters.get("field").size());
+
+        assertTrue(mappedParameters.containsKey("multi"));
+        assertEquals(2, mappedParameters.get("multi").size());
+    }
+
+}