2704. To Be Or Not To Be
Problem Description
This problem asks you to implement a testing utility function called expect
that mimics the behavior of assertion libraries commonly used in unit testing frameworks.
The expect
function should:
- Accept any value
val
as input - Return an object containing two methods:
toBe
andnotToBe
The returned object's methods work as follows:
toBe(val)
method:
- Takes another value as parameter
- Compares it with the original value using strict equality (
===
) - Returns
true
if the values are strictly equal - Throws an error with message
"Not Equal"
if the values are not strictly equal
notToBe(val)
method:
- Takes another value as parameter
- Compares it with the original value using strict inequality (
!==
) - Returns
true
if the values are not strictly equal - Throws an error with message
"Equal"
if the values are strictly equal
For example:
expect(5).toBe(5)
returnstrue
because 5 === 5expect(5).toBe(4)
throws error"Not Equal"
because 5 !== 4expect(5).notToBe(4)
returnstrue
because 5 !== 4expect(5).notToBe(5)
throws error"Equal"
because 5 === 5
The implementation uses closures to capture the initial value passed to expect
, allowing the returned methods to access and compare against it when they are called later.
Intuition
The key insight here is recognizing that we need to create a closure - a function that "remembers" the initial value passed to expect
even after expect
has finished executing.
When we call expect(5)
, we need some way for the returned methods (toBe
and notToBe
) to still have access to that value 5
when they're called later. This is a perfect use case for closures in JavaScript/TypeScript.
Think of it like this: when expect(val)
is called, it creates a "box" that stores val
. Then it returns an object with two functions that can look inside this box and compare its contents with whatever new value they receive.
The solution structure naturally follows from the requirements:
- We need to return an object with two methods → so we return an object literal with two function properties
- Each method needs to compare against the original value → so we use the closure to access
val
- Each method needs to either return
true
or throw an error → so we use anif
statement to check the condition and throw if it fails
The strict equality (===
) and inequality (!==
) operators are used because the problem specifically mentions these operators. This means:
expect(5).toBe('5')
would throw "Not Equal" (number vs string)expect(null).toBe(undefined)
would throw "Not Equal" (even though they're both falsy)
The pattern of returning true
after the condition check ensures that if no error is thrown, the method successfully returns a truthy value, which is common behavior in testing assertions.
Solution Approach
The implementation uses a closure pattern with an object literal return structure. Let's walk through the solution step by step:
1. Function Signature and Type Definition:
type ToBeOrNotToBe = {
toBe: (val: any) => boolean;
notToBe: (val: any) => boolean;
};
We define a type that describes the shape of our return object - it contains two methods, each accepting any value and returning a boolean.
2. Main Function Structure:
function expect(val: any): ToBeOrNotToBe {
return {
// methods here
};
}
The expect
function takes any value as input and returns an object matching our type definition.
3. Implementing toBe
Method:
toBe: (toBeVal: any) => {
if (val !== toBeVal) {
throw new Error('Not Equal');
}
return true;
}
- Uses strict inequality (
!==
) to check if values don't match - If they don't match, throws an error with message "Not Equal"
- If they match (the condition is false), returns
true
- The closure allows access to the original
val
parameter
4. Implementing notToBe
Method:
notToBe: (notToBeVal: any) => {
if (val === notToBeVal) {
throw new Error('Equal');
}
return true;
}
- Uses strict equality (
===
) to check if values match - If they match, throws an error with message "Equal"
- If they don't match (the condition is false), returns
true
- Also uses closure to access the original
val
Key Pattern - Closure:
When expect(5)
is called, the value 5
is captured in the closure. The returned object's methods can access this value even after expect
has finished executing. This allows for the chained method calls like expect(5).toBe(5)
.
Error Handling:
The solution uses JavaScript's built-in Error
constructor to throw exceptions with custom messages. This follows standard testing library conventions where failed assertions throw errors rather than returning false.
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through a concrete example to understand how the solution works:
Example: expect(10).toBe(10)
-
First,
expect(10)
is called:- The value
10
is stored in the parameterval
- A new object is created and returned with two methods:
toBe
andnotToBe
- Due to closure, both methods can access
val = 10
even afterexpect
returns
- The value
-
Next,
.toBe(10)
is called on the returned object:- The
toBe
method receivestoBeVal = 10
- It checks: Is
val !== toBeVal
? → Is10 !== 10
? →false
- Since the condition is false, it doesn't throw an error
- It returns
true
- The
Example: expect(10).notToBe(5)
-
First,
expect(10)
is called:- The value
10
is captured in the closure - Returns an object with
toBe
andnotToBe
methods
- The value
-
Next,
.notToBe(5)
is called:- The
notToBe
method receivesnotToBeVal = 5
- It checks: Is
val === notToBeVal
? → Is10 === 5
? →false
- Since the condition is false, it doesn't throw an error
- It returns
true
- The
Example: expect("hello").toBe("world")
(Error case)
-
First,
expect("hello")
is called:- The string
"hello"
is captured in the closure - Returns an object with both methods
- The string
-
Next,
.toBe("world")
is called:- The
toBe
method receivestoBeVal = "world"
- It checks: Is
val !== toBeVal
? → Is"hello" !== "world"
? →true
- Since the condition is true, it throws
Error('Not Equal')
- The function never reaches the
return true
statement
- The
The beauty of this solution is that each call to expect()
creates its own closure with its own captured value, allowing multiple expect statements to work independently:
const checker1 = expect(5); const checker2 = expect(10); checker1.toBe(5); // returns true (5 === 5) checker2.toBe(5); // throws "Not Equal" (10 !== 5)
Solution Implementation
1class ToBeOrNotToBe:
2 """
3 Class that provides methods for equality comparison.
4 Contains two methods for assertion testing.
5 """
6
7 def __init__(self, value):
8 """
9 Initialize the expectation object with a value to compare against.
10
11 Args:
12 value: The value to be compared in assertions
13 """
14 self._value = value
15
16 def toBe(self, expected_value):
17 """
18 Checks if the value is strictly equal to the expected value.
19
20 Args:
21 expected_value: The value to compare against
22
23 Returns:
24 bool: True if values are equal
25
26 Raises:
27 Exception: With message "Not Equal" if values are not equal
28 """
29 if self._value != expected_value:
30 raise Exception("Not Equal")
31 return True
32
33 def notToBe(self, expected_value):
34 """
35 Checks if the value is strictly not equal to the expected value.
36
37 Args:
38 expected_value: The value to compare against
39
40 Returns:
41 bool: True if values are not equal
42
43 Raises:
44 Exception: With message "Equal" if values are equal
45 """
46 if self._value == expected_value:
47 raise Exception("Equal")
48 return True
49
50
51def expect(value):
52 """
53 Creates an expectation object for value comparison.
54
55 Args:
56 value: The value to be compared against in assertions
57
58 Returns:
59 ToBeOrNotToBe: An object with toBe and notToBe methods for assertions
60 """
61 return ToBeOrNotToBe(value)
62
1/**
2 * Interface definition for the return object of expect function
3 * Contains two methods for equality comparison
4 */
5interface ToBeOrNotToBe {
6 boolean toBe(Object val) throws Exception;
7 boolean notToBe(Object val) throws Exception;
8}
9
10/**
11 * Creates an expectation object for value comparison
12 * @param value The value to be compared against
13 * @return An object with toBe and notToBe methods for assertions
14 */
15public static ToBeOrNotToBe expect(final Object value) {
16 return new ToBeOrNotToBe() {
17 /**
18 * Checks if the value is strictly equal to the expected value
19 * @param expectedValue The value to compare against
20 * @return true if values are equal
21 * @throws Exception with message "Not Equal" if values are not equal
22 */
23 @Override
24 public boolean toBe(Object expectedValue) throws Exception {
25 // Use Objects.equals for null-safe comparison
26 if (!java.util.Objects.equals(value, expectedValue)) {
27 throw new Exception("Not Equal");
28 }
29 return true;
30 }
31
32 /**
33 * Checks if the value is strictly not equal to the expected value
34 * @param expectedValue The value to compare against
35 * @return true if values are not equal
36 * @throws Exception with message "Equal" if values are equal
37 */
38 @Override
39 public boolean notToBe(Object expectedValue) throws Exception {
40 // Use Objects.equals for null-safe comparison
41 if (java.util.Objects.equals(value, expectedValue)) {
42 throw new Exception("Equal");
43 }
44 return true;
45 }
46 };
47}
48
1#include <stdexcept>
2#include <string>
3#include <any>
4
5/**
6 * Class that provides methods for equality comparison
7 * Contains two methods: toBe and notToBe for assertions
8 */
9class ToBeOrNotToBe {
10private:
11 std::any value;
12
13public:
14 /**
15 * Constructor that stores the value to be compared
16 * @param val - The value to be compared against in assertions
17 */
18 explicit ToBeOrNotToBe(const std::any& val) : value(val) {}
19
20 /**
21 * Checks if the stored value is equal to the expected value
22 * @param expected_value - The value to compare against
23 * @return true if values are equal
24 * @throws std::runtime_error with message "Not Equal" if values are not equal
25 */
26 bool toBe(const std::any& expected_value) {
27 // Check if types are the same and values are equal
28 if (value.type() != expected_value.type() ||
29 !areEqual(value, expected_value)) {
30 throw std::runtime_error("Not Equal");
31 }
32 return true;
33 }
34
35 /**
36 * Checks if the stored value is not equal to the expected value
37 * @param expected_value - The value to compare against
38 * @return true if values are not equal
39 * @throws std::runtime_error with message "Equal" if values are equal
40 */
41 bool notToBe(const std::any& expected_value) {
42 // Check if types are the same and values are equal
43 if (value.type() == expected_value.type() &&
44 areEqual(value, expected_value)) {
45 throw std::runtime_error("Equal");
46 }
47 return true;
48 }
49
50private:
51 /**
52 * Helper method to compare two std::any values for equality
53 * @param a - First value to compare
54 * @param b - Second value to compare
55 * @return true if values are equal, false otherwise
56 */
57 bool areEqual(const std::any& a, const std::any& b) {
58 // Handle common types for comparison
59 if (a.type() == typeid(int) && b.type() == typeid(int)) {
60 return std::any_cast<int>(a) == std::any_cast<int>(b);
61 }
62 if (a.type() == typeid(double) && b.type() == typeid(double)) {
63 return std::any_cast<double>(a) == std::any_cast<double>(b);
64 }
65 if (a.type() == typeid(std::string) && b.type() == typeid(std::string)) {
66 return std::any_cast<std::string>(a) == std::any_cast<std::string>(b);
67 }
68 if (a.type() == typeid(bool) && b.type() == typeid(bool)) {
69 return std::any_cast<bool>(a) == std::any_cast<bool>(b);
70 }
71 // For other types or empty any, consider them not equal
72 return false;
73 }
74};
75
76/**
77 * Creates an expectation object for value comparison
78 * @param value - The value to be compared against in assertions
79 * @return A ToBeOrNotToBe object with toBe and notToBe methods
80 */
81ToBeOrNotToBe expect(const std::any& value) {
82 return ToBeOrNotToBe(value);
83}
84
1/**
2 * Type definition for the return object of expect function
3 * Contains two methods for equality comparison
4 */
5type ToBeOrNotToBe = {
6 toBe: (val: any) => boolean;
7 notToBe: (val: any) => boolean;
8};
9
10/**
11 * Creates an expectation object for value comparison
12 * @param value - The value to be compared against
13 * @returns An object with toBe and notToBe methods for assertions
14 */
15function expect(value: any): ToBeOrNotToBe {
16 return {
17 /**
18 * Checks if the value is strictly equal to the expected value
19 * @param expectedValue - The value to compare against
20 * @returns true if values are equal
21 * @throws Error with message "Not Equal" if values are not equal
22 */
23 toBe: (expectedValue: any): boolean => {
24 if (value !== expectedValue) {
25 throw new Error("Not Equal");
26 }
27 return true;
28 },
29
30 /**
31 * Checks if the value is strictly not equal to the expected value
32 * @param expectedValue - The value to compare against
33 * @returns true if values are not equal
34 * @throws Error with message "Equal" if values are equal
35 */
36 notToBe: (expectedValue: any): boolean => {
37 if (value === expectedValue) {
38 throw new Error("Equal");
39 }
40 return true;
41 }
42 };
43}
44
Time and Space Complexity
Time Complexity: O(1)
The expect
function performs the following operations:
- Creates and returns an object with two methods (
toBe
andnotToBe
) - Each method performs a single comparison operation (
===
or!==
) - Both comparison operations and the object creation are constant time operations
- Throwing an error is also a constant time operation
Since all operations execute in constant time regardless of input size, the overall time complexity is O(1)
.
Space Complexity: O(1)
The space analysis includes:
- The function stores a single value
val
in its closure - Creates one object with two method properties
- Each method call uses a fixed amount of memory for the parameter (
toBeVal
ornotToBeVal
) - The error objects created when throwing exceptions use constant space
The memory usage does not scale with input size or depend on the value being compared. All allocations are of fixed size, resulting in O(1)
space complexity.
Common Pitfalls
1. Confusion Between Strict and Loose Equality in JavaScript
Pitfall: In JavaScript, developers might accidentally use loose equality (==
) instead of strict equality (===
), which can lead to unexpected behavior with type coercion.
// Problematic implementation
function expect(val) {
return {
toBe: (toBeVal) => {
if (val != toBeVal) { // Using != instead of !==
throw new Error('Not Equal');
}
return true;
}
};
}
// This would incorrectly pass:
expect(5).toBe('5'); // Should throw, but won't with loose equality
expect(null).toBe(undefined); // Should throw, but won't with loose equality
Solution: Always use strict equality operators (===
and !==
) to ensure type-safe comparisons:
if (val !== toBeVal) { // Correct: strict inequality
throw new Error('Not Equal');
}
2. Incorrect Error Messages or Wrong Error Types
Pitfall: Using incorrect error messages or throwing the wrong type of error can break test suites that depend on specific error messages.
// Incorrect implementations
toBe: (toBeVal) => {
if (val !== toBeVal) {
throw new Error('Values are not equal'); // Wrong message
// or
throw 'Not Equal'; // Wrong: throwing string instead of Error object
// or
return false; // Wrong: should throw, not return false
}
}
Solution: Ensure exact error messages and proper Error objects:
throw new Error('Not Equal'); // Exact message with Error object
throw new Error('Equal'); // For notToBe method
3. Missing Closure or Incorrect Scope Management
Pitfall: Attempting to access the initial value incorrectly, especially when trying to use this
context or global variables.
// Incorrect attempt using this
function expect(val) {
this.val = val; // Won't work as expected
return {
toBe: (toBeVal) => {
if (this.val !== toBeVal) { // this.val is undefined
throw new Error('Not Equal');
}
}
};
}
Solution: Properly utilize closure to capture the initial value:
function expect(val) { // val is captured in closure
return {
toBe: (toBeVal) => {
if (val !== toBeVal) { // Correctly accesses closed-over val
throw new Error('Not Equal');
}
return true;
}
};
}
4. Handling Special JavaScript Values Incorrectly
Pitfall: Not considering JavaScript's special cases like NaN
, which has unique equality behavior.
expect(NaN).toBe(NaN); // Will throw "Not Equal" because NaN !== NaN in JavaScript expect(0).toBe(-0); // Will pass because 0 === -0 in JavaScript
Solution: Document this behavior or add special handling if needed:
toBe: (toBeVal) => {
// Optional: Handle NaN case explicitly
if (Number.isNaN(val) && Number.isNaN(toBeVal)) {
return true;
}
if (val !== toBeVal) {
throw new Error('Not Equal');
}
return true;
}
5. Python-Specific: Using is
Instead of ==
Pitfall: In Python, using is
for comparison checks object identity rather than value equality.
def toBe(self, expected_value):
if self._value is not expected_value: # Wrong: checks identity, not equality
raise Exception("Not Equal")
return True
# This would fail incorrectly:
expect(1000).toBe(1000) # Might throw even though values are equal
expect([1, 2]).toBe([1, 2]) # Will throw because different list objects
Solution: Use ==
and !=
for value comparison in Python:
if self._value != expected_value: # Correct: checks value equality raise Exception("Not Equal")
Which of the following array represent a max heap?
Recommended Readings
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask
Runtime Overview When learning about algorithms and data structures you'll frequently encounter the term time complexity This concept is fundamental in computer science and offers insights into how long an algorithm takes to complete given a certain input size What is Time Complexity Time complexity represents the amount of time
Want a Structured Path to Master System Design Too? Don’t Miss This!