mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-26 01:51:41 +00:00
Remove wpiutil and update to the new build system (#210)
This commit is contained in:
committed by
Peter Johnson
parent
f43675e2bd
commit
5df7463663
347
src/arm-linux-jni/LICENSE
Normal file
347
src/arm-linux-jni/LICENSE
Normal file
@@ -0,0 +1,347 @@
|
||||
The GNU General Public License (GPL)
|
||||
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim copies of this license
|
||||
document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your freedom to share
|
||||
and change it. By contrast, the GNU General Public License is intended to
|
||||
guarantee your freedom to share and change free software--to make sure the
|
||||
software is free for all its users. This General Public License applies to
|
||||
most of the Free Software Foundation's software and to any other program whose
|
||||
authors commit to using it. (Some other Free Software Foundation software is
|
||||
covered by the GNU Library General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not price. Our
|
||||
General Public Licenses are designed to make sure that you have the freedom to
|
||||
distribute copies of free software (and charge for this service if you wish),
|
||||
that you receive source code or can get it if you want it, that you can change
|
||||
the software or use pieces of it in new free programs; and that you know you
|
||||
can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid anyone to deny
|
||||
you these rights or to ask you to surrender the rights. These restrictions
|
||||
translate to certain responsibilities for you if you distribute copies of the
|
||||
software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether gratis or for
|
||||
a fee, you must give the recipients all the rights that you have. You must
|
||||
make sure that they, too, receive or can get the source code. And you must
|
||||
show them these terms so they know their rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and (2)
|
||||
offer you this license which gives you legal permission to copy, distribute
|
||||
and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain that
|
||||
everyone understands that there is no warranty for this free software. If the
|
||||
software is modified by someone else and passed on, we want its recipients to
|
||||
know that what they have is not the original, so that any problems introduced
|
||||
by others will not reflect on the original authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software patents. We
|
||||
wish to avoid the danger that redistributors of a free program will
|
||||
individually obtain patent licenses, in effect making the program proprietary.
|
||||
To prevent this, we have made it clear that any patent must be licensed for
|
||||
everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and modification
|
||||
follow.
|
||||
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains a notice
|
||||
placed by the copyright holder saying it may be distributed under the terms of
|
||||
this General Public License. The "Program", below, refers to any such program
|
||||
or work, and a "work based on the Program" means either the Program or any
|
||||
derivative work under copyright law: that is to say, a work containing the
|
||||
Program or a portion of it, either verbatim or with modifications and/or
|
||||
translated into another language. (Hereinafter, translation is included
|
||||
without limitation in the term "modification".) Each licensee is addressed as
|
||||
"you".
|
||||
|
||||
Activities other than copying, distribution and modification are not covered by
|
||||
this License; they are outside its scope. The act of running the Program is
|
||||
not restricted, and the output from the Program is covered only if its contents
|
||||
constitute a work based on the Program (independent of having been made by
|
||||
running the Program). Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's source code as
|
||||
you receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice and
|
||||
disclaimer of warranty; keep intact all the notices that refer to this License
|
||||
and to the absence of any warranty; and give any other recipients of the
|
||||
Program a copy of this License along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and you may
|
||||
at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion of it, thus
|
||||
forming a work based on the Program, and copy and distribute such modifications
|
||||
or work under the terms of Section 1 above, provided that you also meet all of
|
||||
these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices stating
|
||||
that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in whole or
|
||||
in part contains or is derived from the Program or any part thereof, to be
|
||||
licensed as a whole at no charge to all third parties under the terms of
|
||||
this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively when run,
|
||||
you must cause it, when started running for such interactive use in the
|
||||
most ordinary way, to print or display an announcement including an
|
||||
appropriate copyright notice and a notice that there is no warranty (or
|
||||
else, saying that you provide a warranty) and that users may redistribute
|
||||
the program under these conditions, and telling the user how to view a copy
|
||||
of this License. (Exception: if the Program itself is interactive but does
|
||||
not normally print such an announcement, your work based on the Program is
|
||||
not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If identifiable
|
||||
sections of that work are not derived from the Program, and can be reasonably
|
||||
considered independent and separate works in themselves, then this License, and
|
||||
its terms, do not apply to those sections when you distribute them as separate
|
||||
works. But when you distribute the same sections as part of a whole which is a
|
||||
work based on the Program, the distribution of the whole must be on the terms
|
||||
of this License, whose permissions for other licensees extend to the entire
|
||||
whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest your
|
||||
rights to work written entirely by you; rather, the intent is to exercise the
|
||||
right to control the distribution of derivative or collective works based on
|
||||
the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program with the
|
||||
Program (or with a work based on the Program) on a volume of a storage or
|
||||
distribution medium does not bring the other work under the scope of this
|
||||
License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it, under
|
||||
Section 2) in object code or executable form under the terms of Sections 1 and
|
||||
2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable source
|
||||
code, which must be distributed under the terms of Sections 1 and 2 above
|
||||
on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three years, to
|
||||
give any third party, for a charge no more than your cost of physically
|
||||
performing source distribution, a complete machine-readable copy of the
|
||||
corresponding source code, to be distributed under the terms of Sections 1
|
||||
and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer to
|
||||
distribute corresponding source code. (This alternative is allowed only
|
||||
for noncommercial distribution and only if you received the program in
|
||||
object code or executable form with such an offer, in accord with
|
||||
Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for making
|
||||
modifications to it. For an executable work, complete source code means all
|
||||
the source code for all modules it contains, plus any associated interface
|
||||
definition files, plus the scripts used to control compilation and installation
|
||||
of the executable. However, as a special exception, the source code
|
||||
distributed need not include anything that is normally distributed (in either
|
||||
source or binary form) with the major components (compiler, kernel, and so on)
|
||||
of the operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering access to copy
|
||||
from a designated place, then offering equivalent access to copy the source
|
||||
code from the same place counts as distribution of the source code, even though
|
||||
third parties are not compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program except as
|
||||
expressly provided under this License. Any attempt otherwise to copy, modify,
|
||||
sublicense or distribute the Program is void, and will automatically terminate
|
||||
your rights under this License. However, parties who have received copies, or
|
||||
rights, from you under this License will not have their licenses terminated so
|
||||
long as such parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not signed it.
|
||||
However, nothing else grants you permission to modify or distribute the Program
|
||||
or its derivative works. These actions are prohibited by law if you do not
|
||||
accept this License. Therefore, by modifying or distributing the Program (or
|
||||
any work based on the Program), you indicate your acceptance of this License to
|
||||
do so, and all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the Program),
|
||||
the recipient automatically receives a license from the original licensor to
|
||||
copy, distribute or modify the Program subject to these terms and conditions.
|
||||
You may not impose any further restrictions on the recipients' exercise of the
|
||||
rights granted herein. You are not responsible for enforcing compliance by
|
||||
third parties to this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues), conditions
|
||||
are imposed on you (whether by court order, agreement or otherwise) that
|
||||
contradict the conditions of this License, they do not excuse you from the
|
||||
conditions of this License. If you cannot distribute so as to satisfy
|
||||
simultaneously your obligations under this License and any other pertinent
|
||||
obligations, then as a consequence you may not distribute the Program at all.
|
||||
For example, if a patent license would not permit royalty-free redistribution
|
||||
of the Program by all those who receive copies directly or indirectly through
|
||||
you, then the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under any
|
||||
particular circumstance, the balance of the section is intended to apply and
|
||||
the section as a whole is intended to apply in other circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any patents or
|
||||
other property right claims or to contest validity of any such claims; this
|
||||
section has the sole purpose of protecting the integrity of the free software
|
||||
distribution system, which is implemented by public license practices. Many
|
||||
people have made generous contributions to the wide range of software
|
||||
distributed through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing to
|
||||
distribute software through any other system and a licensee cannot impose that
|
||||
choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to be a
|
||||
consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in certain
|
||||
countries either by patents or by copyrighted interfaces, the original
|
||||
copyright holder who places the Program under this License may add an explicit
|
||||
geographical distribution limitation excluding those countries, so that
|
||||
distribution is permitted only in or among countries not thus excluded. In
|
||||
such case, this License incorporates the limitation as if written in the body
|
||||
of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions of the
|
||||
General Public License from time to time. Such new versions will be similar in
|
||||
spirit to the present version, but may differ in detail to address new problems
|
||||
or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any later
|
||||
version", you have the option of following the terms and conditions either of
|
||||
that version or of any later version published by the Free Software Foundation.
|
||||
If the Program does not specify a version number of this License, you may
|
||||
choose any version ever published by the Free Software Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free programs
|
||||
whose distribution conditions are different, write to the author to ask for
|
||||
permission. For software which is copyrighted by the Free Software Foundation,
|
||||
write to the Free Software Foundation; we sometimes make exceptions for this.
|
||||
Our decision will be guided by the two goals of preserving the free status of
|
||||
all derivatives of our free software and of promoting the sharing and reuse of
|
||||
software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR
|
||||
THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE
|
||||
STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE
|
||||
PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND
|
||||
PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE,
|
||||
YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL
|
||||
ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE
|
||||
PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR
|
||||
INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA
|
||||
BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
|
||||
FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER
|
||||
OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest possible
|
||||
use to the public, the best way to achieve this is to make it free software
|
||||
which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest to attach
|
||||
them to the start of each source file to most effectively convey the exclusion
|
||||
of warranty; and each file should have at least the "copyright" line and a
|
||||
pointer to where the full notice is found.
|
||||
|
||||
One line to give the program's name and a brief idea of what it does.
|
||||
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2 of the License, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program 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 General Public License for
|
||||
more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc., 59
|
||||
Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this when it
|
||||
starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author Gnomovision comes
|
||||
with ABSOLUTELY NO WARRANTY; for details type 'show w'. This is free
|
||||
software, and you are welcome to redistribute it under certain conditions;
|
||||
type 'show c' for details.
|
||||
|
||||
The hypothetical commands 'show w' and 'show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may be
|
||||
called something other than 'show w' and 'show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary. Here
|
||||
is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
'Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
signature of Ty Coon, 1 April 1989
|
||||
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Library General Public
|
||||
License instead of this License.
|
||||
|
||||
|
||||
"CLASSPATH" EXCEPTION TO THE GPL
|
||||
|
||||
Certain source files distributed by Oracle America and/or its affiliates are
|
||||
subject to the following clarification and special exception to the GPL, but
|
||||
only where Oracle has expressly included in the particular source file's header
|
||||
the words "Oracle designates this particular file as subject to the "Classpath"
|
||||
exception as provided by Oracle in the LICENSE file that accompanied this code."
|
||||
|
||||
Linking this library statically or dynamically with other modules is making
|
||||
a combined work based on this library. Thus, the terms and conditions of
|
||||
the GNU General Public License cover the whole combination.
|
||||
|
||||
As a special exception, the copyright holders of this library give you
|
||||
permission to link this library with independent modules to produce an
|
||||
executable, regardless of the license terms of these independent modules,
|
||||
and to copy and distribute the resulting executable under terms of your
|
||||
choice, provided that you also meet, for each linked independent module,
|
||||
the terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library. If
|
||||
you modify this library, you may extend this exception to your version of
|
||||
the library, but you are not obligated to do so. If you do not wish to do
|
||||
so, delete this exception statement from your version.
|
||||
1960
src/arm-linux-jni/jni.h
Normal file
1960
src/arm-linux-jni/jni.h
Normal file
File diff suppressed because it is too large
Load Diff
51
src/arm-linux-jni/linux/jni_md.h
Normal file
51
src/arm-linux-jni/linux/jni_md.h
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#ifndef _JAVASOFT_JNI_MD_H_
|
||||
#define _JAVASOFT_JNI_MD_H_
|
||||
|
||||
#ifndef __has_attribute
|
||||
#define __has_attribute(x) 0
|
||||
#endif
|
||||
#if (defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4) && (__GNUC_MINOR__ > 2))) || __has_attribute(visibility)
|
||||
#define JNIEXPORT __attribute__((visibility("default")))
|
||||
#define JNIIMPORT __attribute__((visibility("default")))
|
||||
#else
|
||||
#define JNIEXPORT
|
||||
#define JNIIMPORT
|
||||
#endif
|
||||
|
||||
#define JNICALL
|
||||
|
||||
typedef int jint;
|
||||
#ifdef _LP64 /* 64-bit Solaris */
|
||||
typedef long jlong;
|
||||
#else
|
||||
typedef long long jlong;
|
||||
#endif
|
||||
|
||||
typedef signed char jbyte;
|
||||
|
||||
#endif /* !_JAVASOFT_JNI_MD_H_ */
|
||||
9
src/dev/native/cpp/main.cpp
Normal file
9
src/dev/native/cpp/main.cpp
Normal file
@@ -0,0 +1,9 @@
|
||||
#include "ntcore.h"
|
||||
#include "nt_Value.h"
|
||||
#include <iostream>
|
||||
|
||||
int main() {
|
||||
nt::SetEntryValue("MyValue", nt::Value::MakeString("Hello World"));
|
||||
|
||||
std::cout << nt::GetEntryValue("MyValue")->GetString() << std::endl;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package edu.wpi.first.wpilibj.networktables;
|
||||
|
||||
public class ConnectionInfo {
|
||||
public final String remote_id;
|
||||
public final String remote_ip;
|
||||
public final int remote_port;
|
||||
public final long last_update;
|
||||
public final int protocol_version;
|
||||
|
||||
public ConnectionInfo(String remote_id, String remote_ip, int remote_port, long last_update, int protocol_version) {
|
||||
this.remote_id = remote_id;
|
||||
this.remote_ip = remote_ip;
|
||||
this.remote_port = remote_port;
|
||||
this.last_update = last_update;
|
||||
this.protocol_version = protocol_version;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package edu.wpi.first.wpilibj.networktables;
|
||||
|
||||
public class EntryInfo {
|
||||
public final String name;
|
||||
public final int type;
|
||||
public final int flags;
|
||||
public final long last_change;
|
||||
|
||||
public EntryInfo(String name, int type, int flags, long last_change) {
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
this.flags = flags;
|
||||
this.last_change = last_change;
|
||||
}
|
||||
}
|
||||
1115
src/main/java/edu/wpi/first/wpilibj/networktables/NetworkTable.java
Normal file
1115
src/main/java/edu/wpi/first/wpilibj/networktables/NetworkTable.java
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,23 @@
|
||||
package edu.wpi.first.wpilibj.networktables;
|
||||
|
||||
import edu.wpi.first.wpilibj.tables.TableKeyNotDefinedException;
|
||||
|
||||
/**
|
||||
* An exception throw when the lookup a a key-value fails in a {@link NetworkTable}
|
||||
*
|
||||
* @deprecated to provide backwards compatability for new api
|
||||
*
|
||||
* @author Mitchell
|
||||
*
|
||||
*/
|
||||
@Deprecated
|
||||
public class NetworkTableKeyNotDefined extends TableKeyNotDefinedException {
|
||||
|
||||
/**
|
||||
* @param key the key that was not defined in the table
|
||||
*/
|
||||
public NetworkTableKeyNotDefined(String key) {
|
||||
super(key);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
package edu.wpi.first.wpilibj.networktables;
|
||||
|
||||
import edu.wpi.first.wpilibj.tables.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import edu.wpi.first.wpiutil.RuntimeDetector;
|
||||
|
||||
public class NetworkTablesJNI {
|
||||
static boolean libraryLoaded = false;
|
||||
static File jniLibrary = null;
|
||||
static {
|
||||
if (!libraryLoaded) {
|
||||
try {
|
||||
System.loadLibrary("ntcore");
|
||||
} catch (UnsatisfiedLinkError e) {
|
||||
try {
|
||||
String resname = RuntimeDetector.getLibraryResource("ntcore");
|
||||
InputStream is = NetworkTablesJNI.class.getResourceAsStream(resname);
|
||||
if (is != null) {
|
||||
// create temporary file
|
||||
if (System.getProperty("os.name").startsWith("Windows"))
|
||||
jniLibrary = File.createTempFile("NetworkTablesJNI", ".dll");
|
||||
else if (System.getProperty("os.name").startsWith("Mac"))
|
||||
jniLibrary = File.createTempFile("libNetworkTablesJNI", ".dylib");
|
||||
else
|
||||
jniLibrary = File.createTempFile("libNetworkTablesJNI", ".so");
|
||||
// flag for delete on exit
|
||||
jniLibrary.deleteOnExit();
|
||||
OutputStream os = new FileOutputStream(jniLibrary);
|
||||
|
||||
byte[] buffer = new byte[1024];
|
||||
int readBytes;
|
||||
try {
|
||||
while ((readBytes = is.read(buffer)) != -1) {
|
||||
os.write(buffer, 0, readBytes);
|
||||
}
|
||||
} finally {
|
||||
os.close();
|
||||
is.close();
|
||||
}
|
||||
System.load(jniLibrary.getAbsolutePath());
|
||||
} else {
|
||||
System.loadLibrary("ntcore");
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
libraryLoaded = true;
|
||||
}
|
||||
}
|
||||
|
||||
public static final int NT_NET_MODE_NONE = 0x00;
|
||||
public static final int NT_NET_MODE_SERVER = 0x01;
|
||||
public static final int NT_NET_MODE_CLIENT = 0x02;
|
||||
public static final int NT_NET_MODE_STARTING = 0x04;
|
||||
public static final int NT_NET_MODE_FAILURE = 0x08;
|
||||
|
||||
public static native boolean containsKey(String key);
|
||||
public static native int getType(String key);
|
||||
|
||||
public static native boolean putBoolean(String key, boolean value);
|
||||
public static native boolean putDouble(String key, double value);
|
||||
public static native boolean putString(String key, String value);
|
||||
public static native boolean putRaw(String key, byte[] value);
|
||||
public static native boolean putRaw(String key, ByteBuffer value, int len);
|
||||
public static native boolean putBooleanArray(String key, boolean[] value);
|
||||
public static native boolean putDoubleArray(String key, double[] value);
|
||||
public static native boolean putStringArray(String key, String[] value);
|
||||
|
||||
public static native void forcePutBoolean(String key, boolean value);
|
||||
public static native void forcePutDouble(String key, double value);
|
||||
public static native void forcePutString(String key, String value);
|
||||
public static native void forcePutRaw(String key, byte[] value);
|
||||
public static native void forcePutRaw(String key, ByteBuffer value, int len);
|
||||
public static native void forcePutBooleanArray(String key, boolean[] value);
|
||||
public static native void forcePutDoubleArray(String key, double[] value);
|
||||
public static native void forcePutStringArray(String key, String[] value);
|
||||
|
||||
public static native Object getValue(String key) throws TableKeyNotDefinedException;
|
||||
public static native boolean getBoolean(String key) throws TableKeyNotDefinedException;
|
||||
public static native double getDouble(String key) throws TableKeyNotDefinedException;
|
||||
public static native String getString(String key) throws TableKeyNotDefinedException;
|
||||
public static native byte[] getRaw(String key) throws TableKeyNotDefinedException;
|
||||
public static native boolean[] getBooleanArray(String key) throws TableKeyNotDefinedException;
|
||||
public static native double[] getDoubleArray(String key) throws TableKeyNotDefinedException;
|
||||
public static native String[] getStringArray(String key) throws TableKeyNotDefinedException;
|
||||
|
||||
public static native Object getValue(String key, Object defaultValue);
|
||||
public static native boolean getBoolean(String key, boolean defaultValue);
|
||||
public static native double getDouble(String key, double defaultValue);
|
||||
public static native String getString(String key, String defaultValue);
|
||||
public static native byte[] getRaw(String key, byte[] defaultValue);
|
||||
public static native boolean[] getBooleanArray(String key, boolean[] defaultValue);
|
||||
public static native double[] getDoubleArray(String key, double[] defaultValue);
|
||||
public static native String[] getStringArray(String key, String[] defaultValue);
|
||||
|
||||
public static native boolean setDefaultBoolean(String key, boolean defaultValue);
|
||||
public static native boolean setDefaultDouble(String key, double defaultValue);
|
||||
public static native boolean setDefaultString(String key, String defaultValue);
|
||||
public static native boolean setDefaultRaw(String key, byte[] defaultValue);
|
||||
public static native boolean setDefaultBooleanArray(String key, boolean[] defaultValue);
|
||||
public static native boolean setDefaultDoubleArray(String key, double[] defaultValue);
|
||||
public static native boolean setDefaultStringArray(String key, String[] defaultValue);
|
||||
|
||||
public static native void setEntryFlags(String key, int flags);
|
||||
public static native int getEntryFlags(String key);
|
||||
|
||||
public static native void deleteEntry(String key);
|
||||
public static native void deleteAllEntries();
|
||||
|
||||
public static native EntryInfo[] getEntries(String prefix, int types);
|
||||
|
||||
public static native void flush();
|
||||
|
||||
@FunctionalInterface
|
||||
public interface EntryListenerFunction {
|
||||
void apply(int uid, String key, Object value, int flags);
|
||||
}
|
||||
public static native int addEntryListener(String prefix, EntryListenerFunction listener, int flags);
|
||||
public static native void removeEntryListener(int entryListenerUid);
|
||||
|
||||
@FunctionalInterface
|
||||
public interface ConnectionListenerFunction {
|
||||
void apply(int uid, boolean connected, ConnectionInfo conn);
|
||||
}
|
||||
public static native int addConnectionListener(ConnectionListenerFunction listener, boolean immediateNotify);
|
||||
public static native void removeConnectionListener(int connListenerUid);
|
||||
|
||||
// public static native void createRpc(String key, byte[] def, IRpc rpc);
|
||||
// public static native void createRpc(String key, ByteBuffer def, int def_len, IRpc rpc);
|
||||
public static native byte[] getRpc(String key) throws TableKeyNotDefinedException;
|
||||
public static native byte[] getRpc(String key, byte[] defaultValue);
|
||||
public static native int callRpc(String key, byte[] params);
|
||||
public static native int callRpc(String key, ByteBuffer params, int params_len);
|
||||
// public static native byte[] getRpcResultBlocking(int callUid);
|
||||
// public static native byte[] getRpcResultNonblocking(int callUid) throws RpcNoResponseException;
|
||||
|
||||
public static native void setNetworkIdentity(String name);
|
||||
public static native int getNetworkMode();
|
||||
public static native void startServer(String persistFilename, String listenAddress, int port);
|
||||
public static native void stopServer();
|
||||
public static native void startClient();
|
||||
public static native void startClient(String serverName, int port);
|
||||
public static native void startClient(String[] serverNames, int[] ports);
|
||||
public static native void stopClient();
|
||||
public static native void setServer(String serverName, int port);
|
||||
public static native void setServer(String[] serverNames, int[] ports);
|
||||
public static native void startDSClient(int port);
|
||||
public static native void stopDSClient();
|
||||
public static native void setUpdateRate(double interval);
|
||||
|
||||
public static native ConnectionInfo[] getConnections();
|
||||
|
||||
public static native void savePersistent(String filename) throws PersistentException;
|
||||
public static native String[] loadPersistent(String filename) throws PersistentException; // returns warnings
|
||||
|
||||
public static native long now();
|
||||
|
||||
@FunctionalInterface
|
||||
public interface LoggerFunction {
|
||||
void apply(int level, String file, int line, String msg);
|
||||
}
|
||||
public static native void setLogger(LoggerFunction func, int minLevel);
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package edu.wpi.first.wpilibj.networktables;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* An exception thrown when persistent load/save fails in a {@link NetworkTable}
|
||||
*
|
||||
*/
|
||||
public class PersistentException extends IOException {
|
||||
|
||||
/**
|
||||
* @param message The error message
|
||||
*/
|
||||
public PersistentException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package edu.wpi.first.wpilibj.networktables2.type;
|
||||
|
||||
/**
|
||||
* @deprecated Use ArrayList instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public class ArrayData {
|
||||
private Object[] data = new Object[0];
|
||||
|
||||
protected Object getAsObject(int index) {
|
||||
return data[index];
|
||||
}
|
||||
protected void _set(int index, Object value) {
|
||||
data[index] = value;
|
||||
}
|
||||
protected void _add(Object value) {
|
||||
setSize(size() + 1);
|
||||
data[size() - 1] = value;
|
||||
}
|
||||
public void remove(int index) {
|
||||
if (index < 0 || index >= size())
|
||||
throw new IndexOutOfBoundsException();
|
||||
if (index < size() - 1)
|
||||
System.arraycopy(data, index + 1, data, index, size() - index - 1);
|
||||
setSize(size() - 1);
|
||||
}
|
||||
public void setSize(int size) {
|
||||
if (size == data.length)
|
||||
return;
|
||||
Object[] newArray = new Object[size];
|
||||
if (size < data.length)
|
||||
System.arraycopy(data, 0, newArray, 0, size);
|
||||
else {
|
||||
System.arraycopy(data, 0, newArray, 0, data.length);
|
||||
for (int i = data.length; i < newArray.length; ++i)
|
||||
newArray[i] = null;
|
||||
}
|
||||
data = newArray;
|
||||
}
|
||||
public int size() {
|
||||
return data.length;
|
||||
}
|
||||
|
||||
public Object[] getDataArray() {
|
||||
return data;
|
||||
}
|
||||
public void setDataArray(Object[] value) {
|
||||
data = value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package edu.wpi.first.wpilibj.networktables2.type;
|
||||
|
||||
/**
|
||||
* @deprecated Use {@literal ArrayList<Boolean>} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public class BooleanArray extends ArrayData {
|
||||
public boolean get(int index) {
|
||||
return ((Boolean)getAsObject(index)).booleanValue();
|
||||
}
|
||||
public void set(int index, boolean value) {
|
||||
_set(index, value?Boolean.TRUE:Boolean.FALSE);
|
||||
}
|
||||
public void add(boolean value) {
|
||||
_add(value?Boolean.TRUE:Boolean.FALSE);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package edu.wpi.first.wpilibj.networktables2.type;
|
||||
|
||||
/**
|
||||
* @deprecated Use {@literal ArrayList<Double>} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public class NumberArray extends ArrayData {
|
||||
public double get(int index) {
|
||||
return ((Double)getAsObject(index)).doubleValue();
|
||||
}
|
||||
public void set(int index, double value) {
|
||||
_set(index, new Double(value));
|
||||
}
|
||||
public void add(double value) {
|
||||
_add(new Double(value));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package edu.wpi.first.wpilibj.networktables2.type;
|
||||
|
||||
/**
|
||||
* @deprecated Use {@literal ArrayList<String>} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public class StringArray extends ArrayData {
|
||||
public String get(int index) {
|
||||
return ((String)getAsObject(index));
|
||||
}
|
||||
public void set(int index, String value) {
|
||||
_set(index, value);
|
||||
}
|
||||
public void add(String value) {
|
||||
_add(value);
|
||||
}
|
||||
}
|
||||
37
src/main/java/edu/wpi/first/wpilibj/tables/IRemote.java
Normal file
37
src/main/java/edu/wpi/first/wpilibj/tables/IRemote.java
Normal file
@@ -0,0 +1,37 @@
|
||||
package edu.wpi.first.wpilibj.tables;
|
||||
|
||||
|
||||
/**
|
||||
* Represents an object that has a remote connection
|
||||
*
|
||||
* @author Mitchell
|
||||
*
|
||||
*/
|
||||
public interface IRemote {
|
||||
/**
|
||||
* Register an object to listen for connection and disconnection events
|
||||
*
|
||||
* @param listener the listener to be register
|
||||
* @param immediateNotify if the listener object should be notified of the current connection state
|
||||
*/
|
||||
public void addConnectionListener(IRemoteConnectionListener listener, boolean immediateNotify);
|
||||
|
||||
/**
|
||||
* Unregister a listener from connection events
|
||||
*
|
||||
* @param listener the listener to be unregistered
|
||||
*/
|
||||
public void removeConnectionListener(IRemoteConnectionListener listener);
|
||||
|
||||
/**
|
||||
* Get the current state of the objects connection
|
||||
* @return the current connection state
|
||||
*/
|
||||
public boolean isConnected();
|
||||
|
||||
/**
|
||||
* If the object is acting as a server
|
||||
* @return if the object is a server
|
||||
*/
|
||||
public boolean isServer();
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package edu.wpi.first.wpilibj.tables;
|
||||
|
||||
import edu.wpi.first.wpilibj.networktables.ConnectionInfo;
|
||||
|
||||
/**
|
||||
* A listener that listens for connection changes in a {@link IRemote} object
|
||||
*
|
||||
* @author Mitchell
|
||||
*
|
||||
*/
|
||||
public interface IRemoteConnectionListener {
|
||||
/**
|
||||
* Called when an IRemote is connected
|
||||
* @param remote the object that connected
|
||||
*/
|
||||
public void connected(IRemote remote);
|
||||
/**
|
||||
* Called when an IRemote is disconnected
|
||||
* @param remote the object that disconnected
|
||||
*/
|
||||
public void disconnected(IRemote remote);
|
||||
/**
|
||||
* Extended version of connected called when an IRemote is connected.
|
||||
* Contains the connection info of the connected remote
|
||||
* @param remote the object that connected
|
||||
* @param info the connection info for the connected remote
|
||||
*/
|
||||
default public void connectedEx(IRemote remote, ConnectionInfo info) {
|
||||
connected(remote);
|
||||
}
|
||||
/**
|
||||
* Extended version of connected called when an IRemote is disconnected.
|
||||
* Contains the connection info of the disconnected remote
|
||||
* @param remote the object that disconnected
|
||||
* @param info the connection info for the disconnected remote
|
||||
*/
|
||||
default public void disconnectedEx(IRemote remote, ConnectionInfo info) {
|
||||
disconnected(remote);
|
||||
}
|
||||
}
|
||||
634
src/main/java/edu/wpi/first/wpilibj/tables/ITable.java
Normal file
634
src/main/java/edu/wpi/first/wpilibj/tables/ITable.java
Normal file
@@ -0,0 +1,634 @@
|
||||
package edu.wpi.first.wpilibj.tables;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Set;
|
||||
|
||||
|
||||
/**
|
||||
* A table whose values can be read and written to
|
||||
*/
|
||||
public interface ITable {
|
||||
|
||||
/**
|
||||
* Checks the table and tells if it contains the specified key
|
||||
*
|
||||
* @param key the key to search for
|
||||
* @return true if the table as a value assigned to the given key
|
||||
*/
|
||||
public boolean containsKey(String key);
|
||||
|
||||
/**
|
||||
* @param key the key to search for
|
||||
* @return true if there is a subtable with the key which contains at least
|
||||
* one key/subtable of its own
|
||||
*/
|
||||
public boolean containsSubTable(String key);
|
||||
|
||||
/**
|
||||
* Returns the table at the specified key. If there is no table at the
|
||||
* specified key, it will create a new table
|
||||
*
|
||||
* @param key the name of the table relative to this one
|
||||
* @return a sub table relative to this one
|
||||
*/
|
||||
public ITable getSubTable(String key);
|
||||
|
||||
/**
|
||||
* @param types bitmask of types; 0 is treated as a "don't care".
|
||||
* @return keys currently in the table
|
||||
*/
|
||||
public Set<String> getKeys(int types);
|
||||
|
||||
/**
|
||||
* @return keys currently in the table
|
||||
*/
|
||||
public Set<String> getKeys();
|
||||
|
||||
/**
|
||||
* @return subtables currently in the table
|
||||
*/
|
||||
public Set<String> getSubTables();
|
||||
|
||||
/**
|
||||
* Makes a key's value persistent through program restarts.
|
||||
* The key cannot be null.
|
||||
*
|
||||
* @param key the key name
|
||||
*/
|
||||
public void setPersistent(String key);
|
||||
|
||||
/**
|
||||
* Stop making a key's value persistent through program restarts.
|
||||
* The key cannot be null.
|
||||
*
|
||||
* @param key the key name
|
||||
*/
|
||||
public void clearPersistent(String key);
|
||||
|
||||
/**
|
||||
* Returns whether the value is persistent through program restarts.
|
||||
* The key cannot be null.
|
||||
*
|
||||
* @param key the key name
|
||||
* @return True if the value is persistent.
|
||||
*/
|
||||
public boolean isPersistent(String key);
|
||||
|
||||
/**
|
||||
* Sets flags on the specified key in this table. The key can
|
||||
* not be null.
|
||||
*
|
||||
* @param key the key name
|
||||
* @param flags the flags to set (bitmask)
|
||||
*/
|
||||
public void setFlags(String key, int flags);
|
||||
|
||||
/**
|
||||
* Clears flags on the specified key in this table. The key can
|
||||
* not be null.
|
||||
*
|
||||
* @param key the key name
|
||||
* @param flags the flags to clear (bitmask)
|
||||
*/
|
||||
public void clearFlags(String key, int flags);
|
||||
|
||||
/**
|
||||
* Returns the flags for the specified key.
|
||||
*
|
||||
* @param key the key name
|
||||
* @return the flags, or 0 if the key is not defined
|
||||
*/
|
||||
public int getFlags(String key);
|
||||
|
||||
/**
|
||||
* Deletes the specified key in this table. The key can
|
||||
* not be null.
|
||||
*
|
||||
* @param key the key name
|
||||
*/
|
||||
public void delete(String key);
|
||||
|
||||
/**
|
||||
* Gets the value associated with a key as an object. If the key does not
|
||||
* exist, it will return the default value
|
||||
* NOTE: If the value is a double, it will return a Double object,
|
||||
* not a primitive. To get the primitive, use
|
||||
* {@link #getDouble(String, double)}.
|
||||
* @param key the key of the value to look up
|
||||
* @return the value associated with the given key
|
||||
* @throws TableKeyNotDefinedException if there is no value associated with
|
||||
* the given key
|
||||
* @deprecated This exception-raising method has been replaced by the
|
||||
* default-taking method {@link #getValue(String, Object)}.
|
||||
*/
|
||||
@Deprecated
|
||||
public Object getValue(String key) throws TableKeyNotDefinedException;
|
||||
|
||||
/**
|
||||
* Gets the value associated with a key as an object.
|
||||
* NOTE: If the value is a double, it will return a Double object,
|
||||
* not a primitive. To get the primitive, use
|
||||
* {@link #getDouble(String, double)}.
|
||||
* @param key the key of the value to look up
|
||||
* @param defaultValue the default value if the key is null
|
||||
* @return the value associated with the given key
|
||||
*/
|
||||
public Object getValue(String key, Object defaultValue);
|
||||
|
||||
/**
|
||||
* Put a value in the table
|
||||
* @param key the key to be assigned to
|
||||
* @param value the value that will be assigned
|
||||
* @return False if the table key already exists with a different type
|
||||
* @throws IllegalArgumentException when the value is not supported by the
|
||||
* table
|
||||
*/
|
||||
public boolean putValue(String key, Object value)
|
||||
throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Retrieve an array data type from the table.
|
||||
* @param key the key to be assigned to
|
||||
* @param externalValue the array data type to retreive into
|
||||
* @throws TableKeyNotDefinedException if there is no value associated with
|
||||
* the given key
|
||||
* @deprecated Use get*Array functions instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public void retrieveValue(String key, Object externalValue) throws TableKeyNotDefinedException;
|
||||
|
||||
/**
|
||||
* Put a number in the table
|
||||
* @param key the key to be assigned to
|
||||
* @param value the value that will be assigned
|
||||
* @return False if the table key already exists with a different type
|
||||
*/
|
||||
public boolean putNumber(String key, double value);
|
||||
|
||||
/**
|
||||
* Gets the current value in the table, setting it if it does not exist.
|
||||
* @param key the key
|
||||
* @param defaultValue the default value to set if key doens't exist.
|
||||
* @return False if the table key exists with a different type
|
||||
*/
|
||||
public boolean setDefaultNumber(String key, double defaultValue);
|
||||
|
||||
/**
|
||||
* Returns the number the key maps to.
|
||||
* @param key the key to look up
|
||||
* @return the value associated with the given key
|
||||
* @throws TableKeyNotDefinedException if there is no value associated with
|
||||
* the given key
|
||||
* @deprecated This exception-raising method has been replaced by the
|
||||
* default-taking method {@link #getNumber(String, double)}.
|
||||
*/
|
||||
@Deprecated
|
||||
public double getNumber(String key) throws TableKeyNotDefinedException;
|
||||
/**
|
||||
* Returns the number the key maps to. If the key does not exist or is of
|
||||
* different type, it will return the default value.
|
||||
* @param key the key to look up
|
||||
* @param defaultValue the value to be returned if no value is found
|
||||
* @return the value associated with the given key or the given default value
|
||||
* if there is no value associated with the key
|
||||
*/
|
||||
public double getNumber(String key, double defaultValue);
|
||||
|
||||
/**
|
||||
* Put a string in the table
|
||||
* @param key the key to be assigned to
|
||||
* @param value the value that will be assigned
|
||||
* @return False if the table key already exists with a different type
|
||||
*/
|
||||
public boolean putString(String key, String value);
|
||||
|
||||
/**
|
||||
* Gets the current value in the table, setting it if it does not exist.
|
||||
* @param key the key
|
||||
* @param defaultValue the default value to set if key doens't exist.
|
||||
* @return False if the table key exists with a different type
|
||||
*/
|
||||
public boolean setDefaultString(String key, String defaultValue);
|
||||
|
||||
/**
|
||||
* Returns the string the key maps to.
|
||||
* @param key the key to look up
|
||||
* @return the value associated with the given key
|
||||
* @throws TableKeyNotDefinedException if there is no value associated with
|
||||
* the given key
|
||||
* @deprecated This exception-raising method has been replaced by the
|
||||
* default-taking method {@link #getString(String, String)}.
|
||||
*/
|
||||
@Deprecated
|
||||
public String getString(String key) throws TableKeyNotDefinedException;
|
||||
/**
|
||||
* Returns the string the key maps to. If the key does not exist or is of
|
||||
* different type, it will return the default value.
|
||||
* @param key the key to look up
|
||||
* @param defaultValue the value to be returned if no value is found
|
||||
* @return the value associated with the given key or the given default value
|
||||
* if there is no value associated with the key
|
||||
*/
|
||||
public String getString(String key, String defaultValue);
|
||||
|
||||
/**
|
||||
* Put a boolean in the table
|
||||
* @param key the key to be assigned to
|
||||
* @param value the value that will be assigned
|
||||
* @return False if the table key already exists with a different type
|
||||
*/
|
||||
public boolean putBoolean(String key, boolean value);
|
||||
|
||||
/**
|
||||
* Gets the current value in the table, setting it if it does not exist.
|
||||
* @param key the key
|
||||
* @param defaultValue the default value to set if key doens't exist.
|
||||
* @return False if the table key exists with a different type
|
||||
*/
|
||||
public boolean setDefaultBoolean(String key, boolean defaultValue);
|
||||
|
||||
/**
|
||||
* Returns the boolean the key maps to.
|
||||
* @param key the key to look up
|
||||
* @return the value associated with the given key
|
||||
* @throws TableKeyNotDefinedException if there is no value associated with
|
||||
* the given key
|
||||
* @deprecated This exception-raising method has been replaced by the
|
||||
* default-taking method {@link #getBoolean(String, boolean)}.
|
||||
*/
|
||||
@Deprecated
|
||||
public boolean getBoolean(String key) throws TableKeyNotDefinedException;
|
||||
/**
|
||||
* Returns the boolean the key maps to. If the key does not exist or is of
|
||||
* different type, it will return the default value.
|
||||
* @param key the key to look up
|
||||
* @param defaultValue the value to be returned if no value is found
|
||||
* @return the value associated with the given key or the given default value
|
||||
* if there is no value associated with the key
|
||||
*/
|
||||
public boolean getBoolean(String key, boolean defaultValue);
|
||||
|
||||
/**
|
||||
* Put a boolean array in the table
|
||||
* @param key the key to be assigned to
|
||||
* @param value the value that will be assigned
|
||||
* @return False if the table key already exists with a different type
|
||||
*/
|
||||
public boolean putBooleanArray(String key, boolean[] value);
|
||||
|
||||
/**
|
||||
* Gets the current value in the table, setting it if it does not exist.
|
||||
* @param key the key
|
||||
* @param defaultValue the default value to set if key doens't exist.
|
||||
* @return False if the table key exists with a different type
|
||||
*/
|
||||
public boolean setDefaultBooleanArray(String key, boolean[] defaultValue);
|
||||
|
||||
/**
|
||||
* Put a boolean array in the table
|
||||
* @param key the key to be assigned to
|
||||
* @param value the value that will be assigned
|
||||
* @return False if the table key already exists with a different type
|
||||
*/
|
||||
public boolean putBooleanArray(String key, Boolean[] value);
|
||||
|
||||
/**
|
||||
* Gets the current value in the table, setting it if it does not exist.
|
||||
* @param key the key
|
||||
* @param defaultValue the default value to set if key doens't exist.
|
||||
* @return False if the table key exists with a different type
|
||||
*/
|
||||
public boolean setDefaultBooleanArray(String key, Boolean[] defaultValue);
|
||||
|
||||
/**
|
||||
* Returns the boolean array the key maps to.
|
||||
* @param key the key to look up
|
||||
* @return the value associated with the given key
|
||||
* @throws TableKeyNotDefinedException if there is no value associated with
|
||||
* the given key
|
||||
* @deprecated This exception-raising method has been replaced by the
|
||||
* default-taking method {@link #getBooleanArray(String, boolean[])}.
|
||||
*/
|
||||
@Deprecated
|
||||
public boolean[] getBooleanArray(String key) throws TableKeyNotDefinedException;
|
||||
/**
|
||||
* Returns the boolean array the key maps to. If the key does not exist or is
|
||||
* of different type, it will return the default value.
|
||||
* @param key the key to look up
|
||||
* @param defaultValue the value to be returned if no value is found
|
||||
* @return the value associated with the given key or the given default value
|
||||
* if there is no value associated with the key
|
||||
*/
|
||||
public boolean[] getBooleanArray(String key, boolean[] defaultValue);
|
||||
/**
|
||||
* Returns the boolean array the key maps to. If the key does not exist or is
|
||||
* of different type, it will return the default value.
|
||||
* @param key the key to look up
|
||||
* @param defaultValue the value to be returned if no value is found
|
||||
* @return the value associated with the given key or the given default value
|
||||
* if there is no value associated with the key
|
||||
*/
|
||||
public Boolean[] getBooleanArray(String key, Boolean[] defaultValue);
|
||||
|
||||
/**
|
||||
* Put a number array in the table
|
||||
* @param key the key to be assigned to
|
||||
* @param value the value that will be assigned
|
||||
* @return False if the table key already exists with a different type
|
||||
*/
|
||||
public boolean putNumberArray(String key, double[] value);
|
||||
|
||||
/**
|
||||
* Gets the current value in the table, setting it if it does not exist.
|
||||
* @param key the key
|
||||
* @param defaultValue the default value to set if key doens't exist.
|
||||
* @return False if the table key exists with a different type
|
||||
*/
|
||||
public boolean setDefaultNumberArray(String key, double[] defaultValue);
|
||||
|
||||
/**
|
||||
* Put a number array in the table
|
||||
* @param key the key to be assigned to
|
||||
* @param value the value that will be assigned
|
||||
* @return False if the table key already exists with a different type
|
||||
*/
|
||||
public boolean putNumberArray(String key, Double[] value);
|
||||
|
||||
/**
|
||||
* Gets the current value in the table, setting it if it does not exist.
|
||||
* @param key the key
|
||||
* @param defaultValue the default value to set if key doens't exist.
|
||||
* @return False if the table key exists with a different type
|
||||
*/
|
||||
public boolean setDefaultNumberArray(String key, Double[] defaultValue);
|
||||
|
||||
/**
|
||||
* Returns the number array the key maps to.
|
||||
* @param key the key to look up
|
||||
* @return the value associated with the given key
|
||||
* @throws TableKeyNotDefinedException if there is no value associated with
|
||||
* the given key
|
||||
* @deprecated This exception-raising method has been replaced by the
|
||||
* default-taking method {@link #getNumberArray(String, double[])}.
|
||||
*/
|
||||
@Deprecated
|
||||
public double[] getNumberArray(String key) throws TableKeyNotDefinedException;
|
||||
/**
|
||||
* Returns the number array the key maps to. If the key does not exist or is
|
||||
* of different type, it will return the default value.
|
||||
* @param key the key to look up
|
||||
* @param defaultValue the value to be returned if no value is found
|
||||
* @return the value associated with the given key or the given default value
|
||||
* if there is no value associated with the key
|
||||
*/
|
||||
public double[] getNumberArray(String key, double[] defaultValue);
|
||||
/**
|
||||
* Returns the number array the key maps to. If the key does not exist or is
|
||||
* of different type, it will return the default value.
|
||||
* @param key the key to look up
|
||||
* @param defaultValue the value to be returned if no value is found
|
||||
* @return the value associated with the given key or the given default value
|
||||
* if there is no value associated with the key
|
||||
*/
|
||||
public Double[] getNumberArray(String key, Double[] defaultValue);
|
||||
|
||||
/**
|
||||
* Put a string array in the table
|
||||
* @param key the key to be assigned to
|
||||
* @param value the value that will be assigned
|
||||
* @return False if the table key already exists with a different type
|
||||
*/
|
||||
public boolean putStringArray(String key, String[] value);
|
||||
|
||||
/**
|
||||
* Gets the current value in the table, setting it if it does not exist.
|
||||
* @param key the key
|
||||
* @param defaultValue the default value to set if key doens't exist.
|
||||
* @return False if the table key exists with a different type
|
||||
*/
|
||||
public boolean setDefaultStringArray(String key, String[] defaultValue);
|
||||
|
||||
/**
|
||||
* Returns the string array the key maps to.
|
||||
* @param key the key to look up
|
||||
* @return the value associated with the given key
|
||||
* @throws TableKeyNotDefinedException if there is no value associated with
|
||||
* the given key
|
||||
* @deprecated This exception-raising method has been replaced by the
|
||||
* default-taking method {@link #getStringArray(String, String[])}.
|
||||
*/
|
||||
@Deprecated
|
||||
public String[] getStringArray(String key) throws TableKeyNotDefinedException;
|
||||
/**
|
||||
* Returns the string array the key maps to. If the key does not exist or is
|
||||
* of different type, it will return the default value.
|
||||
* @param key the key to look up
|
||||
* @param defaultValue the value to be returned if no value is found
|
||||
* @return the value associated with the given key or the given default value
|
||||
* if there is no value associated with the key
|
||||
*/
|
||||
public String[] getStringArray(String key, String[] defaultValue);
|
||||
|
||||
/**
|
||||
* Put a raw value (byte array) in the table
|
||||
* @param key the key to be assigned to
|
||||
* @param value the value that will be assigned
|
||||
* @return False if the table key already exists with a different type
|
||||
*/
|
||||
public boolean putRaw(String key, byte[] value);
|
||||
|
||||
/**
|
||||
* Gets the current value in the table, setting it if it does not exist.
|
||||
* @param key the key
|
||||
* @param defaultValue the default value to set if key doens't exist.
|
||||
* @return False if the table key exists with a different type
|
||||
*/
|
||||
public boolean setDefaultRaw(String key, byte[] defaultValue);
|
||||
|
||||
/**
|
||||
* Put a raw value (bytes from a byte buffer) in the table
|
||||
* @param key the key to be assigned to
|
||||
* @param value the value that will be assigned
|
||||
* @param len the length of the value
|
||||
* @return False if the table key already exists with a different type
|
||||
*/
|
||||
public boolean putRaw(String key, ByteBuffer value, int len);
|
||||
/**
|
||||
* Returns the raw value (byte array) the key maps to.
|
||||
* @param key the key to look up
|
||||
* @return the value associated with the given key
|
||||
* @throws TableKeyNotDefinedException if there is no value associated with
|
||||
* the given key
|
||||
* @deprecated This exception-raising method has been replaced by the
|
||||
* default-taking method {@link #getRaw(String, byte[])}.
|
||||
*/
|
||||
@Deprecated
|
||||
public byte[] getRaw(String key) throws TableKeyNotDefinedException;
|
||||
/**
|
||||
* Returns the raw value (byte array) the key maps to. If the key does not
|
||||
* exist or is of different type, it will return the default value.
|
||||
* @param key the key to look up
|
||||
* @param defaultValue the value to be returned if no value is found
|
||||
* @return the value associated with the given key or the given default value
|
||||
* if there is no value associated with the key
|
||||
*/
|
||||
public byte[] getRaw(String key, byte[] defaultValue);
|
||||
|
||||
/** Notifier flag values. */
|
||||
public static final int NOTIFY_IMMEDIATE = 0x01;
|
||||
public static final int NOTIFY_LOCAL = 0x02;
|
||||
public static final int NOTIFY_NEW = 0x04;
|
||||
public static final int NOTIFY_DELETE = 0x08;
|
||||
public static final int NOTIFY_UPDATE = 0x10;
|
||||
public static final int NOTIFY_FLAGS = 0x20;
|
||||
|
||||
/**
|
||||
* Add a listener for changes to the table
|
||||
* @param listener the listener to add
|
||||
*/
|
||||
public void addTableListener(ITableListener listener);
|
||||
/**
|
||||
* Add a listener for changes to the table
|
||||
* @param listener the listener to add
|
||||
* @param immediateNotify if true then this listener will be notified of all
|
||||
* current entries (marked as new)
|
||||
*/
|
||||
public void addTableListener(ITableListener listener,
|
||||
boolean immediateNotify);
|
||||
/**
|
||||
* Add a listener for changes to the table
|
||||
* @param listener the listener to add
|
||||
* @param flags bitmask specifying desired notifications
|
||||
*/
|
||||
public void addTableListenerEx(ITableListener listener, int flags);
|
||||
|
||||
/**
|
||||
* Add a listener for changes to a specific key the table
|
||||
* @param key the key to listen for
|
||||
* @param listener the listener to add
|
||||
* @param immediateNotify if true then this listener will be notified of all
|
||||
* current entries (marked as new)
|
||||
*/
|
||||
public void addTableListener(String key, ITableListener listener,
|
||||
boolean immediateNotify);
|
||||
/**
|
||||
* Add a listener for changes to a specific key the table
|
||||
* @param key the key to listen for
|
||||
* @param listener the listener to add
|
||||
* @param flags bitmask specifying desired notifications
|
||||
*/
|
||||
public void addTableListenerEx(String key, ITableListener listener,
|
||||
int flags);
|
||||
/**
|
||||
* This will immediately notify the listener of all current sub tables
|
||||
* @param listener the listener to notify
|
||||
*/
|
||||
public void addSubTableListener(final ITableListener listener);
|
||||
/**
|
||||
* This will immediately notify the listener of all current sub tables
|
||||
* @param listener the listener to notify
|
||||
* @param localNotify if true then this listener will be notified of all
|
||||
* local changes in addition to all remote changes
|
||||
*/
|
||||
public void addSubTableListener(final ITableListener listener,
|
||||
boolean localNotify);
|
||||
/**
|
||||
* Remove a listener from receiving table events
|
||||
* @param listener the listener to be removed
|
||||
*/
|
||||
public void removeTableListener(ITableListener listener);
|
||||
|
||||
/*
|
||||
* Deprecated Methods
|
||||
*/
|
||||
|
||||
/**
|
||||
* Maps the specified key to the specified value in this table.
|
||||
* The key can not be null.
|
||||
* The value can be retrieved by calling the get method with a key that is
|
||||
* equal to the original key.
|
||||
* @param key the key
|
||||
* @param value the value
|
||||
* @return False if the table key already exists with a different type
|
||||
* @throws IllegalArgumentException if key is null
|
||||
* @deprecated Use {@link #putNumber(String, double)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public boolean putInt(String key, int value);
|
||||
|
||||
/**
|
||||
* Returns the value at the specified key.
|
||||
* @param key the key
|
||||
* @return the value
|
||||
* @throws TableKeyNotDefinedException if there is no value mapped to by the
|
||||
* key
|
||||
* @throws IllegalArgumentException if the value mapped to by the key is not
|
||||
* an int
|
||||
* @throws IllegalArgumentException if the key is null
|
||||
* @deprecated Use {@link #getNumber(String, double)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public int getInt(String key) throws TableKeyNotDefinedException;
|
||||
|
||||
/**
|
||||
* Returns the value at the specified key.
|
||||
* @param key the key
|
||||
* @param defaultValue the value returned if the key is undefined
|
||||
* @return the value
|
||||
* @throws IllegalArgumentException if the value mapped to by the key is not
|
||||
* an int
|
||||
* @throws IllegalArgumentException if the key is null
|
||||
* @deprecated Use {@link #getNumber(String, double)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public int getInt(String key, int defaultValue)
|
||||
throws TableKeyNotDefinedException;
|
||||
|
||||
/**
|
||||
* Maps the specified key to the specified value in this table.
|
||||
* The key can not be null.
|
||||
* The value can be retrieved by calling the get method with a key that is
|
||||
* equal to the original key.
|
||||
* @param key the key
|
||||
* @param value the value
|
||||
* @return False if the table key already exists with a different type
|
||||
* @throws IllegalArgumentException if key is null
|
||||
* @deprecated Use {@link #putNumber(String, double)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public boolean putDouble(String key, double value);
|
||||
|
||||
/**
|
||||
* Returns the value at the specified key.
|
||||
* @param key the key
|
||||
* @return the value
|
||||
* @throws TableKeyNotDefinedException if there is no
|
||||
* value mapped to by the key
|
||||
* @throws IllegalArgumentException if the value mapped to by the key is not a
|
||||
* double
|
||||
* @throws IllegalArgumentException if the key is null
|
||||
* @deprecated Use {@link #getNumber(String, double)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public double getDouble(String key) throws TableKeyNotDefinedException;
|
||||
|
||||
/**
|
||||
* Returns the value at the specified key.
|
||||
* @param key the key
|
||||
* @param defaultValue the value returned if the key is undefined
|
||||
* @return the value
|
||||
* @throws IllegalArgumentException if the value mapped to by the key is not a
|
||||
* double
|
||||
* @throws IllegalArgumentException if the key is null
|
||||
* @deprecated Use {@link #getNumber(String, double)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public double getDouble(String key, double defaultValue);
|
||||
|
||||
/**
|
||||
* Gets the full path of this table.
|
||||
*/
|
||||
public String getPath();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package edu.wpi.first.wpilibj.tables;
|
||||
|
||||
/**
|
||||
* A listener that listens to changes in values in a {@link ITable}
|
||||
*
|
||||
* @author Mitchell
|
||||
*
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface ITableListener {
|
||||
/**
|
||||
* Called when a key-value pair is changed in a {@link ITable}
|
||||
* @param source the table the key-value pair exists in
|
||||
* @param key the key associated with the value that changed
|
||||
* @param value the new value
|
||||
* @param isNew true if the key did not previously exist in the table, otherwise it is false
|
||||
*/
|
||||
public void valueChanged(ITable source, String key, Object value, boolean isNew);
|
||||
|
||||
/**
|
||||
* Extended version of valueChanged. Called when a key-value pair is
|
||||
* changed in a {@link ITable}. The default implementation simply calls
|
||||
* valueChanged(). If this is overridden, valueChanged() will not be
|
||||
* called.
|
||||
* @param source the table the key-value pair exists in
|
||||
* @param key the key associated with the value that changed
|
||||
* @param value the new value
|
||||
* @param flags update flags; for example, NOTIFY_NEW if the key did not
|
||||
* previously exist in the table
|
||||
*/
|
||||
default public void valueChangedEx(ITable source, String key, Object value, int flags) {
|
||||
// NOTIFY_NEW = 0x04
|
||||
valueChanged(source, key, value, (flags & 0x04) != 0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package edu.wpi.first.wpilibj.tables;
|
||||
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
/**
|
||||
* An exception throw when the lookup a a key-value fails in a {@link ITable}
|
||||
*
|
||||
* @author Mitchell
|
||||
*
|
||||
*/
|
||||
public class TableKeyNotDefinedException extends NoSuchElementException {
|
||||
|
||||
/**
|
||||
* @param key the key that was not defined in the table
|
||||
*/
|
||||
public TableKeyNotDefinedException(String key) {
|
||||
super("Unknown Table Key: "+key);
|
||||
}
|
||||
|
||||
}
|
||||
1749
src/main/native/cpp/jni/NetworkTablesJNI.cpp
Normal file
1749
src/main/native/cpp/jni/NetworkTablesJNI.cpp
Normal file
File diff suppressed because it is too large
Load Diff
572
src/main/native/include/networktables/NetworkTable.h
Normal file
572
src/main/native/include/networktables/NetworkTable.h
Normal file
@@ -0,0 +1,572 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2015. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef NETWORKTABLE_H_
|
||||
#define NETWORKTABLE_H_
|
||||
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
#include "tables/ITable.h"
|
||||
|
||||
/**
|
||||
* A network table that knows its subtable path.
|
||||
*/
|
||||
class NetworkTable : public ITable {
|
||||
private:
|
||||
struct private_init {};
|
||||
|
||||
std::string m_path;
|
||||
std::mutex m_mutex;
|
||||
typedef std::pair<ITableListener*, unsigned int> Listener;
|
||||
std::vector<Listener> m_listeners;
|
||||
|
||||
static std::vector<std::string> s_ip_addresses;
|
||||
static std::string s_persistent_filename;
|
||||
static bool s_client;
|
||||
static bool s_enable_ds;
|
||||
static bool s_running;
|
||||
static unsigned int s_port;
|
||||
|
||||
public:
|
||||
NetworkTable(llvm::StringRef path, const private_init&);
|
||||
virtual ~NetworkTable();
|
||||
|
||||
/**
|
||||
* The path separator for sub-tables and keys
|
||||
*
|
||||
*/
|
||||
static const char PATH_SEPARATOR_CHAR;
|
||||
|
||||
/**
|
||||
* @throws IOException
|
||||
*/
|
||||
static void Initialize();
|
||||
static void Shutdown();
|
||||
|
||||
/**
|
||||
* set that network tables should be a client
|
||||
* This must be called before initialize or GetTable
|
||||
*/
|
||||
static void SetClientMode();
|
||||
|
||||
/**
|
||||
* set that network tables should be a server
|
||||
* This must be called before initialize or GetTable
|
||||
*/
|
||||
static void SetServerMode();
|
||||
|
||||
/**
|
||||
* set the team the robot is configured for (this will set the mdns address
|
||||
* that network tables will connect to in client mode)
|
||||
* This must be called before initialize or GetTable
|
||||
* @param team the team number
|
||||
*/
|
||||
static void SetTeam(int team);
|
||||
|
||||
/**
|
||||
* @param address the adress that network tables will connect to in client
|
||||
* mode
|
||||
*/
|
||||
static void SetIPAddress(llvm::StringRef address);
|
||||
|
||||
/**
|
||||
* @param addresses the addresses that network tables will connect to in
|
||||
* client mode (in round robin order)
|
||||
*/
|
||||
static void SetIPAddress(llvm::ArrayRef<std::string> addresses);
|
||||
|
||||
/**
|
||||
* @param port the port number that network tables will connect to in client
|
||||
* mode or listen to in server mode
|
||||
*/
|
||||
static void SetPort(unsigned int port);
|
||||
|
||||
/**
|
||||
* @param enabled whether to enable the connection to the local DS to get
|
||||
* the robot IP address (defaults to enabled)
|
||||
*/
|
||||
static void SetDSClientEnabled(bool enabled);
|
||||
|
||||
/**
|
||||
* Sets the persistent filename.
|
||||
* @param filename the filename that the network tables server uses for
|
||||
* automatic loading and saving of persistent values
|
||||
*/
|
||||
static void SetPersistentFilename(llvm::StringRef filename);
|
||||
|
||||
/**
|
||||
* Sets the network identity.
|
||||
* This is provided in the connection info on the remote end.
|
||||
* @param name identity
|
||||
*/
|
||||
static void SetNetworkIdentity(llvm::StringRef name);
|
||||
|
||||
/**
|
||||
* Deletes ALL keys in ALL subtables. Use with caution!
|
||||
*/
|
||||
static void GlobalDeleteAll();
|
||||
|
||||
/**
|
||||
* Flushes all updated values immediately to the network.
|
||||
* Note: This is rate-limited to protect the network from flooding.
|
||||
* This is primarily useful for synchronizing network updates with
|
||||
* user code.
|
||||
*/
|
||||
static void Flush();
|
||||
|
||||
/**
|
||||
* Set the periodic update rate.
|
||||
*
|
||||
* @param interval update interval in seconds (range 0.01 to 1.0)
|
||||
*/
|
||||
static void SetUpdateRate(double interval);
|
||||
|
||||
/**
|
||||
* Saves persistent keys to a file. The server does this automatically.
|
||||
*
|
||||
* @param filename file name
|
||||
* @return Error (or nullptr).
|
||||
*/
|
||||
static const char* SavePersistent(llvm::StringRef filename);
|
||||
|
||||
/**
|
||||
* Loads persistent keys from a file. The server does this automatically.
|
||||
*
|
||||
* @param filename file name
|
||||
* @param warn callback function called for warnings
|
||||
* @return Error (or nullptr).
|
||||
*/
|
||||
static const char* LoadPersistent(
|
||||
llvm::StringRef filename,
|
||||
std::function<void(size_t line, const char* msg)> warn);
|
||||
|
||||
/**
|
||||
* Gets the table with the specified key. If the table does not exist, a new
|
||||
* table will be created.<br>
|
||||
* This will automatically initialize network tables if it has not been
|
||||
* already.
|
||||
*
|
||||
* @param key
|
||||
* the key name
|
||||
* @return the network table requested
|
||||
*/
|
||||
static std::shared_ptr<NetworkTable> GetTable(llvm::StringRef key);
|
||||
|
||||
void AddTableListener(ITableListener* listener) override;
|
||||
void AddTableListener(ITableListener* listener,
|
||||
bool immediateNotify) override;
|
||||
void AddTableListenerEx(ITableListener* listener,
|
||||
unsigned int flags) override;
|
||||
void AddTableListener(llvm::StringRef key, ITableListener* listener,
|
||||
bool immediateNotify) override;
|
||||
void AddTableListenerEx(llvm::StringRef key, ITableListener* listener,
|
||||
unsigned int flags) override;
|
||||
void AddSubTableListener(ITableListener* listener) override;
|
||||
void AddSubTableListener(ITableListener* listener, bool localNotify) override;
|
||||
void RemoveTableListener(ITableListener* listener) override;
|
||||
|
||||
/**
|
||||
* Returns the table at the specified key. If there is no table at the
|
||||
* specified key, it will create a new table
|
||||
*
|
||||
* @param key
|
||||
* the key name
|
||||
* @return the networktable to be returned
|
||||
*/
|
||||
std::shared_ptr<ITable> GetSubTable(llvm::StringRef key) const override;
|
||||
|
||||
/**
|
||||
* Determines whether the given key is in this table.
|
||||
*
|
||||
* @param key the key to search for
|
||||
* @return true if the table as a value assigned to the given key
|
||||
*/
|
||||
bool ContainsKey(llvm::StringRef key) const override;
|
||||
|
||||
/**
|
||||
* Determines whether there exists a non-empty subtable for this key
|
||||
* in this table.
|
||||
*
|
||||
* @param key the key to search for
|
||||
* @return true if there is a subtable with the key which contains at least
|
||||
* one key/subtable of its own
|
||||
*/
|
||||
bool ContainsSubTable(llvm::StringRef key) const override;
|
||||
|
||||
/**
|
||||
* @param types bitmask of types; 0 is treated as a "don't care".
|
||||
* @return keys currently in the table
|
||||
*/
|
||||
std::vector<std::string> GetKeys(int types = 0) const override;
|
||||
|
||||
/**
|
||||
* @return subtables currently in the table
|
||||
*/
|
||||
std::vector<std::string> GetSubTables() const override;
|
||||
|
||||
/**
|
||||
* Makes a key's value persistent through program restarts.
|
||||
*
|
||||
* @param key the key to make persistent
|
||||
*/
|
||||
void SetPersistent(llvm::StringRef key) override;
|
||||
|
||||
/**
|
||||
* Stop making a key's value persistent through program restarts.
|
||||
* The key cannot be null.
|
||||
*
|
||||
* @param key the key name
|
||||
*/
|
||||
void ClearPersistent(llvm::StringRef key) override;
|
||||
|
||||
/**
|
||||
* Returns whether the value is persistent through program restarts.
|
||||
* The key cannot be null.
|
||||
*
|
||||
* @param key the key name
|
||||
*/
|
||||
bool IsPersistent(llvm::StringRef key) const override;
|
||||
|
||||
/**
|
||||
* Sets flags on the specified key in this table. The key can
|
||||
* not be null.
|
||||
*
|
||||
* @param key the key name
|
||||
* @param flags the flags to set (bitmask)
|
||||
*/
|
||||
void SetFlags(llvm::StringRef key, unsigned int flags) override;
|
||||
|
||||
/**
|
||||
* Clears flags on the specified key in this table. The key can
|
||||
* not be null.
|
||||
*
|
||||
* @param key the key name
|
||||
* @param flags the flags to clear (bitmask)
|
||||
*/
|
||||
void ClearFlags(llvm::StringRef key, unsigned int flags) override;
|
||||
|
||||
/**
|
||||
* Returns the flags for the specified key.
|
||||
*
|
||||
* @param key the key name
|
||||
* @return the flags, or 0 if the key is not defined
|
||||
*/
|
||||
unsigned int GetFlags(llvm::StringRef key) const override;
|
||||
|
||||
/**
|
||||
* Deletes the specified key in this table.
|
||||
*
|
||||
* @param key the key name
|
||||
*/
|
||||
void Delete(llvm::StringRef key) override;
|
||||
|
||||
/**
|
||||
* Put a number in the table
|
||||
*
|
||||
* @param key the key to be assigned to
|
||||
* @param value the value that will be assigned
|
||||
* @return False if the table key already exists with a different type
|
||||
*/
|
||||
bool PutNumber(llvm::StringRef key, double value) override;
|
||||
|
||||
/**
|
||||
* Gets the current value in the table, setting it if it does not exist.
|
||||
* @param key the key
|
||||
* @param defaultValue the default value to set if key doesn't exist.
|
||||
* @returns False if the table key exists with a different type
|
||||
*/
|
||||
virtual bool SetDefaultNumber(llvm::StringRef key,
|
||||
double defaultValue) override;
|
||||
|
||||
/**
|
||||
* Gets the number associated with the given name.
|
||||
*
|
||||
* @param key the key to look up
|
||||
* @return the value associated with the given key
|
||||
* @throws TableKeyNotDefinedException if there is no value associated with
|
||||
* the given key
|
||||
* @deprecated This exception-raising method has been replaced by the
|
||||
* default-taking method.
|
||||
*/
|
||||
WPI_DEPRECATED(
|
||||
"Raises an exception if key not found; "
|
||||
"use GetNumber(StringRef key, double defaultValue) instead")
|
||||
virtual double GetNumber(llvm::StringRef key) const override;
|
||||
|
||||
/**
|
||||
* Gets the number associated with the given name.
|
||||
*
|
||||
* @param key the key to look up
|
||||
* @param defaultValue the value to be returned if no value is found
|
||||
* @return the value associated with the given key or the given default value
|
||||
* if there is no value associated with the key
|
||||
*/
|
||||
virtual double GetNumber(llvm::StringRef key,
|
||||
double defaultValue) const override;
|
||||
|
||||
/**
|
||||
* Put a string in the table
|
||||
*
|
||||
* @param key the key to be assigned to
|
||||
* @param value the value that will be assigned
|
||||
* @return False if the table key already exists with a different type
|
||||
*/
|
||||
virtual bool PutString(llvm::StringRef key, llvm::StringRef value) override;
|
||||
|
||||
/**
|
||||
* Gets the current value in the table, setting it if it does not exist.
|
||||
* @param key the key
|
||||
* @param defaultValue the default value to set if key doesn't exist.
|
||||
* @returns False if the table key exists with a different type
|
||||
*/
|
||||
virtual bool SetDefaultString(llvm::StringRef key,
|
||||
llvm::StringRef defaultValue) override;
|
||||
|
||||
/**
|
||||
* Gets the string associated with the given name.
|
||||
*
|
||||
* @param key the key to look up
|
||||
* @return the value associated with the given key
|
||||
* @throws TableKeyNotDefinedException if there is no value associated with
|
||||
* the given key
|
||||
* @deprecated This exception-raising method has been replaced by the
|
||||
* default-taking method.
|
||||
*/
|
||||
WPI_DEPRECATED(
|
||||
"Raises an exception if key not found; "
|
||||
"use GetString(StringRef key, StringRef defaultValue) instead")
|
||||
virtual std::string GetString(llvm::StringRef key) const override;
|
||||
|
||||
/**
|
||||
* Gets the string associated with the given name. If the key does not
|
||||
* exist or is of different type, it will return the default value.
|
||||
*
|
||||
* @param key the key to look up
|
||||
* @param defaultValue the value to be returned if no value is found
|
||||
* @return the value associated with the given key or the given default value
|
||||
* if there is no value associated with the key
|
||||
*/
|
||||
virtual std::string GetString(llvm::StringRef key,
|
||||
llvm::StringRef defaultValue) const override;
|
||||
|
||||
/**
|
||||
* Put a boolean in the table
|
||||
*
|
||||
* @param key the key to be assigned to
|
||||
* @param value the value that will be assigned
|
||||
* @return False if the table key already exists with a different type
|
||||
*/
|
||||
virtual bool PutBoolean(llvm::StringRef key, bool value) override;
|
||||
|
||||
/**
|
||||
* Gets the current value in the table, setting it if it does not exist.
|
||||
* @param key the key
|
||||
* @param defaultValue the default value to set if key doesn't exist.
|
||||
* @returns False if the table key exists with a different type
|
||||
*/
|
||||
virtual bool SetDefaultBoolean(llvm::StringRef key,
|
||||
bool defaultValue) override;
|
||||
|
||||
/**
|
||||
* Gets the boolean associated with the given name.
|
||||
*
|
||||
* @param key the key to look up
|
||||
* @return the value associated with the given key
|
||||
* @throws TableKeyNotDefinedException if there is no value associated with
|
||||
* the given key
|
||||
* @deprecated This exception-raising method has been replaced by the
|
||||
* default-taking method.
|
||||
*/
|
||||
WPI_DEPRECATED(
|
||||
"Raises an exception if key not found; "
|
||||
"use GetBoolean(StringRef key, bool defaultValue) instead")
|
||||
virtual bool GetBoolean(llvm::StringRef key) const override;
|
||||
|
||||
/**
|
||||
* Gets the boolean associated with the given name. If the key does not
|
||||
* exist or is of different type, it will return the default value.
|
||||
*
|
||||
* @param key the key to look up
|
||||
* @param defaultValue the value to be returned if no value is found
|
||||
* @return the value associated with the given key or the given default value
|
||||
* if there is no value associated with the key
|
||||
*/
|
||||
virtual bool GetBoolean(llvm::StringRef key,
|
||||
bool defaultValue) const override;
|
||||
|
||||
/**
|
||||
* Put a boolean array in the table
|
||||
* @param key the key to be assigned to
|
||||
* @param value the value that will be assigned
|
||||
* @return False if the table key already exists with a different type
|
||||
*
|
||||
* @note The array must be of int's rather than of bool's because
|
||||
* std::vector<bool> is special-cased in C++. 0 is false, any
|
||||
* non-zero value is true.
|
||||
*/
|
||||
virtual bool PutBooleanArray(llvm::StringRef key,
|
||||
llvm::ArrayRef<int> value) override;
|
||||
|
||||
/**
|
||||
* Gets the current value in the table, setting it if it does not exist.
|
||||
* @param key the key
|
||||
* @param defaultValue the default value to set if key doesn't exist.
|
||||
* @returns False if the table key exists with a different type
|
||||
*/
|
||||
virtual bool SetDefaultBooleanArray(
|
||||
llvm::StringRef key, llvm::ArrayRef<int> defaultValue) override;
|
||||
|
||||
/**
|
||||
* Returns the boolean array the key maps to. If the key does not exist or is
|
||||
* of different type, it will return the default value.
|
||||
* @param key the key to look up
|
||||
* @param defaultValue the value to be returned if no value is found
|
||||
* @return the value associated with the given key or the given default value
|
||||
* if there is no value associated with the key
|
||||
*
|
||||
* @note This makes a copy of the array. If the overhead of this is a
|
||||
* concern, use GetValue() instead.
|
||||
*
|
||||
* @note The returned array is std::vector<int> instead of std::vector<bool>
|
||||
* because std::vector<bool> is special-cased in C++. 0 is false, any
|
||||
* non-zero value is true.
|
||||
*/
|
||||
virtual std::vector<int> GetBooleanArray(
|
||||
llvm::StringRef key, llvm::ArrayRef<int> defaultValue) const override;
|
||||
|
||||
/**
|
||||
* Put a number array in the table
|
||||
* @param key the key to be assigned to
|
||||
* @param value the value that will be assigned
|
||||
* @return False if the table key already exists with a different type
|
||||
*/
|
||||
virtual bool PutNumberArray(llvm::StringRef key,
|
||||
llvm::ArrayRef<double> value) override;
|
||||
|
||||
/**
|
||||
* Gets the current value in the table, setting it if it does not exist.
|
||||
* @param key the key
|
||||
* @param defaultValue the default value to set if key doesn't exist.
|
||||
* @returns False if the table key exists with a different type
|
||||
*/
|
||||
virtual bool SetDefaultNumberArray(
|
||||
llvm::StringRef key, llvm::ArrayRef<double> defaultValue) override;
|
||||
|
||||
/**
|
||||
* Returns the number array the key maps to. If the key does not exist or is
|
||||
* of different type, it will return the default value.
|
||||
* @param key the key to look up
|
||||
* @param defaultValue the value to be returned if no value is found
|
||||
* @return the value associated with the given key or the given default value
|
||||
* if there is no value associated with the key
|
||||
*
|
||||
* @note This makes a copy of the array. If the overhead of this is a
|
||||
* concern, use GetValue() instead.
|
||||
*/
|
||||
virtual std::vector<double> GetNumberArray(
|
||||
llvm::StringRef key, llvm::ArrayRef<double> defaultValue) const override;
|
||||
|
||||
/**
|
||||
* Put a string array in the table
|
||||
* @param key the key to be assigned to
|
||||
* @param value the value that will be assigned
|
||||
* @return False if the table key already exists with a different type
|
||||
*/
|
||||
virtual bool PutStringArray(llvm::StringRef key,
|
||||
llvm::ArrayRef<std::string> value) override;
|
||||
|
||||
/**
|
||||
* Gets the current value in the table, setting it if it does not exist.
|
||||
* @param key the key
|
||||
* @param defaultValue the default value to set if key doesn't exist.
|
||||
* @returns False if the table key exists with a different type
|
||||
*/
|
||||
virtual bool SetDefaultStringArray(
|
||||
llvm::StringRef key, llvm::ArrayRef<std::string> defaultValue) override;
|
||||
|
||||
/**
|
||||
* Returns the string array the key maps to. If the key does not exist or is
|
||||
* of different type, it will return the default value.
|
||||
* @param key the key to look up
|
||||
* @param defaultValue the value to be returned if no value is found
|
||||
* @return the value associated with the given key or the given default value
|
||||
* if there is no value associated with the key
|
||||
*
|
||||
* @note This makes a copy of the array. If the overhead of this is a
|
||||
* concern, use GetValue() instead.
|
||||
*/
|
||||
virtual std::vector<std::string> GetStringArray(
|
||||
llvm::StringRef key,
|
||||
llvm::ArrayRef<std::string> defaultValue) const override;
|
||||
|
||||
/**
|
||||
* Put a raw value (byte array) in the table
|
||||
* @param key the key to be assigned to
|
||||
* @param value the value that will be assigned
|
||||
* @return False if the table key already exists with a different type
|
||||
*/
|
||||
virtual bool PutRaw(llvm::StringRef key, llvm::StringRef value) override;
|
||||
|
||||
/**
|
||||
* Gets the current value in the table, setting it if it does not exist.
|
||||
* @param key the key
|
||||
* @param defaultValue the default value to set if key doesn't exist.
|
||||
* @returns False if the table key exists with a different type
|
||||
*/
|
||||
virtual bool SetDefaultRaw(llvm::StringRef key,
|
||||
llvm::StringRef defaultValue) override;
|
||||
|
||||
/**
|
||||
* Returns the raw value (byte array) the key maps to. If the key does not
|
||||
* exist or is of different type, it will return the default value.
|
||||
* @param key the key to look up
|
||||
* @param defaultValue the value to be returned if no value is found
|
||||
* @return the value associated with the given key or the given default value
|
||||
* if there is no value associated with the key
|
||||
*
|
||||
* @note This makes a copy of the raw contents. If the overhead of this is a
|
||||
* concern, use GetValue() instead.
|
||||
*/
|
||||
virtual std::string GetRaw(llvm::StringRef key,
|
||||
llvm::StringRef defaultValue) const override;
|
||||
|
||||
/**
|
||||
* Put a value in the table
|
||||
*
|
||||
* @param key the key to be assigned to
|
||||
* @param value the value that will be assigned
|
||||
* @return False if the table key already exists with a different type
|
||||
*/
|
||||
bool PutValue(llvm::StringRef key, std::shared_ptr<nt::Value> value) override;
|
||||
|
||||
/**
|
||||
* Gets the current value in the table, setting it if it does not exist.
|
||||
* @param key the key
|
||||
* @param defaultValue the default value to set if key doesn't exist.
|
||||
* @returns False if the table key exists with a different type
|
||||
*/
|
||||
virtual bool SetDefaultValue(
|
||||
llvm::StringRef key, std::shared_ptr<nt::Value> defaultValue) override;
|
||||
|
||||
/**
|
||||
* Gets the value associated with a key as an object
|
||||
*
|
||||
* @param key the key of the value to look up
|
||||
* @return the value associated with the given key, or nullptr if the key
|
||||
* does not exist
|
||||
*/
|
||||
std::shared_ptr<nt::Value> GetValue(llvm::StringRef key) const override;
|
||||
|
||||
/**
|
||||
* Gets the full path of this table.
|
||||
*/
|
||||
llvm::StringRef GetPath() const override;
|
||||
};
|
||||
|
||||
#endif // NETWORKTABLE_H_
|
||||
183
src/main/native/include/nt_Value.h
Normal file
183
src/main/native/include/nt_Value.h
Normal file
@@ -0,0 +1,183 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2015. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef NT_VALUE_H_
|
||||
#define NT_VALUE_H_
|
||||
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#include "llvm/ArrayRef.h"
|
||||
#include "llvm/StringRef.h"
|
||||
|
||||
#include "ntcore_c.h"
|
||||
|
||||
namespace nt {
|
||||
|
||||
using llvm::ArrayRef;
|
||||
using llvm::StringRef;
|
||||
|
||||
/** NetworkTables Entry Value */
|
||||
class Value {
|
||||
struct private_init {};
|
||||
|
||||
public:
|
||||
Value();
|
||||
Value(NT_Type type, const private_init&);
|
||||
~Value();
|
||||
|
||||
NT_Type type() const { return m_val.type; }
|
||||
const NT_Value& value() const { return m_val; }
|
||||
unsigned long long last_change() const { return m_val.last_change; }
|
||||
|
||||
/*
|
||||
* Type Checkers
|
||||
*/
|
||||
bool IsBoolean() const { return m_val.type == NT_BOOLEAN; }
|
||||
bool IsDouble() const { return m_val.type == NT_DOUBLE; }
|
||||
bool IsString() const { return m_val.type == NT_STRING; }
|
||||
bool IsRaw() const { return m_val.type == NT_RAW; }
|
||||
bool IsRpc() const { return m_val.type == NT_RPC; }
|
||||
bool IsBooleanArray() const { return m_val.type == NT_BOOLEAN_ARRAY; }
|
||||
bool IsDoubleArray() const { return m_val.type == NT_DOUBLE_ARRAY; }
|
||||
bool IsStringArray() const { return m_val.type == NT_STRING_ARRAY; }
|
||||
|
||||
/*
|
||||
* Type-Safe Getters
|
||||
*/
|
||||
bool GetBoolean() const {
|
||||
assert(m_val.type == NT_BOOLEAN);
|
||||
return m_val.data.v_boolean != 0;
|
||||
}
|
||||
double GetDouble() const {
|
||||
assert(m_val.type == NT_DOUBLE);
|
||||
return m_val.data.v_double;
|
||||
}
|
||||
StringRef GetString() const {
|
||||
assert(m_val.type == NT_STRING);
|
||||
return m_string;
|
||||
}
|
||||
StringRef GetRaw() const {
|
||||
assert(m_val.type == NT_RAW);
|
||||
return m_string;
|
||||
}
|
||||
StringRef GetRpc() const {
|
||||
assert(m_val.type == NT_RPC);
|
||||
return m_string;
|
||||
}
|
||||
ArrayRef<int> GetBooleanArray() const {
|
||||
assert(m_val.type == NT_BOOLEAN_ARRAY);
|
||||
return ArrayRef<int>(m_val.data.arr_boolean.arr,
|
||||
m_val.data.arr_boolean.size);
|
||||
}
|
||||
ArrayRef<double> GetDoubleArray() const {
|
||||
assert(m_val.type == NT_DOUBLE_ARRAY);
|
||||
return ArrayRef<double>(m_val.data.arr_double.arr,
|
||||
m_val.data.arr_double.size);
|
||||
}
|
||||
ArrayRef<std::string> GetStringArray() const {
|
||||
assert(m_val.type == NT_STRING_ARRAY);
|
||||
return m_string_array;
|
||||
}
|
||||
|
||||
static std::shared_ptr<Value> MakeBoolean(bool value) {
|
||||
auto val = std::make_shared<Value>(NT_BOOLEAN, private_init());
|
||||
val->m_val.data.v_boolean = value;
|
||||
return val;
|
||||
}
|
||||
static std::shared_ptr<Value> MakeDouble(double value) {
|
||||
auto val = std::make_shared<Value>(NT_DOUBLE, private_init());
|
||||
val->m_val.data.v_double = value;
|
||||
return val;
|
||||
}
|
||||
static std::shared_ptr<Value> MakeString(StringRef value) {
|
||||
auto val = std::make_shared<Value>(NT_STRING, private_init());
|
||||
val->m_string = value;
|
||||
val->m_val.data.v_string.str = const_cast<char*>(val->m_string.c_str());
|
||||
val->m_val.data.v_string.len = val->m_string.size();
|
||||
return val;
|
||||
}
|
||||
#ifdef _MSC_VER
|
||||
template <typename T,
|
||||
typename = std::enable_if_t<std::is_same<T, std::string>>>
|
||||
#else
|
||||
template <typename T,
|
||||
typename std::enable_if<std::is_same<T, std::string>::value>::type>
|
||||
#endif
|
||||
static std::shared_ptr<Value> MakeString(T&& value) {
|
||||
auto val = std::make_shared<Value>(NT_STRING, private_init());
|
||||
val->m_string = std::move(value);
|
||||
val->m_val.data.v_string.str = const_cast<char*>(val->m_string.c_str());
|
||||
val->m_val.data.v_string.len = val->m_string.size();
|
||||
return val;
|
||||
}
|
||||
static std::shared_ptr<Value> MakeRaw(StringRef value) {
|
||||
auto val = std::make_shared<Value>(NT_RAW, private_init());
|
||||
val->m_string = value;
|
||||
val->m_val.data.v_raw.str = const_cast<char*>(val->m_string.c_str());
|
||||
val->m_val.data.v_raw.len = val->m_string.size();
|
||||
return val;
|
||||
}
|
||||
#ifdef _MSC_VER
|
||||
template <typename T,
|
||||
typename = std::enable_if_t<std::is_same<T, std::string>>>
|
||||
#else
|
||||
template <typename T,
|
||||
typename std::enable_if<std::is_same<T, std::string>::value>::type>
|
||||
#endif
|
||||
static std::shared_ptr<Value> MakeRaw(T&& value) {
|
||||
auto val = std::make_shared<Value>(NT_RAW, private_init());
|
||||
val->m_string = std::move(value);
|
||||
val->m_val.data.v_raw.str = const_cast<char*>(val->m_string.c_str());
|
||||
val->m_val.data.v_raw.len = val->m_string.size();
|
||||
return val;
|
||||
}
|
||||
static std::shared_ptr<Value> MakeRpc(StringRef value) {
|
||||
auto val = std::make_shared<Value>(NT_RPC, private_init());
|
||||
val->m_string = value;
|
||||
val->m_val.data.v_raw.str = const_cast<char*>(val->m_string.c_str());
|
||||
val->m_val.data.v_raw.len = val->m_string.size();
|
||||
return val;
|
||||
}
|
||||
template <typename T>
|
||||
static std::shared_ptr<Value> MakeRpc(T&& value) {
|
||||
auto val = std::make_shared<Value>(NT_RPC, private_init());
|
||||
val->m_string = std::move(value);
|
||||
val->m_val.data.v_raw.str = const_cast<char*>(val->m_string.c_str());
|
||||
val->m_val.data.v_raw.len = val->m_string.size();
|
||||
return val;
|
||||
}
|
||||
|
||||
static std::shared_ptr<Value> MakeBooleanArray(ArrayRef<int> value);
|
||||
static std::shared_ptr<Value> MakeDoubleArray(ArrayRef<double> value);
|
||||
static std::shared_ptr<Value> MakeStringArray(ArrayRef<std::string> value);
|
||||
|
||||
// Note: This function moves the values out of the vector.
|
||||
static std::shared_ptr<Value> MakeStringArray(
|
||||
std::vector<std::string>&& value);
|
||||
|
||||
Value(const Value&) = delete;
|
||||
Value& operator=(const Value&) = delete;
|
||||
friend bool operator==(const Value& lhs, const Value& rhs);
|
||||
|
||||
private:
|
||||
NT_Value m_val;
|
||||
std::string m_string;
|
||||
std::vector<std::string> m_string_array;
|
||||
};
|
||||
|
||||
bool operator==(const Value& lhs, const Value& rhs);
|
||||
inline bool operator!=(const Value& lhs, const Value& rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
} // namespace nt
|
||||
|
||||
#endif // NT_VALUE_H_
|
||||
19
src/main/native/include/ntcore.h
Normal file
19
src/main/native/include/ntcore.h
Normal file
@@ -0,0 +1,19 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2015. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef NTCORE_H_
|
||||
#define NTCORE_H_
|
||||
|
||||
/* C API */
|
||||
#include "ntcore_c.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
/* C++ API */
|
||||
#include "ntcore_cpp.h"
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* NTCORE_H_ */
|
||||
1076
src/main/native/include/ntcore_c.h
Normal file
1076
src/main/native/include/ntcore_c.h
Normal file
File diff suppressed because it is too large
Load Diff
295
src/main/native/include/ntcore_cpp.h
Normal file
295
src/main/native/include/ntcore_cpp.h
Normal file
@@ -0,0 +1,295 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2015. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef NTCORE_CPP_H_
|
||||
#define NTCORE_CPP_H_
|
||||
|
||||
#include <cassert>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "llvm/ArrayRef.h"
|
||||
#include "llvm/StringRef.h"
|
||||
|
||||
#include "nt_Value.h"
|
||||
|
||||
namespace nt {
|
||||
|
||||
using llvm::ArrayRef;
|
||||
using llvm::StringRef;
|
||||
|
||||
/** NetworkTables Entry Information */
|
||||
struct EntryInfo {
|
||||
/** Entry name */
|
||||
std::string name;
|
||||
|
||||
/** Entry type */
|
||||
NT_Type type;
|
||||
|
||||
/** Entry flags */
|
||||
unsigned int flags;
|
||||
|
||||
/** Timestamp of last change to entry (type or value). */
|
||||
unsigned long long last_change;
|
||||
};
|
||||
|
||||
/** NetworkTables Connection Information */
|
||||
struct ConnectionInfo {
|
||||
std::string remote_id;
|
||||
std::string remote_ip;
|
||||
unsigned int remote_port;
|
||||
unsigned long long last_update;
|
||||
unsigned int protocol_version;
|
||||
};
|
||||
|
||||
/** NetworkTables RPC Parameter Definition */
|
||||
struct RpcParamDef {
|
||||
RpcParamDef() = default;
|
||||
RpcParamDef(StringRef name_, std::shared_ptr<Value> def_value_)
|
||||
: name(name_), def_value(def_value_) {}
|
||||
|
||||
std::string name;
|
||||
std::shared_ptr<Value> def_value;
|
||||
};
|
||||
|
||||
/** NetworkTables RPC Result Definition */
|
||||
struct RpcResultDef {
|
||||
RpcResultDef() = default;
|
||||
RpcResultDef(StringRef name_, NT_Type type_) : name(name_), type(type_) {}
|
||||
|
||||
std::string name;
|
||||
NT_Type type;
|
||||
};
|
||||
|
||||
/** NetworkTables RPC Definition */
|
||||
struct RpcDefinition {
|
||||
unsigned int version;
|
||||
std::string name;
|
||||
std::vector<RpcParamDef> params;
|
||||
std::vector<RpcResultDef> results;
|
||||
};
|
||||
|
||||
/** NetworkTables RPC Call Data */
|
||||
struct RpcCallInfo {
|
||||
unsigned int rpc_id;
|
||||
unsigned int call_uid;
|
||||
std::string name;
|
||||
std::string params;
|
||||
};
|
||||
|
||||
/*
|
||||
* Table Functions
|
||||
*/
|
||||
|
||||
/** Get Entry Value.
|
||||
* Returns copy of current entry value.
|
||||
* Note that one of the type options is "unassigned".
|
||||
*
|
||||
* @param name entry name (UTF-8 string)
|
||||
* @return entry value
|
||||
*/
|
||||
std::shared_ptr<Value> GetEntryValue(StringRef name);
|
||||
|
||||
/** Set Default Entry Value
|
||||
* Returns copy of current entry value if it exists.
|
||||
* Otherwise, sets passed in value, and returns set value.
|
||||
* Note that one of the type options is "unassigned".
|
||||
*
|
||||
* @param name entry name (UTF-8 string)
|
||||
* @param value value to be set if name does not exist
|
||||
* @return False on error (value not set), True on success
|
||||
*/
|
||||
bool SetDefaultEntryValue(StringRef name, std::shared_ptr<Value> value);
|
||||
|
||||
/** Set Entry Value.
|
||||
* Sets new entry value. If type of new value differs from the type of the
|
||||
* currently stored entry, returns error and does not update value.
|
||||
*
|
||||
* @param name entry name (UTF-8 string)
|
||||
* @param value new entry value
|
||||
* @return False on error (type mismatch), True on success
|
||||
*/
|
||||
bool SetEntryValue(StringRef name, std::shared_ptr<Value> value);
|
||||
|
||||
/** Set Entry Type and Value.
|
||||
* Sets new entry value. If type of new value differs from the type of the
|
||||
* currently stored entry, the currently stored entry type is overridden
|
||||
* (generally this will generate an Entry Assignment message).
|
||||
*
|
||||
* This is NOT the preferred method to update a value; generally
|
||||
* SetEntryValue() should be used instead, with appropriate error handling.
|
||||
*
|
||||
* @param name entry name (UTF-8 string)
|
||||
* @param value new entry value
|
||||
*/
|
||||
void SetEntryTypeValue(StringRef name, std::shared_ptr<Value> value);
|
||||
|
||||
/** Set Entry Flags.
|
||||
*/
|
||||
void SetEntryFlags(StringRef name, unsigned int flags);
|
||||
|
||||
/** Get Entry Flags.
|
||||
*/
|
||||
unsigned int GetEntryFlags(StringRef name);
|
||||
|
||||
/** Delete Entry.
|
||||
* Deletes an entry. This is a new feature in version 3.0 of the protocol,
|
||||
* so this may not have an effect if any other node in the network is not
|
||||
* version 3.0 or newer.
|
||||
*
|
||||
* Note: GetConnections() can be used to determine the protocol version
|
||||
* of direct remote connection(s), but this is not sufficient to determine
|
||||
* if all nodes in the network are version 3.0 or newer.
|
||||
*
|
||||
* @param name entry name (UTF-8 string)
|
||||
*/
|
||||
void DeleteEntry(StringRef name);
|
||||
|
||||
/** Delete All Entries.
|
||||
* Deletes ALL table entries. This is a new feature in version 3.0 of the
|
||||
* so this may not have an effect if any other node in the network is not
|
||||
* version 3.0 or newer.
|
||||
*
|
||||
* Note: GetConnections() can be used to determine the protocol version
|
||||
* of direct remote connection(s), but this is not sufficient to determine
|
||||
* if all nodes in the network are version 3.0 or newer.
|
||||
*/
|
||||
void DeleteAllEntries();
|
||||
|
||||
/** Get Entry Information.
|
||||
* Returns an array of entry information (name, entry type,
|
||||
* and timestamp of last change to type/value). The results are optionally
|
||||
* filtered by string prefix and entry type to only return a subset of all
|
||||
* entries.
|
||||
*
|
||||
* @param prefix entry name required prefix; only entries whose name
|
||||
* starts with this string are returned
|
||||
* @param types bitmask of NT_Type values; 0 is treated specially
|
||||
* as a "don't care"
|
||||
* @return Array of entry information.
|
||||
*/
|
||||
std::vector<EntryInfo> GetEntryInfo(StringRef prefix, unsigned int types);
|
||||
|
||||
/** Flush Entries.
|
||||
* Forces an immediate flush of all local entry changes to network.
|
||||
* Normally this is done on a regularly scheduled interval (see
|
||||
* NT_SetUpdateRate()).
|
||||
*
|
||||
* Note: flushes are rate limited to avoid excessive network traffic. If
|
||||
* the time between calls is too short, the flush will occur after the minimum
|
||||
* time elapses (rather than immediately).
|
||||
*/
|
||||
void Flush();
|
||||
|
||||
/*
|
||||
* Callback Creation Functions
|
||||
*/
|
||||
|
||||
void SetListenerOnStart(std::function<void()> on_start);
|
||||
void SetListenerOnExit(std::function<void()> on_exit);
|
||||
|
||||
typedef std::function<void(unsigned int uid, StringRef name,
|
||||
std::shared_ptr<Value> value, unsigned int flags)>
|
||||
EntryListenerCallback;
|
||||
|
||||
typedef std::function<void(unsigned int uid, bool connected,
|
||||
const ConnectionInfo& conn)>
|
||||
ConnectionListenerCallback;
|
||||
|
||||
unsigned int AddEntryListener(StringRef prefix, EntryListenerCallback callback,
|
||||
unsigned int flags);
|
||||
void RemoveEntryListener(unsigned int entry_listener_uid);
|
||||
unsigned int AddConnectionListener(ConnectionListenerCallback callback,
|
||||
bool immediate_notify);
|
||||
void RemoveConnectionListener(unsigned int conn_listener_uid);
|
||||
|
||||
bool NotifierDestroyed();
|
||||
|
||||
/*
|
||||
* Remote Procedure Call Functions
|
||||
*/
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1900
|
||||
const double kTimeout_Indefinite = -1;
|
||||
#else
|
||||
constexpr double kTimeout_Indefinite = -1;
|
||||
#endif
|
||||
|
||||
void SetRpcServerOnStart(std::function<void()> on_start);
|
||||
void SetRpcServerOnExit(std::function<void()> on_exit);
|
||||
|
||||
typedef std::function<std::string(StringRef name, StringRef params,
|
||||
const ConnectionInfo& conn_info)>
|
||||
RpcCallback;
|
||||
|
||||
void CreateRpc(StringRef name, StringRef def, RpcCallback callback);
|
||||
void CreatePolledRpc(StringRef name, StringRef def);
|
||||
|
||||
bool PollRpc(bool blocking, RpcCallInfo* call_info);
|
||||
bool PollRpc(bool blocking, double time_out, RpcCallInfo* call_info);
|
||||
void PostRpcResponse(unsigned int rpc_id, unsigned int call_uid,
|
||||
StringRef result);
|
||||
|
||||
unsigned int CallRpc(StringRef name, StringRef params);
|
||||
bool GetRpcResult(bool blocking, unsigned int call_uid, std::string* result);
|
||||
bool GetRpcResult(bool blocking, unsigned int call_uid, double time_out,
|
||||
std::string* result);
|
||||
void CancelBlockingRpcResult(unsigned int call_uid);
|
||||
|
||||
std::string PackRpcDefinition(const RpcDefinition& def);
|
||||
bool UnpackRpcDefinition(StringRef packed, RpcDefinition* def);
|
||||
std::string PackRpcValues(ArrayRef<std::shared_ptr<Value>> values);
|
||||
std::vector<std::shared_ptr<Value>> UnpackRpcValues(StringRef packed,
|
||||
ArrayRef<NT_Type> types);
|
||||
|
||||
/*
|
||||
* Client/Server Functions
|
||||
*/
|
||||
void SetNetworkIdentity(StringRef name);
|
||||
unsigned int GetNetworkMode();
|
||||
void StartServer(StringRef persist_filename, const char* listen_address,
|
||||
unsigned int port);
|
||||
void StopServer();
|
||||
void StartClient();
|
||||
void StartClient(const char* server_name, unsigned int port);
|
||||
void StartClient(ArrayRef<std::pair<StringRef, unsigned int>> servers);
|
||||
void StopClient();
|
||||
void SetServer(const char* server_name, unsigned int port);
|
||||
void SetServer(ArrayRef<std::pair<StringRef, unsigned int>> servers);
|
||||
void StartDSClient(unsigned int port);
|
||||
void StopDSClient();
|
||||
void StopRpcServer();
|
||||
void StopNotifier();
|
||||
void SetUpdateRate(double interval);
|
||||
std::vector<ConnectionInfo> GetConnections();
|
||||
|
||||
/*
|
||||
* Persistent Functions
|
||||
*/
|
||||
/* return error string, or nullptr if successful */
|
||||
const char* SavePersistent(StringRef filename);
|
||||
const char* LoadPersistent(
|
||||
StringRef filename, std::function<void(size_t line, const char* msg)> warn);
|
||||
|
||||
/*
|
||||
* Utility Functions
|
||||
*/
|
||||
|
||||
/* timestamp */
|
||||
unsigned long long Now();
|
||||
|
||||
/* logging */
|
||||
typedef std::function<void(unsigned int level, const char* file,
|
||||
unsigned int line, const char* msg)>
|
||||
LogFunc;
|
||||
void SetLogger(LogFunc func, unsigned int min_level);
|
||||
|
||||
} // namespace nt
|
||||
|
||||
#endif /* NTCORE_CPP_H_ */
|
||||
84
src/main/native/include/ntcore_test.h
Normal file
84
src/main/native/include/ntcore_test.h
Normal file
@@ -0,0 +1,84 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef NTCORE_TEST_H_
|
||||
#define NTCORE_TEST_H_
|
||||
|
||||
#include "ntcore.h"
|
||||
|
||||
// Functions in this header are to be used only for testing
|
||||
|
||||
extern "C" {
|
||||
struct NT_String* NT_GetStringForTesting(const char* string, int* struct_size);
|
||||
// No need for free as one already exists in main library
|
||||
|
||||
struct NT_EntryInfo* NT_GetEntryInfoForTesting(const char* name,
|
||||
enum NT_Type type,
|
||||
unsigned int flags,
|
||||
unsigned long long last_change,
|
||||
int* struct_size);
|
||||
|
||||
void NT_FreeEntryInfoForTesting(struct NT_EntryInfo* info);
|
||||
|
||||
struct NT_ConnectionInfo* NT_GetConnectionInfoForTesting(
|
||||
const char* remote_id, const char* remote_ip, unsigned int remote_port,
|
||||
unsigned long long last_update, unsigned int protocol_version,
|
||||
int* struct_size);
|
||||
|
||||
void NT_FreeConnectionInfoForTesting(struct NT_ConnectionInfo* info);
|
||||
|
||||
struct NT_Value* NT_GetValueBooleanForTesting(unsigned long long last_change,
|
||||
int val, int* struct_size);
|
||||
|
||||
struct NT_Value* NT_GetValueDoubleForTesting(unsigned long long last_change,
|
||||
double val, int* struct_size);
|
||||
|
||||
struct NT_Value* NT_GetValueStringForTesting(unsigned long long last_change,
|
||||
const char* str, int* struct_size);
|
||||
|
||||
struct NT_Value* NT_GetValueRawForTesting(unsigned long long last_change,
|
||||
const char* raw, int raw_len,
|
||||
int* struct_size);
|
||||
|
||||
struct NT_Value* NT_GetValueBooleanArrayForTesting(
|
||||
unsigned long long last_change, const int* arr, size_t array_len,
|
||||
int* struct_size);
|
||||
|
||||
struct NT_Value* NT_GetValueDoubleArrayForTesting(
|
||||
unsigned long long last_change, const double* arr, size_t array_len,
|
||||
int* struct_size);
|
||||
|
||||
struct NT_Value* NT_GetValueStringArrayForTesting(
|
||||
unsigned long long last_change, const struct NT_String* arr,
|
||||
size_t array_len, int* struct_size);
|
||||
// No need for free as one already exists in the main library
|
||||
|
||||
struct NT_RpcParamDef* NT_GetRpcParamDefForTesting(const char* name,
|
||||
const struct NT_Value* val,
|
||||
int* struct_size);
|
||||
|
||||
void NT_FreeRpcParamDefForTesting(struct NT_RpcParamDef* def);
|
||||
|
||||
struct NT_RpcResultDef* NT_GetRpcResultsDefForTesting(const char* name,
|
||||
enum NT_Type type,
|
||||
int* struct_size);
|
||||
|
||||
void NT_FreeRpcResultsDefForTesting(struct NT_RpcResultDef* def);
|
||||
|
||||
struct NT_RpcDefinition* NT_GetRpcDefinitionForTesting(
|
||||
unsigned int version, const char* name, size_t num_params,
|
||||
const struct NT_RpcParamDef* params, size_t num_results,
|
||||
const struct NT_RpcResultDef* results, int* struct_size);
|
||||
// No need for free as one already exists in the main library
|
||||
|
||||
struct NT_RpcCallInfo* NT_GetRpcCallInfoForTesting(
|
||||
unsigned int rpc_id, unsigned int call_uid, const char* name,
|
||||
const char* params, size_t params_len, int* struct_size);
|
||||
// No need for free as one already exists in the main library
|
||||
}
|
||||
|
||||
#endif /* NTCORE_TEST_H_ */
|
||||
493
src/main/native/include/tables/ITable.h
Normal file
493
src/main/native/include/tables/ITable.h
Normal file
@@ -0,0 +1,493 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2015. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef ITABLE_H_
|
||||
#define ITABLE_H_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "llvm/StringRef.h"
|
||||
#include "nt_Value.h"
|
||||
#include "support/deprecated.h"
|
||||
|
||||
class ITableListener;
|
||||
|
||||
/**
|
||||
* A table whose values can be read and written to
|
||||
*/
|
||||
class ITable {
|
||||
public:
|
||||
/**
|
||||
* Determines whether the given key is in this table.
|
||||
*
|
||||
* @param key the key to search for
|
||||
* @return true if the table as a value assigned to the given key
|
||||
*/
|
||||
virtual bool ContainsKey(llvm::StringRef key) const = 0;
|
||||
|
||||
/**
|
||||
* Determines whether there exists a non-empty subtable for this key
|
||||
* in this table.
|
||||
*
|
||||
* @param key the key to search for
|
||||
* @return true if there is a subtable with the key which contains at least
|
||||
* one key/subtable of its own
|
||||
*/
|
||||
virtual bool ContainsSubTable(llvm::StringRef key) const = 0;
|
||||
|
||||
/**
|
||||
* Gets the subtable in this table for the given name.
|
||||
*
|
||||
* @param key the name of the table relative to this one
|
||||
* @return a sub table relative to this one
|
||||
*/
|
||||
virtual std::shared_ptr<ITable> GetSubTable(llvm::StringRef key) const = 0;
|
||||
|
||||
/**
|
||||
* @param types bitmask of types; 0 is treated as a "don't care".
|
||||
* @return keys currently in the table
|
||||
*/
|
||||
virtual std::vector<std::string> GetKeys(int types = 0) const = 0;
|
||||
|
||||
/**
|
||||
* @return subtables currently in the table
|
||||
*/
|
||||
virtual std::vector<std::string> GetSubTables() const = 0;
|
||||
|
||||
/**
|
||||
* Makes a key's value persistent through program restarts.
|
||||
*
|
||||
* @param key the key to make persistent
|
||||
*/
|
||||
virtual void SetPersistent(llvm::StringRef key) = 0;
|
||||
|
||||
/**
|
||||
* Stop making a key's value persistent through program restarts.
|
||||
* The key cannot be null.
|
||||
*
|
||||
* @param key the key name
|
||||
*/
|
||||
virtual void ClearPersistent(llvm::StringRef key) = 0;
|
||||
|
||||
/**
|
||||
* Returns whether the value is persistent through program restarts.
|
||||
* The key cannot be null.
|
||||
*
|
||||
* @param key the key name
|
||||
*/
|
||||
virtual bool IsPersistent(llvm::StringRef key) const = 0;
|
||||
|
||||
/**
|
||||
* Sets flags on the specified key in this table. The key can
|
||||
* not be null.
|
||||
*
|
||||
* @param key the key name
|
||||
* @param flags the flags to set (bitmask)
|
||||
*/
|
||||
virtual void SetFlags(llvm::StringRef key, unsigned int flags) = 0;
|
||||
|
||||
/**
|
||||
* Clears flags on the specified key in this table. The key can
|
||||
* not be null.
|
||||
*
|
||||
* @param key the key name
|
||||
* @param flags the flags to clear (bitmask)
|
||||
*/
|
||||
virtual void ClearFlags(llvm::StringRef key, unsigned int flags) = 0;
|
||||
|
||||
/**
|
||||
* Returns the flags for the specified key.
|
||||
*
|
||||
* @param key the key name
|
||||
* @return the flags, or 0 if the key is not defined
|
||||
*/
|
||||
virtual unsigned int GetFlags(llvm::StringRef key) const = 0;
|
||||
|
||||
/**
|
||||
* Deletes the specified key in this table.
|
||||
*
|
||||
* @param key the key name
|
||||
*/
|
||||
virtual void Delete(llvm::StringRef key) = 0;
|
||||
|
||||
/**
|
||||
* Gets the value associated with a key as an object
|
||||
*
|
||||
* @param key the key of the value to look up
|
||||
* @return the value associated with the given key, or nullptr if the key
|
||||
* does not exist
|
||||
*/
|
||||
virtual std::shared_ptr<nt::Value> GetValue(llvm::StringRef key) const = 0;
|
||||
|
||||
/**
|
||||
* Gets the current value in the table, setting it if it does not exist.
|
||||
* @param key the key
|
||||
* @param defaultValue the default value to set if key doesn't exist.
|
||||
* @returns False if the table key exists with a different type
|
||||
*/
|
||||
virtual bool SetDefaultValue(llvm::StringRef key,
|
||||
std::shared_ptr<nt::Value> defaultValue) = 0;
|
||||
|
||||
/**
|
||||
* Put a value in the table
|
||||
*
|
||||
* @param key the key to be assigned to
|
||||
* @param value the value that will be assigned
|
||||
* @return False if the table key already exists with a different type
|
||||
*/
|
||||
virtual bool PutValue(llvm::StringRef key,
|
||||
std::shared_ptr<nt::Value> value) = 0;
|
||||
|
||||
/**
|
||||
* Put a number in the table
|
||||
*
|
||||
* @param key the key to be assigned to
|
||||
* @param value the value that will be assigned
|
||||
* @return False if the table key already exists with a different type
|
||||
*/
|
||||
virtual bool PutNumber(llvm::StringRef key, double value) = 0;
|
||||
|
||||
/**
|
||||
* Gets the current value in the table, setting it if it does not exist.
|
||||
* @param key the key
|
||||
* @param defaultValue the default value to set if key doesn't exist.
|
||||
* @returns False if the table key exists with a different type
|
||||
*/
|
||||
virtual bool SetDefaultNumber(llvm::StringRef key, double defaultValue) = 0;
|
||||
|
||||
/**
|
||||
* Gets the number associated with the given name.
|
||||
*
|
||||
* @param key the key to look up
|
||||
* @return the value associated with the given key
|
||||
* @throws TableKeyNotDefinedException if there is no value associated with
|
||||
* the given key
|
||||
* @deprecated This exception-raising method has been replaced by the
|
||||
* default-taking method.
|
||||
*/
|
||||
WPI_DEPRECATED(
|
||||
"Raises an exception if key not found; "
|
||||
"use GetNumber(StringRef key, double defaultValue) instead")
|
||||
virtual double GetNumber(llvm::StringRef key) const = 0;
|
||||
|
||||
/**
|
||||
* Gets the number associated with the given name.
|
||||
*
|
||||
* @param key the key to look up
|
||||
* @param defaultValue the value to be returned if no value is found
|
||||
* @return the value associated with the given key or the given default value
|
||||
* if there is no value associated with the key
|
||||
*/
|
||||
virtual double GetNumber(llvm::StringRef key, double defaultValue) const = 0;
|
||||
|
||||
/**
|
||||
* Put a string in the table
|
||||
*
|
||||
* @param key the key to be assigned to
|
||||
* @param value the value that will be assigned
|
||||
* @return False if the table key already exists with a different type
|
||||
*/
|
||||
virtual bool PutString(llvm::StringRef key, llvm::StringRef value) = 0;
|
||||
|
||||
/**
|
||||
* Gets the current value in the table, setting it if it does not exist.
|
||||
* @param key the key
|
||||
* @param defaultValue the default value to set if key doesn't exist.
|
||||
* @returns False if the table key exists with a different type
|
||||
*/
|
||||
virtual bool SetDefaultString(llvm::StringRef key,
|
||||
llvm::StringRef defaultValue) = 0;
|
||||
|
||||
/**
|
||||
* Gets the string associated with the given name.
|
||||
*
|
||||
* @param key the key to look up
|
||||
* @return the value associated with the given key
|
||||
* @throws TableKeyNotDefinedException if there is no value associated with
|
||||
* the given key
|
||||
* @deprecated This exception-raising method has been replaced by the
|
||||
* default-taking method.
|
||||
*/
|
||||
WPI_DEPRECATED(
|
||||
"Raises an exception if key not found; "
|
||||
"use GetString(StringRef key, StringRef defaultValue) instead")
|
||||
virtual std::string GetString(llvm::StringRef key) const = 0;
|
||||
|
||||
/**
|
||||
* Gets the string associated with the given name. If the key does not
|
||||
* exist or is of different type, it will return the default value.
|
||||
*
|
||||
* @param key the key to look up
|
||||
* @param defaultValue the value to be returned if no value is found
|
||||
* @return the value associated with the given key or the given default value
|
||||
* if there is no value associated with the key
|
||||
*
|
||||
* @note This makes a copy of the string. If the overhead of this is a
|
||||
* concern, use GetValue() instead.
|
||||
*/
|
||||
virtual std::string GetString(llvm::StringRef key,
|
||||
llvm::StringRef defaultValue) const = 0;
|
||||
|
||||
/**
|
||||
* Put a boolean in the table
|
||||
*
|
||||
* @param key the key to be assigned to
|
||||
* @param value the value that will be assigned
|
||||
* @return False if the table key already exists with a different type
|
||||
*/
|
||||
virtual bool PutBoolean(llvm::StringRef key, bool value) = 0;
|
||||
|
||||
/**
|
||||
* Gets the current value in the table, setting it if it does not exist.
|
||||
* @param key the key
|
||||
* @param defaultValue the default value to set if key doesn't exist.
|
||||
* @returns False if the table key exists with a different type
|
||||
*/
|
||||
virtual bool SetDefaultBoolean(llvm::StringRef key, bool defaultValue) = 0;
|
||||
|
||||
/**
|
||||
* Gets the boolean associated with the given name.
|
||||
*
|
||||
* @param key the key to look up
|
||||
* @return the value associated with the given key
|
||||
* @throws TableKeyNotDefinedException if there is no value associated with
|
||||
* the given key
|
||||
* @deprecated This exception-raising method has been replaced by the
|
||||
* default-taking method.
|
||||
*/
|
||||
WPI_DEPRECATED(
|
||||
"Raises an exception if key not found; "
|
||||
"use GetBoolean(StringRef key, bool defaultValue) instead")
|
||||
virtual bool GetBoolean(llvm::StringRef key) const = 0;
|
||||
|
||||
/**
|
||||
* Gets the boolean associated with the given name. If the key does not
|
||||
* exist or is of different type, it will return the default value.
|
||||
*
|
||||
* @param key the key to look up
|
||||
* @param defaultValue the value to be returned if no value is found
|
||||
* @return the value associated with the given key or the given default value
|
||||
* if there is no value associated with the key
|
||||
*/
|
||||
virtual bool GetBoolean(llvm::StringRef key, bool defaultValue) const = 0;
|
||||
|
||||
/**
|
||||
* Put a boolean array in the table
|
||||
* @param key the key to be assigned to
|
||||
* @param value the value that will be assigned
|
||||
* @return False if the table key already exists with a different type
|
||||
*
|
||||
* @note The array must be of int's rather than of bool's because
|
||||
* std::vector<bool> is special-cased in C++. 0 is false, any
|
||||
* non-zero value is true.
|
||||
*/
|
||||
virtual bool PutBooleanArray(llvm::StringRef key,
|
||||
llvm::ArrayRef<int> value) = 0;
|
||||
|
||||
/**
|
||||
* Gets the current value in the table, setting it if it does not exist.
|
||||
* @param key the key
|
||||
* @param defaultValue the default value to set if key doesn't exist.
|
||||
* @returns False if the table key exists with a different type
|
||||
*/
|
||||
virtual bool SetDefaultBooleanArray(llvm::StringRef key,
|
||||
llvm::ArrayRef<int> defaultValue) = 0;
|
||||
|
||||
/**
|
||||
* Returns the boolean array the key maps to. If the key does not exist or is
|
||||
* of different type, it will return the default value.
|
||||
* @param key the key to look up
|
||||
* @param defaultValue the value to be returned if no value is found
|
||||
* @return the value associated with the given key or the given default value
|
||||
* if there is no value associated with the key
|
||||
*
|
||||
* @note This makes a copy of the array. If the overhead of this is a
|
||||
* concern, use GetValue() instead.
|
||||
*
|
||||
* @note The returned array is std::vector<int> instead of std::vector<bool>
|
||||
* because std::vector<bool> is special-cased in C++. 0 is false, any
|
||||
* non-zero value is true.
|
||||
*/
|
||||
virtual std::vector<int> GetBooleanArray(
|
||||
llvm::StringRef key, llvm::ArrayRef<int> defaultValue) const = 0;
|
||||
|
||||
/**
|
||||
* Put a number array in the table
|
||||
* @param key the key to be assigned to
|
||||
* @param value the value that will be assigned
|
||||
* @return False if the table key already exists with a different type
|
||||
*/
|
||||
virtual bool PutNumberArray(llvm::StringRef key,
|
||||
llvm::ArrayRef<double> value) = 0;
|
||||
|
||||
/**
|
||||
* Gets the current value in the table, setting it if it does not exist.
|
||||
* @param key the key
|
||||
* @param defaultValue the default value to set if key doesn't exist.
|
||||
* @returns False if the table key exists with a different type
|
||||
*/
|
||||
virtual bool SetDefaultNumberArray(llvm::StringRef key,
|
||||
llvm::ArrayRef<double> defaultValue) = 0;
|
||||
|
||||
/**
|
||||
* Returns the number array the key maps to. If the key does not exist or is
|
||||
* of different type, it will return the default value.
|
||||
* @param key the key to look up
|
||||
* @param defaultValue the value to be returned if no value is found
|
||||
* @return the value associated with the given key or the given default value
|
||||
* if there is no value associated with the key
|
||||
*
|
||||
* @note This makes a copy of the array. If the overhead of this is a
|
||||
* concern, use GetValue() instead.
|
||||
*/
|
||||
virtual std::vector<double> GetNumberArray(
|
||||
llvm::StringRef key, llvm::ArrayRef<double> defaultValue) const = 0;
|
||||
|
||||
/**
|
||||
* Put a string array in the table
|
||||
* @param key the key to be assigned to
|
||||
* @param value the value that will be assigned
|
||||
* @return False if the table key already exists with a different type
|
||||
*/
|
||||
virtual bool PutStringArray(llvm::StringRef key,
|
||||
llvm::ArrayRef<std::string> value) = 0;
|
||||
|
||||
/**
|
||||
* Gets the current value in the table, setting it if it does not exist.
|
||||
* @param key the key
|
||||
* @param defaultValue the default value to set if key doesn't exist.
|
||||
* @returns False if the table key exists with a different type
|
||||
*/
|
||||
virtual bool SetDefaultStringArray(
|
||||
llvm::StringRef key, llvm::ArrayRef<std::string> defaultValue) = 0;
|
||||
|
||||
/**
|
||||
* Returns the string array the key maps to. If the key does not exist or is
|
||||
* of different type, it will return the default value.
|
||||
* @param key the key to look up
|
||||
* @param defaultValue the value to be returned if no value is found
|
||||
* @return the value associated with the given key or the given default value
|
||||
* if there is no value associated with the key
|
||||
*
|
||||
* @note This makes a copy of the array. If the overhead of this is a
|
||||
* concern, use GetValue() instead.
|
||||
*/
|
||||
virtual std::vector<std::string> GetStringArray(
|
||||
llvm::StringRef key, llvm::ArrayRef<std::string> defaultValue) const = 0;
|
||||
|
||||
/**
|
||||
* Put a raw value (byte array) in the table
|
||||
* @param key the key to be assigned to
|
||||
* @param value the value that will be assigned
|
||||
* @return False if the table key already exists with a different type
|
||||
*/
|
||||
virtual bool PutRaw(llvm::StringRef key, llvm::StringRef value) = 0;
|
||||
|
||||
/**
|
||||
* Gets the current value in the table, setting it if it does not exist.
|
||||
* @param key the key
|
||||
* @param defaultValue the default value to set if key doesn't exist.
|
||||
* @returns False if the table key exists with a different type
|
||||
*/
|
||||
virtual bool SetDefaultRaw(llvm::StringRef key,
|
||||
llvm::StringRef defaultValue) = 0;
|
||||
|
||||
/**
|
||||
* Returns the raw value (byte array) the key maps to. If the key does not
|
||||
* exist or is of different type, it will return the default value.
|
||||
* @param key the key to look up
|
||||
* @param defaultValue the value to be returned if no value is found
|
||||
* @return the value associated with the given key or the given default value
|
||||
* if there is no value associated with the key
|
||||
*
|
||||
* @note This makes a copy of the raw contents. If the overhead of this is a
|
||||
* concern, use GetValue() instead.
|
||||
*/
|
||||
virtual std::string GetRaw(llvm::StringRef key,
|
||||
llvm::StringRef defaultValue) const = 0;
|
||||
|
||||
/**
|
||||
* Add a listener for changes to the table
|
||||
*
|
||||
* @param listener the listener to add
|
||||
*/
|
||||
virtual void AddTableListener(ITableListener* listener) = 0;
|
||||
|
||||
/**
|
||||
* Add a listener for changes to the table
|
||||
*
|
||||
* @param listener the listener to add
|
||||
* @param immediateNotify if true then this listener will be notified of all
|
||||
* current entries (marked as new)
|
||||
*/
|
||||
virtual void AddTableListener(ITableListener* listener,
|
||||
bool immediateNotify) = 0;
|
||||
|
||||
/**
|
||||
* Add a listener for changes to the table
|
||||
*
|
||||
* @param listener the listener to add
|
||||
* @param immediateNotify if true then this listener will be notified of all
|
||||
* current entries (marked as new)
|
||||
* @param flags bitmask of NT_NotifyKind specifying desired notifications
|
||||
*/
|
||||
virtual void AddTableListenerEx(ITableListener* listener,
|
||||
unsigned int flags) = 0;
|
||||
|
||||
/**
|
||||
* Add a listener for changes to a specific key the table
|
||||
*
|
||||
* @param key the key to listen for
|
||||
* @param listener the listener to add
|
||||
* @param immediateNotify if true then this listener will be notified of all
|
||||
* current entries (marked as new)
|
||||
*/
|
||||
virtual void AddTableListener(llvm::StringRef key, ITableListener* listener,
|
||||
bool immediateNotify) = 0;
|
||||
|
||||
/**
|
||||
* Add a listener for changes to a specific key the table
|
||||
*
|
||||
* @param key the key to listen for
|
||||
* @param listener the listener to add
|
||||
* @param immediateNotify if true then this listener will be notified of all
|
||||
* current entries (marked as new)
|
||||
* @param flags bitmask of NT_NotifyKind specifying desired notifications
|
||||
*/
|
||||
virtual void AddTableListenerEx(llvm::StringRef key, ITableListener* listener,
|
||||
unsigned int flags) = 0;
|
||||
|
||||
/**
|
||||
* This will immediately notify the listener of all current sub tables
|
||||
* @param listener the listener to add
|
||||
*/
|
||||
virtual void AddSubTableListener(ITableListener* listener) = 0;
|
||||
|
||||
/**
|
||||
* This will immediately notify the listener of all current sub tables
|
||||
* @param listener the listener to add
|
||||
* @param localNotify if true then this listener will be notified of all
|
||||
* local changes in addition to all remote changes
|
||||
*/
|
||||
virtual void AddSubTableListener(ITableListener* listener,
|
||||
bool localNotify) = 0;
|
||||
|
||||
/**
|
||||
* Remove a listener from receiving table events
|
||||
*
|
||||
* @param listener the listener to be removed
|
||||
*/
|
||||
virtual void RemoveTableListener(ITableListener* listener) = 0;
|
||||
|
||||
/**
|
||||
* Gets the full path of this table.
|
||||
*/
|
||||
virtual llvm::StringRef GetPath() const = 0;
|
||||
|
||||
};
|
||||
|
||||
#endif // ITABLE_H_
|
||||
47
src/main/native/include/tables/ITableListener.h
Normal file
47
src/main/native/include/tables/ITableListener.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* ITableListener.h
|
||||
*/
|
||||
|
||||
#ifndef ITABLELISTENER_H_
|
||||
#define ITABLELISTENER_H_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "llvm/StringRef.h"
|
||||
#include "nt_Value.h"
|
||||
|
||||
class ITable;
|
||||
|
||||
/**
|
||||
* A listener that listens to changes in values in a {@link ITable}
|
||||
*/
|
||||
class ITableListener {
|
||||
public:
|
||||
virtual ~ITableListener() = default;
|
||||
/**
|
||||
* Called when a key-value pair is changed in a {@link ITable}
|
||||
* @param source the table the key-value pair exists in
|
||||
* @param key the key associated with the value that changed
|
||||
* @param value the new value
|
||||
* @param isNew true if the key did not previously exist in the table,
|
||||
* otherwise it is false
|
||||
*/
|
||||
virtual void ValueChanged(ITable* source, llvm::StringRef key,
|
||||
std::shared_ptr<nt::Value> value, bool isNew) = 0;
|
||||
|
||||
/**
|
||||
* Extended version of ValueChanged. Called when a key-value pair is
|
||||
* changed in a {@link ITable}. The default implementation simply calls
|
||||
* ValueChanged(). If this is overridden, ValueChanged() will not be called.
|
||||
* @param source the table the key-value pair exists in
|
||||
* @param key the key associated with the value that changed
|
||||
* @param value the new value
|
||||
* @param flags update flags; for example, NT_NOTIFY_NEW if the key did not
|
||||
* previously exist in the table
|
||||
*/
|
||||
virtual void ValueChangedEx(ITable* source, llvm::StringRef key,
|
||||
std::shared_ptr<nt::Value> value,
|
||||
unsigned int flags);
|
||||
};
|
||||
|
||||
#endif /* ITABLELISTENER_H_ */
|
||||
36
src/main/native/include/tables/TableKeyNotDefinedException.h
Normal file
36
src/main/native/include/tables/TableKeyNotDefinedException.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2015. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef TABLEKEYNOTDEFINEDEXCEPTION_H_
|
||||
#define TABLEKEYNOTDEFINEDEXCEPTION_H_
|
||||
|
||||
#include <exception>
|
||||
#include "llvm/StringRef.h"
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#define NT_NOEXCEPT throw()
|
||||
#else
|
||||
#define NT_NOEXCEPT noexcept
|
||||
#endif
|
||||
|
||||
/**
|
||||
* An exception thrown when the lookup a a key-value fails in a {@link ITable}
|
||||
*/
|
||||
class TableKeyNotDefinedException : public std::exception {
|
||||
public:
|
||||
/**
|
||||
* @param key the key that was not defined in the table
|
||||
*/
|
||||
TableKeyNotDefinedException(llvm::StringRef key);
|
||||
~TableKeyNotDefinedException() NT_NOEXCEPT;
|
||||
const char* what() const NT_NOEXCEPT override;
|
||||
|
||||
private:
|
||||
std::string msg;
|
||||
};
|
||||
|
||||
#endif // TABLEKEYNOTDEFINEDEXCEPTION_H_
|
||||
@@ -0,0 +1,11 @@
|
||||
package edu.wpi.first.wpilibj.networktables;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class JNITest {
|
||||
@Test
|
||||
public void jniLinkTest() {
|
||||
// Test to verify that the JNI test link works correctly.
|
||||
edu.wpi.first.wpilibj.networktables.NetworkTablesJNI.flush();
|
||||
}
|
||||
}
|
||||
27
src/test/native/cpp/NetworkTableTest.cpp
Normal file
27
src/test/native/cpp/NetworkTableTest.cpp
Normal file
@@ -0,0 +1,27 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2015. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#include "networktables/NetworkTable.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
class NetworkTableTest : public ::testing::Test {};
|
||||
|
||||
TEST_F(NetworkTableTest, ContainsKey) {
|
||||
auto nt = NetworkTable::GetTable("containskey");
|
||||
ASSERT_FALSE(nt->ContainsKey("testkey"));
|
||||
nt->PutNumber("testkey", 5);
|
||||
ASSERT_TRUE(nt->ContainsKey("testkey"));
|
||||
}
|
||||
|
||||
TEST_F(NetworkTableTest, LeadingSlash) {
|
||||
auto nt = NetworkTable::GetTable("leadingslash");
|
||||
auto nt2 = NetworkTable::GetTable("/leadingslash");
|
||||
ASSERT_FALSE(nt->ContainsKey("testkey"));
|
||||
nt2->PutNumber("testkey", 5);
|
||||
ASSERT_TRUE(nt->ContainsKey("testkey"));
|
||||
}
|
||||
873
src/test/native/cpp/StorageTest.cpp
Normal file
873
src/test/native/cpp/StorageTest.cpp
Normal file
@@ -0,0 +1,873 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2015. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#include "Storage.h"
|
||||
#include "StorageTest.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "gmock/gmock.h"
|
||||
|
||||
namespace nt {
|
||||
|
||||
class StorageTestEmpty : public StorageTest,
|
||||
public ::testing::TestWithParam<bool> {
|
||||
public:
|
||||
StorageTestEmpty() { HookOutgoing(GetParam()); }
|
||||
};
|
||||
|
||||
class StorageTestPopulateOne : public StorageTestEmpty {
|
||||
public:
|
||||
StorageTestPopulateOne() {
|
||||
storage.SetEntryTypeValue("foo", Value::MakeBoolean(true));
|
||||
outgoing.clear();
|
||||
}
|
||||
};
|
||||
|
||||
class StorageTestPopulated : public StorageTestEmpty {
|
||||
public:
|
||||
StorageTestPopulated() {
|
||||
storage.SetEntryTypeValue("foo", Value::MakeBoolean(true));
|
||||
storage.SetEntryTypeValue("foo2", Value::MakeDouble(0.0));
|
||||
storage.SetEntryTypeValue("bar", Value::MakeDouble(1.0));
|
||||
storage.SetEntryTypeValue("bar2", Value::MakeBoolean(false));
|
||||
outgoing.clear();
|
||||
}
|
||||
};
|
||||
|
||||
class StorageTestPersistent : public StorageTestEmpty {
|
||||
public:
|
||||
StorageTestPersistent() {
|
||||
storage.SetEntryTypeValue("boolean/true", Value::MakeBoolean(true));
|
||||
storage.SetEntryTypeValue("boolean/false", Value::MakeBoolean(false));
|
||||
storage.SetEntryTypeValue("double/neg", Value::MakeDouble(-1.5));
|
||||
storage.SetEntryTypeValue("double/zero", Value::MakeDouble(0.0));
|
||||
storage.SetEntryTypeValue("double/big", Value::MakeDouble(1.3e8));
|
||||
storage.SetEntryTypeValue("string/empty", Value::MakeString(""));
|
||||
storage.SetEntryTypeValue("string/normal", Value::MakeString("hello"));
|
||||
storage.SetEntryTypeValue("string/special",
|
||||
Value::MakeString(StringRef("\0\3\5\n", 4)));
|
||||
storage.SetEntryTypeValue("raw/empty", Value::MakeRaw(""));
|
||||
storage.SetEntryTypeValue("raw/normal", Value::MakeRaw("hello"));
|
||||
storage.SetEntryTypeValue("raw/special",
|
||||
Value::MakeRaw(StringRef("\0\3\5\n", 4)));
|
||||
storage.SetEntryTypeValue("booleanarr/empty",
|
||||
Value::MakeBooleanArray(std::vector<int>{}));
|
||||
storage.SetEntryTypeValue("booleanarr/one",
|
||||
Value::MakeBooleanArray(std::vector<int>{1}));
|
||||
storage.SetEntryTypeValue("booleanarr/two",
|
||||
Value::MakeBooleanArray(std::vector<int>{1, 0}));
|
||||
storage.SetEntryTypeValue("doublearr/empty",
|
||||
Value::MakeDoubleArray(std::vector<double>{}));
|
||||
storage.SetEntryTypeValue("doublearr/one",
|
||||
Value::MakeDoubleArray(std::vector<double>{0.5}));
|
||||
storage.SetEntryTypeValue(
|
||||
"doublearr/two",
|
||||
Value::MakeDoubleArray(std::vector<double>{0.5, -0.25}));
|
||||
storage.SetEntryTypeValue(
|
||||
"stringarr/empty", Value::MakeStringArray(std::vector<std::string>{}));
|
||||
storage.SetEntryTypeValue(
|
||||
"stringarr/one",
|
||||
Value::MakeStringArray(std::vector<std::string>{"hello"}));
|
||||
storage.SetEntryTypeValue(
|
||||
"stringarr/two",
|
||||
Value::MakeStringArray(std::vector<std::string>{"hello", "world\n"}));
|
||||
storage.SetEntryTypeValue(StringRef("\0\3\5\n", 4),
|
||||
Value::MakeBoolean(true));
|
||||
storage.SetEntryTypeValue("=", Value::MakeBoolean(true));
|
||||
outgoing.clear();
|
||||
}
|
||||
};
|
||||
|
||||
class MockLoadWarn {
|
||||
public:
|
||||
MOCK_METHOD2(Warn, void(std::size_t line, llvm::StringRef msg));
|
||||
};
|
||||
|
||||
TEST_P(StorageTestEmpty, Construct) {
|
||||
EXPECT_TRUE(entries().empty());
|
||||
EXPECT_TRUE(idmap().empty());
|
||||
}
|
||||
|
||||
TEST_P(StorageTestEmpty, StorageEntryInit) {
|
||||
auto entry = GetEntry("foo");
|
||||
EXPECT_FALSE(entry->value);
|
||||
EXPECT_EQ(0u, entry->flags);
|
||||
EXPECT_EQ("foobar", entry->name); // since GetEntry uses the tmp_entry.
|
||||
EXPECT_EQ(0xffffu, entry->id);
|
||||
EXPECT_EQ(SequenceNumber(), entry->seq_num);
|
||||
}
|
||||
|
||||
TEST_P(StorageTestEmpty, GetEntryValueNotExist) {
|
||||
EXPECT_FALSE(storage.GetEntryValue("foo"));
|
||||
EXPECT_TRUE(entries().empty());
|
||||
EXPECT_TRUE(idmap().empty());
|
||||
EXPECT_TRUE(outgoing.empty());
|
||||
}
|
||||
|
||||
TEST_P(StorageTestEmpty, GetEntryValueExist) {
|
||||
auto value = Value::MakeBoolean(true);
|
||||
storage.SetEntryTypeValue("foo", value);
|
||||
outgoing.clear();
|
||||
EXPECT_EQ(value, storage.GetEntryValue("foo"));
|
||||
}
|
||||
|
||||
TEST_P(StorageTestEmpty, SetEntryTypeValueAssignNew) {
|
||||
// brand new entry
|
||||
auto value = Value::MakeBoolean(true);
|
||||
storage.SetEntryTypeValue("foo", value);
|
||||
EXPECT_EQ(value, GetEntry("foo")->value);
|
||||
if (GetParam()) {
|
||||
ASSERT_EQ(1u, idmap().size());
|
||||
EXPECT_EQ(value, idmap()[0]->value);
|
||||
} else {
|
||||
EXPECT_TRUE(idmap().empty());
|
||||
}
|
||||
|
||||
ASSERT_EQ(1u, outgoing.size());
|
||||
EXPECT_FALSE(outgoing[0].only);
|
||||
EXPECT_FALSE(outgoing[0].except);
|
||||
auto msg = outgoing[0].msg;
|
||||
EXPECT_EQ(Message::kEntryAssign, msg->type());
|
||||
EXPECT_EQ("foo", msg->str());
|
||||
if (GetParam())
|
||||
EXPECT_EQ(0u, msg->id()); // assigned as server
|
||||
else
|
||||
EXPECT_EQ(0xffffu, msg->id()); // not assigned as client
|
||||
EXPECT_EQ(1u, msg->seq_num_uid());
|
||||
EXPECT_EQ(value, msg->value());
|
||||
EXPECT_EQ(0u, msg->flags());
|
||||
}
|
||||
|
||||
TEST_P(StorageTestPopulateOne, SetEntryTypeValueAssignTypeChange) {
|
||||
// update with different type results in assignment message
|
||||
auto value = Value::MakeDouble(0.0);
|
||||
storage.SetEntryTypeValue("foo", value);
|
||||
EXPECT_EQ(value, GetEntry("foo")->value);
|
||||
|
||||
ASSERT_EQ(1u, outgoing.size());
|
||||
EXPECT_FALSE(outgoing[0].only);
|
||||
EXPECT_FALSE(outgoing[0].except);
|
||||
auto msg = outgoing[0].msg;
|
||||
EXPECT_EQ(Message::kEntryAssign, msg->type());
|
||||
EXPECT_EQ("foo", msg->str());
|
||||
if (GetParam())
|
||||
EXPECT_EQ(0u, msg->id()); // assigned as server
|
||||
else
|
||||
EXPECT_EQ(0xffffu, msg->id()); // not assigned as client
|
||||
EXPECT_EQ(2u, msg->seq_num_uid()); // incremented
|
||||
EXPECT_EQ(value, msg->value());
|
||||
EXPECT_EQ(0u, msg->flags());
|
||||
}
|
||||
|
||||
TEST_P(StorageTestPopulateOne, SetEntryTypeValueEqualValue) {
|
||||
// update with same type and same value: change value contents but no update
|
||||
// message is issued (minimizing bandwidth usage)
|
||||
auto value = Value::MakeBoolean(true);
|
||||
storage.SetEntryTypeValue("foo", value);
|
||||
EXPECT_EQ(value, GetEntry("foo")->value);
|
||||
EXPECT_TRUE(outgoing.empty());
|
||||
}
|
||||
|
||||
TEST_P(StorageTestPopulated, SetEntryTypeValueDifferentValue) {
|
||||
// update with same type and different value results in value update message
|
||||
auto value = Value::MakeDouble(1.0);
|
||||
storage.SetEntryTypeValue("foo2", value);
|
||||
EXPECT_EQ(value, GetEntry("foo2")->value);
|
||||
|
||||
if (GetParam()) {
|
||||
ASSERT_EQ(1u, outgoing.size());
|
||||
EXPECT_FALSE(outgoing[0].only);
|
||||
EXPECT_FALSE(outgoing[0].except);
|
||||
auto msg = outgoing[0].msg;
|
||||
EXPECT_EQ(Message::kEntryUpdate, msg->type());
|
||||
EXPECT_EQ(1u, msg->id()); // assigned as server
|
||||
EXPECT_EQ(2u, msg->seq_num_uid()); // incremented
|
||||
EXPECT_EQ(value, msg->value());
|
||||
} else {
|
||||
// shouldn't send an update id not assigned yet (happens on client only)
|
||||
EXPECT_TRUE(outgoing.empty());
|
||||
EXPECT_EQ(2u, GetEntry("foo2")->seq_num.value()); // still should be incremented
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(StorageTestEmpty, SetEntryTypeValueEmptyName) {
|
||||
auto value = Value::MakeBoolean(true);
|
||||
storage.SetEntryTypeValue("", value);
|
||||
EXPECT_TRUE(entries().empty());
|
||||
EXPECT_TRUE(idmap().empty());
|
||||
EXPECT_TRUE(outgoing.empty());
|
||||
}
|
||||
|
||||
TEST_P(StorageTestEmpty, SetEntryTypeValueEmptyValue) {
|
||||
storage.SetEntryTypeValue("foo", nullptr);
|
||||
EXPECT_TRUE(entries().empty());
|
||||
EXPECT_TRUE(idmap().empty());
|
||||
EXPECT_TRUE(outgoing.empty());
|
||||
}
|
||||
|
||||
TEST_P(StorageTestEmpty, SetEntryValueAssignNew) {
|
||||
// brand new entry
|
||||
auto value = Value::MakeBoolean(true);
|
||||
EXPECT_TRUE(storage.SetEntryValue("foo", value));
|
||||
EXPECT_EQ(value, GetEntry("foo")->value);
|
||||
|
||||
ASSERT_EQ(1u, outgoing.size());
|
||||
EXPECT_FALSE(outgoing[0].only);
|
||||
EXPECT_FALSE(outgoing[0].except);
|
||||
auto msg = outgoing[0].msg;
|
||||
EXPECT_EQ(Message::kEntryAssign, msg->type());
|
||||
EXPECT_EQ("foo", msg->str());
|
||||
if (GetParam())
|
||||
EXPECT_EQ(0u, msg->id()); // assigned as server
|
||||
else
|
||||
EXPECT_EQ(0xffffu, msg->id()); // not assigned as client
|
||||
EXPECT_EQ(0u, msg->seq_num_uid());
|
||||
EXPECT_EQ(value, msg->value());
|
||||
EXPECT_EQ(0u, msg->flags());
|
||||
}
|
||||
|
||||
TEST_P(StorageTestPopulateOne, SetEntryValueAssignTypeChange) {
|
||||
// update with different type results in error and no message
|
||||
auto value = Value::MakeDouble(0.0);
|
||||
EXPECT_FALSE(storage.SetEntryValue("foo", value));
|
||||
auto entry = GetEntry("foo");
|
||||
EXPECT_NE(value, entry->value);
|
||||
EXPECT_TRUE(outgoing.empty());
|
||||
}
|
||||
|
||||
TEST_P(StorageTestPopulateOne, SetEntryValueEqualValue) {
|
||||
// update with same type and same value: change value contents but no update
|
||||
// message is issued (minimizing bandwidth usage)
|
||||
auto value = Value::MakeBoolean(true);
|
||||
EXPECT_TRUE(storage.SetEntryValue("foo", value));
|
||||
auto entry = GetEntry("foo");
|
||||
EXPECT_EQ(value, entry->value);
|
||||
EXPECT_TRUE(outgoing.empty());
|
||||
}
|
||||
|
||||
TEST_P(StorageTestPopulated, SetEntryValueDifferentValue) {
|
||||
// update with same type and different value results in value update message
|
||||
auto value = Value::MakeDouble(1.0);
|
||||
EXPECT_TRUE(storage.SetEntryValue("foo2", value));
|
||||
auto entry = GetEntry("foo2");
|
||||
EXPECT_EQ(value, entry->value);
|
||||
|
||||
if (GetParam()) {
|
||||
ASSERT_EQ(1u, outgoing.size());
|
||||
EXPECT_FALSE(outgoing[0].only);
|
||||
EXPECT_FALSE(outgoing[0].except);
|
||||
auto msg = outgoing[0].msg;
|
||||
EXPECT_EQ(Message::kEntryUpdate, msg->type());
|
||||
EXPECT_EQ(1u, msg->id()); // assigned as server
|
||||
EXPECT_EQ(2u, msg->seq_num_uid()); // incremented
|
||||
EXPECT_EQ(value, msg->value());
|
||||
} else {
|
||||
// shouldn't send an update id not assigned yet (happens on client only)
|
||||
EXPECT_TRUE(outgoing.empty());
|
||||
EXPECT_EQ(2u, GetEntry("foo2")->seq_num.value()); // still should be incremented
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(StorageTestEmpty, SetEntryValueEmptyName) {
|
||||
auto value = Value::MakeBoolean(true);
|
||||
EXPECT_TRUE(storage.SetEntryValue("", value));
|
||||
EXPECT_TRUE(entries().empty());
|
||||
EXPECT_TRUE(idmap().empty());
|
||||
EXPECT_TRUE(outgoing.empty());
|
||||
}
|
||||
|
||||
TEST_P(StorageTestEmpty, SetEntryValueEmptyValue) {
|
||||
EXPECT_TRUE(storage.SetEntryValue("foo", nullptr));
|
||||
EXPECT_TRUE(entries().empty());
|
||||
EXPECT_TRUE(idmap().empty());
|
||||
EXPECT_TRUE(outgoing.empty());
|
||||
}
|
||||
|
||||
TEST_P(StorageTestEmpty, SetDefaultEntryAssignNew) {
|
||||
// brand new entry
|
||||
auto value = Value::MakeBoolean(true);
|
||||
auto ret_val = storage.SetDefaultEntryValue("foo", value);
|
||||
EXPECT_TRUE(ret_val);
|
||||
EXPECT_EQ(value, GetEntry("foo")->value);
|
||||
|
||||
ASSERT_EQ(1u, outgoing.size());
|
||||
EXPECT_FALSE(outgoing[0].only);
|
||||
EXPECT_FALSE(outgoing[0].except);
|
||||
auto msg = outgoing[0].msg;
|
||||
EXPECT_EQ(Message::kEntryAssign, msg->type());
|
||||
EXPECT_EQ("foo", msg->str());
|
||||
if (GetParam())
|
||||
EXPECT_EQ(0u, msg->id()); // assigned as server
|
||||
else
|
||||
EXPECT_EQ(0xffffu, msg->id()); // not assigned as client
|
||||
EXPECT_EQ(0u, msg->seq_num_uid());
|
||||
EXPECT_EQ(value, msg->value());
|
||||
EXPECT_EQ(0u, msg->flags());
|
||||
}
|
||||
|
||||
TEST_P(StorageTestPopulateOne, SetDefaultEntryExistsSameType) {
|
||||
// existing entry
|
||||
auto value = Value::MakeBoolean(true);
|
||||
auto ret_val = storage.SetDefaultEntryValue("foo", value);
|
||||
EXPECT_TRUE(ret_val);
|
||||
EXPECT_NE(value, GetEntry("foo")->value);
|
||||
|
||||
EXPECT_TRUE(outgoing.empty());
|
||||
}
|
||||
|
||||
TEST_P(StorageTestPopulateOne, SetDefaultEntryExistsDifferentType) {
|
||||
// existing entry is boolean
|
||||
auto value = Value::MakeDouble(2.0);
|
||||
auto ret_val = storage.SetDefaultEntryValue("foo", value);
|
||||
EXPECT_FALSE(ret_val);
|
||||
// should not have updated value in table if it already existed.
|
||||
EXPECT_NE(value, GetEntry("foo")->value);
|
||||
|
||||
EXPECT_TRUE(outgoing.empty());
|
||||
}
|
||||
|
||||
TEST_P(StorageTestEmpty, SetDefaultEntryEmptyName) {
|
||||
auto value = Value::MakeBoolean(true);
|
||||
auto ret_val = storage.SetDefaultEntryValue("", value);
|
||||
EXPECT_FALSE(ret_val);
|
||||
auto entry = GetEntry("foo");
|
||||
EXPECT_FALSE(entry->value);
|
||||
EXPECT_EQ(0u, entry->flags);
|
||||
EXPECT_EQ("foobar", entry->name); // since GetEntry uses the tmp_entry.
|
||||
EXPECT_EQ(0xffffu, entry->id);
|
||||
EXPECT_EQ(SequenceNumber(), entry->seq_num);
|
||||
EXPECT_TRUE(entries().empty());
|
||||
EXPECT_TRUE(idmap().empty());
|
||||
EXPECT_TRUE(outgoing.empty());
|
||||
}
|
||||
|
||||
TEST_P(StorageTestEmpty, SetDefaultEntryEmptyValue) {
|
||||
auto value = Value::MakeBoolean(true);
|
||||
auto ret_val = storage.SetDefaultEntryValue("", nullptr);
|
||||
EXPECT_FALSE(ret_val);
|
||||
auto entry = GetEntry("foo");
|
||||
EXPECT_FALSE(entry->value);
|
||||
EXPECT_EQ(0u, entry->flags);
|
||||
EXPECT_EQ("foobar", entry->name); // since GetEntry uses the tmp_entry.
|
||||
EXPECT_EQ(0xffffu, entry->id);
|
||||
EXPECT_EQ(SequenceNumber(), entry->seq_num);
|
||||
EXPECT_TRUE(entries().empty());
|
||||
EXPECT_TRUE(idmap().empty());
|
||||
EXPECT_TRUE(outgoing.empty());
|
||||
}
|
||||
|
||||
TEST_P(StorageTestPopulated, SetDefaultEntryEmptyName) {
|
||||
auto value = Value::MakeBoolean(true);
|
||||
auto ret_val = storage.SetDefaultEntryValue("", value);
|
||||
EXPECT_FALSE(ret_val);
|
||||
// assert that no entries get added
|
||||
EXPECT_EQ(4u, entries().size());
|
||||
if (GetParam())
|
||||
EXPECT_EQ(4u, idmap().size());
|
||||
else
|
||||
EXPECT_EQ(0u, idmap().size());
|
||||
EXPECT_TRUE(outgoing.empty());
|
||||
}
|
||||
|
||||
TEST_P(StorageTestPopulated, SetDefaultEntryEmptyValue) {
|
||||
auto value = Value::MakeBoolean(true);
|
||||
auto ret_val = storage.SetDefaultEntryValue("", nullptr);
|
||||
EXPECT_FALSE(ret_val);
|
||||
// assert that no entries get added
|
||||
EXPECT_EQ(4u, entries().size());
|
||||
if (GetParam())
|
||||
EXPECT_EQ(4u, idmap().size());
|
||||
else
|
||||
EXPECT_EQ(0u, idmap().size());
|
||||
EXPECT_TRUE(outgoing.empty());
|
||||
}
|
||||
|
||||
|
||||
TEST_P(StorageTestEmpty, SetEntryFlagsNew) {
|
||||
// flags setting doesn't create an entry
|
||||
storage.SetEntryFlags("foo", 0u);
|
||||
EXPECT_TRUE(entries().empty());
|
||||
EXPECT_TRUE(idmap().empty());
|
||||
EXPECT_TRUE(outgoing.empty());
|
||||
}
|
||||
|
||||
TEST_P(StorageTestPopulateOne, SetEntryFlagsEqualValue) {
|
||||
// update with same value: no update message is issued (minimizing bandwidth
|
||||
// usage)
|
||||
storage.SetEntryFlags("foo", 0u);
|
||||
auto entry = GetEntry("foo");
|
||||
EXPECT_EQ(0u, entry->flags);
|
||||
EXPECT_TRUE(outgoing.empty());
|
||||
}
|
||||
|
||||
TEST_P(StorageTestPopulated, SetEntryFlagsDifferentValue) {
|
||||
// update with different value results in flags update message
|
||||
storage.SetEntryFlags("foo2", 1u);
|
||||
EXPECT_EQ(1u, GetEntry("foo2")->flags);
|
||||
|
||||
if (GetParam()) {
|
||||
ASSERT_EQ(1u, outgoing.size());
|
||||
EXPECT_FALSE(outgoing[0].only);
|
||||
EXPECT_FALSE(outgoing[0].except);
|
||||
auto msg = outgoing[0].msg;
|
||||
EXPECT_EQ(Message::kFlagsUpdate, msg->type());
|
||||
EXPECT_EQ(1u, msg->id()); // assigned as server
|
||||
EXPECT_EQ(1u, msg->flags());
|
||||
} else {
|
||||
// shouldn't send an update id not assigned yet (happens on client only)
|
||||
EXPECT_TRUE(outgoing.empty());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(StorageTestEmpty, SetEntryFlagsEmptyName) {
|
||||
storage.SetEntryFlags("", 0u);
|
||||
EXPECT_TRUE(entries().empty());
|
||||
EXPECT_TRUE(idmap().empty());
|
||||
EXPECT_TRUE(outgoing.empty());
|
||||
}
|
||||
|
||||
TEST_P(StorageTestEmpty, GetEntryFlagsNotExist) {
|
||||
EXPECT_EQ(0u, storage.GetEntryFlags("foo"));
|
||||
EXPECT_TRUE(entries().empty());
|
||||
EXPECT_TRUE(idmap().empty());
|
||||
EXPECT_TRUE(outgoing.empty());
|
||||
}
|
||||
|
||||
TEST_P(StorageTestPopulateOne, GetEntryFlagsExist) {
|
||||
storage.SetEntryFlags("foo", 1u);
|
||||
outgoing.clear();
|
||||
EXPECT_EQ(1u, storage.GetEntryFlags("foo"));
|
||||
EXPECT_TRUE(outgoing.empty());
|
||||
}
|
||||
|
||||
TEST_P(StorageTestEmpty, DeleteEntryNotExist) {
|
||||
storage.DeleteEntry("foo");
|
||||
EXPECT_TRUE(outgoing.empty());
|
||||
}
|
||||
|
||||
TEST_P(StorageTestPopulated, DeleteEntryExist) {
|
||||
storage.DeleteEntry("foo2");
|
||||
EXPECT_TRUE(entries().count("foo2") == 0);
|
||||
if (GetParam()) {
|
||||
ASSERT_TRUE(idmap().size() >= 2);
|
||||
EXPECT_FALSE(idmap()[1]);
|
||||
}
|
||||
|
||||
if (GetParam()) {
|
||||
ASSERT_EQ(1u, outgoing.size());
|
||||
EXPECT_FALSE(outgoing[0].only);
|
||||
EXPECT_FALSE(outgoing[0].except);
|
||||
auto msg = outgoing[0].msg;
|
||||
EXPECT_EQ(Message::kEntryDelete, msg->type());
|
||||
EXPECT_EQ(1u, msg->id()); // assigned as server
|
||||
} else {
|
||||
// shouldn't send an update id not assigned yet (happens on client only)
|
||||
EXPECT_TRUE(outgoing.empty());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(StorageTestEmpty, DeleteAllEntriesEmpty) {
|
||||
storage.DeleteAllEntries();
|
||||
EXPECT_TRUE(outgoing.empty());
|
||||
}
|
||||
|
||||
TEST_P(StorageTestPopulated, DeleteAllEntries) {
|
||||
storage.DeleteAllEntries();
|
||||
ASSERT_TRUE(entries().empty());
|
||||
|
||||
ASSERT_EQ(1u, outgoing.size());
|
||||
EXPECT_FALSE(outgoing[0].only);
|
||||
EXPECT_FALSE(outgoing[0].except);
|
||||
auto msg = outgoing[0].msg;
|
||||
EXPECT_EQ(Message::kClearEntries, msg->type());
|
||||
}
|
||||
|
||||
TEST_P(StorageTestPopulated, DeleteAllEntriesPersistent) {
|
||||
GetEntry("foo2")->flags = NT_PERSISTENT;
|
||||
storage.DeleteAllEntries();
|
||||
ASSERT_EQ(1u, entries().size());
|
||||
EXPECT_EQ(1u, entries().count("foo2"));
|
||||
|
||||
ASSERT_EQ(1u, outgoing.size());
|
||||
EXPECT_FALSE(outgoing[0].only);
|
||||
EXPECT_FALSE(outgoing[0].except);
|
||||
auto msg = outgoing[0].msg;
|
||||
EXPECT_EQ(Message::kClearEntries, msg->type());
|
||||
}
|
||||
|
||||
TEST_P(StorageTestPopulated, GetEntryInfoAll) {
|
||||
auto info = storage.GetEntryInfo("", 0u);
|
||||
ASSERT_EQ(4u, info.size());
|
||||
}
|
||||
|
||||
TEST_P(StorageTestPopulated, GetEntryInfoPrefix) {
|
||||
auto info = storage.GetEntryInfo("foo", 0u);
|
||||
ASSERT_EQ(2u, info.size());
|
||||
if (info[0].name == "foo") {
|
||||
EXPECT_EQ("foo", info[0].name);
|
||||
EXPECT_EQ(NT_BOOLEAN, info[0].type);
|
||||
EXPECT_EQ("foo2", info[1].name);
|
||||
EXPECT_EQ(NT_DOUBLE, info[1].type);
|
||||
} else {
|
||||
EXPECT_EQ("foo2", info[0].name);
|
||||
EXPECT_EQ(NT_DOUBLE, info[0].type);
|
||||
EXPECT_EQ("foo", info[1].name);
|
||||
EXPECT_EQ(NT_BOOLEAN, info[1].type);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(StorageTestPopulated, GetEntryInfoTypes) {
|
||||
auto info = storage.GetEntryInfo("", NT_DOUBLE);
|
||||
ASSERT_EQ(2u, info.size());
|
||||
EXPECT_EQ(NT_DOUBLE, info[0].type);
|
||||
EXPECT_EQ(NT_DOUBLE, info[1].type);
|
||||
if (info[0].name == "foo2") {
|
||||
EXPECT_EQ("foo2", info[0].name);
|
||||
EXPECT_EQ("bar", info[1].name);
|
||||
} else {
|
||||
EXPECT_EQ("bar", info[0].name);
|
||||
EXPECT_EQ("foo2", info[1].name);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(StorageTestPopulated, GetEntryInfoPrefixTypes) {
|
||||
auto info = storage.GetEntryInfo("bar", NT_BOOLEAN);
|
||||
ASSERT_EQ(1u, info.size());
|
||||
EXPECT_EQ("bar2", info[0].name);
|
||||
EXPECT_EQ(NT_BOOLEAN, info[0].type);
|
||||
}
|
||||
|
||||
TEST_P(StorageTestPersistent, SavePersistentEmpty) {
|
||||
std::ostringstream oss;
|
||||
storage.SavePersistent(oss, false);
|
||||
ASSERT_EQ("[NetworkTables Storage 3.0]\n", oss.str());
|
||||
}
|
||||
|
||||
TEST_P(StorageTestPersistent, SavePersistent) {
|
||||
for (auto& i : entries()) i.getValue()->flags = NT_PERSISTENT;
|
||||
std::ostringstream oss;
|
||||
storage.SavePersistent(oss, false);
|
||||
std::string out = oss.str();
|
||||
//fputs(out.c_str(), stderr);
|
||||
llvm::StringRef line, rem = out;
|
||||
std::tie(line, rem) = rem.split('\n');
|
||||
ASSERT_EQ("[NetworkTables Storage 3.0]", line);
|
||||
std::tie(line, rem) = rem.split('\n');
|
||||
ASSERT_EQ("boolean \"\\x00\\x03\\x05\\n\"=true", line);
|
||||
std::tie(line, rem) = rem.split('\n');
|
||||
ASSERT_EQ("boolean \"\\x3D\"=true", line);
|
||||
std::tie(line, rem) = rem.split('\n');
|
||||
ASSERT_EQ("boolean \"boolean/false\"=false", line);
|
||||
std::tie(line, rem) = rem.split('\n');
|
||||
ASSERT_EQ("boolean \"boolean/true\"=true", line);
|
||||
std::tie(line, rem) = rem.split('\n');
|
||||
ASSERT_EQ("array boolean \"booleanarr/empty\"=", line);
|
||||
std::tie(line, rem) = rem.split('\n');
|
||||
ASSERT_EQ("array boolean \"booleanarr/one\"=true", line);
|
||||
std::tie(line, rem) = rem.split('\n');
|
||||
ASSERT_EQ("array boolean \"booleanarr/two\"=true,false", line);
|
||||
std::tie(line, rem) = rem.split('\n');
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1900
|
||||
ASSERT_EQ("double \"double/big\"=1.3e+008", line);
|
||||
#else
|
||||
ASSERT_EQ("double \"double/big\"=1.3e+08", line);
|
||||
#endif
|
||||
std::tie(line, rem) = rem.split('\n');
|
||||
ASSERT_EQ("double \"double/neg\"=-1.5", line);
|
||||
std::tie(line, rem) = rem.split('\n');
|
||||
ASSERT_EQ("double \"double/zero\"=0", line);
|
||||
std::tie(line, rem) = rem.split('\n');
|
||||
ASSERT_EQ("array double \"doublearr/empty\"=", line);
|
||||
std::tie(line, rem) = rem.split('\n');
|
||||
ASSERT_EQ("array double \"doublearr/one\"=0.5", line);
|
||||
std::tie(line, rem) = rem.split('\n');
|
||||
ASSERT_EQ("array double \"doublearr/two\"=0.5,-0.25", line);
|
||||
std::tie(line, rem) = rem.split('\n');
|
||||
ASSERT_EQ("raw \"raw/empty\"=", line);
|
||||
std::tie(line, rem) = rem.split('\n');
|
||||
ASSERT_EQ("raw \"raw/normal\"=aGVsbG8=", line);
|
||||
std::tie(line, rem) = rem.split('\n');
|
||||
ASSERT_EQ("raw \"raw/special\"=AAMFCg==", line);
|
||||
std::tie(line, rem) = rem.split('\n');
|
||||
ASSERT_EQ("string \"string/empty\"=\"\"", line);
|
||||
std::tie(line, rem) = rem.split('\n');
|
||||
ASSERT_EQ("string \"string/normal\"=\"hello\"", line);
|
||||
std::tie(line, rem) = rem.split('\n');
|
||||
ASSERT_EQ("string \"string/special\"=\"\\x00\\x03\\x05\\n\"", line);
|
||||
std::tie(line, rem) = rem.split('\n');
|
||||
ASSERT_EQ("array string \"stringarr/empty\"=", line);
|
||||
std::tie(line, rem) = rem.split('\n');
|
||||
ASSERT_EQ("array string \"stringarr/one\"=\"hello\"", line);
|
||||
std::tie(line, rem) = rem.split('\n');
|
||||
ASSERT_EQ("array string \"stringarr/two\"=\"hello\",\"world\\n\"", line);
|
||||
std::tie(line, rem) = rem.split('\n');
|
||||
ASSERT_EQ("", line);
|
||||
}
|
||||
|
||||
TEST_P(StorageTestEmpty, LoadPersistentBadHeader) {
|
||||
MockLoadWarn warn;
|
||||
auto warn_func =
|
||||
[&](std::size_t line, const char* msg) { warn.Warn(line, msg); };
|
||||
|
||||
std::istringstream iss("");
|
||||
EXPECT_CALL(warn, Warn(1, llvm::StringRef("header line mismatch, ignoring rest of file")));
|
||||
EXPECT_FALSE(storage.LoadPersistent(iss, warn_func));
|
||||
|
||||
std::istringstream iss2("[NetworkTables");
|
||||
EXPECT_CALL(warn, Warn(1, llvm::StringRef("header line mismatch, ignoring rest of file")));
|
||||
EXPECT_FALSE(storage.LoadPersistent(iss2, warn_func));
|
||||
EXPECT_TRUE(entries().empty());
|
||||
EXPECT_TRUE(idmap().empty());
|
||||
EXPECT_TRUE(outgoing.empty());
|
||||
}
|
||||
|
||||
TEST_P(StorageTestEmpty, LoadPersistentCommentHeader) {
|
||||
MockLoadWarn warn;
|
||||
auto warn_func =
|
||||
[&](std::size_t line, const char* msg) { warn.Warn(line, msg); };
|
||||
|
||||
std::istringstream iss(
|
||||
"\n; comment\n# comment\n[NetworkTables Storage 3.0]\n");
|
||||
EXPECT_TRUE(storage.LoadPersistent(iss, warn_func));
|
||||
EXPECT_TRUE(entries().empty());
|
||||
EXPECT_TRUE(idmap().empty());
|
||||
EXPECT_TRUE(outgoing.empty());
|
||||
}
|
||||
|
||||
TEST_P(StorageTestEmpty, LoadPersistentEmptyName) {
|
||||
MockLoadWarn warn;
|
||||
auto warn_func =
|
||||
[&](std::size_t line, const char* msg) { warn.Warn(line, msg); };
|
||||
|
||||
std::istringstream iss(
|
||||
"[NetworkTables Storage 3.0]\nboolean \"\"=true\n");
|
||||
EXPECT_TRUE(storage.LoadPersistent(iss, warn_func));
|
||||
EXPECT_TRUE(entries().empty());
|
||||
EXPECT_TRUE(idmap().empty());
|
||||
EXPECT_TRUE(outgoing.empty());
|
||||
}
|
||||
|
||||
TEST_P(StorageTestEmpty, LoadPersistentAssign) {
|
||||
MockLoadWarn warn;
|
||||
auto warn_func =
|
||||
[&](std::size_t line, const char* msg) { warn.Warn(line, msg); };
|
||||
|
||||
std::istringstream iss(
|
||||
"[NetworkTables Storage 3.0]\nboolean \"foo\"=true\n");
|
||||
EXPECT_TRUE(storage.LoadPersistent(iss, warn_func));
|
||||
auto entry = GetEntry("foo");
|
||||
EXPECT_EQ(*Value::MakeBoolean(true), *entry->value);
|
||||
EXPECT_EQ(NT_PERSISTENT, entry->flags);
|
||||
|
||||
ASSERT_EQ(1u, outgoing.size());
|
||||
EXPECT_FALSE(outgoing[0].only);
|
||||
EXPECT_FALSE(outgoing[0].except);
|
||||
auto msg = outgoing[0].msg;
|
||||
EXPECT_EQ(Message::kEntryAssign, msg->type());
|
||||
EXPECT_EQ("foo", msg->str());
|
||||
if (GetParam())
|
||||
EXPECT_EQ(0u, msg->id()); // assigned as server
|
||||
else
|
||||
EXPECT_EQ(0xffffu, msg->id()); // not assigned as client
|
||||
EXPECT_EQ(1u, msg->seq_num_uid());
|
||||
EXPECT_EQ(*Value::MakeBoolean(true), *msg->value());
|
||||
EXPECT_EQ(NT_PERSISTENT, msg->flags());
|
||||
}
|
||||
|
||||
TEST_P(StorageTestPopulated, LoadPersistentUpdateFlags) {
|
||||
MockLoadWarn warn;
|
||||
auto warn_func =
|
||||
[&](std::size_t line, const char* msg) { warn.Warn(line, msg); };
|
||||
|
||||
std::istringstream iss(
|
||||
"[NetworkTables Storage 3.0]\ndouble \"foo2\"=0.0\n");
|
||||
EXPECT_TRUE(storage.LoadPersistent(iss, warn_func));
|
||||
auto entry = GetEntry("foo2");
|
||||
EXPECT_EQ(*Value::MakeDouble(0.0), *entry->value);
|
||||
EXPECT_EQ(NT_PERSISTENT, entry->flags);
|
||||
|
||||
if (GetParam()) {
|
||||
ASSERT_EQ(1u, outgoing.size());
|
||||
EXPECT_FALSE(outgoing[0].only);
|
||||
EXPECT_FALSE(outgoing[0].except);
|
||||
auto msg = outgoing[0].msg;
|
||||
EXPECT_EQ(Message::kFlagsUpdate, msg->type());
|
||||
EXPECT_EQ(1u, msg->id()); // assigned as server
|
||||
EXPECT_EQ(NT_PERSISTENT, msg->flags());
|
||||
} else {
|
||||
// shouldn't send an update id not assigned yet (happens on client only)
|
||||
EXPECT_TRUE(outgoing.empty());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(StorageTestPopulated, LoadPersistentUpdateValue) {
|
||||
MockLoadWarn warn;
|
||||
auto warn_func =
|
||||
[&](std::size_t line, const char* msg) { warn.Warn(line, msg); };
|
||||
|
||||
GetEntry("foo2")->flags = NT_PERSISTENT;
|
||||
|
||||
std::istringstream iss(
|
||||
"[NetworkTables Storage 3.0]\ndouble \"foo2\"=1.0\n");
|
||||
EXPECT_TRUE(storage.LoadPersistent(iss, warn_func));
|
||||
auto entry = GetEntry("foo2");
|
||||
EXPECT_EQ(*Value::MakeDouble(1.0), *entry->value);
|
||||
EXPECT_EQ(NT_PERSISTENT, entry->flags);
|
||||
|
||||
if (GetParam()) {
|
||||
ASSERT_EQ(1u, outgoing.size());
|
||||
EXPECT_FALSE(outgoing[0].only);
|
||||
EXPECT_FALSE(outgoing[0].except);
|
||||
auto msg = outgoing[0].msg;
|
||||
EXPECT_EQ(Message::kEntryUpdate, msg->type());
|
||||
EXPECT_EQ(1u, msg->id()); // assigned as server
|
||||
EXPECT_EQ(2u, msg->seq_num_uid()); // incremented
|
||||
EXPECT_EQ(*Value::MakeDouble(1.0), *msg->value());
|
||||
} else {
|
||||
// shouldn't send an update id not assigned yet (happens on client only)
|
||||
EXPECT_TRUE(outgoing.empty());
|
||||
EXPECT_EQ(2u, GetEntry("foo2")->seq_num.value()); // still should be incremented
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(StorageTestPopulated, LoadPersistentUpdateValueFlags) {
|
||||
MockLoadWarn warn;
|
||||
auto warn_func =
|
||||
[&](std::size_t line, const char* msg) { warn.Warn(line, msg); };
|
||||
|
||||
std::istringstream iss(
|
||||
"[NetworkTables Storage 3.0]\ndouble \"foo2\"=1.0\n");
|
||||
EXPECT_TRUE(storage.LoadPersistent(iss, warn_func));
|
||||
auto entry = GetEntry("foo2");
|
||||
EXPECT_EQ(*Value::MakeDouble(1.0), *entry->value);
|
||||
EXPECT_EQ(NT_PERSISTENT, entry->flags);
|
||||
|
||||
if (GetParam()) {
|
||||
ASSERT_EQ(2u, outgoing.size());
|
||||
EXPECT_FALSE(outgoing[0].only);
|
||||
EXPECT_FALSE(outgoing[0].except);
|
||||
auto msg = outgoing[0].msg;
|
||||
EXPECT_EQ(Message::kEntryUpdate, msg->type());
|
||||
EXPECT_EQ(1u, msg->id()); // assigned as server
|
||||
EXPECT_EQ(2u, msg->seq_num_uid()); // incremented
|
||||
EXPECT_EQ(*Value::MakeDouble(1.0), *msg->value());
|
||||
|
||||
EXPECT_FALSE(outgoing[1].only);
|
||||
EXPECT_FALSE(outgoing[1].except);
|
||||
msg = outgoing[1].msg;
|
||||
EXPECT_EQ(Message::kFlagsUpdate, msg->type());
|
||||
EXPECT_EQ(1u, msg->id()); // assigned as server
|
||||
EXPECT_EQ(NT_PERSISTENT, msg->flags());
|
||||
} else {
|
||||
// shouldn't send an update id not assigned yet (happens on client only)
|
||||
EXPECT_TRUE(outgoing.empty());
|
||||
EXPECT_EQ(2u, GetEntry("foo2")->seq_num.value()); // still should be incremented
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(StorageTestEmpty, LoadPersistent) {
|
||||
MockLoadWarn warn;
|
||||
auto warn_func =
|
||||
[&](std::size_t line, const char* msg) { warn.Warn(line, msg); };
|
||||
|
||||
std::string in = "[NetworkTables Storage 3.0]\n";
|
||||
in += "boolean \"\\x00\\x03\\x05\\n\"=true\n";
|
||||
in += "boolean \"\\x3D\"=true\n";
|
||||
in += "boolean \"boolean/false\"=false\n";
|
||||
in += "boolean \"boolean/true\"=true\n";
|
||||
in += "array boolean \"booleanarr/empty\"=\n";
|
||||
in += "array boolean \"booleanarr/one\"=true\n";
|
||||
in += "array boolean \"booleanarr/two\"=true,false\n";
|
||||
in += "double \"double/big\"=1.3e+08\n";
|
||||
in += "double \"double/neg\"=-1.5\n";
|
||||
in += "double \"double/zero\"=0\n";
|
||||
in += "array double \"doublearr/empty\"=\n";
|
||||
in += "array double \"doublearr/one\"=0.5\n";
|
||||
in += "array double \"doublearr/two\"=0.5,-0.25\n";
|
||||
in += "raw \"raw/empty\"=\n";
|
||||
in += "raw \"raw/normal\"=aGVsbG8=\n";
|
||||
in += "raw \"raw/special\"=AAMFCg==\n";
|
||||
in += "string \"string/empty\"=\"\"\n";
|
||||
in += "string \"string/normal\"=\"hello\"\n";
|
||||
in += "string \"string/special\"=\"\\x00\\x03\\x05\\n\"\n";
|
||||
in += "array string \"stringarr/empty\"=\n";
|
||||
in += "array string \"stringarr/one\"=\"hello\"\n";
|
||||
in += "array string \"stringarr/two\"=\"hello\",\"world\\n\"\n";
|
||||
|
||||
std::istringstream iss(in);
|
||||
EXPECT_TRUE(storage.LoadPersistent(iss, warn_func));
|
||||
ASSERT_EQ(22u, entries().size());
|
||||
EXPECT_EQ(22u, outgoing.size());
|
||||
|
||||
EXPECT_EQ(*Value::MakeBoolean(true), *storage.GetEntryValue("boolean/true"));
|
||||
EXPECT_EQ(*Value::MakeBoolean(false),
|
||||
*storage.GetEntryValue("boolean/false"));
|
||||
EXPECT_EQ(*Value::MakeDouble(-1.5), *storage.GetEntryValue("double/neg"));
|
||||
EXPECT_EQ(*Value::MakeDouble(0.0), *storage.GetEntryValue("double/zero"));
|
||||
EXPECT_EQ(*Value::MakeDouble(1.3e8), *storage.GetEntryValue("double/big"));
|
||||
EXPECT_EQ(*Value::MakeString(""), *storage.GetEntryValue("string/empty"));
|
||||
EXPECT_EQ(*Value::MakeString("hello"),
|
||||
*storage.GetEntryValue("string/normal"));
|
||||
EXPECT_EQ(*Value::MakeString(StringRef("\0\3\5\n", 4)),
|
||||
*storage.GetEntryValue("string/special"));
|
||||
EXPECT_EQ(*Value::MakeRaw(""),
|
||||
*storage.GetEntryValue("raw/empty"));
|
||||
EXPECT_EQ(*Value::MakeRaw("hello"),
|
||||
*storage.GetEntryValue("raw/normal"));
|
||||
EXPECT_EQ(*Value::MakeRaw(StringRef("\0\3\5\n", 4)),
|
||||
*storage.GetEntryValue("raw/special"));
|
||||
EXPECT_EQ(*Value::MakeBooleanArray(std::vector<int>{}),
|
||||
*storage.GetEntryValue("booleanarr/empty"));
|
||||
EXPECT_EQ(*Value::MakeBooleanArray(std::vector<int>{1}),
|
||||
*storage.GetEntryValue("booleanarr/one"));
|
||||
EXPECT_EQ(*Value::MakeBooleanArray(std::vector<int>{1, 0}),
|
||||
*storage.GetEntryValue("booleanarr/two"));
|
||||
EXPECT_EQ(*Value::MakeDoubleArray(std::vector<double>{}),
|
||||
*storage.GetEntryValue("doublearr/empty"));
|
||||
EXPECT_EQ(*Value::MakeDoubleArray(std::vector<double>{0.5}),
|
||||
*storage.GetEntryValue("doublearr/one"));
|
||||
EXPECT_EQ(*Value::MakeDoubleArray(std::vector<double>{0.5, -0.25}),
|
||||
*storage.GetEntryValue("doublearr/two"));
|
||||
EXPECT_EQ(*Value::MakeStringArray(std::vector<std::string>{}),
|
||||
*storage.GetEntryValue("stringarr/empty"));
|
||||
EXPECT_EQ(*Value::MakeStringArray(std::vector<std::string>{"hello"}),
|
||||
*storage.GetEntryValue("stringarr/one"));
|
||||
EXPECT_EQ(
|
||||
*Value::MakeStringArray(std::vector<std::string>{"hello", "world\n"}),
|
||||
*storage.GetEntryValue("stringarr/two"));
|
||||
EXPECT_EQ(*Value::MakeBoolean(true),
|
||||
*storage.GetEntryValue(StringRef("\0\3\5\n", 4)));
|
||||
EXPECT_EQ(*Value::MakeBoolean(true), *storage.GetEntryValue("="));
|
||||
}
|
||||
|
||||
TEST_P(StorageTestEmpty, LoadPersistentWarn) {
|
||||
MockLoadWarn warn;
|
||||
auto warn_func =
|
||||
[&](std::size_t line, const char* msg) { warn.Warn(line, msg); };
|
||||
|
||||
std::istringstream iss(
|
||||
"[NetworkTables Storage 3.0]\nboolean \"foo\"=foo\n");
|
||||
EXPECT_CALL(warn,
|
||||
Warn(2, llvm::StringRef("unrecognized boolean value, not 'true' or 'false'")));
|
||||
EXPECT_TRUE(storage.LoadPersistent(iss, warn_func));
|
||||
|
||||
EXPECT_TRUE(entries().empty());
|
||||
EXPECT_TRUE(idmap().empty());
|
||||
EXPECT_TRUE(outgoing.empty());
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(StorageTestsEmpty, StorageTestEmpty, ::testing::Bool());
|
||||
INSTANTIATE_TEST_CASE_P(StorageTestsPopulateOne, StorageTestPopulateOne,
|
||||
::testing::Bool());
|
||||
INSTANTIATE_TEST_CASE_P(StorageTestsPopulated, StorageTestPopulated,
|
||||
::testing::Bool());
|
||||
INSTANTIATE_TEST_CASE_P(StorageTestsPersistent, StorageTestPersistent,
|
||||
::testing::Bool());
|
||||
|
||||
} // namespace nt
|
||||
55
src/test/native/cpp/StorageTest.h
Normal file
55
src/test/native/cpp/StorageTest.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2015. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef NT_TEST_STORAGETEST_H_
|
||||
#define NT_TEST_STORAGETEST_H_
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "Storage.h"
|
||||
|
||||
namespace nt {
|
||||
|
||||
class StorageTest {
|
||||
public:
|
||||
StorageTest() : tmp_entry("foobar") {}
|
||||
|
||||
Storage::EntriesMap& entries() { return storage.m_entries; }
|
||||
Storage::IdMap& idmap() { return storage.m_idmap; }
|
||||
|
||||
Storage::Entry* GetEntry(StringRef name) {
|
||||
auto i = storage.m_entries.find(name);
|
||||
return i == storage.m_entries.end() ? &tmp_entry : i->getValue().get();
|
||||
}
|
||||
|
||||
void HookOutgoing(bool server) {
|
||||
using namespace std::placeholders;
|
||||
storage.SetOutgoing(
|
||||
std::bind(&StorageTest::QueueOutgoing, this, _1, _2, _3), server);
|
||||
}
|
||||
|
||||
struct OutgoingData {
|
||||
std::shared_ptr<Message> msg;
|
||||
NetworkConnection* only;
|
||||
NetworkConnection* except;
|
||||
};
|
||||
|
||||
void QueueOutgoing(std::shared_ptr<Message> msg, NetworkConnection* only,
|
||||
NetworkConnection* except) {
|
||||
outgoing.emplace_back(OutgoingData{msg, only, except});
|
||||
}
|
||||
|
||||
Storage storage;
|
||||
Storage::Entry tmp_entry;
|
||||
std::vector<OutgoingData> outgoing;
|
||||
};
|
||||
|
||||
} // namespace nt
|
||||
|
||||
#endif // NT_TEST_STORAGETEST_H_
|
||||
365
src/test/native/cpp/ValueTest.cpp
Normal file
365
src/test/native/cpp/ValueTest.cpp
Normal file
@@ -0,0 +1,365 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2015. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#include "nt_Value.h"
|
||||
#include "Value_internal.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace nt {
|
||||
|
||||
class ValueTest : public ::testing::Test {};
|
||||
|
||||
typedef ValueTest ValueDeathTest;
|
||||
|
||||
TEST_F(ValueTest, ConstructEmpty) {
|
||||
Value v;
|
||||
ASSERT_EQ(NT_UNASSIGNED, v.type());
|
||||
}
|
||||
|
||||
TEST_F(ValueTest, Boolean) {
|
||||
auto v = Value::MakeBoolean(false);
|
||||
ASSERT_EQ(NT_BOOLEAN, v->type());
|
||||
ASSERT_FALSE(v->GetBoolean());
|
||||
NT_Value cv;
|
||||
NT_InitValue(&cv);
|
||||
ConvertToC(*v, &cv);
|
||||
ASSERT_EQ(NT_BOOLEAN, cv.type);
|
||||
ASSERT_EQ(0, cv.data.v_boolean);
|
||||
|
||||
v = Value::MakeBoolean(true);
|
||||
ASSERT_EQ(NT_BOOLEAN, v->type());
|
||||
ASSERT_TRUE(v->GetBoolean());
|
||||
ConvertToC(*v, &cv);
|
||||
ASSERT_EQ(NT_BOOLEAN, cv.type);
|
||||
ASSERT_EQ(1, cv.data.v_boolean);
|
||||
|
||||
NT_DisposeValue(&cv);
|
||||
}
|
||||
|
||||
TEST_F(ValueTest, Double) {
|
||||
auto v = Value::MakeDouble(0.5);
|
||||
ASSERT_EQ(NT_DOUBLE, v->type());
|
||||
ASSERT_EQ(0.5, v->GetDouble());
|
||||
NT_Value cv;
|
||||
NT_InitValue(&cv);
|
||||
ConvertToC(*v, &cv);
|
||||
ASSERT_EQ(NT_DOUBLE, cv.type);
|
||||
ASSERT_EQ(0.5, cv.data.v_double);
|
||||
|
||||
v = Value::MakeDouble(0.25);
|
||||
ASSERT_EQ(NT_DOUBLE, v->type());
|
||||
ASSERT_EQ(0.25, v->GetDouble());
|
||||
ConvertToC(*v, &cv);
|
||||
ASSERT_EQ(NT_DOUBLE, cv.type);
|
||||
ASSERT_EQ(0.25, cv.data.v_double);
|
||||
|
||||
NT_DisposeValue(&cv);
|
||||
}
|
||||
|
||||
TEST_F(ValueTest, String) {
|
||||
auto v = Value::MakeString("hello");
|
||||
ASSERT_EQ(NT_STRING, v->type());
|
||||
ASSERT_EQ("hello", v->GetString());
|
||||
NT_Value cv;
|
||||
NT_InitValue(&cv);
|
||||
ConvertToC(*v, &cv);
|
||||
ASSERT_EQ(NT_STRING, cv.type);
|
||||
ASSERT_EQ(llvm::StringRef("hello"), cv.data.v_string.str);
|
||||
ASSERT_EQ(5u, cv.data.v_string.len);
|
||||
|
||||
v = Value::MakeString("goodbye");
|
||||
ASSERT_EQ(NT_STRING, v->type());
|
||||
ASSERT_EQ("goodbye", v->GetString());
|
||||
ConvertToC(*v, &cv);
|
||||
ASSERT_EQ(NT_STRING, cv.type);
|
||||
ASSERT_EQ(llvm::StringRef("goodbye"), cv.data.v_string.str);
|
||||
ASSERT_EQ(7u, cv.data.v_string.len);
|
||||
|
||||
NT_DisposeValue(&cv);
|
||||
}
|
||||
|
||||
TEST_F(ValueTest, Raw) {
|
||||
auto v = Value::MakeRaw("hello");
|
||||
ASSERT_EQ(NT_RAW, v->type());
|
||||
ASSERT_EQ("hello", v->GetRaw());
|
||||
NT_Value cv;
|
||||
NT_InitValue(&cv);
|
||||
ConvertToC(*v, &cv);
|
||||
ASSERT_EQ(NT_RAW, cv.type);
|
||||
ASSERT_EQ(llvm::StringRef("hello"), cv.data.v_string.str);
|
||||
ASSERT_EQ(5u, cv.data.v_string.len);
|
||||
|
||||
v = Value::MakeRaw("goodbye");
|
||||
ASSERT_EQ(NT_RAW, v->type());
|
||||
ASSERT_EQ("goodbye", v->GetRaw());
|
||||
ConvertToC(*v, &cv);
|
||||
ASSERT_EQ(NT_RAW, cv.type);
|
||||
ASSERT_EQ(llvm::StringRef("goodbye"), cv.data.v_string.str);
|
||||
ASSERT_EQ(7u, cv.data.v_string.len);
|
||||
|
||||
NT_DisposeValue(&cv);
|
||||
}
|
||||
|
||||
TEST_F(ValueTest, BooleanArray) {
|
||||
std::vector<int> vec{1,0,1};
|
||||
auto v = Value::MakeBooleanArray(vec);
|
||||
ASSERT_EQ(NT_BOOLEAN_ARRAY, v->type());
|
||||
ASSERT_EQ(llvm::ArrayRef<int>(vec), v->GetBooleanArray());
|
||||
NT_Value cv;
|
||||
NT_InitValue(&cv);
|
||||
ConvertToC(*v, &cv);
|
||||
ASSERT_EQ(NT_BOOLEAN_ARRAY, cv.type);
|
||||
ASSERT_EQ(3u, cv.data.arr_boolean.size);
|
||||
ASSERT_EQ(vec[0], cv.data.arr_boolean.arr[0]);
|
||||
ASSERT_EQ(vec[1], cv.data.arr_boolean.arr[1]);
|
||||
ASSERT_EQ(vec[2], cv.data.arr_boolean.arr[2]);
|
||||
|
||||
// assign with same size
|
||||
vec = {0,1,0};
|
||||
v = Value::MakeBooleanArray(vec);
|
||||
ASSERT_EQ(NT_BOOLEAN_ARRAY, v->type());
|
||||
ASSERT_EQ(llvm::ArrayRef<int>(vec), v->GetBooleanArray());
|
||||
ConvertToC(*v, &cv);
|
||||
ASSERT_EQ(NT_BOOLEAN_ARRAY, cv.type);
|
||||
ASSERT_EQ(3u, cv.data.arr_boolean.size);
|
||||
ASSERT_EQ(vec[0], cv.data.arr_boolean.arr[0]);
|
||||
ASSERT_EQ(vec[1], cv.data.arr_boolean.arr[1]);
|
||||
ASSERT_EQ(vec[2], cv.data.arr_boolean.arr[2]);
|
||||
|
||||
// assign with different size
|
||||
vec = {1,0};
|
||||
v = Value::MakeBooleanArray(vec);
|
||||
ASSERT_EQ(NT_BOOLEAN_ARRAY, v->type());
|
||||
ASSERT_EQ(llvm::ArrayRef<int>(vec), v->GetBooleanArray());
|
||||
ConvertToC(*v, &cv);
|
||||
ASSERT_EQ(NT_BOOLEAN_ARRAY, cv.type);
|
||||
ASSERT_EQ(2u, cv.data.arr_boolean.size);
|
||||
ASSERT_EQ(vec[0], cv.data.arr_boolean.arr[0]);
|
||||
ASSERT_EQ(vec[1], cv.data.arr_boolean.arr[1]);
|
||||
|
||||
NT_DisposeValue(&cv);
|
||||
}
|
||||
|
||||
TEST_F(ValueTest, DoubleArray) {
|
||||
std::vector<double> vec{0.5,0.25,0.5};
|
||||
auto v = Value::MakeDoubleArray(vec);
|
||||
ASSERT_EQ(NT_DOUBLE_ARRAY, v->type());
|
||||
ASSERT_EQ(llvm::ArrayRef<double>(vec), v->GetDoubleArray());
|
||||
NT_Value cv;
|
||||
NT_InitValue(&cv);
|
||||
ConvertToC(*v, &cv);
|
||||
ASSERT_EQ(NT_DOUBLE_ARRAY, cv.type);
|
||||
ASSERT_EQ(3u, cv.data.arr_double.size);
|
||||
ASSERT_EQ(vec[0], cv.data.arr_double.arr[0]);
|
||||
ASSERT_EQ(vec[1], cv.data.arr_double.arr[1]);
|
||||
ASSERT_EQ(vec[2], cv.data.arr_double.arr[2]);
|
||||
|
||||
// assign with same size
|
||||
vec = {0.25,0.5,0.25};
|
||||
v = Value::MakeDoubleArray(vec);
|
||||
ASSERT_EQ(NT_DOUBLE_ARRAY, v->type());
|
||||
ASSERT_EQ(llvm::ArrayRef<double>(vec), v->GetDoubleArray());
|
||||
ConvertToC(*v, &cv);
|
||||
ASSERT_EQ(NT_DOUBLE_ARRAY, cv.type);
|
||||
ASSERT_EQ(3u, cv.data.arr_double.size);
|
||||
ASSERT_EQ(vec[0], cv.data.arr_double.arr[0]);
|
||||
ASSERT_EQ(vec[1], cv.data.arr_double.arr[1]);
|
||||
ASSERT_EQ(vec[2], cv.data.arr_double.arr[2]);
|
||||
|
||||
// assign with different size
|
||||
vec = {0.5,0.25};
|
||||
v = Value::MakeDoubleArray(vec);
|
||||
ASSERT_EQ(NT_DOUBLE_ARRAY, v->type());
|
||||
ASSERT_EQ(llvm::ArrayRef<double>(vec), v->GetDoubleArray());
|
||||
ConvertToC(*v, &cv);
|
||||
ASSERT_EQ(NT_DOUBLE_ARRAY, cv.type);
|
||||
ASSERT_EQ(2u, cv.data.arr_double.size);
|
||||
ASSERT_EQ(vec[0], cv.data.arr_double.arr[0]);
|
||||
ASSERT_EQ(vec[1], cv.data.arr_double.arr[1]);
|
||||
|
||||
NT_DisposeValue(&cv);
|
||||
}
|
||||
|
||||
TEST_F(ValueTest, StringArray) {
|
||||
std::vector<std::string> vec;
|
||||
vec.push_back("hello");
|
||||
vec.push_back("goodbye");
|
||||
vec.push_back("string");
|
||||
auto v = Value::MakeStringArray(std::move(vec));
|
||||
ASSERT_EQ(NT_STRING_ARRAY, v->type());
|
||||
ASSERT_EQ(3u, v->GetStringArray().size());
|
||||
ASSERT_EQ(llvm::StringRef("hello"), v->GetStringArray()[0]);
|
||||
ASSERT_EQ(llvm::StringRef("goodbye"), v->GetStringArray()[1]);
|
||||
ASSERT_EQ(llvm::StringRef("string"), v->GetStringArray()[2]);
|
||||
NT_Value cv;
|
||||
NT_InitValue(&cv);
|
||||
ConvertToC(*v, &cv);
|
||||
ASSERT_EQ(NT_STRING_ARRAY, cv.type);
|
||||
ASSERT_EQ(3u, cv.data.arr_string.size);
|
||||
ASSERT_EQ(llvm::StringRef("hello"), cv.data.arr_string.arr[0].str);
|
||||
ASSERT_EQ(llvm::StringRef("goodbye"), cv.data.arr_string.arr[1].str);
|
||||
ASSERT_EQ(llvm::StringRef("string"), cv.data.arr_string.arr[2].str);
|
||||
|
||||
// assign with same size
|
||||
vec.clear();
|
||||
vec.push_back("s1");
|
||||
vec.push_back("str2");
|
||||
vec.push_back("string3");
|
||||
v = Value::MakeStringArray(vec);
|
||||
ASSERT_EQ(NT_STRING_ARRAY, v->type());
|
||||
ASSERT_EQ(3u, v->GetStringArray().size());
|
||||
ASSERT_EQ(llvm::StringRef("s1"), v->GetStringArray()[0]);
|
||||
ASSERT_EQ(llvm::StringRef("str2"), v->GetStringArray()[1]);
|
||||
ASSERT_EQ(llvm::StringRef("string3"), v->GetStringArray()[2]);
|
||||
ConvertToC(*v, &cv);
|
||||
ASSERT_EQ(NT_STRING_ARRAY, cv.type);
|
||||
ASSERT_EQ(3u, cv.data.arr_string.size);
|
||||
ASSERT_EQ(llvm::StringRef("s1"), cv.data.arr_string.arr[0].str);
|
||||
ASSERT_EQ(llvm::StringRef("str2"), cv.data.arr_string.arr[1].str);
|
||||
ASSERT_EQ(llvm::StringRef("string3"), cv.data.arr_string.arr[2].str);
|
||||
|
||||
// assign with different size
|
||||
vec.clear();
|
||||
vec.push_back("short");
|
||||
vec.push_back("er");
|
||||
v = Value::MakeStringArray(std::move(vec));
|
||||
ASSERT_EQ(NT_STRING_ARRAY, v->type());
|
||||
ASSERT_EQ(2u, v->GetStringArray().size());
|
||||
ASSERT_EQ(llvm::StringRef("short"), v->GetStringArray()[0]);
|
||||
ASSERT_EQ(llvm::StringRef("er"), v->GetStringArray()[1]);
|
||||
ConvertToC(*v, &cv);
|
||||
ASSERT_EQ(NT_STRING_ARRAY, cv.type);
|
||||
ASSERT_EQ(2u, cv.data.arr_string.size);
|
||||
ASSERT_EQ(llvm::StringRef("short"), cv.data.arr_string.arr[0].str);
|
||||
ASSERT_EQ(llvm::StringRef("er"), cv.data.arr_string.arr[1].str);
|
||||
|
||||
NT_DisposeValue(&cv);
|
||||
}
|
||||
|
||||
TEST_F(ValueDeathTest, GetAssertions) {
|
||||
Value v;
|
||||
ASSERT_DEATH(v.GetBoolean(), "type == NT_BOOLEAN");
|
||||
ASSERT_DEATH(v.GetDouble(), "type == NT_DOUBLE");
|
||||
ASSERT_DEATH(v.GetString(), "type == NT_STRING");
|
||||
ASSERT_DEATH(v.GetRaw(), "type == NT_RAW");
|
||||
ASSERT_DEATH(v.GetBooleanArray(), "type == NT_BOOLEAN_ARRAY");
|
||||
ASSERT_DEATH(v.GetDoubleArray(), "type == NT_DOUBLE_ARRAY");
|
||||
ASSERT_DEATH(v.GetStringArray(), "type == NT_STRING_ARRAY");
|
||||
}
|
||||
|
||||
TEST_F(ValueTest, UnassignedComparison) {
|
||||
Value v1, v2;
|
||||
ASSERT_EQ(v1, v2);
|
||||
}
|
||||
|
||||
TEST_F(ValueTest, MixedComparison) {
|
||||
Value v1;
|
||||
auto v2 = Value::MakeBoolean(true);
|
||||
ASSERT_NE(v1, *v2); // unassigned vs boolean
|
||||
auto v3 = Value::MakeDouble(0.5);
|
||||
ASSERT_NE(*v2, *v3); // boolean vs double
|
||||
}
|
||||
|
||||
TEST_F(ValueTest, BooleanComparison) {
|
||||
auto v1 = Value::MakeBoolean(true);
|
||||
auto v2 = Value::MakeBoolean(true);
|
||||
ASSERT_EQ(*v1, *v2);
|
||||
v2 = Value::MakeBoolean(false);
|
||||
ASSERT_NE(*v1, *v2);
|
||||
}
|
||||
|
||||
TEST_F(ValueTest, DoubleComparison) {
|
||||
auto v1 = Value::MakeDouble(0.25);
|
||||
auto v2 = Value::MakeDouble(0.25);
|
||||
ASSERT_EQ(*v1, *v2);
|
||||
v2 = Value::MakeDouble(0.5);
|
||||
ASSERT_NE(*v1, *v2);
|
||||
}
|
||||
|
||||
TEST_F(ValueTest, StringComparison) {
|
||||
auto v1 = Value::MakeString("hello");
|
||||
auto v2 = Value::MakeString("hello");
|
||||
ASSERT_EQ(*v1, *v2);
|
||||
v2 = Value::MakeString("world"); // different contents
|
||||
ASSERT_NE(*v1, *v2);
|
||||
v2 = Value::MakeString("goodbye"); // different size
|
||||
ASSERT_NE(*v1, *v2);
|
||||
}
|
||||
|
||||
TEST_F(ValueTest, BooleanArrayComparison) {
|
||||
std::vector<int> vec{1,0,1};
|
||||
auto v1 = Value::MakeBooleanArray(vec);
|
||||
auto v2 = Value::MakeBooleanArray(vec);
|
||||
ASSERT_EQ(*v1, *v2);
|
||||
|
||||
// different contents
|
||||
vec = {1,1,1};
|
||||
v2 = Value::MakeBooleanArray(vec);
|
||||
ASSERT_NE(*v1, *v2);
|
||||
|
||||
// different size
|
||||
vec = {1,0};
|
||||
v2 = Value::MakeBooleanArray(vec);
|
||||
ASSERT_NE(*v1, *v2);
|
||||
}
|
||||
|
||||
TEST_F(ValueTest, DoubleArrayComparison) {
|
||||
std::vector<double> vec{0.5,0.25,0.5};
|
||||
auto v1 = Value::MakeDoubleArray(vec);
|
||||
auto v2 = Value::MakeDoubleArray(vec);
|
||||
ASSERT_EQ(*v1, *v2);
|
||||
|
||||
// different contents
|
||||
vec = {0.5,0.5,0.5};
|
||||
v2 = Value::MakeDoubleArray(vec);
|
||||
ASSERT_NE(*v1, *v2);
|
||||
|
||||
// different size
|
||||
vec = {0.5,0.25};
|
||||
v2 = Value::MakeDoubleArray(vec);
|
||||
ASSERT_NE(*v1, *v2);
|
||||
}
|
||||
|
||||
TEST_F(ValueTest, StringArrayComparison) {
|
||||
std::vector<std::string> vec;
|
||||
vec.push_back("hello");
|
||||
vec.push_back("goodbye");
|
||||
vec.push_back("string");
|
||||
auto v1 = Value::MakeStringArray(vec);
|
||||
vec.clear();
|
||||
vec.push_back("hello");
|
||||
vec.push_back("goodbye");
|
||||
vec.push_back("string");
|
||||
auto v2 = Value::MakeStringArray(std::move(vec));
|
||||
ASSERT_EQ(*v1, *v2);
|
||||
|
||||
// different contents
|
||||
vec.clear();
|
||||
vec.push_back("hello");
|
||||
vec.push_back("goodby2");
|
||||
vec.push_back("string");
|
||||
v2 = Value::MakeStringArray(std::move(vec));
|
||||
ASSERT_NE(*v1, *v2);
|
||||
|
||||
// different sized contents
|
||||
vec.clear();
|
||||
vec.push_back("hello");
|
||||
vec.push_back("goodbye2");
|
||||
vec.push_back("string");
|
||||
v2 = Value::MakeStringArray(vec);
|
||||
ASSERT_NE(*v1, *v2);
|
||||
|
||||
// different size
|
||||
vec.clear();
|
||||
vec.push_back("hello");
|
||||
vec.push_back("goodbye");
|
||||
v2 = Value::MakeStringArray(std::move(vec));
|
||||
ASSERT_NE(*v1, *v2);
|
||||
}
|
||||
|
||||
} // namespace nt
|
||||
602
src/test/native/cpp/WireDecoderTest.cpp
Normal file
602
src/test/native/cpp/WireDecoderTest.cpp
Normal file
@@ -0,0 +1,602 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2015. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#include "WireDecoder.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include <cfloat>
|
||||
#include <climits>
|
||||
#include <string>
|
||||
|
||||
#include "llvm/StringRef.h"
|
||||
|
||||
namespace nt {
|
||||
|
||||
class WireDecoderTest : public ::testing::Test {
|
||||
protected:
|
||||
WireDecoderTest() {
|
||||
v_boolean = Value::MakeBoolean(true);
|
||||
v_double = Value::MakeDouble(1.0);
|
||||
v_string = Value::MakeString(llvm::StringRef("hello"));
|
||||
v_raw = Value::MakeRaw(llvm::StringRef("hello"));
|
||||
v_boolean_array = Value::MakeBooleanArray(std::vector<int>{0, 1, 0});
|
||||
v_boolean_array_big = Value::MakeBooleanArray(std::vector<int>(255));
|
||||
v_double_array = Value::MakeDoubleArray(std::vector<double>{0.5, 0.25});
|
||||
v_double_array_big = Value::MakeDoubleArray(std::vector<double>(255));
|
||||
|
||||
std::vector<std::string> sa;
|
||||
sa.push_back("hello");
|
||||
sa.push_back("goodbye");
|
||||
v_string_array = Value::MakeStringArray(std::move(sa));
|
||||
|
||||
sa.clear();
|
||||
for (int i=0; i<255; ++i)
|
||||
sa.push_back("h");
|
||||
v_string_array_big = Value::MakeStringArray(std::move(sa));
|
||||
|
||||
s_normal = std::string("hello");
|
||||
|
||||
s_long.clear();
|
||||
s_long.append(127, '*');
|
||||
s_long.push_back('x');
|
||||
|
||||
s_big2.clear();
|
||||
s_big2.append(65534, '*');
|
||||
s_big2.push_back('x');
|
||||
|
||||
s_big3.clear();
|
||||
s_big3.append(65534, '*');
|
||||
s_big3.append(3, 'x');
|
||||
}
|
||||
|
||||
std::shared_ptr<Value> v_boolean, v_double, v_string, v_raw;
|
||||
std::shared_ptr<Value> v_boolean_array, v_boolean_array_big;
|
||||
std::shared_ptr<Value> v_double_array, v_double_array_big;
|
||||
std::shared_ptr<Value> v_string_array, v_string_array_big;
|
||||
|
||||
std::string s_normal, s_long, s_big2, s_big3;
|
||||
};
|
||||
|
||||
TEST_F(WireDecoderTest, Construct) {
|
||||
wpi::raw_mem_istream is("", 0);
|
||||
WireDecoder d(is, 0x0300u);
|
||||
EXPECT_EQ(nullptr, d.error());
|
||||
EXPECT_EQ(0x0300u, d.proto_rev());
|
||||
}
|
||||
|
||||
TEST_F(WireDecoderTest, SetProtoRev) {
|
||||
wpi::raw_mem_istream is("", 0);
|
||||
WireDecoder d(is, 0x0300u);
|
||||
d.set_proto_rev(0x0200u);
|
||||
EXPECT_EQ(0x0200u, d.proto_rev());
|
||||
}
|
||||
|
||||
TEST_F(WireDecoderTest, Read8) {
|
||||
wpi::raw_mem_istream is("\x05\x01\x00", 3);
|
||||
WireDecoder d(is, 0x0300u);
|
||||
unsigned int val;
|
||||
ASSERT_TRUE(d.Read8(&val));
|
||||
EXPECT_EQ(5u, val);
|
||||
ASSERT_TRUE(d.Read8(&val));
|
||||
EXPECT_EQ(1u, val);
|
||||
ASSERT_TRUE(d.Read8(&val));
|
||||
EXPECT_EQ(0u, val);
|
||||
ASSERT_FALSE(d.Read8(&val));
|
||||
ASSERT_EQ(nullptr, d.error());
|
||||
}
|
||||
|
||||
TEST_F(WireDecoderTest, Read16) {
|
||||
wpi::raw_mem_istream is("\x00\x05\x00\x01\x45\x67\x00\x00", 8);
|
||||
WireDecoder d(is, 0x0300u);
|
||||
unsigned int val;
|
||||
ASSERT_TRUE(d.Read16(&val));
|
||||
EXPECT_EQ(5u, val);
|
||||
ASSERT_TRUE(d.Read16(&val));
|
||||
EXPECT_EQ(1u, val);
|
||||
ASSERT_TRUE(d.Read16(&val));
|
||||
EXPECT_EQ(0x4567u, val);
|
||||
ASSERT_TRUE(d.Read16(&val));
|
||||
EXPECT_EQ(0u, val);
|
||||
ASSERT_FALSE(d.Read16(&val));
|
||||
ASSERT_EQ(nullptr, d.error());
|
||||
}
|
||||
|
||||
TEST_F(WireDecoderTest, Read32) {
|
||||
wpi::raw_mem_istream is(
|
||||
"\x00\x00\x00\x05\x00\x00\x00\x01\x00\x00\xab\xcd"
|
||||
"\x12\x34\x56\x78\x00\x00\x00\x00",
|
||||
20);
|
||||
WireDecoder d(is, 0x0300u);
|
||||
unsigned long val;
|
||||
ASSERT_TRUE(d.Read32(&val));
|
||||
EXPECT_EQ(5ul, val);
|
||||
ASSERT_TRUE(d.Read32(&val));
|
||||
EXPECT_EQ(1ul, val);
|
||||
ASSERT_TRUE(d.Read32(&val));
|
||||
EXPECT_EQ(0xabcdul, val);
|
||||
ASSERT_TRUE(d.Read32(&val));
|
||||
EXPECT_EQ(0x12345678ul, val);
|
||||
ASSERT_TRUE(d.Read32(&val));
|
||||
EXPECT_EQ(0ul, val);
|
||||
ASSERT_FALSE(d.Read32(&val));
|
||||
ASSERT_EQ(nullptr, d.error());
|
||||
}
|
||||
|
||||
TEST_F(WireDecoderTest, ReadDouble) {
|
||||
// values except min and max from
|
||||
// http://www.binaryconvert.com/result_double.html
|
||||
wpi::raw_mem_istream is(
|
||||
"\x00\x00\x00\x00\x00\x00\x00\x00"
|
||||
"\x41\x0c\x13\x80\x00\x00\x00\x00"
|
||||
"\x7f\xf0\x00\x00\x00\x00\x00\x00"
|
||||
"\x00\x10\x00\x00\x00\x00\x00\x00"
|
||||
"\x7f\xef\xff\xff\xff\xff\xff\xff",
|
||||
40);
|
||||
WireDecoder d(is, 0x0300u);
|
||||
double val;
|
||||
ASSERT_TRUE(d.ReadDouble(&val));
|
||||
EXPECT_EQ(0.0, val);
|
||||
ASSERT_TRUE(d.ReadDouble(&val));
|
||||
EXPECT_EQ(2.3e5, val);
|
||||
ASSERT_TRUE(d.ReadDouble(&val));
|
||||
EXPECT_EQ(std::numeric_limits<double>::infinity(), val);
|
||||
ASSERT_TRUE(d.ReadDouble(&val));
|
||||
EXPECT_EQ(DBL_MIN, val);
|
||||
ASSERT_TRUE(d.ReadDouble(&val));
|
||||
EXPECT_EQ(DBL_MAX, val);
|
||||
ASSERT_FALSE(d.ReadDouble(&val));
|
||||
ASSERT_EQ(nullptr, d.error());
|
||||
}
|
||||
|
||||
TEST_F(WireDecoderTest, ReadUleb128) {
|
||||
wpi::raw_mem_istream is("\x00\x7f\x80\x01\x80", 5);
|
||||
WireDecoder d(is, 0x0300u);
|
||||
unsigned long val;
|
||||
ASSERT_TRUE(d.ReadUleb128(&val));
|
||||
EXPECT_EQ(0ul, val);
|
||||
ASSERT_TRUE(d.ReadUleb128(&val));
|
||||
EXPECT_EQ(0x7ful, val);
|
||||
ASSERT_TRUE(d.ReadUleb128(&val));
|
||||
EXPECT_EQ(0x80ul, val);
|
||||
ASSERT_FALSE(d.ReadUleb128(&val)); // partial
|
||||
ASSERT_EQ(nullptr, d.error());
|
||||
}
|
||||
|
||||
TEST_F(WireDecoderTest, ReadType) {
|
||||
wpi::raw_mem_istream is("\x00\x01\x02\x03\x10\x11\x12\x20", 8);
|
||||
WireDecoder d(is, 0x0300u);
|
||||
NT_Type val;
|
||||
ASSERT_TRUE(d.ReadType(&val));
|
||||
EXPECT_EQ(NT_BOOLEAN, val);
|
||||
ASSERT_TRUE(d.ReadType(&val));
|
||||
EXPECT_EQ(NT_DOUBLE, val);
|
||||
ASSERT_TRUE(d.ReadType(&val));
|
||||
EXPECT_EQ(NT_STRING, val);
|
||||
ASSERT_TRUE(d.ReadType(&val));
|
||||
EXPECT_EQ(NT_RAW, val);
|
||||
ASSERT_TRUE(d.ReadType(&val));
|
||||
EXPECT_EQ(NT_BOOLEAN_ARRAY, val);
|
||||
ASSERT_TRUE(d.ReadType(&val));
|
||||
EXPECT_EQ(NT_DOUBLE_ARRAY, val);
|
||||
ASSERT_TRUE(d.ReadType(&val));
|
||||
EXPECT_EQ(NT_STRING_ARRAY, val);
|
||||
ASSERT_TRUE(d.ReadType(&val));
|
||||
EXPECT_EQ(NT_RPC, val);
|
||||
ASSERT_FALSE(d.ReadType(&val));
|
||||
ASSERT_EQ(nullptr, d.error());
|
||||
}
|
||||
|
||||
TEST_F(WireDecoderTest, ReadTypeError) {
|
||||
wpi::raw_mem_istream is("\x30", 1);
|
||||
WireDecoder d(is, 0x0200u);
|
||||
NT_Type val;
|
||||
ASSERT_FALSE(d.ReadType(&val));
|
||||
EXPECT_EQ(NT_UNASSIGNED, val);
|
||||
ASSERT_NE(nullptr, d.error());
|
||||
}
|
||||
|
||||
TEST_F(WireDecoderTest, Reset) {
|
||||
wpi::raw_mem_istream is("\x30", 1);
|
||||
WireDecoder d(is, 0x0200u);
|
||||
NT_Type val;
|
||||
ASSERT_FALSE(d.ReadType(&val));
|
||||
EXPECT_EQ(NT_UNASSIGNED, val);
|
||||
ASSERT_NE(nullptr, d.error());
|
||||
d.Reset();
|
||||
EXPECT_EQ(nullptr, d.error());
|
||||
}
|
||||
|
||||
TEST_F(WireDecoderTest, ReadBooleanValue2) {
|
||||
wpi::raw_mem_istream is("\x01\x00", 2);
|
||||
WireDecoder d(is, 0x0200u);
|
||||
auto val = d.ReadValue(NT_BOOLEAN);
|
||||
ASSERT_TRUE(bool(val));
|
||||
EXPECT_EQ(*v_boolean, *val);
|
||||
|
||||
auto v_false = Value::MakeBoolean(false);
|
||||
val = d.ReadValue(NT_BOOLEAN);
|
||||
ASSERT_TRUE(bool(val));
|
||||
EXPECT_EQ(*v_false, *val);
|
||||
|
||||
ASSERT_FALSE(d.ReadValue(NT_BOOLEAN));
|
||||
ASSERT_EQ(nullptr, d.error());
|
||||
}
|
||||
|
||||
TEST_F(WireDecoderTest, ReadDoubleValue2) {
|
||||
wpi::raw_mem_istream is(
|
||||
"\x3f\xf0\x00\x00\x00\x00\x00\x00"
|
||||
"\x3f\xf0\x00\x00\x00\x00\x00\x00",
|
||||
16);
|
||||
WireDecoder d(is, 0x0200u);
|
||||
auto val = d.ReadValue(NT_DOUBLE);
|
||||
ASSERT_TRUE(bool(val));
|
||||
EXPECT_EQ(*v_double, *val);
|
||||
|
||||
val = d.ReadValue(NT_DOUBLE);
|
||||
ASSERT_TRUE(bool(val));
|
||||
EXPECT_EQ(*v_double, *val);
|
||||
|
||||
ASSERT_FALSE(d.ReadValue(NT_DOUBLE));
|
||||
ASSERT_EQ(nullptr, d.error());
|
||||
}
|
||||
|
||||
TEST_F(WireDecoderTest, ReadStringValue2) {
|
||||
wpi::raw_mem_istream is("\x00\x05hello\x00\x03" "bye\x55", 13);
|
||||
WireDecoder d(is, 0x0200u);
|
||||
auto val = d.ReadValue(NT_STRING);
|
||||
ASSERT_TRUE(bool(val));
|
||||
EXPECT_EQ(*v_string, *val);
|
||||
|
||||
auto v_bye = Value::MakeString(llvm::StringRef("bye"));
|
||||
val = d.ReadValue(NT_STRING);
|
||||
ASSERT_TRUE(bool(val));
|
||||
EXPECT_EQ(*v_bye, *val);
|
||||
|
||||
unsigned int b;
|
||||
ASSERT_TRUE(d.Read8(&b));
|
||||
EXPECT_EQ(0x55u, b);
|
||||
|
||||
ASSERT_FALSE(d.ReadValue(NT_STRING));
|
||||
ASSERT_EQ(nullptr, d.error());
|
||||
}
|
||||
|
||||
TEST_F(WireDecoderTest, ReadBooleanArrayValue2) {
|
||||
wpi::raw_mem_istream is("\x03\x00\x01\x00\x02\x01\x00\xff", 8);
|
||||
WireDecoder d(is, 0x0200u);
|
||||
auto val = d.ReadValue(NT_BOOLEAN_ARRAY);
|
||||
ASSERT_TRUE(bool(val));
|
||||
EXPECT_EQ(*v_boolean_array, *val);
|
||||
|
||||
auto v_boolean_array2 = Value::MakeBooleanArray(std::vector<int>{1, 0});
|
||||
val = d.ReadValue(NT_BOOLEAN_ARRAY);
|
||||
ASSERT_TRUE(bool(val));
|
||||
EXPECT_EQ(*v_boolean_array2, *val);
|
||||
|
||||
ASSERT_FALSE(d.ReadValue(NT_BOOLEAN_ARRAY));
|
||||
ASSERT_EQ(nullptr, d.error());
|
||||
}
|
||||
|
||||
TEST_F(WireDecoderTest, ReadBooleanArrayBigValue2) {
|
||||
std::string s;
|
||||
s.push_back('\xff');
|
||||
s.append(255, '\x00');
|
||||
wpi::raw_mem_istream is(s.data(), s.size());
|
||||
WireDecoder d(is, 0x0200u);
|
||||
auto val = d.ReadValue(NT_BOOLEAN_ARRAY);
|
||||
ASSERT_TRUE(bool(val));
|
||||
EXPECT_EQ(*v_boolean_array_big, *val);
|
||||
|
||||
ASSERT_FALSE(d.ReadValue(NT_BOOLEAN_ARRAY));
|
||||
ASSERT_EQ(nullptr, d.error());
|
||||
}
|
||||
|
||||
TEST_F(WireDecoderTest, ReadDoubleArrayValue2) {
|
||||
wpi::raw_mem_istream is(
|
||||
"\x02\x3f\xe0\x00\x00\x00\x00\x00\x00"
|
||||
"\x3f\xd0\x00\x00\x00\x00\x00\x00\x55",
|
||||
18);
|
||||
WireDecoder d(is, 0x0200u);
|
||||
auto val = d.ReadValue(NT_DOUBLE_ARRAY);
|
||||
ASSERT_TRUE(bool(val));
|
||||
EXPECT_EQ(*v_double_array, *val);
|
||||
|
||||
unsigned int b;
|
||||
ASSERT_TRUE(d.Read8(&b));
|
||||
EXPECT_EQ(0x55u, b);
|
||||
|
||||
ASSERT_FALSE(d.ReadValue(NT_DOUBLE_ARRAY));
|
||||
ASSERT_EQ(nullptr, d.error());
|
||||
}
|
||||
|
||||
TEST_F(WireDecoderTest, ReadDoubleArrayBigValue2) {
|
||||
std::string s;
|
||||
s.push_back('\xff');
|
||||
s.append(255*8, '\x00');
|
||||
wpi::raw_mem_istream is(s.data(), s.size());
|
||||
WireDecoder d(is, 0x0200u);
|
||||
auto val = d.ReadValue(NT_DOUBLE_ARRAY);
|
||||
ASSERT_TRUE(bool(val));
|
||||
EXPECT_EQ(*v_double_array_big, *val);
|
||||
|
||||
ASSERT_FALSE(d.ReadValue(NT_DOUBLE_ARRAY));
|
||||
ASSERT_EQ(nullptr, d.error());
|
||||
}
|
||||
|
||||
TEST_F(WireDecoderTest, ReadStringArrayValue2) {
|
||||
wpi::raw_mem_istream is("\x02\x00\x05hello\x00\x07goodbye\x55", 18);
|
||||
WireDecoder d(is, 0x0200u);
|
||||
auto val = d.ReadValue(NT_STRING_ARRAY);
|
||||
ASSERT_TRUE(bool(val));
|
||||
EXPECT_EQ(*v_string_array, *val);
|
||||
|
||||
unsigned int b;
|
||||
ASSERT_TRUE(d.Read8(&b));
|
||||
EXPECT_EQ(0x55u, b);
|
||||
|
||||
ASSERT_FALSE(d.ReadValue(NT_STRING_ARRAY));
|
||||
ASSERT_EQ(nullptr, d.error());
|
||||
}
|
||||
|
||||
TEST_F(WireDecoderTest, ReadStringArrayBigValue2) {
|
||||
std::string s;
|
||||
s.push_back('\xff');
|
||||
for (int i=0; i<255; ++i)
|
||||
s.append("\x00\x01h", 3);
|
||||
wpi::raw_mem_istream is(s.data(), s.size());
|
||||
WireDecoder d(is, 0x0200u);
|
||||
auto val = d.ReadValue(NT_STRING_ARRAY);
|
||||
ASSERT_TRUE(bool(val));
|
||||
EXPECT_EQ(*v_string_array_big, *val);
|
||||
|
||||
ASSERT_FALSE(d.ReadValue(NT_STRING_ARRAY));
|
||||
ASSERT_EQ(nullptr, d.error());
|
||||
}
|
||||
|
||||
TEST_F(WireDecoderTest, ReadValueError2) {
|
||||
wpi::raw_mem_istream is("", 0);
|
||||
WireDecoder d(is, 0x0200u);
|
||||
ASSERT_FALSE(d.ReadValue(NT_UNASSIGNED)); // unassigned
|
||||
ASSERT_NE(nullptr, d.error());
|
||||
|
||||
d.Reset();
|
||||
ASSERT_FALSE(d.ReadValue(NT_RAW)); // not supported
|
||||
ASSERT_NE(nullptr, d.error());
|
||||
|
||||
d.Reset();
|
||||
ASSERT_FALSE(d.ReadValue(NT_RPC)); // not supported
|
||||
ASSERT_NE(nullptr, d.error());
|
||||
}
|
||||
|
||||
TEST_F(WireDecoderTest, ReadBooleanValue3) {
|
||||
wpi::raw_mem_istream is("\x01\x00", 2);
|
||||
WireDecoder d(is, 0x0300u);
|
||||
auto val = d.ReadValue(NT_BOOLEAN);
|
||||
ASSERT_TRUE(bool(val));
|
||||
EXPECT_EQ(*v_boolean, *val);
|
||||
|
||||
auto v_false = Value::MakeBoolean(false);
|
||||
val = d.ReadValue(NT_BOOLEAN);
|
||||
ASSERT_TRUE(bool(val));
|
||||
EXPECT_EQ(*v_false, *val);
|
||||
|
||||
ASSERT_FALSE(d.ReadValue(NT_BOOLEAN));
|
||||
ASSERT_EQ(nullptr, d.error());
|
||||
}
|
||||
|
||||
TEST_F(WireDecoderTest, ReadDoubleValue3) {
|
||||
wpi::raw_mem_istream is(
|
||||
"\x3f\xf0\x00\x00\x00\x00\x00\x00"
|
||||
"\x3f\xf0\x00\x00\x00\x00\x00\x00",
|
||||
16);
|
||||
WireDecoder d(is, 0x0300u);
|
||||
auto val = d.ReadValue(NT_DOUBLE);
|
||||
ASSERT_TRUE(bool(val));
|
||||
EXPECT_EQ(*v_double, *val);
|
||||
|
||||
val = d.ReadValue(NT_DOUBLE);
|
||||
ASSERT_TRUE(bool(val));
|
||||
EXPECT_EQ(*v_double, *val);
|
||||
|
||||
ASSERT_FALSE(d.ReadValue(NT_DOUBLE));
|
||||
ASSERT_EQ(nullptr, d.error());
|
||||
}
|
||||
|
||||
TEST_F(WireDecoderTest, ReadStringValue3) {
|
||||
wpi::raw_mem_istream is("\x05hello\x03" "bye\x55", 11);
|
||||
WireDecoder d(is, 0x0300u);
|
||||
auto val = d.ReadValue(NT_STRING);
|
||||
ASSERT_TRUE(bool(val));
|
||||
EXPECT_EQ(*v_string, *val);
|
||||
|
||||
auto v_bye = Value::MakeString(llvm::StringRef("bye"));
|
||||
val = d.ReadValue(NT_STRING);
|
||||
ASSERT_TRUE(bool(val));
|
||||
EXPECT_EQ(*v_bye, *val);
|
||||
|
||||
unsigned int b;
|
||||
ASSERT_TRUE(d.Read8(&b));
|
||||
EXPECT_EQ(0x55u, b);
|
||||
|
||||
ASSERT_FALSE(d.ReadValue(NT_STRING));
|
||||
ASSERT_EQ(nullptr, d.error());
|
||||
}
|
||||
|
||||
TEST_F(WireDecoderTest, ReadRawValue3) {
|
||||
wpi::raw_mem_istream is("\x05hello\x03" "bye\x55", 11);
|
||||
WireDecoder d(is, 0x0300u);
|
||||
auto val = d.ReadValue(NT_RAW);
|
||||
ASSERT_TRUE(bool(val));
|
||||
EXPECT_EQ(*v_raw, *val);
|
||||
|
||||
auto v_bye = Value::MakeRaw(llvm::StringRef("bye"));
|
||||
val = d.ReadValue(NT_RAW);
|
||||
ASSERT_TRUE(bool(val));
|
||||
EXPECT_EQ(*v_bye, *val);
|
||||
|
||||
unsigned int b;
|
||||
ASSERT_TRUE(d.Read8(&b));
|
||||
EXPECT_EQ(0x55u, b);
|
||||
|
||||
ASSERT_FALSE(d.ReadValue(NT_RAW));
|
||||
ASSERT_EQ(nullptr, d.error());
|
||||
}
|
||||
|
||||
TEST_F(WireDecoderTest, ReadBooleanArrayValue3) {
|
||||
wpi::raw_mem_istream is("\x03\x00\x01\x00\x02\x01\x00\xff", 8);
|
||||
WireDecoder d(is, 0x0300u);
|
||||
auto val = d.ReadValue(NT_BOOLEAN_ARRAY);
|
||||
ASSERT_TRUE(bool(val));
|
||||
EXPECT_EQ(*v_boolean_array, *val);
|
||||
|
||||
auto v_boolean_array2 = Value::MakeBooleanArray(std::vector<int>{1, 0});
|
||||
val = d.ReadValue(NT_BOOLEAN_ARRAY);
|
||||
ASSERT_TRUE(bool(val));
|
||||
EXPECT_EQ(*v_boolean_array2, *val);
|
||||
|
||||
ASSERT_FALSE(d.ReadValue(NT_BOOLEAN_ARRAY));
|
||||
ASSERT_EQ(nullptr, d.error());
|
||||
}
|
||||
|
||||
TEST_F(WireDecoderTest, ReadBooleanArrayBigValue3) {
|
||||
std::string s;
|
||||
s.push_back('\xff');
|
||||
s.append(255, '\x00');
|
||||
wpi::raw_mem_istream is(s.data(), s.size());
|
||||
WireDecoder d(is, 0x0300u);
|
||||
auto val = d.ReadValue(NT_BOOLEAN_ARRAY);
|
||||
ASSERT_TRUE(bool(val));
|
||||
EXPECT_EQ(*v_boolean_array_big, *val);
|
||||
|
||||
ASSERT_FALSE(d.ReadValue(NT_BOOLEAN_ARRAY));
|
||||
ASSERT_EQ(nullptr, d.error());
|
||||
}
|
||||
|
||||
TEST_F(WireDecoderTest, ReadDoubleArrayValue3) {
|
||||
wpi::raw_mem_istream is(
|
||||
"\x02\x3f\xe0\x00\x00\x00\x00\x00\x00"
|
||||
"\x3f\xd0\x00\x00\x00\x00\x00\x00\x55",
|
||||
18);
|
||||
WireDecoder d(is, 0x0300u);
|
||||
auto val = d.ReadValue(NT_DOUBLE_ARRAY);
|
||||
ASSERT_TRUE(bool(val));
|
||||
EXPECT_EQ(*v_double_array, *val);
|
||||
|
||||
unsigned int b;
|
||||
ASSERT_TRUE(d.Read8(&b));
|
||||
EXPECT_EQ(0x55u, b);
|
||||
|
||||
ASSERT_FALSE(d.ReadValue(NT_DOUBLE_ARRAY));
|
||||
ASSERT_EQ(nullptr, d.error());
|
||||
}
|
||||
|
||||
TEST_F(WireDecoderTest, ReadDoubleArrayBigValue3) {
|
||||
std::string s;
|
||||
s.push_back('\xff');
|
||||
s.append(255*8, '\x00');
|
||||
wpi::raw_mem_istream is(s.data(), s.size());
|
||||
WireDecoder d(is, 0x0300u);
|
||||
auto val = d.ReadValue(NT_DOUBLE_ARRAY);
|
||||
ASSERT_TRUE(bool(val));
|
||||
EXPECT_EQ(*v_double_array_big, *val);
|
||||
|
||||
ASSERT_FALSE(d.ReadValue(NT_DOUBLE_ARRAY));
|
||||
ASSERT_EQ(nullptr, d.error());
|
||||
}
|
||||
|
||||
TEST_F(WireDecoderTest, ReadStringArrayValue3) {
|
||||
wpi::raw_mem_istream is("\x02\x05hello\x07goodbye\x55", 16);
|
||||
WireDecoder d(is, 0x0300u);
|
||||
auto val = d.ReadValue(NT_STRING_ARRAY);
|
||||
ASSERT_TRUE(bool(val));
|
||||
EXPECT_EQ(*v_string_array, *val);
|
||||
|
||||
unsigned int b;
|
||||
ASSERT_TRUE(d.Read8(&b));
|
||||
EXPECT_EQ(0x55u, b);
|
||||
|
||||
ASSERT_FALSE(d.ReadValue(NT_STRING_ARRAY));
|
||||
ASSERT_EQ(nullptr, d.error());
|
||||
}
|
||||
|
||||
TEST_F(WireDecoderTest, ReadStringArrayBigValue3) {
|
||||
std::string s;
|
||||
s.push_back('\xff');
|
||||
for (int i=0; i<255; ++i)
|
||||
s.append("\x01h", 2);
|
||||
wpi::raw_mem_istream is(s.data(), s.size());
|
||||
WireDecoder d(is, 0x0300u);
|
||||
auto val = d.ReadValue(NT_STRING_ARRAY);
|
||||
ASSERT_TRUE(bool(val));
|
||||
EXPECT_EQ(*v_string_array_big, *val);
|
||||
|
||||
ASSERT_FALSE(d.ReadValue(NT_STRING_ARRAY));
|
||||
ASSERT_EQ(nullptr, d.error());
|
||||
}
|
||||
|
||||
TEST_F(WireDecoderTest, ReadValueError3) {
|
||||
wpi::raw_mem_istream is("", 0);
|
||||
WireDecoder d(is, 0x0200u);
|
||||
ASSERT_FALSE(d.ReadValue(NT_UNASSIGNED)); // unassigned
|
||||
ASSERT_NE(nullptr, d.error());
|
||||
}
|
||||
|
||||
TEST_F(WireDecoderTest, ReadString2) {
|
||||
std::string s;
|
||||
s.append("\x00\x05", 2);
|
||||
s += s_normal;
|
||||
s.append("\x00\x80", 2);
|
||||
s += s_long;
|
||||
s.append("\xff\xff", 2);
|
||||
s += s_big2;
|
||||
s.push_back('\x55');
|
||||
wpi::raw_mem_istream is(s.data(), s.size());
|
||||
WireDecoder d(is, 0x0200u);
|
||||
std::string outs;
|
||||
ASSERT_TRUE(d.ReadString(&outs));
|
||||
EXPECT_EQ(s_normal, outs);
|
||||
ASSERT_TRUE(d.ReadString(&outs));
|
||||
EXPECT_EQ(s_long, outs);
|
||||
ASSERT_TRUE(d.ReadString(&outs));
|
||||
EXPECT_EQ(s_big2, outs);
|
||||
|
||||
unsigned int b;
|
||||
ASSERT_TRUE(d.Read8(&b));
|
||||
EXPECT_EQ(0x55u, b);
|
||||
|
||||
ASSERT_FALSE(d.ReadString(&outs));
|
||||
ASSERT_EQ(nullptr, d.error());
|
||||
}
|
||||
|
||||
TEST_F(WireDecoderTest, ReadString3) {
|
||||
std::string s;
|
||||
s.push_back('\x05');
|
||||
s += s_normal;
|
||||
s.append("\x80\x01", 2);
|
||||
s += s_long;
|
||||
s.append("\x81\x80\x04", 3);
|
||||
s += s_big3;
|
||||
s.push_back('\x55');
|
||||
wpi::raw_mem_istream is(s.data(), s.size());
|
||||
WireDecoder d(is, 0x0300u);
|
||||
std::string outs;
|
||||
ASSERT_TRUE(d.ReadString(&outs));
|
||||
EXPECT_EQ(s_normal, outs);
|
||||
ASSERT_TRUE(d.ReadString(&outs));
|
||||
EXPECT_EQ(s_long, outs);
|
||||
ASSERT_TRUE(d.ReadString(&outs));
|
||||
EXPECT_EQ(s_big3, outs);
|
||||
|
||||
unsigned int b;
|
||||
ASSERT_TRUE(d.Read8(&b));
|
||||
EXPECT_EQ(0x55u, b);
|
||||
|
||||
ASSERT_FALSE(d.ReadString(&outs));
|
||||
ASSERT_EQ(nullptr, d.error());
|
||||
}
|
||||
|
||||
} // namespace nt
|
||||
499
src/test/native/cpp/WireEncoderTest.cpp
Normal file
499
src/test/native/cpp/WireEncoderTest.cpp
Normal file
@@ -0,0 +1,499 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2015. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#include "WireEncoder.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include <cfloat>
|
||||
#include <climits>
|
||||
#include <string>
|
||||
|
||||
#include "llvm/StringRef.h"
|
||||
|
||||
#define BUFSIZE 1024
|
||||
|
||||
namespace nt {
|
||||
|
||||
class WireEncoderTest : public ::testing::Test {
|
||||
protected:
|
||||
WireEncoderTest() {
|
||||
v_empty = std::make_shared<Value>();
|
||||
v_boolean = Value::MakeBoolean(true);
|
||||
v_double = Value::MakeDouble(1.0);
|
||||
v_string = Value::MakeString(llvm::StringRef("hello"));
|
||||
v_raw = Value::MakeRaw(llvm::StringRef("hello"));
|
||||
v_boolean_array = Value::MakeBooleanArray(std::vector<int>{0, 1, 0});
|
||||
v_boolean_array_big = Value::MakeBooleanArray(std::vector<int>(256));
|
||||
v_double_array = Value::MakeDoubleArray(std::vector<double>{0.5, 0.25});
|
||||
v_double_array_big = Value::MakeDoubleArray(std::vector<double>(256));
|
||||
|
||||
std::vector<std::string> sa;
|
||||
sa.push_back("hello");
|
||||
sa.push_back("goodbye");
|
||||
v_string_array = Value::MakeStringArray(std::move(sa));
|
||||
|
||||
sa.clear();
|
||||
for (int i=0; i<256; ++i)
|
||||
sa.push_back("h");
|
||||
v_string_array_big = Value::MakeStringArray(std::move(sa));
|
||||
|
||||
s_normal = "hello";
|
||||
|
||||
s_long.clear();
|
||||
s_long.append(127, '*');
|
||||
s_long.push_back('x');
|
||||
|
||||
s_big.clear();
|
||||
s_big.append(65534, '*');
|
||||
s_big.append(3, 'x');
|
||||
}
|
||||
|
||||
std::shared_ptr<Value> v_empty;
|
||||
std::shared_ptr<Value> v_boolean, v_double, v_string, v_raw;
|
||||
std::shared_ptr<Value> v_boolean_array, v_boolean_array_big;
|
||||
std::shared_ptr<Value> v_double_array, v_double_array_big;
|
||||
std::shared_ptr<Value> v_string_array, v_string_array_big;
|
||||
|
||||
std::string s_normal, s_long, s_big;
|
||||
};
|
||||
|
||||
TEST_F(WireEncoderTest, Construct) {
|
||||
WireEncoder e(0x0300u);
|
||||
EXPECT_EQ(0u, e.size());
|
||||
EXPECT_EQ(nullptr, e.error());
|
||||
EXPECT_EQ(0x0300u, e.proto_rev());
|
||||
}
|
||||
|
||||
TEST_F(WireEncoderTest, SetProtoRev) {
|
||||
WireEncoder e(0x0300u);
|
||||
e.set_proto_rev(0x0200u);
|
||||
EXPECT_EQ(0x0200u, e.proto_rev());
|
||||
}
|
||||
|
||||
TEST_F(WireEncoderTest, Write8) {
|
||||
std::size_t off = BUFSIZE-1;
|
||||
WireEncoder e(0x0300u);
|
||||
for(std::size_t i=0; i<off; ++i) e.Write8(0u); // test across Reserve()
|
||||
e.Write8(5u);
|
||||
e.Write8(0x101u); // should be truncated
|
||||
e.Write8(0u);
|
||||
ASSERT_EQ(3u, e.size()-off);
|
||||
ASSERT_EQ(llvm::StringRef("\x05\x01\x00", 3),
|
||||
llvm::StringRef(e.data(), e.size()).substr(off));
|
||||
}
|
||||
|
||||
TEST_F(WireEncoderTest, Write16) {
|
||||
std::size_t off = BUFSIZE-2;
|
||||
WireEncoder e(0x0300u);
|
||||
for(std::size_t i=0; i<off; ++i) e.Write8(0u); // test across Reserve()
|
||||
e.Write16(5u);
|
||||
e.Write16(0x10001u); // should be truncated
|
||||
e.Write16(0x4567u);
|
||||
e.Write16(0u);
|
||||
ASSERT_EQ(8u, e.size()-off);
|
||||
ASSERT_EQ(llvm::StringRef("\x00\x05\x00\x01\x45\x67\x00\x00", 8),
|
||||
llvm::StringRef(e.data(), e.size()).substr(off));
|
||||
}
|
||||
|
||||
TEST_F(WireEncoderTest, Write32) {
|
||||
std::size_t off = BUFSIZE-4;
|
||||
WireEncoder e(0x0300u);
|
||||
for(std::size_t i=0; i<off; ++i) e.Write8(0u); // test across Reserve()
|
||||
e.Write32(5ul);
|
||||
e.Write32(1ul);
|
||||
e.Write32(0xabcdul);
|
||||
e.Write32(0x12345678ul);
|
||||
e.Write32(0ul);
|
||||
ASSERT_EQ(20u, e.size()-off);
|
||||
ASSERT_EQ(llvm::StringRef(
|
||||
"\x00\x00\x00\x05\x00\x00\x00\x01\x00\x00\xab\xcd"
|
||||
"\x12\x34\x56\x78\x00\x00\x00\x00",
|
||||
20),
|
||||
llvm::StringRef(e.data(), e.size()).substr(off));
|
||||
}
|
||||
|
||||
TEST_F(WireEncoderTest, WriteDouble) {
|
||||
std::size_t off = BUFSIZE-8;
|
||||
WireEncoder e(0x0300u);
|
||||
for(std::size_t i=0; i<off; ++i) e.Write8(0u); // test across Reserve()
|
||||
e.WriteDouble(0.0);
|
||||
e.WriteDouble(2.3e5);
|
||||
e.WriteDouble(std::numeric_limits<double>::infinity());
|
||||
e.WriteDouble(DBL_MIN);
|
||||
e.WriteDouble(DBL_MAX);
|
||||
ASSERT_EQ(40u, e.size()-off);
|
||||
// golden values except min and max from
|
||||
// http://www.binaryconvert.com/result_double.html
|
||||
ASSERT_EQ(llvm::StringRef(
|
||||
"\x00\x00\x00\x00\x00\x00\x00\x00"
|
||||
"\x41\x0c\x13\x80\x00\x00\x00\x00"
|
||||
"\x7f\xf0\x00\x00\x00\x00\x00\x00"
|
||||
"\x00\x10\x00\x00\x00\x00\x00\x00"
|
||||
"\x7f\xef\xff\xff\xff\xff\xff\xff",
|
||||
40),
|
||||
llvm::StringRef(e.data(), e.size()).substr(off));
|
||||
}
|
||||
|
||||
TEST_F(WireEncoderTest, WriteUleb128) {
|
||||
std::size_t off = BUFSIZE-2;
|
||||
WireEncoder e(0x0300u);
|
||||
for(std::size_t i=0; i<off; ++i) e.Write8(0u); // test across Reserve()
|
||||
e.WriteUleb128(0ul);
|
||||
e.WriteUleb128(0x7ful);
|
||||
e.WriteUleb128(0x80ul);
|
||||
ASSERT_EQ(4u, e.size()-off);
|
||||
ASSERT_EQ(llvm::StringRef("\x00\x7f\x80\x01", 4),
|
||||
llvm::StringRef(e.data(), e.size()).substr(off));
|
||||
}
|
||||
|
||||
TEST_F(WireEncoderTest, WriteType) {
|
||||
std::size_t off = BUFSIZE-1;
|
||||
WireEncoder e(0x0300u);
|
||||
for(std::size_t i=0; i<off; ++i) e.Write8(0u); // test across Reserve()
|
||||
e.WriteType(NT_BOOLEAN);
|
||||
e.WriteType(NT_DOUBLE);
|
||||
e.WriteType(NT_STRING);
|
||||
e.WriteType(NT_RAW);
|
||||
e.WriteType(NT_BOOLEAN_ARRAY);
|
||||
e.WriteType(NT_DOUBLE_ARRAY);
|
||||
e.WriteType(NT_STRING_ARRAY);
|
||||
e.WriteType(NT_RPC);
|
||||
ASSERT_EQ(nullptr, e.error());
|
||||
ASSERT_EQ(8u, e.size()-off);
|
||||
ASSERT_EQ(llvm::StringRef("\x00\x01\x02\x03\x10\x11\x12\x20", 8),
|
||||
llvm::StringRef(e.data(), e.size()).substr(off));
|
||||
}
|
||||
|
||||
TEST_F(WireEncoderTest, WriteTypeError) {
|
||||
WireEncoder e(0x0200u);
|
||||
e.WriteType(NT_UNASSIGNED);
|
||||
EXPECT_EQ(0u, e.size());
|
||||
EXPECT_EQ(std::string("unrecognized type"), e.error());
|
||||
|
||||
e.Reset();
|
||||
e.WriteType(NT_RAW);
|
||||
EXPECT_EQ(0u, e.size());
|
||||
EXPECT_EQ(std::string("raw type not supported in protocol < 3.0"), e.error());
|
||||
|
||||
e.Reset();
|
||||
e.WriteType(NT_RPC);
|
||||
EXPECT_EQ(0u, e.size());
|
||||
EXPECT_EQ(std::string("RPC type not supported in protocol < 3.0"), e.error());
|
||||
}
|
||||
|
||||
TEST_F(WireEncoderTest, Reset) {
|
||||
WireEncoder e(0x0300u);
|
||||
e.WriteType(NT_UNASSIGNED);
|
||||
EXPECT_NE(nullptr, e.error());
|
||||
e.Reset();
|
||||
EXPECT_EQ(nullptr, e.error());
|
||||
|
||||
e.Write8(0u);
|
||||
EXPECT_EQ(1u, e.size());
|
||||
e.Reset();
|
||||
EXPECT_EQ(0u, e.size());
|
||||
}
|
||||
|
||||
TEST_F(WireEncoderTest, GetValueSize2) {
|
||||
WireEncoder e(0x0200u);
|
||||
EXPECT_EQ(0u, e.GetValueSize(*v_empty)); // empty
|
||||
EXPECT_EQ(1u, e.GetValueSize(*v_boolean));
|
||||
EXPECT_EQ(8u, e.GetValueSize(*v_double));
|
||||
EXPECT_EQ(7u, e.GetValueSize(*v_string));
|
||||
EXPECT_EQ(0u, e.GetValueSize(*v_raw)); // not supported
|
||||
|
||||
EXPECT_EQ(1u+3u, e.GetValueSize(*v_boolean_array));
|
||||
// truncated
|
||||
EXPECT_EQ(1u+255u, e.GetValueSize(*v_boolean_array_big));
|
||||
|
||||
EXPECT_EQ(1u+2u*8u, e.GetValueSize(*v_double_array));
|
||||
// truncated
|
||||
EXPECT_EQ(1u+255u*8u, e.GetValueSize(*v_double_array_big));
|
||||
|
||||
EXPECT_EQ(1u+7u+9u, e.GetValueSize(*v_string_array));
|
||||
// truncated
|
||||
EXPECT_EQ(1u+255u*3u, e.GetValueSize(*v_string_array_big));
|
||||
}
|
||||
|
||||
TEST_F(WireEncoderTest, WriteBooleanValue2) {
|
||||
WireEncoder e(0x0200u);
|
||||
e.WriteValue(*v_boolean);
|
||||
auto v_false = Value::MakeBoolean(false);
|
||||
e.WriteValue(*v_false);
|
||||
ASSERT_EQ(nullptr, e.error());
|
||||
ASSERT_EQ(2u, e.size());
|
||||
ASSERT_EQ(llvm::StringRef("\x01\x00", 2),
|
||||
llvm::StringRef(e.data(), e.size()));
|
||||
}
|
||||
|
||||
TEST_F(WireEncoderTest, WriteDoubleValue2) {
|
||||
WireEncoder e(0x0200u);
|
||||
e.WriteValue(*v_double);
|
||||
ASSERT_EQ(nullptr, e.error());
|
||||
ASSERT_EQ(8u, e.size());
|
||||
ASSERT_EQ(llvm::StringRef("\x3f\xf0\x00\x00\x00\x00\x00\x00", 8),
|
||||
llvm::StringRef(e.data(), e.size()));
|
||||
}
|
||||
|
||||
TEST_F(WireEncoderTest, WriteStringValue2) {
|
||||
WireEncoder e(0x0200u);
|
||||
e.WriteValue(*v_string);
|
||||
ASSERT_EQ(nullptr, e.error());
|
||||
ASSERT_EQ(7u, e.size());
|
||||
ASSERT_EQ(llvm::StringRef("\x00\x05hello", 7),
|
||||
llvm::StringRef(e.data(), e.size()));
|
||||
}
|
||||
|
||||
TEST_F(WireEncoderTest, WriteBooleanArrayValue2) {
|
||||
WireEncoder e(0x0200u);
|
||||
e.WriteValue(*v_boolean_array);
|
||||
ASSERT_EQ(nullptr, e.error());
|
||||
ASSERT_EQ(1u+3u, e.size());
|
||||
ASSERT_EQ(llvm::StringRef("\x03\x00\x01\x00", 4),
|
||||
llvm::StringRef(e.data(), e.size()));
|
||||
|
||||
// truncated
|
||||
e.Reset();
|
||||
e.WriteValue(*v_boolean_array_big);
|
||||
ASSERT_EQ(nullptr, e.error());
|
||||
ASSERT_EQ(1u+255u, e.size());
|
||||
ASSERT_EQ(llvm::StringRef("\xff\x00", 2), llvm::StringRef(e.data(), 2));
|
||||
}
|
||||
|
||||
TEST_F(WireEncoderTest, WriteDoubleArrayValue2) {
|
||||
WireEncoder e(0x0200u);
|
||||
e.WriteValue(*v_double_array);
|
||||
ASSERT_EQ(nullptr, e.error());
|
||||
ASSERT_EQ(1u+2u*8u, e.size());
|
||||
ASSERT_EQ(llvm::StringRef("\x02\x3f\xe0\x00\x00\x00\x00\x00\x00"
|
||||
"\x3f\xd0\x00\x00\x00\x00\x00\x00", 17),
|
||||
llvm::StringRef(e.data(), e.size()));
|
||||
|
||||
// truncated
|
||||
e.Reset();
|
||||
e.WriteValue(*v_double_array_big);
|
||||
ASSERT_EQ(nullptr, e.error());
|
||||
ASSERT_EQ(1u+255u*8u, e.size());
|
||||
ASSERT_EQ(llvm::StringRef("\xff\x00", 2), llvm::StringRef(e.data(), 2));
|
||||
}
|
||||
|
||||
TEST_F(WireEncoderTest, WriteStringArrayValue2) {
|
||||
WireEncoder e(0x0200u);
|
||||
e.WriteValue(*v_string_array);
|
||||
ASSERT_EQ(nullptr, e.error());
|
||||
ASSERT_EQ(1u+7u+9u, e.size());
|
||||
ASSERT_EQ(llvm::StringRef("\x02\x00\x05hello\x00\x07goodbye", 17),
|
||||
llvm::StringRef(e.data(), e.size()));
|
||||
|
||||
// truncated
|
||||
e.Reset();
|
||||
e.WriteValue(*v_string_array_big);
|
||||
ASSERT_EQ(nullptr, e.error());
|
||||
ASSERT_EQ(1u+255u*3u, e.size());
|
||||
ASSERT_EQ(llvm::StringRef("\xff\x00\x01", 3), llvm::StringRef(e.data(), 3));
|
||||
}
|
||||
|
||||
TEST_F(WireEncoderTest, WriteValueError2) {
|
||||
WireEncoder e(0x0200u);
|
||||
e.WriteValue(*v_empty); // empty
|
||||
ASSERT_EQ(0u, e.size());
|
||||
ASSERT_NE(nullptr, e.error());
|
||||
|
||||
e.Reset();
|
||||
e.WriteValue(*v_raw); // not supported
|
||||
ASSERT_EQ(0u, e.size());
|
||||
ASSERT_NE(nullptr, e.error());
|
||||
}
|
||||
|
||||
TEST_F(WireEncoderTest, GetValueSize3) {
|
||||
WireEncoder e(0x0300u);
|
||||
EXPECT_EQ(0u, e.GetValueSize(*v_empty)); // empty
|
||||
EXPECT_EQ(1u, e.GetValueSize(*v_boolean));
|
||||
EXPECT_EQ(8u, e.GetValueSize(*v_double));
|
||||
EXPECT_EQ(6u, e.GetValueSize(*v_string));
|
||||
EXPECT_EQ(6u, e.GetValueSize(*v_raw));
|
||||
|
||||
EXPECT_EQ(1u+3u, e.GetValueSize(*v_boolean_array));
|
||||
// truncated
|
||||
EXPECT_EQ(1u+255u, e.GetValueSize(*v_boolean_array_big));
|
||||
|
||||
EXPECT_EQ(1u+2u*8u, e.GetValueSize(*v_double_array));
|
||||
// truncated
|
||||
EXPECT_EQ(1u+255u*8u, e.GetValueSize(*v_double_array_big));
|
||||
|
||||
EXPECT_EQ(1u+6u+8u, e.GetValueSize(*v_string_array));
|
||||
// truncated
|
||||
EXPECT_EQ(1u+255u*2u, e.GetValueSize(*v_string_array_big));
|
||||
}
|
||||
|
||||
TEST_F(WireEncoderTest, WriteBooleanValue3) {
|
||||
WireEncoder e(0x0300u);
|
||||
e.WriteValue(*v_boolean);
|
||||
auto v_false = Value::MakeBoolean(false);
|
||||
e.WriteValue(*v_false);
|
||||
ASSERT_EQ(nullptr, e.error());
|
||||
ASSERT_EQ(2u, e.size());
|
||||
ASSERT_EQ(llvm::StringRef("\x01\x00", 2),
|
||||
llvm::StringRef(e.data(), e.size()));
|
||||
}
|
||||
|
||||
TEST_F(WireEncoderTest, WriteDoubleValue3) {
|
||||
WireEncoder e(0x0300u);
|
||||
e.WriteValue(*v_double);
|
||||
ASSERT_EQ(nullptr, e.error());
|
||||
ASSERT_EQ(8u, e.size());
|
||||
ASSERT_EQ(llvm::StringRef("\x3f\xf0\x00\x00\x00\x00\x00\x00", 8),
|
||||
llvm::StringRef(e.data(), e.size()));
|
||||
}
|
||||
|
||||
TEST_F(WireEncoderTest, WriteStringValue3) {
|
||||
WireEncoder e(0x0300u);
|
||||
e.WriteValue(*v_string);
|
||||
ASSERT_EQ(nullptr, e.error());
|
||||
ASSERT_EQ(6u, e.size());
|
||||
ASSERT_EQ(llvm::StringRef("\x05hello", 6),
|
||||
llvm::StringRef(e.data(), e.size()));
|
||||
}
|
||||
|
||||
TEST_F(WireEncoderTest, WriteRawValue3) {
|
||||
WireEncoder e(0x0300u);
|
||||
e.WriteValue(*v_raw);
|
||||
ASSERT_EQ(nullptr, e.error());
|
||||
ASSERT_EQ(6u, e.size());
|
||||
ASSERT_EQ(llvm::StringRef("\x05hello", 6),
|
||||
llvm::StringRef(e.data(), e.size()));
|
||||
}
|
||||
|
||||
TEST_F(WireEncoderTest, WriteBooleanArrayValue3) {
|
||||
WireEncoder e(0x0300u);
|
||||
e.WriteValue(*v_boolean_array);
|
||||
ASSERT_EQ(nullptr, e.error());
|
||||
ASSERT_EQ(1u+3u, e.size());
|
||||
ASSERT_EQ(llvm::StringRef("\x03\x00\x01\x00", 4),
|
||||
llvm::StringRef(e.data(), e.size()));
|
||||
|
||||
// truncated
|
||||
e.Reset();
|
||||
e.WriteValue(*v_boolean_array_big);
|
||||
ASSERT_EQ(nullptr, e.error());
|
||||
ASSERT_EQ(1u+255u, e.size());
|
||||
ASSERT_EQ(llvm::StringRef("\xff\x00", 2), llvm::StringRef(e.data(), 2));
|
||||
}
|
||||
|
||||
TEST_F(WireEncoderTest, WriteDoubleArrayValue3) {
|
||||
WireEncoder e(0x0300u);
|
||||
e.WriteValue(*v_double_array);
|
||||
ASSERT_EQ(nullptr, e.error());
|
||||
ASSERT_EQ(1u+2u*8u, e.size());
|
||||
ASSERT_EQ(llvm::StringRef("\x02\x3f\xe0\x00\x00\x00\x00\x00\x00"
|
||||
"\x3f\xd0\x00\x00\x00\x00\x00\x00", 17),
|
||||
llvm::StringRef(e.data(), e.size()));
|
||||
|
||||
// truncated
|
||||
e.Reset();
|
||||
e.WriteValue(*v_double_array_big);
|
||||
ASSERT_EQ(nullptr, e.error());
|
||||
ASSERT_EQ(1u+255u*8u, e.size());
|
||||
ASSERT_EQ(llvm::StringRef("\xff\x00", 2), llvm::StringRef(e.data(), 2));
|
||||
}
|
||||
|
||||
TEST_F(WireEncoderTest, WriteStringArrayValue3) {
|
||||
WireEncoder e(0x0300u);
|
||||
e.WriteValue(*v_string_array);
|
||||
ASSERT_EQ(nullptr, e.error());
|
||||
ASSERT_EQ(1u+6u+8u, e.size());
|
||||
ASSERT_EQ(llvm::StringRef("\x02\x05hello\x07goodbye", 15),
|
||||
llvm::StringRef(e.data(), e.size()));
|
||||
|
||||
// truncated
|
||||
e.Reset();
|
||||
e.WriteValue(*v_string_array_big);
|
||||
ASSERT_EQ(nullptr, e.error());
|
||||
ASSERT_EQ(1u+255u*2u, e.size());
|
||||
ASSERT_EQ(llvm::StringRef("\xff\x01", 2), llvm::StringRef(e.data(), 2));
|
||||
}
|
||||
|
||||
TEST_F(WireEncoderTest, WriteValueError3) {
|
||||
WireEncoder e(0x0300u);
|
||||
e.WriteValue(*v_empty); // empty
|
||||
ASSERT_EQ(0u, e.size());
|
||||
ASSERT_NE(nullptr, e.error());
|
||||
}
|
||||
|
||||
TEST_F(WireEncoderTest, GetStringSize2) {
|
||||
// 2-byte length
|
||||
WireEncoder e(0x0200u);
|
||||
EXPECT_EQ(7u, e.GetStringSize(s_normal));
|
||||
EXPECT_EQ(130u, e.GetStringSize(s_long));
|
||||
// truncated
|
||||
EXPECT_EQ(65537u, e.GetStringSize(s_big));
|
||||
}
|
||||
|
||||
TEST_F(WireEncoderTest, WriteString2) {
|
||||
WireEncoder e(0x0200u);
|
||||
e.WriteString(s_normal);
|
||||
EXPECT_EQ(nullptr, e.error());
|
||||
EXPECT_EQ(7u, e.size());
|
||||
EXPECT_EQ(llvm::StringRef("\x00\x05hello", 7),
|
||||
llvm::StringRef(e.data(), e.size()));
|
||||
|
||||
e.Reset();
|
||||
e.WriteString(s_long);
|
||||
EXPECT_EQ(nullptr, e.error());
|
||||
ASSERT_EQ(130u, e.size());
|
||||
EXPECT_EQ(llvm::StringRef("\x00\x80**", 4), llvm::StringRef(e.data(), 4));
|
||||
EXPECT_EQ('*', e.data()[128]);
|
||||
EXPECT_EQ('x', e.data()[129]);
|
||||
|
||||
// truncated
|
||||
e.Reset();
|
||||
e.WriteString(s_big);
|
||||
EXPECT_EQ(nullptr, e.error());
|
||||
ASSERT_EQ(65537u, e.size());
|
||||
EXPECT_EQ(llvm::StringRef("\xff\xff**", 4), llvm::StringRef(e.data(), 4));
|
||||
EXPECT_EQ('*', e.data()[65535]);
|
||||
EXPECT_EQ('x', e.data()[65536]);
|
||||
}
|
||||
|
||||
TEST_F(WireEncoderTest, GetStringSize3) {
|
||||
// leb128-encoded length
|
||||
WireEncoder e(0x0300u);
|
||||
EXPECT_EQ(6u, e.GetStringSize(s_normal));
|
||||
EXPECT_EQ(130u, e.GetStringSize(s_long));
|
||||
EXPECT_EQ(65540u, e.GetStringSize(s_big));
|
||||
}
|
||||
|
||||
TEST_F(WireEncoderTest, WriteString3) {
|
||||
WireEncoder e(0x0300u);
|
||||
e.WriteString(s_normal);
|
||||
EXPECT_EQ(nullptr, e.error());
|
||||
EXPECT_EQ(6u, e.size());
|
||||
EXPECT_EQ(llvm::StringRef("\x05hello", 6),
|
||||
llvm::StringRef(e.data(), e.size()));
|
||||
|
||||
e.Reset();
|
||||
e.WriteString(s_long);
|
||||
EXPECT_EQ(nullptr, e.error());
|
||||
ASSERT_EQ(130u, e.size());
|
||||
EXPECT_EQ(llvm::StringRef("\x80\x01**", 4), llvm::StringRef(e.data(), 4));
|
||||
EXPECT_EQ('*', e.data()[128]);
|
||||
EXPECT_EQ('x', e.data()[129]);
|
||||
|
||||
// NOT truncated
|
||||
e.Reset();
|
||||
e.WriteString(s_big);
|
||||
EXPECT_EQ(nullptr, e.error());
|
||||
ASSERT_EQ(65540u, e.size());
|
||||
EXPECT_EQ(llvm::StringRef("\x81\x80\x04*", 4), llvm::StringRef(e.data(), 4));
|
||||
EXPECT_EQ('*', e.data()[65536]);
|
||||
EXPECT_EQ('x', e.data()[65537]);
|
||||
EXPECT_EQ('x', e.data()[65538]);
|
||||
EXPECT_EQ('x', e.data()[65539]);
|
||||
}
|
||||
|
||||
} // namespace nt
|
||||
24
src/test/native/cpp/main.cpp
Normal file
24
src/test/native/cpp/main.cpp
Normal file
@@ -0,0 +1,24 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2015. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "Log.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
nt::Logger::GetInstance().SetLogger(
|
||||
[](unsigned int level, const char* file, unsigned int line,
|
||||
const char* msg) {
|
||||
std::fputs(msg, stderr);
|
||||
std::fputc('\n', stderr);
|
||||
});
|
||||
nt::Logger::GetInstance().set_min_level(0);
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
int ret = RUN_ALL_TESTS();
|
||||
return ret;
|
||||
}
|
||||
Reference in New Issue
Block a user