/* * Copyright 2016 Cel Skeggs * * This file is part of the CCRE, the Common Chicken Runtime Engine. * * The CCRE is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * The CCRE is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with the CCRE. If not, see <http://www.gnu.org/licenses/>. */ package ccre.behaviors; import static org.junit.Assert.*; import org.junit.After; import org.junit.Before; import org.junit.Test; import ccre.channel.BooleanCell; import ccre.channel.BooleanInput; import ccre.channel.EventCell; import ccre.channel.EventInput; import ccre.channel.FloatCell; import ccre.channel.FloatInput; import ccre.rconf.RConf; import ccre.testing.CountingBooleanOutput; import ccre.testing.CountingEventOutput; import ccre.testing.CountingFloatOutput; import ccre.util.Values; @SuppressWarnings("javadoc") public class BehaviorArbitratorTest { private static final String NAME = "Example Arbitrator"; private static final String NAME_BEHAVIOR = "Example Behavior"; private static final String NAME_BEHAVIOR_ALT = "Example Behavior Alternate"; private static final String NAME_BEHAVIOR_ALT_2 = "Example Behavior Alternate 2"; private BehaviorArbitrator arbitrator; @Before public void setUp() throws Exception { this.arbitrator = new BehaviorArbitrator(NAME); } @After public void tearDown() throws Exception { arbitrator = null; } @Test public void testGetName() { assertEquals(NAME, arbitrator.getName()); } @Test public void testToString() { assertEquals("[BehaviorArbitrator " + NAME + "]", arbitrator.toString()); } @Test public void testOneBehavior() { BooleanCell request = new BooleanCell(); Behavior behavior = arbitrator.addBehavior(NAME_BEHAVIOR, request); CountingBooleanOutput inactive = new CountingBooleanOutput(); CountingBooleanOutput active = new CountingBooleanOutput(); inactive.ifExpected = true; inactive.valueExpected = true; arbitrator.getIsInactive().send(inactive); inactive.check(); active.ifExpected = true; active.valueExpected = false; arbitrator.getIsActive(behavior).send(active); active.check(); for (int i = 0; i < 10; i++) { inactive.ifExpected = active.ifExpected = true; inactive.valueExpected = !(active.valueExpected = !request.get()); request.toggle(); active.check(); inactive.check(); } } @Test public void testTwoBehaviors() { BooleanCell requestL = new BooleanCell(), requestH = new BooleanCell(); Behavior behaviorL = arbitrator.addBehavior(NAME_BEHAVIOR, requestL); Behavior behaviorH = arbitrator.addBehavior(NAME_BEHAVIOR_ALT, requestH); CountingBooleanOutput cL = new CountingBooleanOutput(), cH = new CountingBooleanOutput(), cI = new CountingBooleanOutput(); cL.ifExpected = true; cL.valueExpected = false; arbitrator.getIsActive(behaviorL).send(cL); cL.check(); cH.ifExpected = true; cH.valueExpected = false; arbitrator.getIsActive(behaviorH).send(cH); cH.check(); cI.ifExpected = true; cI.valueExpected = true; arbitrator.getIsInactive().send(cI); cI.check(); for (int i = 0; i < 100; i++) { if (Values.getRandomBoolean()) { if (!requestH.get()) { // if H is true, nothing should change cI.ifExpected = cL.ifExpected = true; cL.valueExpected = !(cI.valueExpected = requestL.get()); } requestL.toggle(); } else { if (!requestH.get()) { cH.ifExpected = true; cH.valueExpected = true; if (requestL.get()) { cL.ifExpected = true; cL.valueExpected = false; } else { cI.ifExpected = true; cI.valueExpected = false; } } else { cH.ifExpected = true; cH.valueExpected = false; if (requestL.get()) { cL.ifExpected = true; cL.valueExpected = true; } else { cI.ifExpected = true; cI.valueExpected = true; } } requestH.toggle(); } cH.check(); cI.check(); cL.check(); } } @Test(expected = NullPointerException.class) public void testAddBehaviorNullA() { arbitrator.addBehavior(null, BooleanInput.alwaysTrue); } @Test(expected = NullPointerException.class) public void testAddBehaviorNullB() { arbitrator.addBehavior(NAME_BEHAVIOR, null); } @Test(expected = NullPointerException.class) public void testAddGetIsActiveNull() { arbitrator.getIsActive(null); } @Test(expected = NullPointerException.class) public void testAddEventNull() { arbitrator.addEvent(null); } @Test(expected = NullPointerException.class) public void testAddBooleanNull() { arbitrator.addBoolean(null); } @Test(expected = NullPointerException.class) public void testAddFloatNull() { arbitrator.addFloat(null); } @Test public void testAddEventIBasic() { EventCell base = new EventCell(); ArbitratedEvent event = arbitrator.addEvent(base); CountingEventOutput ceo = new CountingEventOutput(); event.send(ceo); for (int i = 0; i < 10; i++) { ceo.ifExpected = true; base.event(); ceo.check(); } } @Test public void testAddEventIAdvanced() { BooleanCell rqL = new BooleanCell(), rqM = new BooleanCell(), rqH = new BooleanCell(); Behavior behaviorL = arbitrator.addBehavior(NAME_BEHAVIOR, rqL); /* Behavior behaviorM = */ arbitrator.addBehavior(NAME_BEHAVIOR_ALT, rqM); Behavior behaviorH = arbitrator.addBehavior(NAME_BEHAVIOR_ALT_2, rqH); EventCell base = new EventCell(), extraL = new EventCell(), extraH = new EventCell(); ArbitratedEvent arb = arbitrator.addEvent(base); arb.attach(behaviorL, extraL); // and nothing on behaviorM arb.attach(behaviorH, extraH); CountingEventOutput ceo = new CountingEventOutput(); arb.send(ceo); for (int i = 0; i < 100; i++) { boolean l = Values.getRandomBoolean(), m = Values.getRandomBoolean(), h = Values.getRandomBoolean(); rqL.set(l); rqM.set(m); rqH.set(h); for (int j = 0; j < 10; j++) { if (h) { base.event(); extraL.event(); ceo.ifExpected = true; extraH.event(); ceo.check(); } else if (m) { // same as the inactive case, since we didn't specify // anything extraL.event(); extraH.event(); ceo.ifExpected = true; base.event(); ceo.check(); } else if (l) { base.event(); extraH.event(); ceo.ifExpected = true; extraL.event(); ceo.check(); } else { extraL.event(); extraH.event(); ceo.ifExpected = true; base.event(); ceo.check(); } } } } @Test(expected = NullPointerException.class) public void testArbitratedEventAttachNullA() { arbitrator.addEvent().attach(null, EventInput.never); } @Test(expected = NullPointerException.class) public void testArbitratedEventAttachNullB() { arbitrator.addEvent().attach(arbitrator.addBehavior(NAME_BEHAVIOR, BooleanInput.alwaysFalse), null); } @Test(expected = IllegalArgumentException.class) public void testArbitratedEventAttachWrongChain() { arbitrator.addEvent().attach(new BehaviorArbitrator(NAME).addBehavior(NAME_BEHAVIOR, BooleanInput.alwaysFalse), EventInput.never); } @Test(expected = IllegalArgumentException.class) public void testArbitratedEventAttachDouble() { Behavior behavior = arbitrator.addBehavior(NAME_BEHAVIOR, BooleanInput.alwaysFalse); ArbitratedEvent event = arbitrator.addEvent(); event.attach(behavior, new EventCell()); event.attach(behavior, new EventCell()); } @Test public void testAddBooleanIBasic() { for (boolean b0 : new boolean[] { false, true }) { BooleanCell base = new BooleanCell(b0); ArbitratedBoolean bool = arbitrator.addBoolean(base); CountingBooleanOutput cbo = new CountingBooleanOutput(); cbo.ifExpected = true; cbo.valueExpected = b0; bool.send(cbo); cbo.check(); for (int i = 0; i < 10; i++) { cbo.valueExpected = !cbo.valueExpected; cbo.ifExpected = true; base.set(cbo.valueExpected); cbo.check(); } } } @Test public void testAddBooleanIAdvanced() { BooleanCell rqL = new BooleanCell(), rqM = new BooleanCell(), rqH = new BooleanCell(); Behavior behaviorL = arbitrator.addBehavior(NAME_BEHAVIOR, rqL); /* Behavior behaviorM = */ arbitrator.addBehavior(NAME_BEHAVIOR_ALT, rqM); Behavior behaviorH = arbitrator.addBehavior(NAME_BEHAVIOR_ALT_2, rqH); BooleanCell base = new BooleanCell(), extraL = new BooleanCell(), extraH = new BooleanCell(); ArbitratedBoolean arb = arbitrator.addBoolean(base); arb.attach(behaviorL, extraL); // and nothing on behaviorM arb.attach(behaviorH, extraH); BooleanCell out = new BooleanCell(); arb.send(out); for (int i = 0; i < 100; i++) { boolean l = Values.getRandomBoolean(), m = Values.getRandomBoolean(), h = Values.getRandomBoolean(); rqL.set(l); rqM.set(m); rqH.set(h); for (int j = 0; j < 30; j++) { base.set(Values.getRandomBoolean()); extraL.set(Values.getRandomBoolean()); extraH.set(Values.getRandomBoolean()); if (h) { assertEquals(extraH.get(), out.get()); } else if (m) { // nothing attached on behaviorM, so fall back // to base assertEquals(base.get(), out.get()); } else if (l) { assertEquals(extraL.get(), out.get()); } else { assertEquals(base.get(), out.get()); } } } } @Test(expected = NullPointerException.class) public void testArbitratedBooleanAttachNullA() { arbitrator.addBoolean().attach(null, BooleanInput.alwaysFalse); } @Test(expected = NullPointerException.class) public void testArbitratedBooleanAttachNullB() { arbitrator.addBoolean().attach(arbitrator.addBehavior(NAME_BEHAVIOR, BooleanInput.alwaysFalse), null); } @Test(expected = IllegalArgumentException.class) public void testArbitratedBooleanAttachWrongChain() { arbitrator.addBoolean().attach(new BehaviorArbitrator(NAME).addBehavior(NAME_BEHAVIOR, BooleanInput.alwaysFalse), BooleanInput.alwaysFalse); } @Test(expected = IllegalArgumentException.class) public void testArbitratedBooleanAttachDouble() { Behavior behavior = arbitrator.addBehavior(NAME_BEHAVIOR, BooleanInput.alwaysFalse); ArbitratedBoolean event = arbitrator.addBoolean(); event.attach(behavior, new BooleanCell()); event.attach(behavior, new BooleanCell()); } @Test public void testAddFloatIBasic() { for (float f0 : Values.interestingFloats) { FloatCell base = new FloatCell(f0); ArbitratedFloat flo = arbitrator.addFloat(base); CountingFloatOutput cfo = new CountingFloatOutput(); cfo.ifExpected = true; cfo.valueExpected = f0; flo.send(cfo); cfo.check(); for (float f1 : Values.interestingFloats) { if (f1 == f0) { continue; } cfo.valueExpected = f1; cfo.ifExpected = true; base.set(cfo.valueExpected); cfo.check(); } } } @Test public void testAddFloatIAdvanced() { BooleanCell rqL = new BooleanCell(), rqM = new BooleanCell(), rqH = new BooleanCell(); Behavior behaviorL = arbitrator.addBehavior(NAME_BEHAVIOR, rqL); /* Behavior behaviorM = */ arbitrator.addBehavior(NAME_BEHAVIOR_ALT, rqM); Behavior behaviorH = arbitrator.addBehavior(NAME_BEHAVIOR_ALT_2, rqH); FloatCell base = new FloatCell(), extraL = new FloatCell(), extraH = new FloatCell(); ArbitratedFloat arb = arbitrator.addFloat(base); arb.attach(behaviorL, extraL); // and nothing on behaviorM arb.attach(behaviorH, extraH); FloatCell out = new FloatCell(); arb.send(out); for (int i = 0; i < 100; i++) { boolean l = Values.getRandomBoolean(), m = Values.getRandomBoolean(), h = Values.getRandomBoolean(); rqL.set(l); rqM.set(m); rqH.set(h); for (int j = 0; j < 30; j++) { base.set(Values.getRandomFloat()); extraL.set(Values.getRandomFloat()); extraH.set(Values.getRandomFloat()); if (h) { assertEquals(Float.floatToIntBits(extraH.get()), Float.floatToIntBits(out.get())); } else if (m) { // nothing attached on behaviorM, so fall back // to base assertEquals(Float.floatToIntBits(base.get()), Float.floatToIntBits(out.get())); } else if (l) { assertEquals(Float.floatToIntBits(extraL.get()), Float.floatToIntBits(out.get())); } else { assertEquals(Float.floatToIntBits(base.get()), Float.floatToIntBits(out.get())); } } } } @Test(expected = NullPointerException.class) public void testArbitratedFloatAttachNullA() { arbitrator.addFloat().attach(null, FloatInput.zero); } @Test(expected = NullPointerException.class) public void testArbitratedFloatAttachNullB() { arbitrator.addFloat().attach(arbitrator.addBehavior(NAME_BEHAVIOR, BooleanInput.alwaysFalse), null); } @Test(expected = IllegalArgumentException.class) public void testArbitratedFloatAttachWrongChain() { arbitrator.addFloat().attach(new BehaviorArbitrator(NAME).addBehavior(NAME_BEHAVIOR, BooleanInput.alwaysFalse), FloatInput.zero); } @Test(expected = IllegalArgumentException.class) public void testArbitratedFloatAttachDouble() { Behavior behavior = arbitrator.addBehavior(NAME_BEHAVIOR, BooleanInput.alwaysFalse); ArbitratedFloat event = arbitrator.addFloat(); event.attach(behavior, new FloatCell()); event.attach(behavior, new FloatCell()); } @Test public void testSignalRConf() { arbitrator.addBehavior(NAME_BEHAVIOR, BooleanInput.alwaysTrue); arbitrator.addBehavior(NAME_BEHAVIOR_ALT, BooleanInput.alwaysTrue); arbitrator.addBehavior(NAME_BEHAVIOR_ALT_2, BooleanInput.alwaysTrue); int n = arbitrator.queryRConf().length; for (int i = 0; i < n; i++) { // this will have actual testing once we have SOMETHING being // available over signalRConf assertFalse(arbitrator.signalRConf(i, new byte[0])); } } @Test public void testQueryRConf() { for (int length = 0; length < 8; length++) { BehaviorArbitrator arbitrator = new BehaviorArbitrator(NAME); BooleanCell[] cells = new BooleanCell[length]; for (int i = 0; i < length; i++) { cells[i] = new BooleanCell(); arbitrator.addBehavior(NAME_BEHAVIOR + i, cells[i]); } for (int j = 0; j < 30; j++) { int active_id = -1; for (int i = 0; i < length; i++) { boolean b = Values.getRandomBoolean(); cells[i].set(b); if (b) { active_id = i; } } RConf.Entry[] entries = arbitrator.queryRConf(); assertEquals(3 + length, entries.length); assertEquals(RConf.F_TITLE, entries[0].type); assertEquals("Behaviors for " + NAME, entries[0].parseTextual()); for (int enti = 1; enti < length + 1; enti++) { int i = enti - 1; assertEquals(RConf.F_STRING, entries[enti].type); String name = entries[enti].parseTextual(); String[] parts = name.split(": ", 2); assertEquals(8, parts[0].length()); String prefix = parts[0].trim(); if (!cells[i].get()) { assertEquals("Inactive", prefix); } else if (i == active_id) { assertEquals("Active", prefix); } else { assertEquals("Standby", prefix); } assertEquals(NAME_BEHAVIOR + i, parts[1]); } assertEquals(RConf.F_STRING, entries[length + 1].type); assertEquals(active_id == -1 ? "No active behavior" : "Active behavior", entries[length + 1].parseTextual()); assertEquals(RConf.F_AUTO_REFRESH, entries[length + 2].type); assertEquals(1000, entries[length + 2].parseInteger().intValue()); } } } }