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; 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.io.ByteArrayInputStream; 029import java.io.ByteArrayOutputStream; 030import java.io.ObjectInputStream; 031import java.io.ObjectOutputStream; 032import java.util.ArrayList; 033import java.util.Collection; 034import java.util.HashMap; 035import java.util.Iterator; 036import java.util.Map; 037import java.util.Set; 038 039import org.junit.jupiter.api.AfterEach; 040import org.junit.jupiter.api.BeforeEach; 041import org.junit.jupiter.api.Test; 042 043/** 044 * Test case for the {@code ContextBase} class. 045 * 046 * @author Craig R. McClanahan 047 * @version $Revision$ $Date$ 048 */ 049public abstract class ContextTestCase<C extends Context> { 050 051 // ---------------------------------------------------- Instance Variables 052 053 /** 054 * The {@link Context} instance under test. 055 */ 056 protected C context = null; 057 058 // ---------------------------------------------------------- Constructors 059 060 /** 061 * The Default-Constructor for this class. 062 */ 063 public ContextTestCase() { 064 } 065 066 // -------------------------------------------------- Overall Test Methods 067 068 /** 069 * Set up instance variables required by this test case. 070 */ 071 @BeforeEach 072 public void init() { 073 context = createContext(); 074 } 075 076 /** 077 * Tear down instance variables required by this test case. 078 */ 079 @AfterEach 080 public void tearDown() { 081 context = null; 082 } 083 084 // ------------------------------------------------ Individual Test Methods 085 086 /** 087 * Test ability to get, put, and remove attributes 088 */ 089 @Test 090 public void testAttributes() { 091 Object value = null; 092 checkAttributeCount(0); 093 094 context.put("foo", "This is foo"); 095 checkAttributeCount(1); 096 value = context.get("foo"); 097 assertNotNull(value, "Returned foo"); 098 assertInstanceOf(String.class, value, "Returned foo type"); 099 assertEquals("This is foo", value, 100 "Returned foo value"); 101 102 context.put("bar", "This is bar"); 103 checkAttributeCount(2); 104 value = context.get("bar"); 105 assertNotNull(value, "Returned bar"); 106 assertInstanceOf(String.class, value, "Returned bar type"); 107 assertEquals("This is bar", value, 108 "Returned bar value"); 109 110 context.put("baz", "This is baz"); 111 checkAttributeCount(3); 112 value = context.get("baz"); 113 assertNotNull(value, "Returned baz"); 114 assertInstanceOf(String.class, value, "Returned baz type"); 115 assertEquals("This is baz", value, 116 "Returned baz value"); 117 118 context.put("baz", "This is new baz"); 119 checkAttributeCount(3); // Replaced, not added 120 value = context.get("baz"); 121 assertNotNull(value, "Returned baz"); 122 assertInstanceOf(String.class, value, "Returned baz type"); 123 assertEquals("This is new baz", value, 124 "Returned baz value"); 125 126 context.remove("bar"); 127 checkAttributeCount(2); 128 assertNull(context.get("bar"), 129 "Did not return bar"); 130 assertNotNull(context.get("foo"), 131 "Still returned foo"); 132 assertNotNull(context.get("baz"), 133 "Still returned baz"); 134 135 context.clear(); 136 checkAttributeCount(0); 137 assertNull(context.get("foo"), 138 "Did not return foo"); 139 assertNull(context.get("bar"), 140 "Did not return bar"); 141 assertNull(context.get("baz"), 142 "Did not return baz"); 143 } 144 145 /** 146 * Test {@code containsKey()} and {@code containsValue()} 147 */ 148 @Test 149 public void testContains() { 150 assertFalse(context.containsKey("bop")); 151 assertFalse(context.containsValue("bop value")); 152 context.put("bop", "bop value"); 153 assertTrue(context.containsKey("bop")); 154 assertTrue(context.containsValue("bop value")); 155 context.remove("bop"); 156 assertFalse(context.containsKey("bop")); 157 assertFalse(context.containsValue("bop value")); 158 } 159 160 /** 161 * Test {@code equals()} and {@code hashCode()} 162 */ 163 @Test 164 public void testEquals() { 165 // Compare to self 166 assertTrue(context.equals(context)); 167 assertEquals(context.hashCode(), context.hashCode()); 168 169 // Compare to equivalent instance 170 Context other = createContext(); 171 assertTrue(context.equals(other)); 172 assertEquals(context.hashCode(), other.hashCode()); 173 174 // Compare to non-equivalent instance - other modified 175 other.put("bop", "bop value"); 176 assertFalse(context.equals(other)); 177 assertNotEquals(context.hashCode(), other.hashCode()); 178 179 // Compare to non-equivalent instance - self modified 180 other = createContext(); // reset to equivalence 181 context.put("bop", "bop value"); 182 assertFalse(context.equals(other)); 183 assertNotEquals(context.hashCode(), other.hashCode()); 184 } 185 186 /** 187 * Test {@code keySet()} 188 */ 189 @Test 190 public void testKeySet() { 191 Set<String> keySet = null; 192 Collection<String> all = new ArrayList<>(); 193 194 // Unsupported operations 195 keySet = context.keySet(); 196 try { 197 keySet.add("bop"); 198 fail("Should have thrown UnsupportedOperationException"); 199 } catch (UnsupportedOperationException e) { 200 ; // Expected result 201 } 202 try { 203 Collection<String> adds = new ArrayList<>(); 204 adds.add("bop"); 205 keySet.addAll(adds); 206 fail("Should have thrown UnsupportedOperationException"); 207 } catch (UnsupportedOperationException e) { 208 ; // Expected result 209 } 210 211 // Before-modification checks 212 keySet = context.keySet(); 213 assertEquals(createContext().size(), keySet.size()); 214 assertFalse(keySet.contains("foo")); 215 assertFalse(keySet.contains("bar")); 216 assertFalse(keySet.contains("baz")); 217 assertFalse(keySet.contains("bop")); 218 219 // Add the new elements 220 context.put("foo", "foo value"); 221 context.put("bar", "bar value"); 222 context.put("baz", "baz value"); 223 all.add("foo"); 224 all.add("bar"); 225 all.add("baz"); 226 227 // After-modification checks 228 keySet = context.keySet(); 229 assertEquals(expectedAttributeCount() + 3, keySet.size()); 230 assertTrue(keySet.contains("foo")); 231 assertTrue(keySet.contains("bar")); 232 assertTrue(keySet.contains("baz")); 233 assertFalse(keySet.contains("bop")); 234 assertTrue(keySet.containsAll(all)); 235 236 // Remove a single element via remove() 237 context.remove("bar"); 238 all.remove("bar"); 239 keySet = context.keySet(); 240 assertEquals(expectedAttributeCount() + 2, keySet.size()); 241 assertTrue(keySet.contains("foo")); 242 assertFalse(keySet.contains("bar")); 243 assertTrue(keySet.contains("baz")); 244 assertFalse(keySet.contains("bop")); 245 assertTrue(keySet.containsAll(all)); 246 247 // Remove a single element via keySet.remove() 248 keySet.remove("baz"); 249 all.remove("baz"); 250 keySet = context.keySet(); 251 assertEquals(expectedAttributeCount() + 1, keySet.size()); 252 assertTrue(keySet.contains("foo")); 253 assertFalse(keySet.contains("bar")); 254 assertFalse(keySet.contains("baz")); 255 assertFalse(keySet.contains("bop")); 256 assertTrue(keySet.containsAll(all)); 257 258 // Remove all elements via keySet.clear() 259 keySet.clear(); 260 all.clear(); 261 assertEquals(expectedAttributeCount(), keySet.size()); 262 assertFalse(keySet.contains("foo")); 263 assertFalse(keySet.contains("bar")); 264 assertFalse(keySet.contains("baz")); 265 assertFalse(keySet.contains("bop")); 266 assertTrue(keySet.containsAll(all)); 267 268 // Add the new elements #2 269 context.put("foo", "foo value"); 270 context.put("bar", "bar value"); 271 context.put("baz", "baz value"); 272 all.add("foo"); 273 all.add("bar"); 274 all.add("baz"); 275 276 // After-modification checks #2 277 keySet = context.keySet(); 278 assertEquals(expectedAttributeCount() + 3, keySet.size()); 279 assertTrue(keySet.contains("foo")); 280 assertTrue(keySet.contains("bar")); 281 assertTrue(keySet.contains("baz")); 282 assertFalse(keySet.contains("bop")); 283 assertTrue(keySet.containsAll(all)); 284 } 285 286 /** 287 * Test state of newly created instance 288 */ 289 @Test 290 public void testPristine() { 291 checkAttributeCount(0); 292 assertNull(context.get("foo"), 293 "No 'foo' attribute"); 294 } 295 296 /** 297 * Test {@code putAll()} 298 */ 299 @Test 300 public void testPutAll() { 301 // Check preconditions 302 checkAttributeCount(0); 303 assertNull(context.get("foo")); 304 assertNull(context.get("bar")); 305 assertNull(context.get("baz")); 306 assertFalse(context.containsKey("foo")); 307 assertFalse(context.containsKey("bar")); 308 assertFalse(context.containsKey("baz")); 309 assertFalse(context.containsValue("foo value")); 310 assertFalse(context.containsValue("bar value")); 311 assertFalse(context.containsValue("baz value")); 312 313 // Call putAll() 314 Map<String, String> adds = new HashMap<>(); 315 adds.put("foo", "foo value"); 316 adds.put("bar", "bar value"); 317 adds.put("baz", "baz value"); 318 context.putAll(adds); 319 320 // Check postconditions 321 checkAttributeCount(3); 322 assertEquals("foo value", context.get("foo")); 323 assertEquals("bar value", context.get("bar")); 324 assertEquals("baz value", context.get("baz")); 325 assertTrue(context.containsKey("foo")); 326 assertTrue(context.containsKey("bar")); 327 assertTrue(context.containsKey("baz")); 328 assertTrue(context.containsValue("foo value")); 329 assertTrue(context.containsValue("bar value")); 330 assertTrue(context.containsValue("baz value")); 331 } 332 333 /** 334 * Test serialization 335 * 336 * @throws Exception any error 337 */ 338 @Test 339 public void testSerialization() throws Exception { 340 // Set up the context with some parameters 341 context.put("foo", "foo value"); 342 context.put("bar", "bar value"); 343 context.put("baz", "baz value"); 344 checkAttributeCount(3); 345 346 // Serialize to a byte array 347 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 348 ObjectOutputStream oos = new ObjectOutputStream(baos); 349 oos.writeObject(context); 350 oos.close(); 351 352 // Deserialize back to a new object 353 ByteArrayInputStream bais = 354 new ByteArrayInputStream(baos.toByteArray()); 355 ObjectInputStream ois = new ObjectInputStream(bais); 356 @SuppressWarnings("unchecked") 357 C newContext = (C) ois.readObject(); 358 context = newContext; 359 ois.close(); 360 361 // Do some rudimentary checks to make sure we have the same contents 362 assertTrue(context.containsKey("foo")); 363 assertTrue(context.containsKey("bar")); 364 assertTrue(context.containsKey("baz")); 365 checkAttributeCount(3); 366 } 367 368 // -------------------------------------------------------- Support Methods 369 370 /** 371 * Verify the number of defined attributes 372 * 373 * @param expected the expected value 374 */ 375 protected void checkAttributeCount(int expected) { 376 int actual = 0; 377 Iterator<String> keys = context.keySet().iterator(); 378 while (keys.hasNext()) { 379 keys.next(); 380 actual++; 381 } 382 assertEquals(expectedAttributeCount() + expected, actual, 383 "Correct attribute count"); 384 if (expected == 0) { 385 assertTrue(context.isEmpty(), "Context should be empty"); 386 } else { 387 assertFalse(context.isEmpty(), "Context should not be empty"); 388 } 389 } 390 391 /** 392 * Return the expected {@code size()} for a Context for this test case 393 * 394 * @return the expected {@code size()} for a Context 395 */ 396 protected int expectedAttributeCount() { 397 return createContext().size(); 398 } 399 400 /** 401 * Create a new instance of the appropriate Context type for this test case 402 * 403 * @return the new instance of the appropriate Context type 404 */ 405 protected abstract C createContext(); 406}