Skip to content
Merged
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

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,260 @@
/*
* 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.maven.model;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

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

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;

/**
* Comprehensive test suite for Properties behavior in Maven models.
* Tests order preservation, caching behavior, and WrapperProperties functionality.
*/
class PropertiesTest {

@Nested
class OrderPreservationTests {
Comment on lines +39 to +40
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
@Nested
class OrderPreservationTests {

why nested if no rivals?

i like this, but only if its really in use. ATM it seems not.

FYI: see the nested feature again. @elharo

Copy link
Contributor

@Pankraz76 Pankraz76 Jun 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

overhead for no obvious reason, seems to be the thing here all around.


@Test
void testPropertiesOrderPreservedInImmutableModel() {
// Create properties with specific insertion order using LinkedHashMap
Map<String, String> orderedMap = new LinkedHashMap<>();
orderedMap.put("third", "3");
orderedMap.put("first", "1");
orderedMap.put("second", "2");

// Create model and set properties
Model model = new Model();
Properties props = model.getProperties();

// Create properties and populate from map to maintain order
orderedMap.forEach(props::setProperty);

// Get the immutable delegate (v4 API model is already immutable)
org.apache.maven.api.model.Model immutable = model.getDelegate();

// Verify order is preserved
Map<String, String> resultProps = immutable.getProperties();
assertNotNull(resultProps);

// Check order by collecting keys in iteration order
List<String> keys = new ArrayList<>(resultProps.keySet());

// Verify the original insertion order is maintained
assertEquals(3, keys.size());
assertEquals("third", keys.get(0));
assertEquals("first", keys.get(1));
assertEquals("second", keys.get(2));
}

@Test
void testPropertiesOrderPreservedInMutableModel() {
// Create ordered map to simulate properties with specific order
Map<String, String> orderedMap = new LinkedHashMap<>();
orderedMap.put("z-property", "z");
orderedMap.put("a-property", "a");
orderedMap.put("m-property", "m");

// Create and populate model
Model model = new Model();
Properties props = model.getProperties();

// Create properties and populate from map to maintain order
orderedMap.forEach(props::setProperty);

// Get properties back and verify order
Properties resultProps = model.getProperties();

// Check order by collecting keys in iteration order
List<String> keys = new ArrayList<>();
resultProps.keySet().forEach(k -> keys.add(k.toString()));

// Verify the original insertion order is maintained
assertEquals(3, keys.size());
assertEquals("z-property", keys.get(0));
assertEquals("a-property", keys.get(1));
assertEquals("m-property", keys.get(2));
}

@Test
void testOrderPreservationAfterModification() {
// Create a model with properties
Model model = new Model();
Properties modelProps = model.getProperties();

// Add properties in specific order
modelProps.setProperty("first", "1");
modelProps.setProperty("second", "2");

// Modify existing property
modelProps.setProperty("first", "modified");

// Add new property
modelProps.setProperty("third", "3");

// Collect keys in iteration order
List<String> keys = new ArrayList<>();
modelProps.keySet().forEach(k -> keys.add(k.toString()));

// Verify order is preserved (first should still be first since it was modified, not re-added)
assertEquals(3, keys.size());
assertEquals("first", keys.get(0));
assertEquals("second", keys.get(1));
assertEquals("third", keys.get(2));

// Verify value was updated
assertEquals("modified", modelProps.getProperty("first"));
}
}

@Nested
class WrapperPropertiesBehaviorTests {

@Test
void testWriteOperationBehavior() {
// Create a Model with initial properties
Model model = new Model();

// Set initial properties using setProperties to establish the backend
Properties initialProps = new Properties();
initialProps.setProperty("initial.key", "initial.value");
model.setProperties(initialProps);

// Get the WrapperProperties instance
Properties wrapperProps = model.getProperties();

// First read - should initialize cache
assertEquals("initial.value", wrapperProps.getProperty("initial.key"));

// Simulate external change by directly calling setProperties (another WrapperProperties instance)
Properties externalProps = new Properties();
externalProps.setProperty("initial.key", "externally.modified");
externalProps.setProperty("external.key", "external.value");
model.setProperties(externalProps);

// Read again - should return fresh value (no caching in current implementation)
assertEquals("externally.modified", wrapperProps.getProperty("initial.key"));

// Now perform a write operation
wrapperProps.setProperty("new.key", "new.value");

// Read the initial key again - should return the current value
assertEquals("externally.modified", wrapperProps.getProperty("initial.key"));

// Read the external key that was set before the write operation
assertEquals("external.value", wrapperProps.getProperty("external.key"));

// Read the new key that was just set
assertEquals("new.value", wrapperProps.getProperty("new.key"));
}

@Test
void testMultipleWrapperPropertiesShareSameBackend() {
// Create a Model with initial properties
Model model = new Model();

Properties initialProps = new Properties();
initialProps.setProperty("shared.key", "initial.value");
model.setProperties(initialProps);

// Get two WrapperProperties instances from the same Model
Properties wrapper1 = model.getProperties();
Properties wrapper2 = model.getProperties();

// Both wrappers should read the same initial value
assertEquals("initial.value", wrapper1.getProperty("shared.key"));
assertEquals("initial.value", wrapper2.getProperty("shared.key"));

// Write through wrapper1
wrapper1.setProperty("from.wrapper1", "value1");

// wrapper2 should see the changes immediately (no caching)
assertEquals("value1", wrapper2.getProperty("from.wrapper1"));
assertEquals("initial.value", wrapper2.getProperty("shared.key"));

// Now wrapper2 performs a write operation
wrapper2.setProperty("from.wrapper2", "value2");

// Both wrappers should see all changes immediately
assertEquals("value1", wrapper1.getProperty("from.wrapper1"));
assertEquals("value2", wrapper1.getProperty("from.wrapper2"));
assertEquals("value1", wrapper2.getProperty("from.wrapper1"));
assertEquals("value2", wrapper2.getProperty("from.wrapper2"));

// Add another property through wrapper1
wrapper1.setProperty("another.key", "another.value");
assertEquals("another.value", wrapper1.getProperty("another.key"));
assertEquals("another.value", wrapper2.getProperty("another.key"));
}

@Test
void testVariousWriteOperations() {
// Create a Model with initial properties
Model model = new Model();

Properties initialProps = new Properties();
initialProps.setProperty("key1", "value1");
model.setProperties(initialProps);

Properties wrapper = model.getProperties();

// Initial read
assertEquals("value1", wrapper.getProperty("key1"));

// Test put() method
wrapper.put("key2", "value2");
assertEquals("value2", wrapper.getProperty("key2"));

// Simulate external change
Properties externalProps1 = new Properties();
externalProps1.setProperty("key1", "modified_after_put");
externalProps1.setProperty("key2", "value2");
externalProps1.setProperty("external.key", "external.value");
model.setProperties(externalProps1);
assertEquals("modified_after_put", wrapper.getProperty("key1"));

// Test remove() method
wrapper.remove("key2");
assertEquals(null, wrapper.getProperty("key2"));

// Simulate external change
Properties externalProps2 = new Properties();
externalProps2.setProperty("key1", "modified_after_remove");
externalProps2.setProperty("external.key", "external.value");
model.setProperties(externalProps2);
assertEquals("modified_after_remove", wrapper.getProperty("key1"));

// Test putAll() method
Properties newProps = new Properties();
newProps.setProperty("putall.key1", "putall.value1");
newProps.setProperty("putall.key2", "putall.value2");
wrapper.putAll(newProps);
assertEquals("putall.value1", wrapper.getProperty("putall.key1"));
assertEquals("putall.value2", wrapper.getProperty("putall.key2"));
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
}

}
Loading