I've been fumbling around with this issue for what has seemed like weeks,
and I cannot get the issue resolved.
I spent days trying to get to where I can be able to call the actual function outside of the original .js file.
All I want to be able to do in node.js is create a function that will be able to generate a random number within a specific parameters such as (1-10 or 1-100), and relay it back to the console or a variable specified by the user.
This is the current code that I have:
server.js
var myModule = require("./my_module.js");
console.log("your random number is" + myModule.hello(10)); //<-- the 10 represents the TOP number that will generate, if you look in the proceeding file, it adds a 1 to it as required by the code
my_module.js
function hello(foo) {
return Math.floor((Math.random()*foo)+1);
}
module.exports.hello = hello;
The issue that underlines here is i get a NaN, ( not a number ) from the console.
I realize that this means somewhere in translation, the number may be turning into a string and not being able to be read by the mathFloor string.
You can use the jQuery method isNumeric to validate whether they gave you a number. http://api.jquery.com/jQuery.isNumeric/
To make sure it is still a number and you didn't inadvertently make it a string, use parseInt() or parseFloat().
function hello(foo) {
return Math.floor((Math.random()*parseInt(foo))+1);
}
While Erik's answer solves the problem, it won't tell you where the string is coming from. You can use console.trace to make your debugging life easier.
function hello(foo) {
var result = Math.floor((Math.random()*parseInt(foo))+1);
if (isNaN(result)) {
console.trace("result is NaN")
}
return result;
}
> hello("a")
Trace: NaN
at hello (repl:4:9)
at repl:1:2
at REPLServer.self.eval (repl.js:109:21)
at Interface.<anonymous> (repl.js:248:12)
at Interface.EventEmitter.emit (events.js:96:17)
at Interface._onLine (readline.js:200:10)
at Interface._line (readline.js:518:8)
at Interface._ttyWrite (readline.js:736:14)
at ReadStream.onkeypress (readline.js:97:10)
at ReadStream.EventEmitter.emit (events.js:126:20)
at emitKey (readline.js:1058:12)
at ReadStream.onData (readline.js:807:7)
NaN
>
By looking at the stack trace you will be able to find the code that provided a non-Number parameter.
Related
I'm trying unit testing for the first time with Jest on a personal project, and some of my tests failed even though the data received was the exact same as expected, here's an example:
test("decrypt method works correctly", () =>{
const myAES = new rijndael("", "0bdfa595235c307a105d593fb78fbb13", { key: "SOME 128 BIT KEY", bits: 128, rounds: 9 })
expect(myAES.decrypt()).toStrictEqual({
"c": "0bdfa595235c307a105d593fb78fbb13",
"p": "ATTACK AT DAWN!",
"errors": []
})
}
So then I tried to check if it's a problem with Jest or my code:
const r = myAES.decrypt()
console.log(typeof r.p) // string
console.log(r.p === "ATTACK AT DAWN!") // false
Which just made me even more confused as the strings look the same. The code that I'm testing is an AES encryption function (Don't worry it's just a personal project for fun won't be used in production) that processes text as nodeJS Buffers, and in the end uses the toString() method to convert it back to a string. I'm thinking that may be why I'm having issues, but can't seem to find exactly why. Would love it if someone could point me in the right direction so I can get rid of this error. Thank you in advance.
P.S. I'll save everyone the pain of reading my AES implementation for now as I don't think it's a problem with the encryption but let me know if that's necessary
Ok, so turns out it was a stupid mistake where I overlooked the series of null bytes that tend to end up in the end of the buffer after decryption. While toString() will turn the buffer into the string I want the computer will not recognise it as the same string. So all I had to do was strip the null bytes that follow. Assuming that the null bytes should only appear at the end of the string as they normally do:
const i = buffer.indexOf(0x00)
const result = buffer.slice(0, i).toString() //solves the problem
TypeScript does not produce any errors for the following code:
const maybe_a_string: undefined | string = undefined;
const false_or_string: false | string = false;
// I'd like the following to produce an error/warning...
const message_string = `Some readable string info should be here: ${maybe_a_string} ${false_or_string}`;
Is there some kind of setting I can turn on, or simple alternative ways to write the last line that will warn me about trying to use non-string variables inside strings like this? (but without needing to add extra lines of code for every sub-string to be asserted individually)
I guess it treats them as fine because some types like bools, numbers and misc objects have a .toString() method...
But especially in the case of undefined (which actually doesn't have a .toString() method) - it's quite common for you to have a bug there, as the only time you really want to see the string "undefined" inside another string is for debugging purposes. But there's a lot of these bugs out there in the wild where end users are seeing stuff like "hello undefined" unintentionally.
Personally I would handle this by making the string template into a function. That way you can specify that the arguments must be strings.
const createMessageString = (first: string, second: string): string => {
return `Some readable string info should be here: ${first} ${second}`;
}
const message_string = createMessageString( maybe_a_string, false_or_string );
// will give an error unless types are refined
Vote for https://github.com/microsoft/TypeScript/issues/30239 [Restrict template literal interpolation expressions to strings]
Additionally, you can try workarounds from the issue comments.
When setting a large number as the value for a Range (cell), the number that is written to the spreadsheet is different than the original number. E.g.
If I set 42300000000, the number in excel becomes -649672960. This doesn't happen with smaller numbers
I tested it with the basic project sample from Visual Studio. Just replaced the original loadSampleData function with:
function loadSampleData() {
var values = [
[4230, 42300, 423000],
[4230000, 42300000, 423000000],
[4230000000, 42300000000, 423000000000]
];
// Run a batch operation against the Excel object model
Excel.run(function (ctx) {
// Create a proxy object for the active sheet
var sheet = ctx.workbook.worksheets.getActiveWorksheet();
// Queue a command to write the sample data to the worksheet
sheet.getRange("B3:D5").values = values;
// Run the queued-up commands, and return a promise to indicate task completion
return ctx.sync();
})
.catch(errorHandler);
}
When I run the add-in, I get this in Excel:
4230 42300 423000
4230000 42300000 423000000
-64967296 -649672960 2093204992
Is this some kind of overflow? Am I doing something wrong?
Thanks!
Thanks for reporting this bug.
The problem seems to be in the JSON parser that we are using to deserialize the incoming request. It incorrectly assumes that any integer number fits in int32_t. The correct behavior would be to parse such large values as double despite of the fact that they are integers.
Since this isn't Excel code, a fix may take a long time.
Unfortunately, appending .0 or E0 at the end of these literals, doesn't drive the parser to parse these literals as double. As Charles Williams pointed out, enclosing the literals in single or double quotes serves your purpose [for some unknown reason].
I haven't been able to find a more deterministic work around. Other suggestions will be welcome.
Zlatko
When I explore this bug I get the following results
9876543210 and 9876543210.0 give 1286608618 - fail
9876543210.9 gives 9876543210.9 - works
'9876543210' and "9876543210" - do not result in a string (I would consider that a bug but maybe this is just a JS type confusion nasty) but give
9876543210 as a number (so a possible hack bypass to the original bug)
"'9876543210" gives '9876543210 which excel recognises as a string -
correct
using the following code with 1704.8017.1000
async function setValue() {
try {
await Excel.run(async (context) => {
let sheet = context.workbook.worksheets.getActiveWorksheet();
let range = sheet.getRange("C3");
range.values = [[ 9876543210.0 ]];
range.format.autofitColumns();
await context.sync();
});
console.log("Done!");
}
catch (error) {
OfficeHelpers.Utilities.log(error);
}
}
I have no idea how to check for this. My method(if condition in method) should only work (execute) if the first argument passed in is a string. I know how to check other types, but I can't seem to find anything for checking for a string.
For a hash I would do something like;
if(ref eq 'HASH') {...}
If someone could provide a simple example I'm sure I would be able to apply it to what I'm doing. I will put up the code for the method and an explanation for the whole operational details of the method if needed.
Added Information
This is a method for handling different types of errors in the software, here are the 3 possible input formats:
$class->new("error string message")
$class->new("error string message", code => "UNABLE_TO_PING_SWITCH_ERROR")
$class->new("error string message", code => "UNABLE_TO_PING_SWITCH_ERROR", switch_ip => $ip3, timeout => $timeout)
There will always be an error message string first.
With the 1st case there is also a hashref to an error hash structure that is located in a library,
this method new will go into a template processing if the word "code" exists as an arg. where the longer detailed error message is constructed. (I already have the logic for this).
But I have to add logic so that the error message string is added to the hash, so the output is one hash, and not strings.
The second case is very similar to the first, where there are parameters eg. switch_ip , which are inserted into the string using a similar template processing logic, (already have this too).
So I think the first and second cases can be handled in the same way, but I'm not sure, so separated them in this question.
The last case is just can error message string by itself, which at the minute I just insert it into a one key message hash { message => "error string}.
So after all that how should I be checking or dividing up these error cases, At the minute my idea for the ones with code , is to dump the arguments into a hash and just use something like:
if(exists($param{code}) { doTemplateProcess()...}
I need to ensure that there is a string passed in first though. Which was my original question. Does any of my context information help? I hope I didn't go off the topic of my question, if so I'll open this a new question. Thanks.
Error hash - located in Type.pm
use constant ERROR_CODE => {
UNABLE_TO_PING_SWITCH_ERROR => {
category => 'Connection Error:',
template => 'Could not ping switch %s in %s minutes',
tt => {template => 'disabled'},
fatal => 1,
wiki_page => www.error-solution.com/,
},
}
From comments:
These will be called in the software's code like so
ASC::Builder::Error->new(
"Phase x this occured because y was happening:",
code => UNABLE_TO_PING_SWITCH_ERROR,
switch_ip => $ip3,
timeout => 30,
);
Putting the wisdom of your particular problem aside and channeling Jeff Foxworthy:
If you have a scalar and it's not a reference, you might have a string.
If your non-reference scalar doesn't look like a number, it might be a string.
If your non-reference scalar looks like a number, it can still be a string.
If your non-reference scalar has a different string and number value, it might be a dualvar.
You know that your argument list is just that: a list. A list is a collection of scalar values. A scalar can be a reference or not a reference. I think you're looking for the not a reference case:
die "You can't do that" if ref $first_argument;
Past that, you'd have to do fancier things to determine if it's the sort of value that you want. This might also mean that you reject objects that pretend to be strings through overloading and whatnot.
Perhaps you can make the first argument part of the key-value pairs that you pass. You can then access that key to extract the value and delete it before you use the remaining pairs.
You may easily check only whether the error string is a simple scalar value or a reference. You would do that with ref, but you must consider what you want to do if the first parameter isn't a string
You should write your constructor in the ASC::Builder::Error package along these lines
sub new {
my $class = shift;
my ($error, %options) = #_;
die if ref $error;
bless { string => $error }, $class;
}
This example simply dies, and so kills the program, if it is called with anything other than a simple string or number as the first parameter
You may call it as
ASC::Builder::Error->new('error')
or
ASC::Builder::Error->new(42)
and all will be well. If you try
ASC::Builder::Error->new('message', 'code')
then you will see a warning
Odd number of elements in hash assignment
And you may make that warning fatal
If there is anything more then you should explain
Supporting all of the following is simple:
$class->new("s")
$class->new("s", code => "s")
$class->new("s", code => "s", switch_ip => "s", timeout => "s")
All you need is the following:
sub new {
my ($class, $msg, %opts) = #_;
...
}
You can checks such as the following to examine what the called provided:
if (exists($opts{code}))
if (defined($opts{code}))
if ($opts{code})
Despite saying that the string will always be provided, you now ask how to check if was provided. As such, you are probably trying to perform validation rather than polymorphism. You shouldn't waste your time doing this.
Let's look at the hash reference example you gave. ref($arg) eq 'HASH' is wrong. That returns false for some hash references, and it returns false for some things that act like a reference to a hash. The following is a more proper check:
eval { %$arg; 1 }
The equivalent for strings would be the following:
eval { "$arg"; 1 }
Unfortunately, it will always return true! Every value can act as a string. That means the best thing you can do is simply to check if any argument is provided.
use Carp qw( croak );
croak("usage") if !#_;
It's rare for Perl subs to perform argument validation. Not only is it tricky, it's also expensive. It also provides very little benefits. Bad or missing arguments usually results in exceptions or warnings shortly after.
You might see suggestions to use croak("usage") if ref($arg); (or worse, die if ref($arg);), but keep in mind that those will cause the rejection of perfectly fine objects that overload stringification (which is somewhat common), and they will fail to detect the problem with ASC::Builder::Error->new(code => ...) because code produces a string. Again, performing type-based argument validation is an expensive and buggy practice in Perl.
I've got a few methods which set the text within a text file.
I've set-up my jasmine tests to create the files with wrong values before I run my tests.
var gpioPath = 'tests/gpio-test/class/gpio';
//setup the filesystem with the exports path
fs.outputFileSync(gpioPath+'/export',0);
for(var i=0;i<6;i++){
fs.outputFileSync(gpioPath+i+'/value',2,'utf-8');
fs.outputFileSync(gpioPath+i+'/direction','none','utf-8');
}
Then, I run the methods which update the values in the files, and then I check that the files now have the correct values.
expect(fs.readFileSync(gpioPath+'/export','utf-8')).toBeGreaterThan(0);
var pin1d = fs.readFileSync(gpioPath+'1/direction','utf-8');
var pin1v = fs.readFileSync(gpioPath+'1/value','utf-8');
expect(pin1d).toBe('out');
expect(pin1v).toBe(0);
For some reason, these tests are all failing. I get
'0' expected to be greater than '0'
But when I look in the file, I have a value of 6.
I've tried putting a waits before running the test, just in case the files hadn't been changed yet, but even with a 10 second wait this is still failing.
I don't get any errors from the fileWrite method, which is what is updating the data, and as I've said, I can see that the file is updated, so why don't my tests reflect this?
fs.readFileSync(gpioPath+'/export','utf-8') will return a string, so you are essentially doing if (0 > '0'), which is false.
if you need to test numbers, you need to parse it as a number:
expect(parseInt(fs.readFileSync(gpioPath+'/export','utf-8'), 10))
.toBeGreaterThan(0);
This is assuming the file contains an ascii zero, and not a null byte.