001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *     http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.chain.web.jakarta.servlet;
018
019import static org.junit.jupiter.api.Assertions.assertEquals;
020import static org.junit.jupiter.api.Assertions.assertFalse;
021import static org.junit.jupiter.api.Assertions.assertInstanceOf;
022import static org.junit.jupiter.api.Assertions.assertNotEquals;
023import static org.junit.jupiter.api.Assertions.assertNotNull;
024import static org.junit.jupiter.api.Assertions.assertNull;
025import static org.junit.jupiter.api.Assertions.assertTrue;
026import static org.junit.jupiter.api.Assertions.fail;
027
028import java.util.Collection;
029import java.util.Collections;
030import java.util.HashMap;
031import java.util.Iterator;
032import java.util.Map;
033import java.util.Map.Entry;
034import java.util.Set;
035
036import org.apache.commons.chain.Context;
037import org.apache.commons.chain.web.ContextBaseTestWeb;
038import org.junit.jupiter.api.AfterEach;
039import org.junit.jupiter.api.BeforeEach;
040import org.junit.jupiter.api.Test;
041
042import jakarta.servlet.ServletContext;
043import jakarta.servlet.http.Cookie;
044import jakarta.servlet.http.HttpServletRequest;
045import jakarta.servlet.http.HttpServletResponse;
046import jakarta.servlet.http.HttpSession;
047
048/**
049 * Extension of {@code ContextBaseTestCase} to validate the
050 * extra functionality of this implementation.
051 */
052public class ServletWebContextTestCase extends ContextBaseTestWeb<ServletWebContext> {
053
054    // ----------------------------------------------------- Instance Variables
055
056    /**
057     * Servlet API Objects - Context
058     */
059    protected ServletContext scontext = null;
060
061    /**
062     * Servlet API Objects - Request
063     */
064    protected HttpServletRequest request = null;
065
066    /**
067     * Servlet API Objects - Response
068     */
069    protected HttpServletResponse response = null;
070
071    /**
072     * Servlet API Objects - Session
073     */
074    protected HttpSession session = null;
075
076    // ---------------------------------------------------------- Constructors
077
078    /**
079     * The Default-Constructor for this class.
080     */
081    public ServletWebContextTestCase() {
082    }
083
084    // -------------------------------------------------- Overall Test Methods
085
086    /**
087     * Set up instance variables required by this test case.
088     */
089    @Override
090    @BeforeEach
091    public void init() {
092        scontext = new MockServletContext();
093        scontext.setAttribute("akey1", "avalue1");
094        scontext.setAttribute("akey2", "avalue2");
095        scontext.setAttribute("akey3", "avalue3");
096        scontext.setAttribute("akey4", "avalue4");
097        ((MockServletContext) scontext).addInitParameter("ikey1", "ivalue1");
098        ((MockServletContext) scontext).addInitParameter("ikey2", "ivalue2");
099        ((MockServletContext) scontext).addInitParameter("ikey3", "ivalue3");
100        session = new MockHttpSession(scontext);
101        session.setAttribute("skey1", "svalue1");
102        session.setAttribute("skey2", "svalue2");
103        session.setAttribute("skey3", "svalue3");
104        request = new MockHttpServletRequest("/context", "/servlet",
105                                             "/path/info", "a=b&c=d",
106                                             session);
107        request.setAttribute("rkey1", "rvalue1");
108        request.setAttribute("rkey2", "rvalue2");
109        ((MockHttpServletRequest) request).addHeader("hkey1", "hvalue1");
110        ((MockHttpServletRequest) request).addHeader("hkey2", "hvalue2a");
111        ((MockHttpServletRequest) request).addHeader("hkey2", "hvalue2b");
112        ((MockHttpServletRequest) request).addParameter("pkey1", "pvalue1");
113        ((MockHttpServletRequest) request).addParameter("pkey2", "pvalue2a");
114        ((MockHttpServletRequest) request).addParameter("pkey2", "pvalue2b");
115        ((MockHttpServletRequest) request).addCookie("ckey1", "cvalue1");
116        ((MockHttpServletRequest) request).addCookie("ckey2", "cvalue2");
117        response = new MockHttpServletResponse();
118        context = createContext();
119    }
120
121    /**
122     * Tear down instance variables required by this test case.
123     */
124    @Override
125    @AfterEach
126    public void tearDown() {
127        scontext = null;
128        session = null;
129        request = null;
130        response = null;
131        context = null;
132    }
133
134    // ------------------------------------------------ Individual Test Methods
135
136    /**
137     * Test {@code getApplicationScope()}
138     */
139    @Test
140    public void testApplicationScope() {
141        Map<String, Object> map = context.getApplicationScope();
142        assertNotNull(map);
143
144        // Initial contents
145        checkMapSize(map, 4);
146        assertEquals("avalue1", map.get("akey1"));
147        assertEquals("avalue2", map.get("akey2"));
148        assertEquals("avalue3", map.get("akey3"));
149        assertEquals("avalue4", map.get("akey4"));
150
151        // Transparency - entrySet()
152        checkEntrySet(map, true);
153
154        // Transparency - removal via web object
155        scontext.removeAttribute("akey1");
156        checkMapSize(map, 3);
157        assertNull(map.get("akey1"));
158
159        // Transparency - removal via map
160        map.remove("akey2");
161        checkMapSize(map, 2);
162        assertNull(scontext.getAttribute("akey2"));
163
164        // Transparency - addition via web object
165        scontext.setAttribute("akeyA", "avalueA");
166        checkMapSize(map, 3);
167        assertEquals("avalueA", map.get("akeyA"));
168
169        // Transparency - addition via map
170        map.put("akeyB", "avalueB");
171        checkMapSize(map, 4);
172        assertEquals("avalueB", scontext.getAttribute("akeyB"));
173
174        // Transparency - replacement via web object
175        scontext.setAttribute("akeyA", "newvalueA");
176        checkMapSize(map, 4);
177        assertEquals("newvalueA", map.get("akeyA"));
178
179        // Transparency - replacement via map
180        map.put("akeyB", "newvalueB");
181        assertEquals(4, map.size());
182        assertEquals("newvalueB", scontext.getAttribute("akeyB"));
183
184        // Clearing the map
185        map.clear();
186        checkMapSize(map, 0);
187
188        // Test putAll()
189        Map<String, String> values = new HashMap<>();
190        values.put("1", "One");
191        values.put("2", "Two");
192        map.putAll(values);
193        assertEquals("One", map.get("1"), "putAll(1)");
194        assertEquals("Two", map.get("2"), "putAll(2)");
195        checkMapSize(map, 2);
196    }
197
198    /**
199     * Test {@code equals()} and {@code hashCode()}
200     * Copied from ContextBaseTestCase with customized creation of "other"
201     */
202    @Override
203    @Test
204    public void testEquals() {
205        // FIXME - ServletWebContext needs a better equals()
206
207        // Compare to self
208        assertTrue(context.equals(context));
209        assertEquals(context.hashCode(), context.hashCode());
210
211        // Compare to equivalent instance
212        Context other = new ServletWebContext(scontext, request, response);
213        // assertTrue(context.equals(other));
214        assertEquals(context.hashCode(), other.hashCode());
215
216        // Compare to non-equivalent instance - other modified
217        other.put("bop", "bop value");
218        // assertFalse(context.equals(other));
219        assertNotEquals(context.hashCode(), other.hashCode());
220
221        // Compare to non-equivalent instance - self modified
222        other = new ServletWebContext(scontext, request, response);
223        context.put("bop", "bop value");
224        // assertFalse(context.equals(other));
225        assertNotEquals(context.hashCode(), other.hashCode());
226    }
227
228    /**
229     * Test {@code getHeader()}
230     */
231    @Test
232    public void testHeader() {
233        Map<String, String> map = context.getHeader();
234        assertNotNull(map);
235
236        // Initial contents
237        checkMapSize(map, 2);
238        assertEquals("hvalue1", map.get("hkey1"));
239        assertEquals("hvalue2a", map.get("hkey2"));
240        assertTrue(map.containsKey("hkey1"));
241        assertTrue(map.containsKey("hkey2"));
242        assertTrue(map.containsValue("hvalue1"));
243        assertTrue(map.containsValue("hvalue2a"));
244
245        // Transparency - entrySet()
246        checkEntrySet(map, false);
247
248        // Unsupported operations on read-only map
249        try {
250            map.clear();
251            fail("Should have thrown UnsupportedOperationException");
252        } catch (UnsupportedOperationException e) {
253            ; // expected result
254        }
255        try {
256            map.put("hkey3", "hvalue3");
257            fail("Should have thrown UnsupportedOperationException");
258        } catch (UnsupportedOperationException e) {
259            ; // expected result
260        }
261        try {
262            map.putAll(new HashMap<>());
263            fail("Should have thrown UnsupportedOperationException");
264        } catch (UnsupportedOperationException e) {
265            ; // expected result
266        }
267        try {
268            map.remove("hkey1");
269            fail("Should have thrown UnsupportedOperationException");
270        } catch (UnsupportedOperationException e) {
271            ; // expected result
272        }
273    }
274
275    /**
276     * Test {@code getHeaderValues()}
277     */
278    @Test
279    public void testHeaderValues() {
280        Map<String, String[]> map = context.getHeaderValues();
281        assertNotNull(map);
282
283        // Initial contents
284        checkMapSize(map, 2);
285        Object value1 = map.get("hkey1");
286        assertNotNull(value1);
287        assertInstanceOf(String[].class, value1);
288        String values1[] = (String[]) value1;
289        assertEquals(1, values1.length);
290        assertEquals("hvalue1", values1[0]);
291        Object value2 = map.get("hkey2");
292        assertNotNull(value2);
293        assertInstanceOf(String[].class, value2);
294        String values2[] = (String[]) value2;
295        assertEquals(2, values2.length);
296        assertEquals("hvalue2a", values2[0]);
297        assertEquals("hvalue2b", values2[1]);
298        assertTrue(map.containsKey("hkey1"));
299        assertTrue(map.containsKey("hkey2"));
300        assertTrue(map.containsValue(values1));
301        assertTrue(map.containsValue(values2));
302
303        // Transparency - entrySet()
304        checkEntrySet(map, false);
305
306        // Unsupported operations on read-only map
307        try {
308            map.clear();
309            fail("Should have thrown UnsupportedOperationException");
310        } catch (UnsupportedOperationException e) {
311            ; // expected result
312        }
313        try {
314            map.put("hkey3", values2);
315            fail("Should have thrown UnsupportedOperationException");
316        } catch (UnsupportedOperationException e) {
317            ; // expected result
318        }
319        try {
320            map.putAll(new HashMap<>());
321            fail("Should have thrown UnsupportedOperationException");
322        } catch (UnsupportedOperationException e) {
323            ; // expected result
324        }
325        try {
326            map.remove("hkey1");
327            fail("Should have thrown UnsupportedOperationException");
328        } catch (UnsupportedOperationException e) {
329            ; // expected result
330        }
331    }
332
333    /**
334     * Test {@code getInitParam()}
335     */
336    @Test
337    public void testInitParam() {
338        Map<String, String> map = context.getInitParam();
339        assertNotNull(map);
340
341        // Initial contents
342        checkMapSize(map, 3);
343        assertEquals("ivalue1", map.get("ikey1"));
344        assertEquals("ivalue2", map.get("ikey2"));
345        assertEquals("ivalue3", map.get("ikey3"));
346        assertTrue(map.containsKey("ikey1"));
347        assertTrue(map.containsKey("ikey2"));
348        assertTrue(map.containsKey("ikey3"));
349        assertTrue(map.containsValue("ivalue1"));
350        assertTrue(map.containsValue("ivalue2"));
351        assertTrue(map.containsValue("ivalue3"));
352
353        // Transparency - entrySet()
354        checkEntrySet(map, false);
355
356        // Unsupported operations on read-only map
357        try {
358            map.clear();
359            fail("Should have thrown UnsupportedOperationException");
360        } catch (UnsupportedOperationException e) {
361            ; // expected result
362        }
363        try {
364            map.put("ikey4", "ivalue4");
365            fail("Should have thrown UnsupportedOperationException");
366        } catch (UnsupportedOperationException e) {
367            ; // expected result
368        }
369        try {
370            map.putAll(new HashMap<>());
371            fail("Should have thrown UnsupportedOperationException");
372        } catch (UnsupportedOperationException e) {
373            ; // expected result
374        }
375        try {
376            map.remove("ikey1");
377            fail("Should have thrown UnsupportedOperationException");
378        } catch (UnsupportedOperationException e) {
379            ; // expected result
380        }
381    }
382
383    /**
384     * Test {@code getParam()}
385     */
386    @Test
387    public void testParam() {
388        Map<String, String> map = context.getParam();
389        assertNotNull(map);
390
391        // Initial contents
392        checkMapSize(map, 2);
393        assertEquals("pvalue1", map.get("pkey1"));
394        assertEquals("pvalue2a", map.get("pkey2"));
395        assertTrue(map.containsKey("pkey1"));
396        assertTrue(map.containsKey("pkey2"));
397        assertTrue(map.containsValue("pvalue1"));
398        assertTrue(map.containsValue("pvalue2a"));
399
400        checkEntrySet(map, false);
401
402        // Unsupported operations on read-only map
403        try {
404            map.clear();
405            fail("Should have thrown UnsupportedOperationException");
406        } catch (UnsupportedOperationException e) {
407            ; // expected result
408        }
409        try {
410            map.put("pkey3", "pvalue3");
411            fail("Should have thrown UnsupportedOperationException");
412        } catch (UnsupportedOperationException e) {
413            ; // expected result
414        }
415        try {
416            map.putAll(new HashMap<>());
417            fail("Should have thrown UnsupportedOperationException");
418        } catch (UnsupportedOperationException e) {
419            ; // expected result
420        }
421        try {
422            map.remove("pkey1");
423            fail("Should have thrown UnsupportedOperationException");
424        } catch (UnsupportedOperationException e) {
425            ; // expected result
426        }
427    }
428
429    /**
430     * Test {@code getParamValues()}
431     */
432    @Test
433    public void testParamValues() {
434        Map<String, String[]> map = context.getParamValues();
435        assertNotNull(map);
436
437        // Initial contents
438        checkMapSize(map, 2);
439        Object value1 = map.get("pkey1");
440        assertNotNull(value1);
441        assertInstanceOf(String[].class, value1);
442        String values1[] = (String[]) value1;
443        assertEquals(1, values1.length);
444        assertEquals("pvalue1", values1[0]);
445        Object value2 = map.get("pkey2");
446        assertNotNull(value2);
447        assertInstanceOf(String[].class, value2);
448        String values2[] = (String[]) value2;
449        assertEquals(2, values2.length);
450        assertEquals("pvalue2a", values2[0]);
451        assertEquals("pvalue2b", values2[1]);
452        assertTrue(map.containsKey("pkey1"));
453        assertTrue(map.containsKey("pkey2"));
454        assertTrue(map.containsValue(values1));
455        assertTrue(map.containsValue(values2));
456
457        // Unsupported operations on read-only map
458        try {
459            map.clear();
460            fail("Should have thrown UnsupportedOperationException");
461        } catch (UnsupportedOperationException e) {
462            ; // expected result
463        }
464        try {
465            map.put("pkey3", values2);
466            fail("Should have thrown UnsupportedOperationException");
467        } catch (UnsupportedOperationException e) {
468            ; // expected result
469        }
470        try {
471            map.putAll(new HashMap<>());
472            fail("Should have thrown UnsupportedOperationException");
473        } catch (UnsupportedOperationException e) {
474            ; // expected result
475        }
476        try {
477            map.remove("pkey1");
478            fail("Should have thrown UnsupportedOperationException");
479        } catch (UnsupportedOperationException e) {
480            ; // expected result
481        }
482    }
483
484    /**
485     * Test {@code getCookies()}
486     */
487    @Test
488    public void testCookies() {
489        Map<String, Cookie> map = context.getCookies();
490        assertNotNull(map);
491
492        // Initial contents
493        checkMapSize(map, 2);
494        Cookie cookie1 = map.get("ckey1");
495        assertNotNull(cookie1);
496        assertEquals("cvalue1", cookie1.getValue());
497        Cookie cookie2 = map.get("ckey2");
498        assertNotNull(cookie2);
499        assertEquals("cvalue2", cookie2.getValue());
500        assertTrue(map.containsKey("ckey1"));
501        assertTrue(map.containsKey("ckey2"));
502        assertTrue(map.containsValue(cookie1));
503        assertTrue(map.containsValue(cookie2));
504
505        // Unsupported operations on read-only map
506        try {
507            map.clear();
508            fail("Should have thrown UnsupportedOperationException");
509        } catch (UnsupportedOperationException e) {
510            ; // expected result
511        }
512        try {
513            map.put("ckey3", new Cookie("XXX", "XXX"));
514            fail("Should have thrown UnsupportedOperationException");
515        } catch (UnsupportedOperationException e) {
516            ; // expected result
517        }
518        try {
519            map.putAll(new HashMap<>());
520            fail("Should have thrown UnsupportedOperationException");
521        } catch (UnsupportedOperationException e) {
522            ; // expected result
523        }
524        try {
525            map.remove("ckey1");
526            fail("Should have thrown UnsupportedOperationException");
527        } catch (UnsupportedOperationException e) {
528            ; // expected result
529        }
530    }
531
532    /**
533     * Test state of newly created instance
534     */
535    @Override
536    @Test
537    public void testPristine() {
538        super.testPristine();
539
540        // Properties should all be non-null
541        assertNotNull(context.getApplicationScope());
542        assertNotNull(context.getHeader());
543        assertNotNull(context.getHeaderValues());
544        assertNotNull(context.getInitParam());
545        assertNotNull(context.getParam());
546        assertNotNull(context.getParamValues());
547        assertNotNull(context.getCookies());
548        assertNotNull(context.getRequestScope());
549        assertNotNull(context.getSessionScope());
550
551        // Attribute-property transparency
552        assertTrue(context.getApplicationScope() ==
553                     context.get("applicationScope"));
554        assertTrue(context.getHeader() ==
555                     context.get("header"));
556        assertTrue(context.getHeaderValues() ==
557                     context.get("headerValues"));
558        assertTrue(context.getInitParam() ==
559                     context.get("initParam"));
560        assertTrue(context.getParam() ==
561                     context.get("param"));
562        assertTrue(context.getParamValues() ==
563                     context.get("paramValues"));
564        assertTrue(context.getCookies() ==
565                     context.get("cookies"));
566        assertTrue(context.getRequestScope() ==
567                     context.get("requestScope"));
568        assertTrue(context.getSessionScope() ==
569                     context.get("sessionScope"));
570    }
571
572    /**
573     * Test {@code release()}
574     */
575    @Test
576    public void testRelease() {
577        context.release();
578
579        // Properties should all be null
580        assertNull(context.getApplicationScope());
581        assertNull(context.getHeader());
582        assertNull(context.getHeaderValues());
583        assertNull(context.getInitParam());
584        assertNull(context.getParam());
585        assertNull(context.getParamValues());
586        assertNull(context.getCookies());
587        assertNull(context.getRequestScope());
588        assertNull(context.getSessionScope());
589
590        // Attributes should all be null
591        assertNull(context.get("applicationScope"));
592        assertNull(context.get("header"));
593        assertNull(context.get("headerValues"));
594        assertNull(context.get("initParam"));
595        assertNull(context.get("param"));
596        assertNull(context.get("paramValues"));
597        assertNull(context.get("cookies"));
598        assertNull(context.get("requestScope"));
599        assertNull(context.get("sessionScope"));
600    }
601
602    /**
603     * Test {@code getRequestScope()}
604     */
605    @Test
606    public void testRequestScope() {
607        Map<String, Object> map = context.getRequestScope();
608        assertNotNull(map);
609
610        // Initial contents
611        checkMapSize(map, 2);
612        assertEquals("rvalue1", map.get("rkey1"));
613        assertEquals("rvalue2", map.get("rkey2"));
614
615        // Transparency - entrySet()
616        checkEntrySet(map, true);
617
618        // Transparency - removal via web object
619        request.removeAttribute("rkey1");
620        checkMapSize(map, 1);
621        assertNull(map.get("rkey1"));
622
623       // Transparency - removal via map
624        map.remove("rkey2");
625        checkMapSize(map, 0);
626        assertNull(request.getAttribute("rkey2"));
627
628        // Transparency - addition via web object
629        request.setAttribute("rkeyA", "rvalueA");
630        checkMapSize(map, 1);
631        assertEquals("rvalueA", map.get("rkeyA"));
632
633        // Transparency - addition via map
634        map.put("rkeyB", "rvalueB");
635        checkMapSize(map, 2);
636        assertEquals("rvalueB", request.getAttribute("rkeyB"));
637
638        // Transparency - replacement via web object
639        request.setAttribute("rkeyA", "newvalueA");
640        checkMapSize(map, 2);
641        assertEquals("newvalueA", map.get("rkeyA"));
642
643        // Transparency - replacement via map
644        map.put("rkeyB", "newvalueB");
645        checkMapSize(map, 2);
646        assertEquals("newvalueB", request.getAttribute("rkeyB"));
647
648        // Clearing the map
649        map.clear();
650        checkMapSize(map, 0);
651
652        // Test putAll()
653        Map<String, String> values = new HashMap<>();
654        values.put("1", "One");
655        values.put("2", "Two");
656        map.putAll(values);
657        assertEquals("One", map.get("1"), "putAll(1)");
658        assertEquals("Two", map.get("2"), "putAll(2)");
659        checkMapSize(map, 2);
660    }
661
662    /**
663     * Test {@code getSessionScope()}
664     */
665    @Test
666    public void testSessionScope() {
667        Map<String, Object> map = context.getSessionScope();
668        assertNotNull(map);
669
670        // Initial contents
671        checkMapSize(map, 3);
672        assertEquals("svalue1", map.get("skey1"));
673        assertEquals("svalue2", map.get("skey2"));
674        assertEquals("svalue3", map.get("skey3"));
675
676        // Transparency - entrySet()
677        checkEntrySet(map, true);
678
679        // Transparency - removal via web object
680        session.removeAttribute("skey1");
681        checkMapSize(map, 2);
682        assertNull(map.get("skey1"));
683
684        // Transparency - removal via map
685        map.remove("skey2");
686        checkMapSize(map, 1);
687        assertNull(session.getAttribute("skey2"));
688
689        // Transparency - addition via web object
690        session.setAttribute("skeyA", "svalueA");
691        checkMapSize(map, 2);
692        assertEquals("svalueA", map.get("skeyA"));
693
694        // Transparency - addition via map
695        map.put("skeyB", "svalueB");
696        checkMapSize(map, 3);
697        assertEquals("svalueB", session.getAttribute("skeyB"));
698
699        // Transparency - replacement via web object
700        session.setAttribute("skeyA", "newvalueA");
701        checkMapSize(map, 3);
702        assertEquals("newvalueA", map.get("skeyA"));
703
704        // Transparency - replacement via map
705        map.put("skeyB", "newvalueB");
706        checkMapSize(map, 3);
707        assertEquals("newvalueB", session.getAttribute("skeyB"));
708
709        // Clearing the map
710        map.clear();
711        checkMapSize(map, 0);
712
713        // Test putAll()
714        Map<String, String> values = new HashMap<>();
715        values.put("1", "One");
716        values.put("2", "Two");
717        map.putAll(values);
718        assertEquals("One", map.get("1"), "putAll(1)");
719        assertEquals("Two", map.get("2"), "putAll(2)");
720        checkMapSize(map, 2);
721    }
722
723    /**
724     * Test {@code getSessionScope()} without Session
725     */
726    @Test
727    public void testSessionScopeWithoutSession() {
728        // Create a Context without a session
729        ServletWebContext ctx = new ServletWebContext(scontext,
730           new MockHttpServletRequest(), response);
731        assertNull(ctx.getRequest().getSession(false), "Session(A)");
732
733        // Get the session Map & check session doesn't exist
734        Map<String, Object> sessionMap = ctx.getSessionScope();
735        assertNull(ctx.getRequest().getSession(false), "Session(B)");
736        assertNotNull(sessionMap, "Session Map(A)");
737
738        // test clear()
739        sessionMap.clear();
740        assertNull(ctx.getRequest().getSession(false), "Session(C)");
741
742        // test containsKey()
743        assertFalse(sessionMap.containsKey("ABC"), "containsKey()");
744        assertNull(ctx.getRequest().getSession(false), "Session(D)");
745
746        // test containsValue()
747        assertFalse(sessionMap.containsValue("ABC"), "containsValue()");
748        assertNull(ctx.getRequest().getSession(false), "Session(E)");
749
750        // test entrySet()
751        Set<Entry<String, Object>> entrySet = sessionMap.entrySet();
752        assertNotNull(entrySet, "entrySet");
753        assertEquals(0, entrySet.size(), "entrySet Size");
754        assertNull(ctx.getRequest().getSession(false), "Session(F)");
755
756        // test equals()
757        assertFalse(sessionMap.equals(Collections.singletonMap("ABC", "ABC")), "equals()");
758        assertNull(ctx.getRequest().getSession(false), "Session(G)");
759
760        // test get()
761        assertNull(sessionMap.get("ABC"), "get()");
762        assertNull(ctx.getRequest().getSession(false), "Session(H)");
763
764        // test hashCode()
765        sessionMap.hashCode();
766        assertNull(ctx.getRequest().getSession(false), "Session(I)");
767
768        // test isEmpty()
769        assertTrue(sessionMap.isEmpty(), "isEmpty()");
770        assertNull(ctx.getRequest().getSession(false), "Session(J)");
771
772        // test keySet()
773        Set<String> keySet = sessionMap.keySet();
774        assertNotNull(keySet, "keySet");
775        assertEquals(0, keySet.size(), "keySet Size");
776        assertNull(ctx.getRequest().getSession(false), "Session(K)");
777
778        // test putAll() with an empty Map
779        sessionMap.putAll(new HashMap<>());
780        assertNull(ctx.getRequest().getSession(false), "Session(L)");
781
782        // test remove()
783        assertNull(sessionMap.remove("ABC"), "remove()");
784        assertNull(ctx.getRequest().getSession(false), "Session(M)");
785
786        // test size()
787        assertEquals(0, sessionMap.size(), "size() Size");
788        assertNull(ctx.getRequest().getSession(false), "Session(N)");
789
790        // test values()
791        Collection<Object> values = sessionMap.values();
792        assertNotNull(values, "values");
793        assertEquals(0, values.size(), "values Size");
794        assertNull(ctx.getRequest().getSession(false), "Session(O)");
795
796        // test put()
797        try {
798            assertNull(sessionMap.put("ABC", "XYZ"), "put()");
799            assertNotNull(ctx.getRequest().getSession(false), "Session(P)");
800        } catch(UnsupportedOperationException ex) {
801            // expected: currently MockHttpServletRequest throws this
802            //           when trying to create a HttpSession
803        }
804    }
805
806    // ------------------------------------------------------- Protected Methods
807
808    protected void checkMapSize(Map<String, ?> map, int size) {
809        // Check reported size of the map
810        assertEquals(size, map.size());
811        // Iterate over key set
812        int nk = 0;
813        Iterator<String> keys = map.keySet().iterator();
814        while (keys.hasNext()) {
815            keys.next();
816            nk++;
817        }
818        assertEquals(size, nk);
819        // Iterate over entry set
820        int nv = 0;
821        Iterator<?> values = map.entrySet().iterator();
822        while (values.hasNext()) {
823            values.next();
824            nv++;
825        }
826        assertEquals(size, nv);
827        // Count the values
828        assertEquals(size, map.values().size());
829    }
830
831    /**
832     * Test to ensure proper entrySet() and are modifiable optionally
833     *
834     * @param map to test
835     * @param modifiable {@code true} if map is modifiable
836     */
837    protected void checkEntrySet(Map<String, ?> map, boolean modifiable) {
838        assertTrue(map.size() > 1);
839        Set<?> entries = map.entrySet();
840        assertEquals(map.size(), entries.size());
841        Object o = entries.iterator().next();
842
843        assertInstanceOf(Map.Entry.class, o);
844
845        @SuppressWarnings("unchecked")
846        Map.Entry<?, Object> mapEntry = (Map.Entry<?, Object>)o;
847        if (!modifiable) {
848            try {
849                mapEntry.setValue(new Object());
850                fail("Should have thrown UnsupportedOperationException");
851            } catch (UnsupportedOperationException e) {
852                ; // expected result
853            }
854        } else {
855            // Should pass and not throw UnsupportedOperationException
856            mapEntry.setValue(mapEntry.setValue(new Object()));
857        }
858    }
859
860    /**
861     * Create a new instance of the appropriate Context type for this test case
862     *
863     * @return a new instance of the appropriate Context type
864     */
865    @Override
866    protected ServletWebContext createContext() {
867        return new ServletWebContext(scontext, request, response);
868    }
869}