-
Notifications
You must be signed in to change notification settings - Fork 0
/
BugFreeMotionDetector.java
170 lines (141 loc) · 5.29 KB
/
BugFreeMotionDetector.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
/*
* Copyright (C) 2020 Stefano Fornari.
* All Rights Reserved. No use, copying or distribution of this
* work may be made except in accordance with a valid license
* agreement from Stefano Fornari. This notice must be
* included on all copies, modifications and derivatives of this
* work.
*
* STEFANO FORNARI MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY
* OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
* THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT. STEFANO FORNARI SHALL NOT BE LIABLE FOR ANY
* DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
* THIS SOFTWARE OR ITS DERIVATIVES.
*/
package ste.falco;
import com.pi4j.io.gpio.GpioController;
import com.pi4j.io.gpio.GpioFactory;
import com.pi4j.io.gpio.RaspiPin;
import com.pi4j.io.gpio.exception.GpioPinExistsException;
import static org.assertj.core.api.AssertionsForClassTypes.fail;
import static org.assertj.core.api.BDDAssertions.then;
import org.junit.Rule;
import org.junit.Test;
import org.junit.contrib.java.lang.system.SystemOutRule;
/**
*
*
*/
public class BugFreeMotionDetector extends BugFreePIRBase {
@Rule
public final SystemOutRule STDOUT = new SystemOutRule().enableLog();
@Test
public void startup_provisions_GPIO_04() throws Exception {
GpioController gpio = GpioFactory.getInstance();
MotionDetector smd = new InnerMotionDetector();
then(gpio.getProvisionedPins()).isEmpty();
smd.startup();
//
// only PIN_04 should be providions
//
then(gpio.getProvisionedPins()).hasSize(1);
then(gpio.getProvisionedPin(RaspiPin.GPIO_04)).isNotNull();
smd.shutdown();
}
@Test
public void shutdown_unprovisions_the_pin() throws Exception {
GpioController gpio = GpioFactory.getInstance();
MotionDetector smd = new InnerMotionDetector();
//
// if not yet provisioned, silently execute
//
smd.shutdown();
then(gpio.getProvisionedPins()).isEmpty();
//
// now when provisione
//
smd.startup(); smd.shutdown();
then(gpio.getProvisionedPins()).isEmpty();
}
@Test
public void call_moved_when_motion_detected() throws Exception {
try (InnerMotionDetector moctor = new InnerMotionDetector()) {
moctor.startup();
//
// NOTE: pint state changes and event handling is concurrent, we need to
// give it time to propagate
//
PIR.up(); Thread.sleep(50); then(moctor.count).isEqualTo(1);
PIR.down();
PIR.up(); Thread.sleep(50); then(moctor.count).isEqualTo(2);
}
}
@Test
public void is_auto_closeable() throws Exception {
GpioController gpio = GpioFactory.getInstance();
//
// no exception
//
try (MotionDetector moctor = new InnerMotionDetector()) {
moctor.startup();
} finally {
then(gpio.getProvisionedPins()).isEmpty();
}
//
// with exception
//
try (MotionDetector moctor = new InnerMotionDetector()) {
moctor.startup(); moctor.startup();
} catch (GpioPinExistsException x) {
then(gpio.getProvisionedPins()).isEmpty();
}
}
@Test
public void finalize_shutdowns_the_detector_with_message() throws Exception {
GpioController gpio = GpioFactory.getInstance();
MotionDetector moctor = new InnerMotionDetector();
moctor.startup();
moctor.finalize();
then(gpio.getProvisionedPins()).isEmpty();
then(STDOUT.getLog()).contains("MotionDetector closed in finalize(); use shutdown() explicitely instead!")
.contains("java.lang.IllegalStateException\n");
}
@Test
public void error_if_moved_is_called_before_startup() {
try (MotionDetector smd = new MotionDetector() {}) {
smd.moved();
fail("moved when not ready");
} catch (IllegalStateException x) {
then(x).hasMessage("moved() called before the instance is started up; make sure to call startup()");
}
}
@Test
public void moved_ok() throws Exception {
try (MotionDetector smd = new MotionDetector() {}) {
smd.startup();
smd.moved();
}
}
@Test
public void shutdown_resets_the_instance() throws Exception {
//
// NOTE: after the instance is reset, it must be started up again before
// using it.
//
try (MotionDetector smd = new MotionDetector() {}) {
smd.startup(); smd.moved(); smd.shutdown();
smd.moved();
} catch (IllegalStateException x) {
then(x).hasMessage("moved() called before the instance is started up; make sure to call startup()");
}
}
// ----------------------------------------------------- InnerMotionDetector
private class InnerMotionDetector extends MotionDetector {
public int count = 0;
@Override
public void moved() {
count += 1;
}
}
}