/*_############################################################################
  _##
  _##  SNMP4J-Agent 3 - PropertyMOInputTest.java
  _##
  _##  Copyright (C) 2005-2026  Frank Fock (SNMP4J.org)
  _##
  _##  Licensed 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.snmp4j.agent.io.prop;

import org.junit.Test;
import org.snmp4j.smi.OctetString;
import org.snmp4j.smi.Variable;

import java.util.Properties;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;

/**
 * Tests the predefined named random value (secret) support of {@link PropertyMOInput}.
 *
 * @author Frank Fock
 */
public class PropertyMOInputTest {

    private static PropertyMOInput newInput() {
        Properties props = new Properties();
        // scanContexts requires the contexts property to be present (empty = default context only).
        props.setProperty(PropertyMOInput.CONFIG_PREFIX + PropertyMOInput.CONTEXTS_ID, "");
        return new PropertyMOInput(props);
    }

    @Test
    public void testPredefinedNamedSecretIsUsed() {
        PropertyMOInput input = newInput();
        OctetString adminPasskey = new OctetString("S3cr3tAdminPassKey");
        input.setRandomValue("admin", adminPasskey);

        // A {r}admin reference must resolve to the predefined secret instead of a random value.
        Variable v = input.createVariableFromString("{r}admin", Variable.class);
        assertEquals(adminPasskey, v);
        assertEquals(adminPasskey, input.getRandomValue("admin"));

        // The same named secret is reused for a {R}admin reference as well.
        Variable v2 = input.createVariableFromString("{R}admin", Variable.class);
        assertSame(v, v2);
    }

    @Test
    public void testRandomValueGeneratedWhenNotPredefinedAndReused() {
        PropertyMOInput input = newInput();
        input.setRandomOctetStringDefaultLength(24);

        Variable generated = input.createVariableFromString("{r}viewer", Variable.class);
        assertNotNull(generated);
        assertEquals(24, ((OctetString) generated).length());
        // printable: all bytes must be in the ASCII printable range '!'..'~'
        for (byte b : ((OctetString) generated).getValue()) {
            assertEquals(true, (b >= '!') && (b <= '~'));
        }
        // Subsequent references with the same name reuse the generated value.
        Variable reused = input.createVariableFromString("{r}viewer", Variable.class);
        assertSame(generated, reused);
    }

    @Test
    public void testSetRandomValueNullRemovesPredefinedValue() {
        PropertyMOInput input = newInput();
        OctetString secret = new OctetString("secret");
        input.setRandomValue("k", secret);
        assertSame(secret, input.getRandomValue("k"));
        input.setRandomValue("k", null);
        // After removal, a reference generates a fresh (non-equal) random value.
        Variable generated = input.createVariableFromString("{R}k", Variable.class);
        assertNotNull(generated);
    }
}
