Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,9 @@ public static boolean isWindows() {
}

/**
* Checks whether the operating system this JVM runs on is Windows.
* Checks whether the operating system this JVM runs on is Mac OS.
*
* @return <code>true</code> if the operating system this JVM runs on is Windows, <code>false
* @return <code>true</code> if the operating system this JVM runs on is Mac OS, <code>false
* </code> otherwise
*/
public static boolean isMac() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.apache.fluss.utils;

import org.junit.jupiter.api.Test;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.NoSuchElementException;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;

/** Tests for {@link AbstractIterator}. */
class AbstractIteratorTest {

/** Simple iterator over a list of integers for testing. */
private static class IntIterator extends AbstractIterator<Integer> {
private final List<Integer> data;
private int index = 0;

IntIterator(List<Integer> data) {
this.data = data;
}

@Override
protected Integer makeNext() {
if (index >= data.size()) {
return allDone();
}
return data.get(index++);
}
}

/** Iterator that throws on first makeNext() call to test FAILED state. */
private static class FailingIterator extends AbstractIterator<Integer> {
@Override
protected Integer makeNext() {
throw new RuntimeException("Intentional failure");
}
}

@Test
void testNormalIteration() {
IntIterator iter = new IntIterator(Arrays.asList(1, 2, 3));
List<Integer> result = new ArrayList<>();
while (iter.hasNext()) {
result.add(iter.next());
}
assertThat(result).containsExactly(1, 2, 3);
}

@Test
void testEmptyIterator() {
IntIterator iter = new IntIterator(new ArrayList<Integer>());
assertThat(iter.hasNext()).isFalse();
assertThatThrownBy(iter::next).isInstanceOf(NoSuchElementException.class);
}

@Test
void testPeek() {
IntIterator iter = new IntIterator(Arrays.asList(10, 20));
assertThat(iter.peek()).isEqualTo(10);
// peek does not advance
assertThat(iter.peek()).isEqualTo(10);
assertThat(iter.next()).isEqualTo(10);
assertThat(iter.peek()).isEqualTo(20);
assertThat(iter.next()).isEqualTo(20);
assertThatThrownBy(iter::peek).isInstanceOf(NoSuchElementException.class);
}

@Test
void testNextAfterExhaustion() {
IntIterator iter = new IntIterator(Arrays.asList(1));
iter.next();
assertThatThrownBy(iter::next).isInstanceOf(NoSuchElementException.class);
}

@Test
void testRemoveThrowsUnsupportedOperationException() {
IntIterator iter = new IntIterator(Arrays.asList(1));
assertThatThrownBy(iter::remove).isInstanceOf(UnsupportedOperationException.class);
}

@Test
void testMultipleHasNextCallsAreIdempotent() {
IntIterator iter = new IntIterator(Arrays.asList(5));
assertThat(iter.hasNext()).isTrue();
assertThat(iter.hasNext()).isTrue();
assertThat(iter.next()).isEqualTo(5);
assertThat(iter.hasNext()).isFalse();
assertThat(iter.hasNext()).isFalse();
}

@Test
void testFailedStateThrowsIllegalStateException() {
FailingIterator iter = new FailingIterator();
// First call triggers FAILED state via RuntimeException in makeNext()
assertThatThrownBy(iter::hasNext).isInstanceOf(RuntimeException.class);
// Subsequent calls should throw IllegalStateException (FAILED state)
assertThatThrownBy(iter::hasNext).isInstanceOf(IllegalStateException.class);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.apache.fluss.utils;

import org.junit.jupiter.api.Test;

import java.util.HashMap;

import static org.apache.fluss.utils.CollectionUtils.HASH_MAP_DEFAULT_LOAD_FACTOR;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;

/** Tests for {@link CollectionUtils}. */
class CollectionUtilsTest {

@Test
void testComputeRequiredCapacity() {
// expectedSize <= 2 returns expectedSize + 1
assertThat(CollectionUtils.computeRequiredCapacity(0, 0.75f)).isEqualTo(1);
assertThat(CollectionUtils.computeRequiredCapacity(1, 0.75f)).isEqualTo(2);
assertThat(CollectionUtils.computeRequiredCapacity(2, 0.75f)).isEqualTo(3);

// expectedSize > 2 uses ceil(expectedSize / loadFactor)
assertThat(CollectionUtils.computeRequiredCapacity(3, 0.75f)).isEqualTo(4);
assertThat(CollectionUtils.computeRequiredCapacity(10, 0.75f)).isEqualTo(14);
assertThat(CollectionUtils.computeRequiredCapacity(100, 0.75f)).isEqualTo(134);

// Large expectedSize threshold
int maxThreshold = Integer.MAX_VALUE / 2 + 1;
assertThat(CollectionUtils.computeRequiredCapacity(maxThreshold, 0.75f))
.isEqualTo(Integer.MAX_VALUE);
assertThat(CollectionUtils.computeRequiredCapacity(Integer.MAX_VALUE, 0.75f))
.isEqualTo(Integer.MAX_VALUE);

// Invalid arguments
assertThatThrownBy(() -> CollectionUtils.computeRequiredCapacity(-1, 0.75f))
.isInstanceOf(IllegalArgumentException.class);
assertThatThrownBy(() -> CollectionUtils.computeRequiredCapacity(5, 0f))
.isInstanceOf(IllegalArgumentException.class);
assertThatThrownBy(() -> CollectionUtils.computeRequiredCapacity(5, -0.5f))
.isInstanceOf(IllegalArgumentException.class);
}

@Test
void testNewHashMapWithExpectedSize() {
HashMap<String, Integer> map = CollectionUtils.newHashMapWithExpectedSize(5);
assertThat(map).isNotNull();
assertThat(map).isEmpty();

for (int i = 0; i < 5; i++) {
map.put("key" + i, i);
}
assertThat(map).hasSize(5);
for (int i = 0; i < 5; i++) {
assertThat(map.get("key" + i)).isEqualTo(i);
}

// Test with 0 expected size
HashMap<String, String> emptyMap = CollectionUtils.newHashMapWithExpectedSize(0);
assertThat(emptyMap).isNotNull().isEmpty();

// Test default load factor constant
assertThat(HASH_MAP_DEFAULT_LOAD_FACTOR).isEqualTo(0.75f);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.apache.fluss.utils;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import static org.assertj.core.api.Assertions.assertThat;

/** Tests for {@link CopyOnWriteMap}. */
class CopyOnWriteMapTest {

private CopyOnWriteMap<String, Integer> map;

@BeforeEach
void setUp() {
map = new CopyOnWriteMap<>();
}

@Test
void testPutAndGet() {
assertThat(map.isEmpty()).isTrue();
assertThat(map.size()).isEqualTo(0);

map.put("a", 1);
assertThat(map.get("a")).isEqualTo(1);
assertThat(map.size()).isEqualTo(1);
assertThat(map.isEmpty()).isFalse();
}

@Test
void testContainsKeyAndValue() {
map.put("x", 42);
assertThat(map.containsKey("x")).isTrue();
assertThat(map.containsKey("y")).isFalse();
assertThat(map.containsValue(42)).isTrue();
assertThat(map.containsValue(99)).isFalse();
}

@Test
void testRemove() {
map.put("k", 10);
assertThat(map.remove("k")).isEqualTo(10);
assertThat(map.containsKey("k")).isFalse();
assertThat(map.remove("nonexistent")).isNull();
}

@Test
void testClear() {
map.put("a", 1);
map.put("b", 2);
map.clear();
assertThat(map).isEmpty();
assertThat(map.size()).isEqualTo(0);
}

@Test
void testPutAll() {
Map<String, Integer> source = new HashMap<>();
source.put("p", 100);
source.put("q", 200);
map.putAll(source);
assertThat(map.size()).isEqualTo(2);
assertThat(map.get("p")).isEqualTo(100);
assertThat(map.get("q")).isEqualTo(200);
}

@Test
void testKeySetEntrySetValues() {
map.put("a", 1);
map.put("b", 2);

Set<String> keys = map.keySet();
assertThat(keys).containsExactlyInAnyOrder("a", "b");

Set<Map.Entry<String, Integer>> entries = map.entrySet();
assertThat(entries).hasSize(2);

Collection<Integer> values = map.values();
assertThat(values).containsExactlyInAnyOrder(1, 2);
}

@Test
void testPutIfAbsent() {
// Key absent: inserts and returns null
Integer prev = map.putIfAbsent("k", 5);
assertThat(prev).isNull();
assertThat(map.get("k")).isEqualTo(5);

// Key present: does NOT overwrite, returns existing value
Integer existing = map.putIfAbsent("k", 99);
assertThat(existing).isEqualTo(5);
assertThat(map.get("k")).isEqualTo(5);
}

@Test
void testRemoveKeyValue() {
map.put("k", 10);

// Wrong value: does not remove
assertThat(map.remove("k", 999)).isFalse();
assertThat(map.containsKey("k")).isTrue();

// Correct value: removes and returns true
assertThat(map.remove("k", 10)).isTrue();
assertThat(map.containsKey("k")).isFalse();
}

@Test
void testReplaceOldNewValue() {
map.put("k", 1);

// Wrong old value: no replacement
assertThat(map.replace("k", 99, 2)).isFalse();
assertThat(map.get("k")).isEqualTo(1);

// Correct old value: replaces
assertThat(map.replace("k", 1, 2)).isTrue();
assertThat(map.get("k")).isEqualTo(2);

// Non-existent key: false
assertThat(map.replace("missing", 1, 2)).isFalse();
}

@Test
void testReplaceExistingKey() {
map.put("k", 1);
assertThat(map.replace("k", 42)).isEqualTo(1);
assertThat(map.get("k")).isEqualTo(42);

// Non-existent key returns null
assertThat(map.replace("missing", 42)).isNull();
}

@Test
void testCopyOnWriteIsolation() {
map.put("a", 1);
// Capture a snapshot of the key set before modification
Set<String> snapshotKeys = map.keySet();
assertThat(snapshotKeys).contains("a");

// Modify the map
map.put("b", 2);
// The snapshot should still only see what it had when captured
// (CopyOnWriteMap returns the underlying map's keySet, which is now the new map)
// The new keySet should reflect both entries
assertThat(map.keySet()).containsExactlyInAnyOrder("a", "b");
}
}
Loading