1/*
2 * Copyright 2008 the original author or authors.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.mockftpserver.fake.filesystem
17
18import org.apache.log4j.Logger
19import org.mockftpserver.core.util.IoUtil
20
21/**
22 * Tests for FileEntry
23 *
24 * @version $Revision$ - $Date$
25 *
26 * @author Chris Mair
27 */
28public class FileEntryTest extends AbstractFileSystemEntryTest {
29
30    private static final LOG = Logger.getLogger(FileEntryTest)
31    private static final CONTENTS = "abc 123 %^& xxx"
32
33    private FileEntry entry
34
35    void testConstructorWithStringContents() {
36        entry = new FileEntry(PATH, CONTENTS)
37        verifyContents(CONTENTS)
38    }
39
40    void testSettingContentsFromString() {
41        entry.setContents(CONTENTS)
42        verifyContents(CONTENTS)
43    }
44
45    void testSettingContentsFromBytes() {
46        byte[] contents = CONTENTS.getBytes()
47        entry.setContents(contents)
48        // Now corrupt the original byte array to make sure the file entry is not affected
49        contents[1] = (byte) '#'
50        verifyContents(CONTENTS)
51    }
52
53    void testSetContents_BytesNotInCharSet() {
54        byte[] contents = [65, -99, 91, -115] as byte[]
55        entry.setContents(contents)
56        verifyContents(contents)
57    }
58
59    void testSetContents_NullString() {
60        entry.setContents((String) null)
61        assert entry.size == 0
62    }
63
64    void testSetContents_NullBytes() {
65        entry.setContents((byte[]) null)
66        assert entry.size == 0
67    }
68
69    void testCreateOutputStream() {
70        // New, empty file
71        OutputStream out = entry.createOutputStream(false)
72        out.write(CONTENTS.getBytes())
73        verifyContents(CONTENTS)
74
75        // Another OutputStream, append=false
76        out = entry.createOutputStream(false)
77        out.write(CONTENTS.getBytes())
78        verifyContents(CONTENTS)
79
80        // Another OutputStream, append=true
81        out = entry.createOutputStream(true)
82        out.write(CONTENTS.getBytes())
83        verifyContents(CONTENTS + CONTENTS)
84
85        // Set contents directly
86        final String NEW_CONTENTS = ",./'\t\r[]-\n="
87        entry.setContents(NEW_CONTENTS)
88        verifyContents(NEW_CONTENTS)
89
90        // New OutputStream, append=true (so should append to contents we set directly)
91        out = entry.createOutputStream(true)
92        out.write(CONTENTS.getBytes())
93        verifyContents(NEW_CONTENTS + CONTENTS)
94
95        // Yet another OutputStream, append=true (so should append to accumulated contents)
96        OutputStream out2 = entry.createOutputStream(true)
97        out2.write(CONTENTS.getBytes())
98        out2.close()       // should have no effect
99        verifyContents(NEW_CONTENTS + CONTENTS + CONTENTS)
100
101        // Write with the previous OutputStream (simulate 2 OututStreams writing "concurrently")
102        out.write(NEW_CONTENTS.getBytes())
103        verifyContents(NEW_CONTENTS + CONTENTS + CONTENTS + NEW_CONTENTS)
104    }
105
106    void testCreateInputStream_NullContents() {
107        verifyContents("")
108    }
109
110    void testCloneWithNewPath() {
111        entry.lastModified = LAST_MODIFIED
112        entry.owner = USER
113        entry.group = GROUP
114        entry.permissions = PERMISSIONS
115        entry.setContents('abc')
116        def clone = entry.cloneWithNewPath(NEW_PATH)
117
118        assert !clone.is(entry)
119        assert clone.path == NEW_PATH
120        assert clone.lastModified == LAST_MODIFIED
121        assert clone.owner == USER
122        assert clone.group == GROUP
123        assert clone.permissions == PERMISSIONS
124        assert clone.createInputStream().text == 'abc'
125        assert !clone.directory
126    }
127
128    void testCloneWithNewPath_WriteToOutputStream() {
129        def outputStream = entry.createOutputStream(false)
130        outputStream.withWriter { writer -> writer.write('ABCDEF') }
131        def clone = entry.cloneWithNewPath(NEW_PATH)
132
133        assert !clone.is(entry)
134        assert clone.path == NEW_PATH
135        assert clone.createInputStream().text == 'ABCDEF'
136        assert !clone.directory
137    }
138
139//    void testEquals() {
140//        assert entry.equals(entry)
141//        assert entry.equals(new FileEntry(path:PATH, lastModified:LAST_MODIFIED))
142//        assert entry.equals(new FileEntry(path:PATH, lastModified:new Date())) // lastModified ignored
143//
144//        assert !entry.equals(new FileEntry("xyz", lastModified:LAST_MODIFIED))
145//        assert !entry.equals(new FileEntry(path:PATH, contents:'abc', lastModified:LAST_MODIFIED))
146//        assert !entry.equals("ABC")
147//        assert !entry.equals(null)
148//    }
149//
150//    void testHashCode() {
151//        assert entry.hashCode() == entry.hashCode()
152//        assert entry.hashCode() == new FileEntry(path:PATH, contents:'abc', lastModified:LAST_MODIFIED).hashCode()
153//        assert entry.hashCode() == new FileEntry(path:PATH, contents:'abc', new Date()).hashCode()  // lastModified ignored
154//
155//        assert entry.hashCode() != new FileEntry(path:PATH, contents:'abc', lastModified:LAST_MODIFIED).hashCode()
156//        assert entry.hashCode() != new FileEntry(path:PATH, contents:'abcdef', lastModified:LAST_MODIFIED).hashCode()
157//
158//        assert entry.hashCode() == new DirectoryEntry(path:PATH, lastModified:LAST_MODIFIED).hashCode()
159//    }
160
161    //-------------------------------------------------------------------------
162    // Implementation of Required Abstract Methods
163    //-------------------------------------------------------------------------
164
165    /**
166     * @see org.mockftpserver.fake.filesystem.AbstractFileSystemEntryTest#getImplementationClass()
167     */
168    protected Class getImplementationClass() {
169        return FileEntry.class
170    }
171
172    /**
173     * @see org.mockftpserver.fake.filesystem.AbstractFileSystemEntryTest#isDirectory()
174     */
175    protected boolean isDirectory() {
176        return false
177    }
178
179    //-------------------------------------------------------------------------
180    // Test setup
181    //-------------------------------------------------------------------------
182
183    void setUp() {
184        super.setUp()
185        entry = new FileEntry(PATH)
186    }
187
188    //-------------------------------------------------------------------------
189    // Internal Helper Methods
190    //-------------------------------------------------------------------------
191
192    /**
193     * Verify the expected contents of the file entry, read from its InputSteam
194     * @param expectedContents - the expected contents, as a String
195     * @throws IOException
196     */
197    private void verifyContents(String expectedContents) {
198        LOG.info("expectedContents=$expectedContents")
199        verifyContents(expectedContents.bytes)
200    }
201
202    /**
203     * Verify the expected contents of the file entry, read from its InputSteam
204     * @param expectedContents - the expected contents, as a byte[]
205     * @throws IOException
206     */
207    private void verifyContents(byte[] expectedContents) {
208        byte[] bytes = IoUtil.readBytes(entry.createInputStream())
209        def bytesAsList = bytes as List
210        LOG.info("bytes=$bytesAsList")
211        assert bytes == expectedContents, "actual=$bytesAsList  expected=${expectedContents as byte[]}"
212        assert entry.getSize() == expectedContents.length
213    }
214
215}
216