ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/test/tck/ExecutorsTest.java
(Generate patch)

Comparing jsr166/src/test/tck/ExecutorsTest.java (file contents):
Revision 1.3 by dl, Sun Sep 14 20:42:40 2003 UTC vs.
Revision 1.5 by dl, Thu Sep 25 11:02:41 2003 UTC

# Line 12 | Line 12 | import java.util.concurrent.*;
12   import java.math.BigInteger;
13  
14   public class ExecutorsTest extends JSR166TestCase{
15    
15      public static void main(String[] args) {
16          junit.textui.TestRunner.run (suite());  
17      }
19    
20
18      public static Test suite() {
19          return new TestSuite(ExecutorsTest.class);
20      }
21  
22 +    private static final String TEST_STRING = "a test string";
23 +
24 +    private static class MyTask implements Runnable {
25 +        public void run() { completed = true; }
26 +        public boolean isCompleted() { return completed; }
27 +        public void reset() { completed = false; }
28 +        private boolean completed = false;
29 +    }
30 +
31 +    private static class StringTask implements Callable<String> {
32 +        public String call() { return TEST_STRING; }
33 +    }
34 +
35 +    static class DirectExecutor implements Executor {
36 +        public void execute(Runnable r) {
37 +            r.run();
38 +        }
39 +    }
40 +
41 +    static class TimedCallable<T> implements Callable<T> {
42 +        private final Executor exec;
43 +        private final Callable<T> func;
44 +        private final long msecs;
45 +        
46 +        TimedCallable(Executor exec, Callable<T> func, long msecs) {
47 +            this.exec = exec;
48 +            this.func = func;
49 +            this.msecs = msecs;
50 +        }
51 +        
52 +        public T call() throws Exception {
53 +            Future<T> ftask = Executors.execute(exec, func);
54 +            try {
55 +                return ftask.get(msecs, TimeUnit.MILLISECONDS);
56 +            } finally {
57 +                ftask.cancel(true);
58 +            }
59 +        }
60 +    }
61 +
62 +
63 +    private static class Fib implements Callable<BigInteger> {
64 +        private final BigInteger n;
65 +        Fib(long n) {
66 +            if (n < 0) throw new IllegalArgumentException("need non-negative arg, but got " + n);
67 +            this.n = BigInteger.valueOf(n);
68 +        }
69 +        public BigInteger call() {
70 +            BigInteger f1 = BigInteger.ONE;
71 +            BigInteger f2 = f1;
72 +            for (BigInteger i = BigInteger.ZERO; i.compareTo(n) < 0; i = i.add(BigInteger.ONE)) {
73 +                BigInteger t = f1.add(f2);
74 +                f1 = f2;
75 +                f2 = t;
76 +            }
77 +            return f1;
78 +        }
79 +    };
80 +
81 +    /**
82 +     * For use as ThreadFactory in constructors
83 +     */
84 +    static class MyThreadFactory implements ThreadFactory{
85 +        public Thread newThread(Runnable r){
86 +            return new Thread(r);
87 +        }  
88 +    }
89 +
90 +    /**
91 +     * A newCachedThreadPool can execute runnables
92 +     */
93 +    public void testNewCachedThreadPool1() {
94 +        ExecutorService e = Executors.newCachedThreadPool();
95 +        e.execute(new NoOpRunnable());
96 +        e.execute(new NoOpRunnable());
97 +        e.execute(new NoOpRunnable());
98 +        e.shutdown();
99 +    }
100 +
101 +    /**
102 +     * A newCachedThreadPool with given ThreadFactory can execute runnables
103 +     */
104 +    public void testNewCachedThreadPool2() {
105 +        ExecutorService e = Executors.newCachedThreadPool(new MyThreadFactory());
106 +        e.execute(new NoOpRunnable());
107 +        e.execute(new NoOpRunnable());
108 +        e.execute(new NoOpRunnable());
109 +        e.shutdown();
110 +    }
111 +
112 +    /**
113 +     * A newCachedThreadPool with null ThreadFactory throws NPE
114 +     */
115 +    public void testNewCachedThreadPool3() {
116 +        try {
117 +            ExecutorService e = Executors.newCachedThreadPool(null);
118 +            shouldThrow();
119 +        }
120 +        catch(NullPointerException success) {
121 +        }
122 +    }
123 +
124 +
125 +    /**
126 +     * A new SingleThreadExecutor can execute runnables
127 +     */
128 +    public void testNewSingleThreadExecutor1() {
129 +        ExecutorService e = Executors.newSingleThreadExecutor();
130 +        e.execute(new NoOpRunnable());
131 +        e.execute(new NoOpRunnable());
132 +        e.execute(new NoOpRunnable());
133 +        e.shutdown();
134 +    }
135 +
136      /**
137 <     *   execute(Executor, Runnable) will throw
27 <     *  RejectedExecutionException Attempting to execute a runnable on
28 <     *  a full ThreadPool will cause such an exception here, up to 5
29 <     *  runnables are attempted on a pool capable on handling one
30 <     *  until it throws an exception
137 >     * A new SingleThreadExecutor with given ThreadFactory can execute runnables
138       */
139 <    public void testExecute1(){
139 >    public void testNewSingleThreadExecutor2() {
140 >        ExecutorService e = Executors.newSingleThreadExecutor(new MyThreadFactory());
141 >        e.execute(new NoOpRunnable());
142 >        e.execute(new NoOpRunnable());
143 >        e.execute(new NoOpRunnable());
144 >        e.shutdown();
145 >    }
146 >
147 >    /**
148 >     * A new SingleThreadExecutor with null ThreadFactory throws NPE
149 >     */
150 >    public void testNewSingleThreadExecutor3() {
151 >        try {
152 >            ExecutorService e = Executors.newSingleThreadExecutor(null);
153 >            shouldThrow();
154 >        }
155 >        catch(NullPointerException success) {
156 >        }
157 >    }
158 >
159 >    /**
160 >     * A new newFixedThreadPool can execute runnables
161 >     */
162 >    public void testNewFixedThreadPool1() {
163 >        ExecutorService e = Executors.newFixedThreadPool(2);
164 >        e.execute(new NoOpRunnable());
165 >        e.execute(new NoOpRunnable());
166 >        e.execute(new NoOpRunnable());
167 >        e.shutdown();
168 >    }
169 >
170 >    /**
171 >     * A new newFixedThreadPool with given ThreadFactory can execute runnables
172 >     */
173 >    public void testNewFixedThreadPool2() {
174 >        ExecutorService e = Executors.newFixedThreadPool(2, new MyThreadFactory());
175 >        e.execute(new NoOpRunnable());
176 >        e.execute(new NoOpRunnable());
177 >        e.execute(new NoOpRunnable());
178 >        e.shutdown();
179 >    }
180 >
181 >    /**
182 >     * A new newFixedThreadPool with null ThreadFactory throws NPE
183 >     */
184 >    public void testNewFixedThreadPool3() {
185 >        try {
186 >            ExecutorService e = Executors.newFixedThreadPool(2, null);
187 >            shouldThrow();
188 >        }
189 >        catch(NullPointerException success) {
190 >        }
191 >    }
192 >
193 >    /**
194 >     * A new newFixedThreadPool with 0 threads throws IAE
195 >     */
196 >    public void testNewFixedThreadPool4() {
197 >        try {
198 >            ExecutorService e = Executors.newFixedThreadPool(0);
199 >            shouldThrow();
200 >        }
201 >        catch(IllegalArgumentException success) {
202 >        }
203 >    }
204 >
205 >    /**
206 >     * execute of runnable runs it to completion
207 >     */
208 >    public void testExecuteRunnable () {
209 >        try {
210 >            Executor e = new DirectExecutor();
211 >            MyTask task = new MyTask();
212 >            assertFalse(task.isCompleted());
213 >            Future<String> future = Executors.execute(e, task, TEST_STRING);
214 >            String result = future.get();
215 >            assertTrue(task.isCompleted());
216 >            assertSame(TEST_STRING, result);
217 >        }
218 >        catch (ExecutionException ex) {
219 >            unexpectedException();
220 >        }
221 >        catch (InterruptedException ex) {
222 >            unexpectedException();
223 >        }
224 >    }
225 >
226 >    /**
227 >     * invoke of a runnable runs it to completion
228 >     */
229 >    public void testInvokeRunnable () {
230 >        try {
231 >            Executor e = new DirectExecutor();
232 >            MyTask task = new MyTask();
233 >            assertFalse(task.isCompleted());
234 >            Executors.invoke(e, task);
235 >            assertTrue(task.isCompleted());
236 >        }
237 >        catch (ExecutionException ex) {
238 >            unexpectedException();
239 >        }
240 >        catch (InterruptedException ex) {
241 >            unexpectedException();
242 >        }
243 >    }
244 >
245 >    /**
246 >     * execute of a callable runs it to completion
247 >     */
248 >    public void testExecuteCallable () {
249 >        try {
250 >            Executor e = new DirectExecutor();
251 >            Future<String> future = Executors.execute(e, new StringTask());
252 >            String result = future.get();
253 >            assertSame(TEST_STRING, result);
254 >        }
255 >        catch (ExecutionException ex) {
256 >            unexpectedException();
257 >        }
258 >        catch (InterruptedException ex) {
259 >            unexpectedException();
260 >        }
261 >    }
262 >
263 >    /**
264 >     * invoke of a collable runs it to completion
265 >     */
266 >    public void testInvokeCallable () {
267 >        try {
268 >            Executor e = new DirectExecutor();
269 >            String result = Executors.invoke(e, new StringTask());
270 >
271 >            assertSame(TEST_STRING, result);
272 >        }
273 >        catch (ExecutionException ex) {
274 >            unexpectedException();
275 >        }
276 >        catch (InterruptedException ex) {
277 >            unexpectedException();
278 >        }
279 >    }
280 >
281 >    /**
282 >     * execute with null executor throws NPE
283 >     */
284 >    public void testNullExecuteRunnable () {
285 >        try {
286 >            MyTask task = new MyTask();
287 >            assertFalse(task.isCompleted());
288 >            Future<String> future = Executors.execute(null, task, TEST_STRING);
289 >            shouldThrow();
290 >        }
291 >        catch (NullPointerException success) {
292 >        }
293 >        catch (Exception ex) {
294 >            unexpectedException();
295 >        }
296 >    }
297 >
298 >    /**
299 >     * execute with a null runnable throws NPE
300 >     */
301 >    public void testExecuteNullRunnable() {
302 >        try {
303 >            Executor e = new DirectExecutor();
304 >            MyTask task = null;
305 >            Future<String> future = Executors.execute(e, task, TEST_STRING);
306 >            shouldThrow();
307 >        }
308 >        catch (NullPointerException success) {
309 >        }
310 >        catch (Exception ex) {
311 >            unexpectedException();
312 >        }
313 >    }
314 >
315 >    /**
316 >     * invoke of a null runnable throws NPE
317 >     */
318 >    public void testInvokeNullRunnable () {
319 >        try {
320 >            Executor e = new DirectExecutor();
321 >            MyTask task = null;
322 >            Executors.invoke(e, task);
323 >            shouldThrow();
324 >        }
325 >        catch (NullPointerException success) {
326 >        }
327 >        catch (Exception ex) {
328 >            unexpectedException();
329 >        }
330 >    }
331 >
332 >    /**
333 >     * execute of a null callable throws NPE
334 >     */
335 >    public void testExecuteNullCallable () {
336 >        try {
337 >            Executor e = new DirectExecutor();
338 >            StringTask t = null;
339 >            Future<String> future = Executors.execute(e, t);
340 >            shouldThrow();
341 >        }
342 >        catch (NullPointerException success) {
343 >        }
344 >        catch (Exception ex) {
345 >            unexpectedException();
346 >        }
347 >    }
348 >
349 >    /**
350 >     * invoke of a null callable throws NPE
351 >     */
352 >    public void testInvokeNullCallable () {
353 >        try {
354 >            Executor e = new DirectExecutor();
355 >            StringTask t = null;
356 >            String result = Executors.invoke(e, t);
357 >            shouldThrow();
358 >        }
359 >        catch (NullPointerException success) {
360 >        }
361 >        catch (Exception ex) {
362 >            unexpectedException();
363 >        }
364 >    }
365 >
366 >    /**
367 >     *  execute(Executor, Runnable) throws RejectedExecutionException
368 >     *  if saturated.
369 >     */
370 >    public void testExecute1() {
371          ThreadPoolExecutor p = new ThreadPoolExecutor(1,1, SHORT_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(1));
372 <        try{
372 >        try {
373              
374              for(int i = 0; i < 5; ++i){
375                  Executors.execute(p, new MediumRunnable(), Boolean.TRUE);
376              }
377 <            fail("should throw");
377 >            shouldThrow();
378          } catch(RejectedExecutionException success){}
379          joinPool(p);
380      }
381  
382      /**
383 <     *   execute(Executor, Callable) will throw
384 <     *  RejectedExecutionException Attempting to execute a callable on
47 <     *  a full ThreadPool will cause such an exception here, up to 5
48 <     *  runnables are attempted on a pool capable on handling one
49 <     *  until it throws an exception
383 >     *  execute(Executor, Callable)throws RejectedExecutionException
384 >     *  if saturated.
385       */
386 <    public void testExecute2(){
386 >    public void testExecute2() {
387           ThreadPoolExecutor p = new ThreadPoolExecutor(1,1, SHORT_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(1));
388 <        try{
388 >        try {
389              for(int i = 0; i < 5; ++i) {
390                  Executors.execute(p, new SmallCallable());
391              }
392 <            fail("should throw");
393 <        }catch(RejectedExecutionException e){}
392 >            shouldThrow();
393 >        } catch(RejectedExecutionException e){}
394          joinPool(p);
395      }
396  
397  
398      /**
399 <     *   invoke(Executor, Runnable) throws InterruptedException
400 <     *  A single use of invoke starts that will wait long enough
66 <     *  for the invoking thread to be interrupted
399 >     *  invoke(Executor, Runnable) throws InterruptedException if
400 >     *  caller interrupted.
401       */
402 <    public void testInvoke2(){
402 >    public void testInterruptedInvoke() {
403          final ThreadPoolExecutor p = new ThreadPoolExecutor(1,1,SHORT_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
404          Thread t = new Thread(new Runnable() {
405 <                public void run(){
406 <                    try{
407 <                        Executors.invoke(p,new Runnable(){
408 <                                public void run(){
409 <                                    try{
405 >                public void run() {
406 >                    try {
407 >                        Executors.invoke(p,new Runnable() {
408 >                                public void run() {
409 >                                    try {
410                                          Thread.sleep(MEDIUM_DELAY_MS);
411 <                                        fail("should throw");
412 <                                    }catch(InterruptedException e){
411 >                                        shouldThrow();
412 >                                    } catch(InterruptedException e){
413                                      }
414                                  }
415                              });
416                      } catch(InterruptedException success){
417                      } catch(Exception e) {
418 <                        fail("unexpected exception");
418 >                        unexpectedException();
419                      }
420                      
421                  }
422              });
423 <        try{
423 >        try {
424              t.start();
425              Thread.sleep(SHORT_DELAY_MS);
426              t.interrupt();
427 <        }catch(Exception e){
428 <            fail("unexpected exception");
427 >        } catch(Exception e){
428 >            unexpectedException();
429          }
430          joinPool(p);
431      }
432  
433      /**
434 <     *   invoke(Executor, Runnable) will throw
435 <     *  ExecutionException An ExecutionException occurs when the
102 <     *  underlying Runnable throws an exception, here the
103 <     *  DivideByZeroException will cause an ExecutionException
434 >     *  invoke(Executor, Runnable) throws ExecutionException if
435 >     *  runnable throws exception.
436       */
437 <    public void testInvoke3(){
437 >    public void testInvoke3() {
438          ThreadPoolExecutor p = new ThreadPoolExecutor(1,1,SHORT_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
439 <        try{
440 <            Runnable r = new Runnable(){
441 <                    public void run(){
439 >        try {
440 >            Runnable r = new Runnable() {
441 >                    public void run() {
442                          int i = 5/0;
443                      }
444                  };
# Line 115 | Line 447 | public class ExecutorsTest extends JSR16
447                  Executors.invoke(p,r);
448              }
449              
450 <            fail("should throw");
450 >            shouldThrow();
451          } catch(ExecutionException success){
452          } catch(Exception e){
453 <            fail("should throw EE");
453 >            unexpectedException();
454          }
455          joinPool(p);
456      }
# Line 126 | Line 458 | public class ExecutorsTest extends JSR16
458  
459  
460      /**
461 <     *   invoke(Executor, Callable) throws
462 <     *  InterruptedException A single use of invoke starts that will
131 <     *  wait long enough for the invoking thread to be interrupted
461 >     *  invoke(Executor, Callable) throws InterruptedException if
462 >     *  callable throws exception
463       */
464 <    public void testInvoke5(){
464 >    public void testInvoke5() {
465          final ThreadPoolExecutor p = new ThreadPoolExecutor(1,1,SHORT_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
466          
467 <        final Callable c = new Callable(){
468 <                public Object call(){
469 <                    try{
467 >        final Callable c = new Callable() {
468 >                public Object call() {
469 >                    try {
470                          Executors.invoke(p, new SmallCallable());
471 <                        fail("should throw");
472 <                    }catch(InterruptedException e){}
471 >                        shouldThrow();
472 >                    } catch(InterruptedException e){}
473                      catch(RejectedExecutionException e2){}
474                      catch(ExecutionException e3){}
475                      return Boolean.TRUE;
# Line 147 | Line 478 | public class ExecutorsTest extends JSR16
478  
479  
480          
481 <        Thread t = new Thread(new Runnable(){
482 <                public void run(){
483 <                    try{
481 >        Thread t = new Thread(new Runnable() {
482 >                public void run() {
483 >                    try {
484                          c.call();
485 <                    }catch(Exception e){}
485 >                    } catch(Exception e){}
486                  }
487            });
488 <        try{
488 >        try {
489              t.start();
490              Thread.sleep(SHORT_DELAY_MS);
491              t.interrupt();
492              t.join();
493 <        }catch(InterruptedException e){
494 <            fail("unexpected exception");
493 >        } catch(InterruptedException e){
494 >            unexpectedException();
495          }
496          
497          joinPool(p);
498      }
499  
500      /**
501 <     *   invoke(Executor, Callable) will throw ExecutionException
502 <     *  An ExecutionException occurs when the underlying Runnable throws
172 <     *  an exception, here the DivideByZeroException will cause an ExecutionException
501 >     *  invoke(Executor, Callable) will throw ExecutionException
502 >     *  if callable throws exception
503       */
504 <    public void testInvoke6(){
504 >    public void testInvoke6() {
505          ThreadPoolExecutor p = new ThreadPoolExecutor(1,1,SHORT_DELAY_MS, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10));
506  
507 <        try{
508 <            Callable c = new Callable(){
509 <                    public Object call(){
507 >        try {
508 >            Callable c = new Callable() {
509 >                    public Object call() {
510                          int i = 5/0;
511                          return Boolean.TRUE;
512                      }
# Line 186 | Line 516 | public class ExecutorsTest extends JSR16
516                  Executors.invoke(p,c);
517              }
518              
519 <            fail("should throw");
520 <        }catch(RejectedExecutionException e){}
521 <        catch(InterruptedException e2){}
522 <        catch(ExecutionException e3){}
523 <        joinPool(p);
194 <    }
195 <
196 <    public void testExecuteRunnable () {
197 <        try {
198 <            Executor e = new DirectExecutor();
199 <            Task task = new Task();
200 <
201 <            assertFalse("task should not be complete", task.isCompleted());
202 <
203 <            Future<String> future = Executors.execute(e, task, TEST_STRING);
204 <            String result = future.get();
205 <
206 <            assertTrue("task should be complete", task.isCompleted());
207 <            assertSame("should return test string", TEST_STRING, result);
208 <        }
209 <        catch (ExecutionException ex) {
210 <            fail("Unexpected exception");
519 >            shouldThrow();
520 >        }
521 >        catch(ExecutionException success){
522 >        } catch(Exception e) {
523 >            unexpectedException();
524          }
525 <        catch (InterruptedException ex) {
213 <            fail("Unexpected exception");
214 <        }
215 <    }
216 <
217 <    public void testInvokeRunnable () {
218 <        try {
219 <            Executor e = new DirectExecutor();
220 <            Task task = new Task();
221 <
222 <            assertFalse("task should not be complete", task.isCompleted());
223 <
224 <            Executors.invoke(e, task);
225 <
226 <            assertTrue("task should be complete", task.isCompleted());
227 <        }
228 <        catch (ExecutionException ex) {
229 <            fail("Unexpected exception");
230 <        }
231 <        catch (InterruptedException ex) {
232 <            fail("Unexpected exception");
233 <        }
234 <    }
235 <
236 <    public void testExecuteCallable () {
237 <        try {
238 <            Executor e = new DirectExecutor();
239 <            Future<String> future = Executors.execute(e, new StringTask());
240 <            String result = future.get();
241 <
242 <            assertSame("should return test string", TEST_STRING, result);
243 <        }
244 <        catch (ExecutionException ex) {
245 <            fail("Unexpected exception");
246 <        }
247 <        catch (InterruptedException ex) {
248 <            fail("Unexpected exception");
249 <        }
250 <    }
251 <
252 <    public void testInvokeCallable () {
253 <        try {
254 <            Executor e = new DirectExecutor();
255 <            String result = Executors.invoke(e, new StringTask());
256 <
257 <            assertSame("should return test string", TEST_STRING, result);
258 <        }
259 <        catch (ExecutionException ex) {
260 <            fail("Unexpected exception" );
261 <        }
262 <        catch (InterruptedException ex) {
263 <            fail("Unexpected exception");
264 <        }
265 <    }
266 <
267 <    private static final String TEST_STRING = "a test string";
268 <
269 <    private static class Task implements Runnable {
270 <        public void run() { completed = true; }
271 <        public boolean isCompleted() { return completed; }
272 <        public void reset() { completed = false; }
273 <        private boolean completed = false;
525 >        joinPool(p);
526      }
527  
276    private static class StringTask implements Callable<String> {
277        public String call() { return TEST_STRING; }
278    }
528  
280    static class DirectExecutor implements Executor {
281        public void execute(Runnable r) {
282            r.run();
283        }
284    }
529  
530      /**
531 <     * Check that timeouts from execute will time out if they compute
288 <     * too long.
531 >     *  timeouts from execute will time out if they compute too long.
532       */
290
533      public void testTimedCallable() {
534          int N = 10000;
535          ExecutorService executor = Executors.newSingleThreadExecutor();
# Line 313 | Line 555 | public class ExecutorsTest extends JSR16
555                      return;
556                  }
557                  catch (Exception e) {
558 <                    fail("unexpected exception: " + e);
558 >                    unexpectedException();
559                  }
560              }
561              // if by chance we didn't ever time out, total time must be small
# Line 326 | Line 568 | public class ExecutorsTest extends JSR16
568      }
569  
570      
329    static class TimedCallable<T> implements Callable<T> {
330        private final Executor exec;
331        private final Callable<T> func;
332        private final long msecs;
333        
334        TimedCallable(Executor exec, Callable<T> func, long msecs) {
335            this.exec = exec;
336            this.func = func;
337            this.msecs = msecs;
338        }
339        
340        public T call() throws Exception {
341            Future<T> ftask = Executors.execute(exec, func);
342            try {
343                return ftask.get(msecs, TimeUnit.MILLISECONDS);
344            } finally {
345                ftask.cancel(true);
346            }
347        }
348    }
349
350
351    private static class Fib implements Callable<BigInteger> {
352        private final BigInteger n;
353        Fib(long n) {
354            if (n < 0) throw new IllegalArgumentException("need non-negative arg, but got " + n);
355            this.n = BigInteger.valueOf(n);
356        }
357        public BigInteger call() {
358            BigInteger f1 = BigInteger.ONE;
359            BigInteger f2 = f1;
360            for (BigInteger i = BigInteger.ZERO; i.compareTo(n) < 0; i = i.add(BigInteger.ONE)) {
361                BigInteger t = f1.add(f2);
362                f1 = f2;
363                f2 = t;
364            }
365            return f1;
366        }
367    };
368
571  
572  
573   }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines