UtilTest.java 11.6 KB
Newer Older
K
kohsuke 已提交
1 2 3
/*
 * The MIT License
 * 
4 5
 * Copyright (c) 2004-2010, Sun Microsystems, Inc., Kohsuke Kawaguchi,
 * Daniel Dyer, Erik Ramfelt, Richard Bair, id:cactusman
K
kohsuke 已提交
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
K
kohsuke 已提交
25 26 27 28
package hudson;

import java.util.Map;
import java.util.HashMap;
29
import java.util.Locale;
30
import java.io.ByteArrayOutputStream;
K
kohsuke 已提交
31
import java.io.File;
32
import java.io.IOException;
K
kohsuke 已提交
33

34
import static org.junit.Assert.*;
35
import org.junit.Assume;
36
import org.junit.Test;
37 38
import org.jvnet.hudson.test.Bug;

K
kohsuke 已提交
39
import hudson.util.StreamTaskListener;
K
kohsuke 已提交
40 41 42 43

/**
 * @author Kohsuke Kawaguchi
 */
44 45
public class UtilTest {
    @Test
K
kohsuke 已提交
46 47 48 49 50
    public void testReplaceMacro() {
        Map<String,String> m = new HashMap<String,String>();
        m.put("A","a");
        m.put("AA","aa");
        m.put("B","B");
51 52
        m.put("DOLLAR", "$");
        m.put("ENCLOSED", "a${A}");
K
kohsuke 已提交
53 54 55 56 57 58

        // longest match
        assertEquals("aa",Util.replaceMacro("$AA",m));

        // invalid keys are ignored
        assertEquals("$AAB",Util.replaceMacro("$AAB",m));
59

60 61 62
        assertEquals("aaB",Util.replaceMacro("${AA}B",m));
        assertEquals("${AAB}",Util.replaceMacro("${AAB}",m));

63 64
        // $ escaping
        assertEquals("asd$${AA}dd", Util.replaceMacro("asd$$$${AA}dd",m));
K
kohsuke 已提交
65 66
        assertEquals("$", Util.replaceMacro("$$",m));
        assertEquals("$$", Util.replaceMacro("$$$$",m));
67

68
    	// test that more complex scenarios work
69
        assertEquals("/a/B/aa", Util.replaceMacro("/$A/$B/$AA",m));
70 71
        assertEquals("a-aa", Util.replaceMacro("$A-$AA",m));
        assertEquals("/a/foo/can/B/you-believe_aa~it?", Util.replaceMacro("/$A/foo/can/$B/you-believe_$AA~it?",m));
72
        assertEquals("$$aa$Ba${A}$it", Util.replaceMacro("$$$DOLLAR${AA}$$B${ENCLOSED}$it",m));
K
kohsuke 已提交
73
    }
74

75
    @Test
76 77 78 79 80 81
    public void testTimeSpanString() {
        // Check that amounts less than 365 days are not rounded up to a whole year.
        // In the previous implementation there were 360 days in a year.
        // We're still working on the assumption that a month is 30 days, so there will
        // be 5 days at the end of the year that will be "12 months" but not "1 year".
        // First check 359 days.
C
cactusman 已提交
82
        assertEquals(Messages.Util_month(11), Util.getTimeSpanString(31017600000L));
83
        // And 362 days.
C
cactusman 已提交
84
        assertEquals(Messages.Util_month(12), Util.getTimeSpanString(31276800000L));
85 86

        // 11.25 years - Check that if the first unit has 2 or more digits, a second unit isn't used.
C
cactusman 已提交
87
        assertEquals(Messages.Util_year(11), Util.getTimeSpanString(354780000000L));
88
        // 9.25 years - Check that if the first unit has only 1 digit, a second unit is used.
C
cactusman 已提交
89
        assertEquals(Messages.Util_year(9)+ " " + Messages.Util_month(3), Util.getTimeSpanString(291708000000L));
90
        // 67 seconds
C
cactusman 已提交
91
        assertEquals(Messages.Util_minute(1) + " " + Messages.Util_second(7), Util.getTimeSpanString(67000L));
92
        // 17 seconds - Check that times less than a minute only use seconds.
C
cactusman 已提交
93
        assertEquals(Messages.Util_second(17), Util.getTimeSpanString(17000L));
94 95 96 97 98
        // 1712ms -> 1.7sec
        assertEquals(Messages.Util_second(1.7), Util.getTimeSpanString(1712L));
        // 171ms -> 0.17sec
        assertEquals(Messages.Util_second(0.17), Util.getTimeSpanString(171L));
        // 101ms -> 0.10sec
99
        assertEquals(Messages.Util_second(0.1), Util.getTimeSpanString(101L));
100 101 102 103
        // 17ms
        assertEquals(Messages.Util_millisecond(17), Util.getTimeSpanString(17L));
        // 1ms
        assertEquals(Messages.Util_millisecond(1), Util.getTimeSpanString(1L));
104 105 106 107 108 109 110 111 112
        // Test HUDSON-2843 (locale with comma as fraction separator got exception for <10 sec)
        Locale saveLocale = Locale.getDefault();
        Locale.setDefault(Locale.GERMANY);
        try {
            // Just verifying no exception is thrown:
            assertNotNull("German locale", Util.getTimeSpanString(1234));
            assertNotNull("German locale <1 sec", Util.getTimeSpanString(123));
        }
        finally { Locale.setDefault(saveLocale); }
113
    }
C
cactusman 已提交
114

115 116 117 118

    /**
     * Test that Strings that contain spaces are correctly URL encoded.
     */
119
    @Test
120 121 122 123 124
    public void testEncodeSpaces() {
        final String urlWithSpaces = "http://hudson/job/Hudson Job";
        String encoded = Util.encode(urlWithSpaces);
        assertEquals(encoded, "http://hudson/job/Hudson%20Job");
    }
125
        
126 127 128
    /**
     * Test the rawEncode() method.
     */
129
    @Test
130 131 132 133
    public void testRawEncode() {
        String[] data = {  // Alternating raw,encoded
            "abcdefghijklmnopqrstuvwxyz", "abcdefghijklmnopqrstuvwxyz",
            "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
134
            "01234567890!@$&*()-_=+',.", "01234567890!@$&*()-_=+',.",
135 136
            " \"#%/:;<>?", "%20%22%23%25%2F%3A%3B%3C%3E%3F",
            "[\\]^`{|}~", "%5B%5C%5D%5E%60%7B%7C%7D%7E",
137
            "d\u00E9velopp\u00E9s", "d%C3%A9velopp%C3%A9s",
138 139 140 141 142 143
        };
        for (int i = 0; i < data.length; i += 2) {
            assertEquals("test " + i, data[i + 1], Util.rawEncode(data[i]));
        }
    }

144 145 146
    /**
     * Test the tryParseNumber() method.
     */
147
    @Test
148 149 150 151 152 153
    public void testTryParseNumber() {
        assertEquals("Successful parse did not return the parsed value", 20, Util.tryParseNumber("20", 10).intValue());
        assertEquals("Failed parse did not return the default value", 10, Util.tryParseNumber("ss", 10).intValue());
        assertEquals("Parsing empty string did not return the default value", 10, Util.tryParseNumber("", 10).intValue());
        assertEquals("Parsing null string did not return the default value", 10, Util.tryParseNumber(null, 10).intValue());
    }
K
kohsuke 已提交
154

155
    @Test
K
kohsuke 已提交
156
    public void testSymlink() throws Exception {
157
        Assume.assumeTrue(!Functions.isWindows());
K
kohsuke 已提交
158

159 160
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        StreamTaskListener l = new StreamTaskListener(baos);
K
kohsuke 已提交
161 162 163
        File d = Util.createTempDir();
        try {
            new FilePath(new File(d, "a")).touch(0);
164
            assertNull(Util.resolveSymlink(new File(d, "a")));
K
kohsuke 已提交
165
            Util.createSymlink(d,"a","x", l);
166
            assertEquals("a",Util.resolveSymlink(new File(d,"x")));
K
kohsuke 已提交
167 168 169 170

            // test a long name
            StringBuilder buf = new StringBuilder(768);
            for( int i=0; i<768; i++)
171
                buf.append((char)('0'+(i%10)));
K
kohsuke 已提交
172
            Util.createSymlink(d,buf.toString(),"x", l);
173 174

            String log = baos.toString();
175
            if (log.length() > 0)
176 177
                System.err.println("log output: " + log);

178
            assertEquals(buf.toString(),Util.resolveSymlink(new File(d,"x")));
179 180 181 182 183 184 185
            
            
            // test linking from another directory
            File anotherDir = new File(d,"anotherDir");
            assertTrue("Couldn't create "+anotherDir,anotherDir.mkdir());
            
            Util.createSymlink(d,"a","anotherDir/link",l);
186
            assertEquals("a",Util.resolveSymlink(new File(d,"anotherDir/link")));
187 188 189
            
            // JENKINS-12331: either a bug in createSymlink or this isn't supposed to work: 
            //assertTrue(Util.isSymlink(new File(d,"anotherDir/link")));
190 191 192 193 194 195 196 197

            File external = File.createTempFile("something", "");
            try {
                Util.createSymlink(d, external.getAbsolutePath(), "outside", l);
                assertEquals(external.getAbsolutePath(), Util.resolveSymlink(new File(d, "outside")));
            } finally {
                assertTrue(external.delete());
            }
198 199 200 201 202
        } finally {
            Util.deleteRecursive(d);
        }
    }
    
203
    @Test
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227
    public void testIsSymlink() throws IOException, InterruptedException {
        Assume.assumeTrue(!Functions.isWindows());
        
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        StreamTaskListener l = new StreamTaskListener(baos);
        File d = Util.createTempDir();
        try {
            new FilePath(new File(d, "original")).touch(0);
            assertFalse(Util.isSymlink(new File(d, "original")));
            Util.createSymlink(d,"original","link", l);
            
            assertTrue(Util.isSymlink(new File(d, "link")));
            
            // test linking to another directory
            File dir = new File(d,"dir");
            assertTrue("Couldn't create "+dir,dir.mkdir());
            assertFalse(Util.isSymlink(new File(d,"dir")));
            
            File anotherDir = new File(d,"anotherDir");
            assertTrue("Couldn't create "+anotherDir,anotherDir.mkdir());
            
            Util.createSymlink(d,"dir","anotherDir/symlinkDir",l);
            // JENKINS-12331: either a bug in createSymlink or this isn't supposed to work:
            // assertTrue(Util.isSymlink(new File(d,"anotherDir/symlinkDir")));
K
kohsuke 已提交
228 229 230 231
        } finally {
            Util.deleteRecursive(d);
        }
    }
S
Seiji Sogabe 已提交
232

233 234
    @Test
    public void testHtmlEscape() {
S
Seiji Sogabe 已提交
235 236
        assertEquals("<br>", Util.escape("\n"));
        assertEquals("&lt;a>", Util.escape("<a>"));
237
        assertEquals("&#039;&quot;", Util.escape("'\""));
S
Seiji Sogabe 已提交
238 239
        assertEquals("&nbsp; ", Util.escape("  "));
    }
240 241 242 243 244 245
    
    /**
     * Compute 'known-correct' digests and see if I still get them when computed concurrently
     * to another digest.
     */
    @Bug(10346)
246
    @Test
247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291
    public void testDigestThreadSafety() throws InterruptedException {
    	String a = "abcdefgh";
    	String b = "123456789";
    	
    	String digestA = Util.getDigestOf(a);
    	String digestB = Util.getDigestOf(b);
    	
    	DigesterThread t1 = new DigesterThread(a, digestA);
    	DigesterThread t2 = new DigesterThread(b, digestB);
    	
    	t1.start();
    	t2.start();
    	
    	t1.join();
    	t2.join();
    	
    	if (t1.error != null) {
    		fail(t1.error);
    	}
    	if (t2.error != null) {
    		fail(t2.error);
    	}
    }
    
    private static class DigesterThread extends Thread {
    	private String string;
		private String expectedDigest;
		
		private String error;

		public DigesterThread(String string, String expectedDigest) {
    		this.string = string;
    		this.expectedDigest = expectedDigest;
    	}
		
		public void run() {
			for (int i=0; i < 1000; i++) {
				String digest = Util.getDigestOf(this.string);
				if (!this.expectedDigest.equals(digest)) {
					this.error = "Expected " + this.expectedDigest + ", but got " + digest;
					break;
				}
			}
		}
    }
K
Kohsuke Kawaguchi 已提交
292 293 294 295 296 297 298 299 300 301

    public void testIsAbsoluteUri() {
        assertTrue(Util.isAbsoluteUri("http://foobar/"));
        assertTrue(Util.isAbsoluteUri("mailto:kk@kohsuke.org"));
        assertTrue(Util.isAbsoluteUri("d123://test/"));
        assertFalse(Util.isAbsoluteUri("foo/bar/abc:def"));
        assertFalse(Util.isAbsoluteUri("foo?abc:def"));
        assertFalse(Util.isAbsoluteUri("foo#abc:def"));
        assertFalse(Util.isAbsoluteUri("foo/bar"));
    }
K
kohsuke 已提交
302
}